/* =========================================================================
   RANGMANCH — velvet auditorium, brass marquee, ticket-stub cards
   Palette:  ink #14090E · velvet #241019 · curtain #7A2436
             brass #C9A24B · ivory #F3E9D6 · smoke #A08D82
   ========================================================================= */

:root {
  --ink: #14090e;
  --ink-deep: #0d0509;
  --velvet: #241019;
  --velvet-raised: #2e141f;
  --curtain: #7a2436;
  --curtain-deep: #571522;
  --brass: #c9a24b;
  --brass-bright: #e8cd8a;
  --ivory: #f3e9d6;
  --smoke: #a68f80;
  --line: rgba(201, 162, 75, 0.22);
  --line-soft: rgba(201, 162, 75, 0.12);
  --danger: #d4634f;
  --ok: #7fae7a;
  --display: "Fraunces", Georgia, serif;
  --body: "Archivo", system-ui, sans-serif;
  --mono: "Spline Sans Mono", ui-monospace, monospace;
  --radius: 10px;
  --shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  background:
    radial-gradient(1100px 600px at 50% -10%, rgba(201, 162, 75, 0.07), transparent 60%),
    radial-gradient(900px 700px at 85% 110%, rgba(122, 36, 54, 0.22), transparent 60%),
    var(--ink);
  color: var(--ivory);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--curtain); color: var(--ivory); }

button { font-family: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }

a { color: var(--brass-bright); }

/* ---------- shared bits ------------------------------------------------- */

.eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--brass);
}

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 18px;
  background: linear-gradient(180deg, var(--brass-bright), var(--brass));
  color: #2a1a06;
  border: none; border-radius: 999px;
  font-weight: 600; font-size: 13.5px; letter-spacing: 0.02em;
  transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s;
  box-shadow: 0 2px 14px rgba(201, 162, 75, 0.25);
}
.btn:hover { transform: translateY(-1px); filter: brightness(1.05); }
.btn:active { transform: translateY(0); }

.btn.ghost {
  background: transparent; color: var(--ivory);
  border: 1px solid var(--line);
  box-shadow: none;
}
.btn.ghost:hover { border-color: var(--brass); color: var(--brass-bright); }

.btn.danger {
  background: transparent; color: var(--danger);
  border: 1px solid rgba(212, 99, 79, 0.4); box-shadow: none;
}
.btn.danger:hover { background: rgba(212, 99, 79, 0.12); }

.btn.small { padding: 5px 12px; font-size: 12px; }

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

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

.field { margin-bottom: 16px; }
.field label {
  display: block; margin-bottom: 6px;
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--smoke);
}
.field input[type="text"], .field input[type="email"], .field input[type="password"],
.field input[type="date"], .field input[type="time"], .field input[type="number"],
.field input[type="url"], .field select, .field textarea {
  width: 100%; padding: 10px 12px;
  background: var(--ink-deep);
  border: 1px solid var(--line-soft);
  border-radius: 8px; color: var(--ivory);
  transition: border-color 0.15s;
}
.field textarea { min-height: 92px; resize: vertical; line-height: 1.6; }

/* The dropdown POPUP is drawn by the operating system, and it does not inherit
   the page's background — only the colour. A pale --ivory on the OS's own pale
   list made the options nearly invisible. Naming both halves fixes it in every
   theme, since --ink-deep and --ivory are always a matched pair (a light theme
   like Nukkad Beat flips both together). */
select option, select optgroup {
  background: var(--ink-deep);
  color: var(--ivory);
}
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--brass); outline: none;
}
.field .hint { margin-top: 4px; font-size: 12px; color: var(--smoke); }

/* tag chips input */
.chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 8px; background: var(--ink-deep);
  border: 1px solid var(--line-soft); border-radius: 8px;
}
.chips input {
  flex: 1; min-width: 120px; background: transparent; border: none; outline: none;
  padding: 4px; color: var(--ivory);
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  background: var(--velvet-raised);
  border: 1px solid var(--line);
  font-size: 12.5px; color: var(--ivory);
  white-space: nowrap;
}
.chip button {
  background: none; border: none; color: var(--smoke);
  font-size: 14px; line-height: 1; padding: 0;
}
.chip button:hover { color: var(--danger); }
.chip.label-chip { background: rgba(122, 36, 54, 0.35); border-color: rgba(122, 36, 54, 0.7); }
/* "Inserted" is a system stamp, not a role/custom label — hollow, dashed, brass, mono. */
.chip.inserted-chip {
  background: transparent !important;
  border: 1px dashed var(--brass) !important;
  color: var(--brass) !important;
  font-family: var(--mono);
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.12em;
  font-weight: 500 !important;
}
.chip.inserted-chip button { color: var(--brass); }
.chip.inserted-chip.filter-on { background: rgba(201, 162, 75, 0.16) !important; color: var(--brass-bright, var(--brass)) !important; }
.chip.filter-on { background: var(--curtain); border-color: var(--brass); }

/* Supporting Crew (crewPairs) rows on the play form: Name : Skill, with a remove ✕. */
.crewpairs-items { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.crewpair-row { display: flex; align-items: center; gap: 8px; }
.crewpair-row .cp-name,
.crewpair-row .cp-skill {
  flex: 1; min-width: 0; background: var(--ink-deep);
  border: 1px solid var(--line-soft); border-radius: 8px;
  padding: 8px; color: var(--ivory); outline: none;
}
.crewpair-row .cp-name:focus,
.crewpair-row .cp-skill:focus { border-color: var(--brass); }
.crewpair-row .cp-colon { color: var(--smoke); font-weight: 700; }
.crewpair-row .cp-remove { flex: 0 0 auto; }

/* star ratings */
.stars { display: inline-flex; gap: 3px; }
.stars button {
  background: none; border: none; font-size: 19px; color: rgba(201, 162, 75, 0.25);
  padding: 0 1px; transition: color 0.1s, transform 0.1s;
}
.stars button.on { color: var(--brass-bright); }
.stars button:hover { transform: scale(1.15); }
.stars.readonly button { cursor: default; font-size: 15px; }
.stars.readonly button:hover { transform: none; }
.rating-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 0; border-bottom: 1px dashed var(--line-soft); }
.rating-row:last-child { border-bottom: none; }
.rating-row span { font-size: 13px; color: var(--smoke); }

/* ---------- login stage --------------------------------------------------- */

.stage {
  min-height: 100vh;
  display: grid; place-items: center;
  position: relative; overflow: hidden;
  background:
    radial-gradient(ellipse 60% 45% at 50% 0%, rgba(232, 205, 138, 0.13), transparent 70%),
    linear-gradient(180deg, #1b0c12 0%, var(--ink) 55%, #0a0407 100%);
}
/* velvet curtains */
.stage::before, .stage::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 26vw;
  background:
    repeating-linear-gradient(90deg,
      var(--curtain-deep) 0 22px,
      var(--curtain) 22px 46px,
      #8d2b40 46px 52px,
      var(--curtain) 52px 74px);
  filter: brightness(0.9);
  box-shadow: inset 0 0 90px rgba(0, 0, 0, 0.75);
}
.stage::before { left: 0; border-right: 3px solid rgba(201, 162, 75, 0.35); transform: skewX(-1deg); }
.stage::after { right: 0; border-left: 3px solid rgba(201, 162, 75, 0.35); transform: skewX(1deg); }

.marquee { text-align: center; margin-bottom: 30px; animation: rise 0.8s ease both; }
.marquee .rule {
  display: flex; align-items: center; gap: 14px; justify-content: center;
  color: var(--brass); margin: 10px 0;
}
.marquee .rule::before, .marquee .rule::after {
  content: ""; height: 1px; width: 70px;
  background: linear-gradient(90deg, transparent, var(--brass));
}
.marquee .rule::after { background: linear-gradient(90deg, var(--brass), transparent); }
.marquee h1 {
  font-family: var(--display);
  font-size: clamp(44px, 7vw, 76px);
  font-weight: 500; letter-spacing: 0.04em;
  color: var(--ivory);
  text-shadow: 0 0 40px rgba(232, 205, 138, 0.35);
}
.marquee h1 em { font-style: italic; color: var(--brass-bright); }
.marquee p { color: var(--smoke); font-size: 14px; margin-top: 6px; }

/* the ADMIT ONE ticket */
.ticket-login {
  position: relative; width: min(420px, 92vw);
  background: linear-gradient(180deg, #2f1520, var(--velvet));
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 30px 34px 26px;
  box-shadow: var(--shadow);
  animation: rise 0.8s 0.15s ease both;
}
.ticket-login::before, .ticket-login::after {
  content: ""; position: absolute; width: 26px; height: 26px; border-radius: 50%;
  background: var(--ink); border: 1px solid var(--line);
  top: 50%; transform: translateY(-50%);
}
.ticket-login::before { left: -14px; }
.ticket-login::after { right: -14px; }
.ticket-login .admit {
  text-align: center; margin-bottom: 18px;
  border-bottom: 1px dashed var(--line); padding-bottom: 14px;
}
.ticket-login .admit .eyebrow { font-size: 12px; letter-spacing: 0.4em; }
.ticket-login .btn { width: 100%; justify-content: center; margin-top: 6px; }
.ticket-login .foot { text-align: center; margin-top: 14px; font-size: 12px; color: var(--smoke); }
.ticket-login .error {
  margin: 6px 0 10px; padding: 8px 12px; border-radius: 8px;
  background: rgba(212, 99, 79, 0.13); border: 1px solid rgba(212, 99, 79, 0.4);
  color: #eba193; font-size: 13px;
}

@keyframes rise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* ---------- portal shell --------------------------------------------------- */

.masthead {
  position: sticky; top: 0; z-index: 40;
  background: rgba(13, 5, 9, 0.88);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line-soft);
}
.masthead-inner {
  max-width: 1280px; margin: 0 auto; padding: 14px 28px 0;
  display: flex; align-items: center; gap: 20px;
}
.brand { display: flex; align-items: baseline; gap: 12px; }
.brand h1 {
  font-family: var(--display); font-size: 24px; font-weight: 500;
  letter-spacing: 0.03em; color: var(--ivory);
}
.brand h1 em { color: var(--brass-bright); font-style: italic; }
.brand-logo { display: flex; flex-direction: column; align-items: flex-end; }
.brand .version {
  font-style: italic; font-size: 10.5px; font-weight: 400; line-height: 1;
  color: var(--smoke); letter-spacing: 0.03em; margin-top: 1px;
  display: inline-flex; align-items: baseline; gap: 5px;
}
/* The release-line name ("Sakura" for all of v7.x) rides to the RIGHT of the
   number. Brass rather than smoke, and upright rather than italic, so the two
   read as a pair without the name being mistaken for part of the number. */
.brand .version-name {
  font-style: normal; font-weight: 500; font-size: 9.5px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--brass);
}
.brand .eyebrow { display: none; }
@media (min-width: 900px) { .brand .eyebrow { display: inline; } }

.search-wrap { flex: 1; display: flex; gap: 10px; align-items: center; max-width: 520px; margin-left: auto; }
.search-wrap input {
  flex: 1; padding: 9px 16px;
  background: var(--ink-deep); border: 1px solid var(--line-soft);
  border-radius: 999px; color: var(--ivory);
}
.search-wrap input:focus { border-color: var(--brass); outline: none; }

/* The account cluster and the brand both host drop-downs. Those menus must
   out-rank the masthead's own decoration — every theme paints a marquee or a
   bunting strip on .masthead::before/::after at z-index 41, and because those
   pseudo-elements come after the menu in paint order, an equal or lower menu
   loses the tie and ends up behind a curtain of bulbs with its buttons
   unclickable. Lifting the HOST (not just the menu) creates a stacking context
   above 41, so the whole drawer — and its hit area — sits clear of the decor.
   See .menu / .theme-menu, which stay at 60 INSIDE this raised host. */
.account, .masthead .brand { position: relative; z-index: 50; }
.account > button {
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--curtain); color: var(--ivory);
  border: 1px solid var(--line);
  font-family: var(--display); font-size: 16px;
}
.menu {
  position: absolute; right: 0; top: 48px; min-width: 230px;
  background: var(--velvet-raised); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 8px; z-index: 60;
}
.menu .who { padding: 8px 12px; border-bottom: 1px solid var(--line-soft); margin-bottom: 6px; }
.menu .who strong { display: block; font-family: var(--display); font-size: 16px; }
.menu .who span { font-size: 12px; color: var(--smoke); }
.menu button.item {
  display: block; width: 100%; text-align: left;
  padding: 9px 12px; background: none; border: none;
  color: var(--ivory); border-radius: 6px; font-size: 13.5px;
}
.menu button.item:hover { background: rgba(201, 162, 75, 0.1); color: var(--brass-bright); }

/* tab strip — the playbill index */
/* A single horizontal bar that slides. However many tabs future builds add, the
   labels keep their natural size and the row scrolls sideways instead of shrinking.
   Affordances (all driven by .can-left / .can-right, toggled in syncTabScroll):
     · soft gradient fades at whichever edge has hidden tabs
     · ‹ › nudge buttons that appear only when there's somewhere to scroll
     · the active tab is always scrolled into view
   Touch swipe (mobile) and shift/trackpad wheel (desktop) work natively too. */
.tabs {
  position: relative;
  max-width: 1280px; margin: 10px auto 0; padding: 0 28px;
  display: flex; align-items: stretch;
}
.tabs-scroll {
  display: flex; gap: 4px; flex: 1 1 auto; min-width: 0;
  overflow-x: auto; scroll-behavior: smooth;
  scrollbar-width: none; -ms-overflow-style: none;
}
.tabs-scroll::-webkit-scrollbar { height: 0; display: none; }
.tabs::before, .tabs::after {
  content: ""; position: absolute; top: 0; bottom: 4px; width: 40px;
  pointer-events: none; opacity: 0; transition: opacity 0.22s; z-index: 2;
}
.tabs::before { left: 28px;  background: linear-gradient(to right, var(--ink), transparent); }
.tabs::after  { right: 28px; background: linear-gradient(to left,  var(--ink), transparent); }
.tabs.can-left::before  { opacity: 1; }
.tabs.can-right::after  { opacity: 1; }
.tab-arrow {
  flex: 0 0 auto; width: 24px; align-self: stretch; padding: 0;
  background: none; border: none; cursor: pointer; z-index: 3;
  color: var(--smoke); font-size: 19px; line-height: 1;
  display: none; align-items: center; justify-content: center;
  transition: color 0.15s;
}
.tab-arrow:hover { color: var(--brass-bright); }
.tabs.can-left  .tab-arrow[data-scroll="-1"] { display: flex; }
.tabs.can-right .tab-arrow[data-scroll="1"]  { display: flex; }
.tabs button {
  padding: 11px 18px 13px;
  background: none; border: none;
  color: var(--smoke); font-size: 13.5px; font-weight: 500;
  letter-spacing: 0.04em; white-space: nowrap;
  border-bottom: 2px solid transparent;
  transition: color 0.15s, border-color 0.15s;
}
.tabs button:hover { color: var(--ivory); }
.tabs button.on { color: var(--brass-bright); border-bottom-color: var(--brass); }
.tabs button .count { font-family: var(--mono); font-size: 10px; color: var(--smoke); margin-left: 6px; }

/* content area */
.content { max-width: 1280px; margin: 0 auto; padding: 26px 28px 90px; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; margin-bottom: 20px; flex-wrap: wrap;
}
.section-head h2 {
  font-family: var(--display); font-weight: 500;
  font-size: clamp(26px, 4vw, 38px); letter-spacing: 0.01em;
}
.section-head .sub { color: var(--smoke); font-size: 13.5px; margin-top: 2px; }

/* Sort dropdown that sits beside "+ New …" on every tab */
.head-tools { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.sort-control { display: flex; flex-direction: column; gap: 4px; }
.sort-control .eyebrow { margin: 0; }
.sort-control select {
  background: var(--ink-deep); color: var(--ivory);
  border: 1px solid var(--line); border-radius: 8px;
  padding: 7px 10px; font-size: 13px; font-family: inherit;
  cursor: pointer; outline: none;
  transition: border-color 0.15s;
}
.sort-control select:hover, .sort-control select:focus { border-color: var(--brass); }

/* Per-tab search box (Acts 1–8), sitting beside Sort in the section head */
.tab-search-control { display: flex; flex-direction: column; gap: 4px; }
.tab-search-control .eyebrow { margin: 0; }
.tab-search-control input {
  background: var(--ink-deep); color: var(--ivory);
  border: 1px solid var(--line); border-radius: 8px;
  padding: 7px 12px; font-size: 13px; font-family: inherit;
  min-width: 230px; outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.tab-search-control input:focus { border-color: var(--brass); box-shadow: 0 0 0 3px rgba(201, 162, 75, 0.12); }
.tab-search-control input::placeholder { color: var(--smoke); }

/* Cast chips that can be dragged between Actors ↔ Revolving Cast on a play */
.chips .draggable-chip { cursor: grab; }
.chips .draggable-chip:active { cursor: grabbing; }
.chips .draggable-chip.dragging { opacity: 0.45; }
.chips.drop-ok {
  outline: 1.5px dashed var(--brass);
  outline-offset: 2px;
  background: rgba(201, 162, 75, 0.07);
}

/* Data tab · single-parameter bulk update from Excel/CSV */
.param-update-row { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; margin: 12px 0 4px; }
.param-update-row label {
  display: flex; flex-direction: column; gap: 5px;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--smoke);
}
.param-update-row select {
  background: var(--ink-deep); color: var(--ivory);
  border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 10px; font-size: 13.5px; font-family: var(--body, inherit);
  letter-spacing: normal; text-transform: none; min-width: 180px;
  cursor: pointer; outline: none; transition: border-color 0.15s;
}
.param-update-row select:hover, .param-update-row select:focus { border-color: var(--brass); }
.param-update-row input[type="number"] {
  background: var(--ink-deep); color: var(--ivory);
  border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 10px; font-size: 13.5px; font-family: var(--body, inherit);
  letter-spacing: normal; width: 76px; outline: none; transition: border-color 0.15s;
}
.param-update-row input[type="number"]:hover, .param-update-row input[type="number"]:focus { border-color: var(--brass); }
#paramup-fields { margin-top: 2px; }
.paramup-summary {
  margin-top: 12px; padding: 12px 14px;
  background: var(--ink-deep); border: 1px dashed var(--line);
  border-radius: 10px; font-size: 13px; line-height: 1.65;
  display: flex; flex-direction: column; gap: 6px;
}
.paramup-line.ok { color: var(--ok); }
.paramup-line.bad { color: var(--danger); }
.paramup-line.muted { color: var(--smoke); }

.filter-bar { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; align-items: center; }
.filter-bar .eyebrow { margin-right: 6px; }

/* ---------- ticket-stub cards ---------------------------------------------- */

.grid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

.stub {
  position: relative;
  background: linear-gradient(160deg, var(--velvet-raised), var(--velvet) 70%);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  padding: 18px 20px 16px 30px;
  cursor: pointer;
  transition: transform 0.18s ease, border-color 0.18s, box-shadow 0.18s;
  overflow: hidden;
}
.stub::before { /* perforated ticket edge */
  content: ""; position: absolute; left: 11px; top: 8px; bottom: 8px; width: 0;
  border-left: 2px dashed var(--line);
}
.stub::after { /* brass seat-row marker */
  content: attr(data-serial);
  position: absolute; right: 14px; bottom: 10px;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.2em;
  color: rgba(201, 162, 75, 0.4);
}
.stub:hover {
  transform: translateY(-3px);
  border-color: var(--brass);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.5);
}
.stub h3 {
  font-family: var(--display); font-weight: 500;
  font-size: 20px; line-height: 1.25; margin: 3px 0 4px;
  color: var(--ivory);
}
.stub .sub { font-size: 13px; color: var(--smoke); }
.stub .chips-row { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 12px; }
.stub .chips-row .chip { font-size: 11px; padding: 2px 9px; }
.stub .stars { margin-top: 10px; }

/* People directory: every card holds the same ticket size as the other tabs —
   one credit line, one row of role buttons, full lists in the modal */
.people-stub { min-height: 122px; }
.people-stub .eyebrow, .people-stub .sub {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: block; max-width: 100%;
}
.people-stub .chips-row { margin-top: 10px; max-height: 26px; overflow: hidden; }
.stub .avatar {
  float: right; width: 52px; height: 52px; border-radius: 50%;
  object-fit: cover; border: 2px solid var(--line);
  margin-left: 12px;
}

.empty {
  text-align: center; padding: 70px 20px; color: var(--smoke);
  border: 1px dashed var(--line); border-radius: var(--radius);
}
.empty .mask { font-size: 40px; opacity: 0.7; }
.empty h3 { font-family: var(--display); font-weight: 500; color: var(--ivory); margin: 10px 0 4px; font-size: 22px; }

/* ---------- profile drawer -------------------------------------------------- */

.overlay {
  position: fixed; inset: 0; background: rgba(8, 3, 5, 0.68);
  backdrop-filter: blur(3px); z-index: 70;
  animation: fade 0.2s ease;
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 80;
  width: min(560px, 96vw);
  background: linear-gradient(180deg, #2b1420, var(--velvet) 40%);
  border-left: 1px solid var(--line);
  box-shadow: -30px 0 70px rgba(0, 0, 0, 0.6);
  overflow-y: auto;
  animation: slide 0.25s ease;
}
@keyframes slide { from { transform: translateX(40px); opacity: 0; } to { transform: none; opacity: 1; } }

.drawer-head {
  padding: 26px 30px 18px;
  border-bottom: 1px dashed var(--line);
  position: relative;
}
.drawer-head .close {
  position: absolute; top: 18px; right: 18px;
  background: none; border: 1px solid var(--line); border-radius: 50%;
  width: 32px; height: 32px; color: var(--smoke); font-size: 15px;
}
.drawer-head .close:hover { color: var(--ivory); border-color: var(--brass); }
.drawer-head h2 { font-family: var(--display); font-weight: 500; font-size: 30px; margin: 8px 0 4px; line-height: 1.15; }
.drawer-head .portrait {
  width: 88px; height: 88px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--brass); margin-bottom: 10px; display: block;
}
.drawer-body { padding: 20px 30px 40px; }
.drawer .actions { display: flex; gap: 10px; margin-top: 14px; }

.spec { padding: 11px 0; border-bottom: 1px solid var(--line-soft); }
.spec:last-child { border-bottom: none; }
.spec dt {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--smoke); margin-bottom: 3px;
}
.spec dd { font-size: 14.5px; line-height: 1.6; }
.spec dd .chip { margin: 2px 3px 2px 0; }
.spec dd .rel { cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.spec dd .rel:hover { color: var(--brass-bright); }

/* ---------- modal (forms) ----------------------------------------------------- */

.modal-wrap {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 24px;
  overflow-y: auto;
}
.modal {
  width: min(640px, 100%);
  max-height: calc(100vh - 60px); overflow-y: auto;
  background: linear-gradient(180deg, #2d1520, var(--velvet) 30%);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 26px 30px;
  animation: rise 0.25s ease;
}
.modal h2 { font-family: var(--display); font-weight: 500; font-size: 26px; margin-bottom: 4px; }
.modal .modal-sub { color: var(--smoke); font-size: 13px; margin-bottom: 20px; }
.modal .switch-row { display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--velvet-raised); cursor: pointer; font-size: 14px; color: var(--ivory); }
.modal .switch-row input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--brass); cursor: pointer; flex: none; }
.modal .form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; padding-top: 16px; border-top: 1px dashed var(--line); }
.modal .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
@media (max-width: 560px) { .modal .two-col { grid-template-columns: 1fr; } }

.image-drop {
  display: flex; align-items: center; gap: 14px;
  padding: 12px; border: 1px dashed var(--line); border-radius: 8px;
}
.image-drop img { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; border: 2px solid var(--brass); }
.image-drop .ph {
  width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center;
  background: var(--ink-deep); color: var(--smoke); font-size: 22px;
}

/* ---------- graph stage --------------------------------------------------------- */

.graph-shell {
  position: relative;
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  background:
    radial-gradient(700px 420px at 50% 0%, rgba(232, 205, 138, 0.05), transparent 70%),
    var(--ink-deep);
  overflow: hidden;
  height: calc(100vh - 260px); min-height: 480px;
}
/* Spectacle dressing: a deeper, warmer house for the full production */
.graph-shell.fancy {
  background:
    radial-gradient(700px 420px at 50% 0%, rgba(232, 205, 138, 0.06), transparent 70%),
    radial-gradient(900px 300px at 50% 100%, rgba(120, 42, 60, 0.18), transparent 75%),
    linear-gradient(180deg, #0b0409 0%, #12060c 60%, #180a10 100%),
    var(--ink-deep);
}

/* the Classic ↔ Spectacle switch in the hint card */
.graph-fx-bar { display: flex; align-items: center; justify-content: flex-end; gap: 8px; white-space: nowrap; font-size: 9.5px; }
.graph-fx-bar .fx-sep { opacity: 0.4; }
.graph-look-row { display: flex; align-items: center; gap: 7px; justify-content: flex-end; cursor: pointer; }
.graph-look-row .look-label { opacity: 0.45; transition: opacity 0.25s ease, color 0.25s ease; }
.graph-look-row .look-label.on { opacity: 1; color: var(--brass); }
.look-switch {
  position: relative; width: 30px; height: 15px; border-radius: 999px;
  background: rgba(20, 9, 14, 0.9); border: 1px solid var(--line);
  cursor: pointer; flex: 0 0 auto; transition: background 0.25s ease, border-color 0.25s ease;
}
.look-switch .knob {
  position: absolute; top: 1px; left: 1px; width: 11px; height: 11px; border-radius: 50%;
  background: var(--smoke); transition: transform 0.25s cubic-bezier(0.5, 0, 0.2, 1.4), background 0.25s ease;
}
.look-switch.on { background: rgba(201, 162, 75, 0.28); border-color: var(--brass); }
.look-switch.on .knob { transform: translateX(15px); background: var(--brass); box-shadow: 0 0 6px rgba(232, 205, 138, 0.7); }
.look-switch:focus-visible { outline: 1px solid var(--brass); outline-offset: 2px; }

/* the house curtain — two velvet halves that part once the graph is set */
.graph-curtain {
  position: absolute; top: 0; bottom: 0; width: 51%;
  z-index: 6; pointer-events: none;
  background:
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, 0.30) 0 10px,
      rgba(255, 255, 255, 0.05) 10px 20px,
      rgba(0, 0, 0, 0.18) 20px 42px),
    linear-gradient(180deg, #4a0f1e 0%, #6a1626 45%, #3d0c19 100%);
  box-shadow: inset 0 -40px 60px rgba(0, 0, 0, 0.55);
  border-bottom: 6px solid rgba(201, 162, 75, 0.65);
  transition: transform 1.35s cubic-bezier(0.65, 0, 0.25, 1);
}
.graph-curtain.left  { left: 0;  transform: translateX(0); border-right: 2px solid rgba(201, 162, 75, 0.35); }
.graph-curtain.right { right: 0; transform: translateX(0); border-left: 2px solid rgba(201, 162, 75, 0.35); }
.graph-curtain.left.open  { transform: translateX(-102%) skewX(-2deg); }
.graph-curtain.right.open { transform: translateX(102%) skewX(2deg); }

/* the effect picker living inside the hint card */
.graph-effect-row { display: flex; align-items: center; gap: 6px; justify-content: flex-end; }
.graph-effect-row select {
  background: rgba(20, 9, 14, 0.9); color: var(--ivory);
  border: 1px solid var(--line); border-radius: 6px;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 2px 5px; cursor: pointer;
}
.graph-effect-row select:hover { border-color: var(--brass); }
.graph-effect-desc { display: block; opacity: 0.7; text-transform: none; letter-spacing: 0.04em; white-space: nowrap; font-size: 8.5px; }
.graph-shell canvas { display: block; width: 100%; height: 100%; cursor: grab; }
.graph-shell canvas:active { cursor: grabbing; }
.graph-legend {
  position: absolute; left: 14px; top: 14px;
  background: rgba(20, 9, 14, 0.85); border: 1px solid var(--line-soft);
  border-radius: 8px; padding: 10px 14px; font-size: 12px;
  backdrop-filter: blur(4px);
}
.graph-legend .row { display: flex; align-items: center; gap: 8px; padding: 2px 0; color: var(--smoke); }
.graph-legend .dot { width: 9px; height: 9px; border-radius: 50%; }
.graph-hint {
  position: absolute; right: 14px; bottom: 12px; z-index: 6;
  background: rgba(20, 9, 14, 0.85); border: 1px solid var(--line-soft);
  border-radius: 10px; padding: 9px 12px;
  backdrop-filter: blur(4px);
  display: flex; flex-direction: column; align-items: flex-end; gap: 5px;
  text-align: right;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.15em;
  color: var(--smoke); text-transform: uppercase;
}
.graph-hint .hint-line { font-size: 10.5px; opacity: 0.85; }

/* the View bar — hide picks or spotlight picks, a way of looking only */
/* City Lens — a vertical floating box on the graph's left flank */
.graph-citybox {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 6px;
  background: rgba(12, 8, 12, 0.82); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 10px 8px; z-index: 5;
  backdrop-filter: blur(6px); max-width: 150px;
}
.graph-citybox .gc-list { display: flex; flex-direction: column; gap: 4px; }
.graph-citybox .gc-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: none; border: 1px solid transparent; border-radius: 7px;
  color: var(--smoke); font-size: 12.5px; padding: 5px 8px; text-align: left;
  transition: color .15s, border-color .15s, background .15s;
}
.graph-citybox .gc-btn:hover { color: var(--ivory); border-color: var(--line); }
.graph-citybox .gc-btn.on { color: var(--brass-bright); border-color: var(--brass); background: rgba(201, 162, 75, 0.1); }
.graph-citybox .gc-count { font-family: var(--mono); font-size: 10px; color: var(--smoke); }
.graph-citybox .gc-all { margin-top: 3px; border-top: 1px dashed var(--line); border-radius: 0 0 7px 7px; padding-top: 7px; font-size: 11.5px; }
@media (max-width: 860px) { .graph-citybox { position: static; transform: none; margin: 8px; flex-direction: row; max-width: none; } .graph-citybox .gc-list { flex-direction: row; flex-wrap: wrap; } }

.graph-viewbar {
  position: absolute; left: 14px; bottom: 12px; z-index: 6;
  max-width: min(340px, calc(100% - 28px));
  background: rgba(20, 9, 14, 0.85); border: 1px solid var(--line-soft);
  border-radius: 10px; padding: 9px 12px;
  backdrop-filter: blur(4px);
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
}
.gv-btn {
  background: var(--ink-deep); color: var(--smoke);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 11px; font-size: 11.5px; font-family: inherit;
  cursor: pointer; transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.gv-btn:hover { border-color: var(--brass); color: var(--ivory); }
.gv-btn.on {
  background: rgba(201, 162, 75, 0.22); border-color: var(--brass);
  color: var(--brass-bright); font-weight: 600;
}
.gv-btn.gv-reset { color: var(--danger); border-color: rgba(212, 99, 79, 0.5); }
.gv-btn.gv-reset:hover { border-color: var(--danger); }
.gv-status { flex-basis: 100%; font-size: 11px; color: var(--smoke); }
.gv-chips { display: flex; flex-wrap: wrap; gap: 5px; flex-basis: 100%; }
.gv-chips:empty { display: none; }
.gv-chip {
  display: inline-flex; align-items: center; gap: 5px;
  background: rgba(30, 13, 21, 0.9); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 8px; font-size: 11px; color: var(--ivory);
}
.gv-chip .dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.gv-chip button {
  background: none; border: 0; color: var(--smoke);
  cursor: pointer; font-size: 11px; padding: 0 0 0 2px;
}
.gv-chip button:hover { color: var(--danger); }
.graph-panel {
  position: absolute; right: 14px; top: 14px; width: 250px;
  background: rgba(30, 13, 21, 0.94); border: 1px solid var(--line);
  border-radius: 10px; padding: 14px 16px; backdrop-filter: blur(6px);
}
.graph-panel h4 { font-family: var(--display); font-weight: 500; font-size: 18px; }
.graph-panel .eyebrow { display: block; margin-bottom: 2px; }
.graph-panel ul { list-style: none; margin-top: 8px; max-height: 220px; overflow-y: auto; }
.graph-panel li { padding: 4px 0; font-size: 12.5px; color: var(--smoke); border-bottom: 1px solid var(--line-soft); }
.graph-panel li b { color: var(--ivory); font-weight: 500; }
.graph-panel .btn { margin-top: 10px; width: 100%; justify-content: center; }

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

#toast-stack { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%); z-index: 200; display: flex; flex-direction: column; gap: 8px; }
.toast {
  padding: 10px 22px; border-radius: 999px;
  background: var(--velvet-raised); border: 1px solid var(--brass);
  color: var(--ivory); font-size: 13.5px;
  box-shadow: var(--shadow); animation: rise 0.25s ease;
}
.toast.err { border-color: var(--danger); color: #eba193; }

/* users table */
.user-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--line-soft);
}
/* The fold-out under a demo account: another stretch of time, a date, or none. */
/* ---------- the demo strip ---------------------------------------------------
   Its background is the curtain, which is dark in EVERY theme. Its text used to
   be var(--ivory) — but a light theme like Nukkad Beat inverts that variable to
   near-black ink (#201a10), which landed dark-on-dark against Nukkad's #191919
   curtain and made the whole strip, access date included, unreadable. So the
   strip carries its own foreground: fixed, pale, and beholden to no theme. */
.demo-banner {
  --demo-fg: #fdf6e6;
  --demo-fg-dim: rgba(253, 246, 230, 0.72);
  background: linear-gradient(90deg, var(--curtain-deep), var(--curtain));
  color: var(--demo-fg);
  font-size: 13px; padding: 7px 18px;
  display: flex; gap: 14px; align-items: center; justify-content: center;
  flex-wrap: wrap; border-bottom: 1px solid rgba(253, 246, 230, 0.22);
}
.demo-banner b { color: #fff; font-weight: 600; }
/* The buttons live on the curtain too, so they can't inherit the page's either. */
.demo-banner .demo-reset {
  padding: 2px 12px; color: var(--demo-fg);
  border-color: rgba(253, 246, 230, 0.45); background: rgba(253, 246, 230, 0.08);
}
.demo-banner .demo-reset:hover { background: rgba(253, 246, 230, 0.18); color: #fff; }
.demo-banner .demo-min {
  background: none; border: none; cursor: pointer; padding: 0 4px;
  color: var(--demo-fg-dim); font-size: 17px; line-height: 1;
}
.demo-banner .demo-min:hover { color: #fff; }
/* Tucked away: a pill at the left instead of a strip across every screen. */
.demo-banner.mini {
  background: none; border-bottom: none; padding: 4px 14px; justify-content: flex-start;
}
.demo-banner.mini .demo-pill {
  cursor: pointer; font-size: 11.5px; letter-spacing: .04em;
  color: var(--demo-fg); background: linear-gradient(90deg, var(--curtain-deep), var(--curtain));
  border: 1px solid rgba(253, 246, 230, 0.3); border-radius: 999px; padding: 3px 12px;
}
.demo-banner.mini .demo-pill:hover { border-color: rgba(253, 246, 230, 0.7); }

.user-block .user-row { border-bottom: none; }
.user-block { border-bottom: 1px solid var(--line-soft); }
.extend-panel {
  padding: 4px 0 12px; margin: -2px 0 0;
}
.extend-panel .extend-row {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.extend-panel .extend-row input, .extend-panel .extend-row select { margin: 0; }
/* Long enough that the whole label reads, closed or open. */
.extend-panel .extend-row select[data-extmode] { min-width: 220px; }
.extend-panel .hint { margin-top: 6px; }
.user-row .role-pill {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.15em;
  text-transform: uppercase; padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--brass);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
@media (max-width: 720px) {
  .masthead-inner { flex-wrap: wrap; padding: 12px 16px 0; }
  .search-wrap { order: 3; width: 100%; max-width: none; margin: 8px 0 0; }
  .tabs, .content { padding-left: 16px; padding-right: 16px; }
  .tabs::before { left: 16px; } .tabs::after { right: 16px; }
  .stage::before, .stage::after { width: 14vw; }
}

/* ---------- Data Upload ------------------------------------------------------------- */

.upload-stats-badge {
  position: fixed; right: 18px; bottom: 18px; z-index: 150;
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  background: var(--velvet-raised); border: 1px solid var(--brass);
  border-radius: 12px; padding: 10px 14px; box-shadow: var(--shadow);
  cursor: pointer; user-select: none; min-width: 168px;
}
.upload-stats-badge .stats-row { display: flex; flex-direction: column; align-items: flex-end; }
.upload-stats-badge .stats-row + .stats-row { border-top: 1px solid var(--line-soft); padding-top: 6px; }
.upload-stats-badge .eyebrow { font-size: 10px; }
.upload-stats-badge strong { font-family: var(--display); font-size: 20px; color: var(--brass); line-height: 1.1; }
.upload-stats-badge .hint { margin: 0; font-size: 11px; }
.upload-stats-badge [data-reset-session] { align-self: center; cursor: pointer; }

/* Minimize control + collapsed pill */
.upload-stats-badge { position: fixed; }
.upload-stats-badge .stats-min-btn {
  position: absolute; top: 4px; left: 6px;
  background: none; border: none; color: var(--smoke);
  font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 6px;
}
.upload-stats-badge .stats-min-btn:hover { color: var(--brass); }
.upload-stats-badge.minimized {
  min-width: 0; padding: 6px 12px; border-radius: 999px;
  flex-direction: row; align-items: center;
}
.upload-stats-badge.minimized .stats-mini {
  font-size: 12px; color: var(--brass); white-space: nowrap;
}

.upload-section {
  border: 1px solid var(--line-soft); border-radius: 12px;
  padding: 18px 20px; margin-bottom: 20px; background: var(--velvet-raised);
}
.upload-section h3 {
  font-family: var(--display); font-weight: 500; font-size: 17px;
  margin-bottom: 10px; color: var(--ivory);
}
.upload-section input[type="file"] { display: block; margin-bottom: 8px; color: var(--smoke); }
.upload-card { grid-column: span 2; cursor: default; }
.upload-card:hover { transform: none; box-shadow: none; }
.upload-card .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; margin-top: 10px; }
.upload-card .two-col > .field:not([data-half]) { grid-column: 1 / -1; }
.upload-card .form-actions { margin-top: 12px; flex-wrap: wrap; }
.dup-banner {
  margin-top: 10px; padding: 10px 12px; border-radius: 8px;
  background: rgba(196, 90, 74, 0.12); border: 1px solid var(--danger);
  font-size: 13px; color: var(--ivory);
}
.dup-banner a { color: var(--brass); }
.dup-banner .form-actions { margin-top: 8px; }
@media (max-width: 720px) {
  .upload-card { grid-column: span 1; }
}

/* ---------- Transit & Rejection dump: compact, three-across review cards ------------ */

.grid.staging-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.staging-grid .upload-card {
  grid-column: span 1;
  padding: 12px 14px 14px 24px;
}
.staging-grid .upload-card::before { left: 9px; top: 7px; bottom: 7px; }
.staging-grid .upload-card .eyebrow {
  font-size: 9px; letter-spacing: 0.14em;
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.staging-grid .upload-card h3 { font-size: 16px; margin: 2px 0 3px; }
.staging-grid .upload-card .sub { font-size: 12px; }
.staging-grid .upload-card .avatar { width: 40px; height: 40px; margin-left: 8px; }
.staging-grid .upload-card .chips-row { margin-top: 8px; }
.staging-grid .upload-card .chips-row .chip { font-size: 10px; padding: 1px 7px; }
.staging-grid .upload-card .form-actions { margin-top: 10px; gap: 6px; }
.staging-grid .upload-card .form-actions .btn { padding: 4px 9px; font-size: 11px; }
.staging-grid .upload-card .two-col { grid-template-columns: 1fr; gap: 8px; } /* edit form stacks inside the narrow card */
.staging-grid .upload-card .field label { font-size: 10px; }
.staging-grid .upload-card .dup-banner { font-size: 12px; padding: 8px 10px; }

@media (max-width: 1200px) {
  .grid.staging-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .grid.staging-grid { grid-template-columns: 1fr; }
}

/* ---------- Unidentified (green room) cards ------------------------------------------ */

.unid-card { cursor: default; }
.unid-card:hover { transform: none; box-shadow: none; }
.unid-card h3 a {
  color: var(--brass-bright); text-decoration: none;
  border-bottom: 1px dashed rgba(232, 205, 138, 0.55);
  transition: color 0.15s, border-color 0.15s;
}
.unid-card h3 a:hover { color: var(--ivory); border-bottom-style: solid; border-color: var(--ivory); }
.unid-card .chips-row .chip.rel { cursor: pointer; }
.unid-card .chips-row .chip.rel:hover { border-color: var(--brass); color: var(--brass-bright); }
button.chip { font: inherit; cursor: pointer; }
.chip.rel { cursor: pointer; }
.chip.rel:hover { border-color: var(--brass); color: var(--brass-bright); }
.crosslink-row { margin-top: 10px; }
.crosslink-btn:disabled { opacity: 0.55; cursor: default; }

/* ---------- Stage Graph search --------------------------------------------------------- */

.graph-search {
  position: absolute; left: 50%; top: 14px; transform: translateX(-50%);
  width: min(340px, calc(100% - 28px)); z-index: 6;
}
.graph-search input {
  width: 100%; padding: 9px 16px;
  background: rgba(20, 9, 14, 0.88); border: 1px solid var(--line);
  border-radius: 999px; color: var(--ivory); font-size: 13.5px;
  backdrop-filter: blur(4px); outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.graph-search input::placeholder { color: var(--smoke); }
.graph-search input:focus { border-color: var(--brass); box-shadow: 0 0 0 3px rgba(201, 162, 75, 0.15); }
.graph-search-results {
  margin-top: 6px;
  background: rgba(30, 13, 21, 0.96); border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden auto; max-height: 262px;
  backdrop-filter: blur(6px); box-shadow: var(--shadow);
}
.gs-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 12px; background: none; border: 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ivory); font-size: 13px; text-align: left;
}
.gs-item:last-child { border-bottom: 0; }
.gs-item:hover, .gs-item.active { background: rgba(201, 162, 75, 0.13); }
.gs-item .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.gs-item .gs-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-item .gs-name b { color: var(--brass-bright); font-weight: 600; }
.gs-item .gs-type {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--smoke); flex: 0 0 auto;
}
.gs-empty { padding: 10px 14px; font-size: 12.5px; color: var(--smoke); }

/* --- Unidentified section (Data tab) + same-person threads ------------------------------- */
/* The stub's perforated ticket edge sits at left:11px — content must clear it, so the
   left padding stays wider than the other three sides (12px flat used to overlap it). */
.staging-grid .unid-card { padding: 12px 12px 12px 24px; }
.staging-grid .unid-card::before { left: 9px; top: 7px; bottom: 7px; }
.staging-grid .unid-card h3 { font-size: 1.05rem; }
.staging-grid .unid-card .eyebrow { font-size: .6rem; }
.staging-grid .unid-card .form-actions { margin-top: 8px !important; }
.same-person-hint { color: rgba(216, 224, 238, 0.78); font-size: .78rem; }

/* Ghost credits — remembered by the credits ledger after their source record was deleted */
.ghost-credit-hint { color: rgba(216, 224, 238, 0.62); font-size: .78rem; font-style: italic; }
.unid-card .chips-row .chip.rel.gone,
.chip.rel.gone {
  cursor: default;
  opacity: .62;
  border-style: dashed;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
.unid-card .chips-row .chip.rel.gone:hover,
.chip.rel.gone:hover { border-color: inherit; color: inherit; }
.same-person-row .twin-chip { cursor: pointer; }
.same-person-row .twin-chip:hover { border-color: var(--brass); color: var(--brass-bright); }
.graph-legend .dash-sample { width: 16px; height: 0; border-top: 2px dashed rgba(190, 200, 215, 0.65); display: inline-block; }

/* Cross-link section at the bottom of a people profile drawer */
.crosslink-section {
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px dashed var(--line, rgba(255,255,255,0.14));
}
.crosslink-section .hint { margin: 6px 0 10px; }

/* ---------- Blogs: label dots, list, editor ------------------------------------- */

.label-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 6px; vertical-align: 0;
}
.chip.label-chip.graph-tinted { font-weight: 600; letter-spacing: 0.01em; }

.blog-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }
.blog-card h3 { font-family: var(--display); font-weight: 500; font-size: 19px; margin: 6px 0 2px; }
.blog-card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.blog-card-excerpt { color: var(--smoke); font-size: 13px; margin-top: 8px; }
.blog-card-link { display: block; margin-top: 8px; font-size: 12px; word-break: break-all; }
.blog-status.is-published { background: rgba(127, 174, 122, 0.2); border-color: var(--ok); color: var(--ok); }

.blog-editor-head { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
.blog-save-state { color: var(--smoke); font-size: 12px; }
.blog-editor-wrap { position: relative; max-width: 820px; margin: 0 auto; }
.blog-title, .blog-subtitle {
  display: block; width: 100%; background: transparent; border: none; outline: none;
  color: var(--ivory); font-family: var(--display);
}
.blog-title { font-size: 34px; font-weight: 600; line-height: 1.2; margin-bottom: 4px; }
.blog-subtitle { font-size: 17px; color: var(--smoke); margin-bottom: 16px; }
.blog-title::placeholder, .blog-subtitle::placeholder { color: var(--smoke); opacity: .55; }

.blog-toolbar {
  position: sticky; top: 118px; z-index: 45;
  display: flex; flex-wrap: wrap; gap: 3px; align-items: center;
  padding: 7px 9px; margin-bottom: 14px;
  background: var(--velvet-raised); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow);
}
.blog-toolbar button {
  min-width: 30px; height: 28px; padding: 0 7px;
  background: transparent; border: 1px solid transparent; border-radius: 7px;
  color: var(--ivory); font-size: 13px;
  transition: background .12s, border-color .12s;
}
.blog-toolbar button:hover { background: rgba(255,255,255,.07); border-color: var(--line); }
.tb-sep { width: 1px; height: 18px; background: var(--line-soft); margin: 0 5px; }

.blog-canvas {
  min-height: 46vh; outline: none;
  font-size: 16.5px; line-height: 1.75; color: var(--ivory);
}
.blog-canvas:empty::before { content: "Raise the curtain — start writing…"; color: var(--smoke); opacity: .55; }
.blog-canvas p { margin: 0 0 14px; }
.blog-canvas h2 { font-family: var(--display); font-size: 27px; font-weight: 600; margin: 26px 0 10px; }
.blog-canvas h3 { font-family: var(--display); font-size: 21px; font-weight: 600; margin: 22px 0 8px; }
.blog-canvas h4 { font-family: var(--display); font-size: 17px; font-weight: 600; margin: 18px 0 6px; color: var(--brass-bright); }
.blog-canvas blockquote {
  margin: 18px 0; padding: 6px 18px;
  border-left: 3px solid var(--brass); color: var(--brass-bright);
  font-family: var(--display); font-style: italic; font-size: 18px;
}
.blog-canvas pre {
  margin: 16px 0; padding: 14px 16px; overflow-x: auto;
  background: var(--ink-deep); border: 1px solid var(--line-soft); border-radius: 10px;
  font-family: var(--mono); font-size: 13px; line-height: 1.6; white-space: pre-wrap;
}
.blog-canvas ul, .blog-canvas ol { margin: 0 0 14px 26px; }
.blog-canvas a { color: var(--brass-bright); }
.blog-hr { border: none; border-top: 1px dashed var(--line); margin: 26px 0; }

/* media figures */
figure.blog-media { margin: 20px auto; position: relative; }
figure.blog-media img, figure.blog-media video { width: 100%; display: block; border-radius: 10px; border: 1px solid var(--line-soft); }
figure.blog-media .blog-video-frame { position: relative; padding-top: 56.25%; border-radius: 10px; overflow: hidden; border: 1px solid var(--line-soft); }
figure.blog-media .blog-video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
figure.blog-media figcaption {
  margin-top: 7px; text-align: center; font-size: 12.5px; color: var(--smoke); min-height: 16px;
}
figure.blog-media figcaption:empty::before { content: "Write a caption…"; opacity: .5; }
figure.blog-media[data-align="left"] { float: left; margin: 6px 22px 12px 0; }
figure.blog-media[data-align="right"] { float: right; margin: 6px 0 12px 22px; }
figure.blog-media[data-align="center"] { float: none; margin-left: auto; margin-right: auto; }
figure.blog-media[data-align="full"] { float: none; width: 100% !important; }
figure.blog-media.sel { outline: 2px solid var(--brass); outline-offset: 3px; border-radius: 10px; }

.blog-media-bar {
  position: absolute; z-index: 46;
  display: flex; gap: 2px; align-items: center;
  padding: 4px 6px; background: var(--velvet-raised);
  border: 1px solid var(--brass); border-radius: 9px; box-shadow: var(--shadow);
}
.blog-media-bar button {
  min-width: 26px; height: 24px; background: transparent; border: none; border-radius: 6px;
  color: var(--ivory); font-size: 13px;
}
.blog-media-bar button:hover { background: rgba(255,255,255,.09); }

/* embedded profile cards */
.blog-embed-card {
  position: relative; margin: 20px 0; padding: 14px 16px 12px;
  background: var(--velvet-raised);
  border: 1px solid var(--line); border-left: 4px solid var(--embed-c, var(--brass));
  border-radius: 10px; box-shadow: var(--shadow);
}
.blog-embed-card strong { display: block; font-family: var(--display); font-size: 19px; margin: 4px 0 2px; }
.blog-embed-card .embed-fields { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 6px; font-size: 12.5px; color: var(--smoke); }
.blog-embed-card .embed-fields b { color: var(--ivory); font-weight: 600; }
.blog-embed-card .chips-row { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
.blog-embed-card .chips-row .chip { font-size: 11px; padding: 2px 9px; }
.blog-embed-card .embed-remove {
  position: absolute; top: 6px; right: 8px;
  background: none; border: none; color: var(--smoke); font-size: 13px; padding: 3px; cursor: pointer;
}
.blog-embed-card .embed-remove:hover { color: var(--danger); }

.blog-footer { margin-top: 14px; color: var(--smoke); font-size: 12px; }

.blog-publish {
  clear: both; margin-top: 34px; padding: 20px 22px;
  border: 1px dashed var(--line); border-radius: 12px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
}
.blog-publish h3 { font-family: var(--display); font-weight: 500; }

/* pickers + publish modal */
.blog-modal-overlay {
  position: fixed; inset: 0; z-index: 160;
  background: rgba(8, 3, 6, 0.6); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 18px;
}
.blog-modal {
  width: min(620px, 100%); max-height: 84vh; overflow: auto;
  background: var(--velvet-raised); border: 1px solid var(--brass);
  border-radius: 14px; box-shadow: var(--shadow); padding: 18px 20px;
}
.blog-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.blog-modal-head h3 { font-family: var(--display); font-weight: 500; font-size: 19px; }
.blog-modal-body input[type="text"], .blog-modal-body input[type="password"], .blog-modal-body select {
  width: 100%; padding: 9px 12px; margin: 6px 0 10px;
  background: var(--velvet); border: 1px solid var(--line); border-radius: 9px; outline: none;
}
.blog-modal-label { font-size: 12px; color: var(--smoke); }
.blog-or { text-align: center; color: var(--smoke); font-size: 11px; margin: 8px 0; }
.blog-picker-row { display: flex; gap: 8px; }
.blog-picker-row select { flex: 0 0 42%; }
.blog-pick-results { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; min-height: 120px; }
.blog-pick-item {
  text-align: left; padding: 8px 11px; border-radius: 8px;
  background: transparent; border: 1px solid var(--line-soft); color: var(--ivory); font-size: 13.5px;
}
.blog-pick-item:hover { border-color: var(--brass); background: rgba(255,255,255,.05); }
.blog-publish-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.blog-publish-block { display: flex; flex-direction: column; align-items: flex-start; gap: 7px; }
.blog-publish-block .btn { width: 100%; justify-content: center; }
@media (max-width: 640px) { .blog-publish-grid { grid-template-columns: 1fr; } }

/* stale-server warning banner */
#stale-server-banner {
  position: sticky; top: 0; z-index: 300;
  padding: 10px 18px; text-align: center;
  background: var(--danger, #d4634f); color: #fff;
  font-size: 13px; line-height: 1.5;
}
#stale-server-banner code {
  background: rgba(0, 0, 0, 0.25); padding: 1px 6px; border-radius: 5px;
  font-family: var(--mono, monospace); font-size: 12px;
}

/* Data tab: section bars, minimise, per-section filters */
.upload-section .section-bar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; }
.section-tools { display: flex; align-items: center; gap: 8px; }
.section-min {
  width: 27px; height: 27px; padding: 0;
  background: transparent; border: 1px solid var(--line); border-radius: 7px;
  color: var(--ivory); font-size: 16px; line-height: 1;
}
.section-min:hover { border-color: var(--brass); color: var(--brass-bright); }
.upload-section.collapsed .section-body { display: none; }
.upload-section.collapsed { padding-bottom: 14px; }
.section-search-row { margin: 12px 0 2px; }
.section-search {
  width: 100%; max-width: 440px; padding: 9px 14px;
  background: var(--ink-deep); border: 1px solid var(--line-soft);
  border-radius: 999px; color: var(--ivory);
  font: inherit; font-size: 14px;
  transition: border-color 0.15s;
}
.section-search:focus { border-color: var(--brass); outline: none; }
.section-search::placeholder { color: var(--smoke); }
.section-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 12px 0 2px; }
.section-filter .eyebrow { margin-right: 4px; }
.section-filter:empty { margin: 0; }
.data-filter-chip { cursor: pointer; }

/* Blogs: reader view + logo home link + 3-way publish grid */
.brand h1.brand-home { cursor: pointer; transition: opacity .15s; }
.brand h1.brand-home:hover { opacity: .82; }
.blog-reader .blog-canvas { min-height: 0; }
.blog-reader .embed-remove { display: none; }
.blog-read-title { font-family: var(--display); font-size: 36px; font-weight: 600; line-height: 1.2; margin-bottom: 6px; }
.blog-read-sub { font-family: var(--display); font-size: 18px; color: var(--smoke); margin-bottom: 12px; }
.blog-byline { color: var(--smoke); font-size: 12.5px; margin-bottom: 4px; }
.blog-publish-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* ---------- Themes ------------------------------------------------------------------ */

#themes-btn { white-space: nowrap; }

.themes-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px; margin: 16px 0;
}
.theme-card {
  border: 1px solid var(--line-soft); border-radius: 12px; padding: 14px;
  background: var(--ink-deep); text-align: center; transition: border-color .15s;
}
.theme-card.active { border-color: var(--brass); }
.theme-card h4 { font-family: var(--display); font-size: 15px; margin: 8px 0 2px; }
.theme-card .hint { min-height: 32px; }
.theme-swatch-dots { display: inline-flex; gap: 4px; justify-content: center; }
.theme-swatch-dots span {
  width: 18px; height: 18px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.25);
  display: inline-block;
}
.theme-swatch-dots.empty {
  width: 96px; height: 20px; border-radius: 999px; background: none;
  border: 1px dashed var(--line); color: var(--smoke); font-size: 12px;
  display: flex; align-items: center; justify-content: center;
}

.color-row { display: flex; gap: 8px; align-items: center; }
.color-row input[type="color"] {
  width: 38px; height: 34px; padding: 2px; border-radius: 8px;
  border: 1px solid var(--line-soft); background: var(--ink-deep); cursor: pointer;
}
.color-row input[type="text"] { flex: 1; font-family: var(--mono); font-size: 13px; }

.theme-preview-mock {
  border-radius: 12px; padding: 18px; margin: 14px 0 18px;
  background: var(--pv-ink, var(--ink));
}
.theme-preview-mock .tpm-card {
  background: var(--pv-velvet, var(--velvet)); border: 1px solid var(--pv-brass, var(--brass));
  border-radius: 10px; padding: 16px;
}
.tpm-eyebrow {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--pv-brass, var(--brass));
}
.tpm-card h4 { font-family: var(--display); color: var(--pv-ivory, var(--ivory)); font-size: 19px; margin: 6px 0 2px; }
.tpm-sub { color: var(--pv-smoke, var(--smoke)); font-size: 13px; margin-bottom: 12px; }
.tpm-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.tpm-btn {
  background: var(--pv-curtain, var(--curtain)); color: var(--pv-ivory, var(--ivory));
  border: none; border-radius: 8px; padding: 7px 16px; font: inherit; cursor: default;
}
.tpm-chip {
  background: var(--pv-velvet-raised, var(--velvet-raised)); color: var(--pv-ivory, var(--ivory));
  border: 1px solid var(--pv-brass, var(--brass)); border-radius: 999px; padding: 3px 12px; font-size: 12.5px;
}
.tpm-chip.tpm-danger { border-color: var(--pv-danger, var(--danger)); color: var(--pv-danger, var(--danger)); }
.tpm-chip.tpm-ok { border-color: var(--pv-ok, var(--ok)); color: var(--pv-ok, var(--ok)); }

/* =========================================================================
   THE GREEN ROOM — floating community chat (marquee-lit)
   ========================================================================= */

/* launcher pill — the minimised state, pinned mid-right */
#forum-launcher {
  position: fixed; right: 0; top: 60%; transform: translateY(-50%);
  z-index: 120; display: flex; align-items: center; justify-content: center;
  width: 46px; height: 48px; padding: 0;
  background: linear-gradient(180deg, var(--velvet-raised), var(--velvet));
  color: var(--ivory); border: 1px solid var(--line); border-right: none;
  border-radius: 14px 0 0 14px; cursor: pointer; font-size: 20px;
  box-shadow: -8px 6px 22px rgba(0, 0, 0, .45);
  transition: transform .18s ease, filter .18s ease, box-shadow .18s ease;
}
#forum-launcher:hover { filter: brightness(1.08); box-shadow: -10px 8px 26px rgba(0, 0, 0, .55); }
#forum-launcher.has-unread { border-color: var(--brass); box-shadow: -8px 6px 22px rgba(201, 162, 75, .28); }
.forum-launcher-ico { line-height: 1; }

/* "Community" — the invitation beside the minimised mask.
   Sits immediately left of the launcher and shares its vertical centre, with a
   small brass tail pointing at the emoji so the label is unmistakably ITS
   label. One z-index below the launcher, so the mask always stays on top.
   Shown once per device: see forumMountBubble / FORUM_BUBBLE_LS in app.js. */
#forum-bubble {
  position: fixed; right: 58px; top: 60%;
  transform: translateY(-50%) translateX(10px);
  z-index: 119; width: 210px; padding: 11px 13px 12px;
  background: var(--velvet-raised); color: var(--ivory);
  border: 1px solid var(--brass); border-radius: 12px;
  box-shadow: -10px 8px 26px rgba(0, 0, 0, .5);
  cursor: pointer; opacity: 0;
  transition: opacity .22s ease, transform .22s ease;
}
#forum-bubble.up { opacity: 1; transform: translateY(-50%) translateX(0); }
#forum-bubble:hover { border-color: var(--brass-bright); }
#forum-bubble b {
  display: block; font-family: var(--display); font-size: 15px;
  font-weight: 600; color: var(--brass-bright); margin-bottom: 2px;
}
#forum-bubble > span { display: block; font-size: 12px; color: var(--smoke); line-height: 1.45; }
/* the tail — a rotated square straddling the bubble's right edge */
#forum-bubble::after {
  content: ""; position: absolute; right: -6px; top: 50%;
  width: 10px; height: 10px; margin-top: -5px;
  background: var(--velvet-raised);
  border-right: 1px solid var(--brass); border-top: 1px solid var(--brass);
  transform: rotate(45deg);
}
.forum-bubble-x {
  position: absolute; top: 3px; right: 5px;
  background: none; border: none; color: var(--smoke);
  font-size: 12px; line-height: 1; padding: 3px 4px; cursor: pointer;
}
.forum-bubble-x:hover { color: var(--brass-bright); }
/* No room for it beside a narrow window — the title attribute still explains
   the launcher there. */
@media (max-width: 720px) { #forum-bubble { display: none; } }
@media (prefers-reduced-motion: reduce) {
  #forum-bubble { transition: opacity .22s ease; transform: translateY(-50%); }
  #forum-bubble.up { transform: translateY(-50%); }
}

/* the unread badge — on the launcher, and pinned to the top edge of the window */
.forum-badge {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--curtain); color: var(--ivory);
  font: 600 11px/1 var(--body); place-items: center;
  box-shadow: 0 0 0 2px var(--velvet);
}
#forum-launcher-badge { position: absolute; top: -6px; left: -6px; }
.forum-badge.on-window {
  position: absolute; top: -9px; right: 26px; z-index: 3;
  background: var(--curtain); box-shadow: 0 2px 10px rgba(0, 0, 0, .5), 0 0 0 2px var(--ink);
}

/* the window — vertical, right-aligned, vertically centred */
#forum-window {
  position: fixed; right: 20px; top: 50%;
  width: min(370px, 92vw); height: min(74vh, 660px);
  z-index: 120; transform: translate(120%, -50%); opacity: 0;
  transition: transform .3s cubic-bezier(.2, .8, .25, 1), opacity .3s ease;
}
#forum-window.up { transform: translate(0, -50%); opacity: 1; }

/* the marquee frame that carries the bulbs */
.fchat-frame {
  position: absolute; inset: 0; border-radius: 24px;
  background: radial-gradient(120% 120% at 50% 0%, #1c0b12, var(--ink-deep));
  box-shadow: 0 26px 60px rgba(0, 0, 0, .6), inset 0 0 0 1px rgba(201, 162, 75, .16);
}
.fchat-bulbs { position: absolute; inset: 0; pointer-events: none; }
.fchat-bulb {
  position: absolute; width: 9px; height: 9px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle at 38% 34%, #fff8e6 0%, #ffe6a6 40%, #d9a63f 100%);
  box-shadow: 0 0 6px 1px rgba(255, 210, 130, .85), 0 0 12px 3px rgba(232, 205, 138, .4);
  animation: fchat-flicker var(--d, 1.6s) ease-in-out var(--dl, 0s) infinite;
}
.fchat-bulb.warm {
  background: radial-gradient(circle at 38% 34%, #fff2d2 0%, #ffcf7e 45%, #c47f2a 100%);
  box-shadow: 0 0 6px 1px rgba(255, 186, 92, .85), 0 0 12px 3px rgba(196, 127, 42, .4);
}
@keyframes fchat-flicker {
  0% { opacity: 1; } 8% { opacity: var(--dim, .3); } 15% { opacity: .92; }
  30% { opacity: var(--dim, .3); } 43% { opacity: 1; } 60% { opacity: var(--dim, .3); }
  72% { opacity: .86; } 87% { opacity: var(--dim, .3); } 100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .fchat-bulb { animation: none; opacity: .95; } }

/* the chat surface, inset from the bulbs */
.fchat-panel {
  position: absolute; inset: 14px; border-radius: 15px; overflow: hidden;
  background: linear-gradient(180deg, var(--velvet), var(--ink));
  border: 1px solid var(--line); display: flex; flex-direction: column;
}
.fchat-head {
  display: flex; align-items: center; gap: 8px; padding: 11px 12px;
  border-bottom: 1px solid var(--line-soft);
  background: linear-gradient(180deg, rgba(122, 36, 54, .28), transparent);
}
.fchat-title { margin-right: auto; line-height: 1.05; }
.fchat-title .eyebrow { display: block; margin: 0 0 1px; }
.fchat-title b { font-family: var(--display); font-size: 17px; color: var(--ivory); }
.fchat-ic {
  width: 30px; height: 30px; display: grid; place-items: center;
  background: transparent; border: 1px solid var(--line); border-radius: 9px;
  color: var(--ivory); cursor: pointer; font-size: 14px; transition: border-color .15s, color .15s;
}
.fchat-ic:hover { border-color: var(--brass); color: var(--brass-bright); }

.fchat-filter {
  display: flex; align-items: center; gap: 8px; padding: 7px 12px;
  border-bottom: 1px solid var(--line-soft); background: var(--ink-deep);
  font-size: 12.5px; color: var(--smoke);
}
.fchat-filter-lbl { margin-right: auto; } .fchat-filter-lbl b { color: var(--ivory); }
.fchat-filter-x {
  background: transparent; border: 1px solid var(--line); border-radius: 7px;
  color: var(--brass-bright); cursor: pointer; font-size: 11.5px; padding: 3px 8px;
}
.fchat-filter-x:hover { border-color: var(--brass); }

/* feed */
.fchat-feed { flex: 1; overflow-y: auto; padding: 12px 12px 6px; display: flex; flex-direction: column; gap: 11px; }
.fchat-empty { margin: auto; text-align: center; color: var(--smoke); font-size: 13px; line-height: 1.6; padding: 20px; }
.fchat-msg { display: flex; gap: 9px; align-items: flex-start; }
.fchat-msg.mine { flex-direction: row-reverse; }
.fchat-ava {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; font: 600 11px/1 var(--body);
  color: #17100a; background: var(--ava, var(--brass)); box-shadow: 0 0 0 1px rgba(0, 0, 0, .25);
}
.fchat-bubble {
  max-width: 76%; background: var(--velvet-raised); border: 1px solid var(--line-soft);
  border-radius: 12px; padding: 7px 10px 8px;
}
.fchat-msg.mine .fchat-bubble { background: linear-gradient(180deg, #3a1a25, #2c1019); border-color: var(--line); }
.fchat-meta { display: flex; align-items: baseline; gap: 6px; margin-bottom: 3px; flex-wrap: wrap; }
.fchat-meta b { font-size: 12.5px; color: var(--brass-bright); }
/* the account handle, sitting quietly beside the display name */
.fchat-handle { font-family: var(--mono); font-size: 10.5px; color: var(--smoke); }
.fchat-demo { font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--smoke); border: 1px solid var(--line-soft); border-radius: 5px; padding: 0 4px; }
.fchat-time { font-size: 10.5px; color: var(--smoke); margin-left: auto; }
.fchat-body { font-size: 14px; line-height: 1.5; color: var(--ivory); white-space: pre-wrap; word-break: break-word; }

/* object reference chip — in the feed and inside the composer */
.fchat-chip {
  display: inline-flex; align-items: center; gap: 3px; vertical-align: baseline;
  background: rgba(201, 162, 75, .13); border: 1px solid var(--line);
  border-radius: 7px; padding: 0 6px 1px; margin: 0 1px; line-height: 1.5;
  color: var(--brass-bright); font-size: 13px; cursor: pointer;
  transition: background .14s, border-color .14s;
}
.fchat-chip:hover { background: rgba(201, 162, 75, .22); border-color: var(--brass); }
.fchat-chip .fchat-chip-i { font-size: 11px; }
.fchat-chip.in-input { cursor: default; user-select: none; }

/* composer */
.fchat-composer { border-top: 1px solid var(--line-soft); padding: 9px 10px 10px; background: var(--ink-deep); }
.fchat-input {
  min-height: 22px; max-height: 120px; overflow-y: auto;
  font-size: 14px; line-height: 1.5; color: var(--ivory);
  border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; outline: none;
}
.fchat-input:focus { border-color: var(--brass); }
.fchat-input:empty::before { content: attr(data-placeholder); color: var(--smoke); pointer-events: none; }
.fchat-input.shake { animation: fchat-shake .32s; border-color: var(--danger); }
@keyframes fchat-shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-5px)} 75%{transform:translateX(5px)} }
.fchat-tools { display: flex; align-items: center; gap: 7px; margin-top: 8px; }
.fchat-tool {
  width: 30px; height: 30px; display: grid; place-items: center; font-size: 15px;
  background: transparent; border: 1px solid var(--line); border-radius: 9px; color: var(--ivory); cursor: pointer;
}
.fchat-tool:hover { border-color: var(--brass); color: var(--brass-bright); }
.fchat-count { margin-left: auto; font: 500 12px/1 var(--mono); color: var(--smoke); }
.fchat-count.over { color: var(--danger); font-weight: 600; }
.fchat-send {
  background: linear-gradient(180deg, var(--brass-bright), var(--brass)); color: #241019;
  border: none; border-radius: 9px; padding: 7px 15px; font: 600 13px var(--body); cursor: pointer;
}
.fchat-send:hover { filter: brightness(1.05); }
.fchat-send:disabled { opacity: .45; cursor: not-allowed; filter: none; }

/* popovers: settings, emoji, object picker */
.fchat-pop {
  position: fixed; z-index: 130; width: 262px;
  background: var(--velvet-raised); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); padding: 10px; color: var(--ivory);
}
.fchat-pop-h { font: 600 12px var(--body); letter-spacing: .04em; text-transform: uppercase; color: var(--brass); margin-bottom: 8px; }
.fchat-pop-note { font-size: 11px; color: var(--smoke); margin-top: 8px; line-height: 1.45; }
.fchat-toggle { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 13px; cursor: pointer; }
.fchat-toggle input { width: 16px; height: 16px; accent-color: var(--brass); cursor: pointer; }
.fchat-emoji-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; }
.fchat-emoji { font-size: 19px; background: transparent; border: none; border-radius: 8px; padding: 5px; cursor: pointer; }
.fchat-emoji:hover { background: rgba(201, 162, 75, .16); }
.fchat-pop-search {
  width: 100%; background: var(--ink-deep); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ivory); font-size: 13px; padding: 7px 9px; outline: none; margin-bottom: 8px;
}
.fchat-pop-search:focus { border-color: var(--brass); }
.fchat-obj-list { max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.fchat-obj-hint { font-size: 12px; color: var(--smoke); padding: 8px 4px; }
.fchat-obj {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  background: transparent; border: none; border-radius: 8px; padding: 7px 8px; cursor: pointer; color: var(--ivory);
}
.fchat-obj:hover { background: rgba(201, 162, 75, .14); }
.fchat-obj-i { font-size: 16px; width: 20px; text-align: center; }
.fchat-obj-t { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.fchat-obj-t b { font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fchat-obj-t small { font-size: 11px; color: var(--smoke); }

@media (max-width: 560px) {
  #forum-window { right: 0; width: 100vw; height: 84vh; }
  #forum-window.up { transform: translate(0, -50%); }
  .fchat-frame { border-radius: 20px 0 0 20px; }
}

/* ---------- v7.0 · private fields, contact requests -------------------------- */

/* The private-fields card: one switch per owner-only group. */
.privacy-groups { display: flex; flex-direction: column; gap: 14px; margin: 4px 0 10px; }
.privacy-row {
  border: 1px solid var(--line-soft); border-radius: 10px;
  padding: 10px 12px; background: var(--ink-deep);
}
.privacy-row .switch-row { margin: 0; }

/* Contact details a non-owner hasn't been cleared for: blurred placeholder text
   that carries no real information, plus the ask/status row. */
.contact-locked {
  margin-top: 16px; padding: 12px 14px;
  border: 1px dashed var(--line); border-radius: 10px;
  background: var(--ink-deep);
}
.contact-blur-rows { margin: 6px 0 10px; }
.contact-blur-rows .spec { opacity: 0.85; }
.blurred {
  filter: blur(5px); user-select: none; pointer-events: none;
  color: var(--smoke); letter-spacing: 0.5px;
}
.contact-ask-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.contact-status {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  font-family: var(--mono); font-weight: 600;
  border: 1px solid var(--line); color: var(--smoke);
}
.contact-status-pending     { border-color: var(--brass); color: var(--brass); }
.contact-status-accepted    { border-color: #7fae7a; color: #9ed09a; }
.contact-status-rejected    { border-color: var(--danger, #c05a5a); color: #d98787; }
.contact-status-unavailable { border-color: var(--line); color: var(--smoke); }

/* Section headings inside the Review tab (contact requests vs demo worlds). */
.rv-subhead {
  margin: 18px 0 10px; font-size: 13px; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--smoke); font-weight: 600;
}
.rv-subhead:first-child { margin-top: 0; }

/* v7.1 — the two halves of a locked contact block: the portal's records (blurred
   until approved) and this account's own note (private to them). */
.contact-portal { margin-bottom: 4px; }
.contact-own {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
.contact-own .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.contact-own input {
  width: 100%; background: var(--ink-deep); color: var(--ivory);
  border: 1px solid var(--line-soft); border-radius: 8px; padding: 8px; outline: none;
}
.contact-own input:focus { border-color: var(--brass); }
@media (max-width: 560px) { .contact-own .two-col { grid-template-columns: 1fr; } }

/* ---------- v7.3 · the dressed login stage ------------------------------------
   A gate of theatre bric-a-brac arching over the login card and pooling on the
   floor. Everything sits in a pointer-events:none layer behind .stage-inner, so
   the form stays fully usable no matter how dense the decoration gets. */

.stage-dressed { position: relative; overflow: hidden; }
.stage-dressed .stage-inner { position: relative; z-index: 3; }

/* the card gets a pool of light so it stays legible against the clutter */
.stage-dressed .ticket-login,
.stage-dressed .marquee,
.stage-dressed .invite-gate {
  position: relative;
}
/* the box everything sits in — same marquee frame as the Green Room chat window */
.stage-box { position: relative; padding: 0; }
.stage-box .fchat-frame { border-radius: 24px; }
.stage-panel {
  position: relative; z-index: 2;
  margin: 14px; padding: 30px 28px 32px; border-radius: 15px;
  background: linear-gradient(180deg, var(--velvet), var(--ink));
  border: 1px solid var(--line);
}
.stage-dressed .marquee { margin-bottom: 22px; }
.stage-dressed .ticket-login { margin: 0 auto; }
@media (max-width: 620px) { .stage-panel { margin: 11px; padding: 22px 16px 24px; } }

/* Above the window, not behind it: the blooms rain onto the lid and cling to the
   edges in full view. pointer-events stays off, so the form underneath is
   completely unaffected — every click passes straight through. */
.proscenium { position: absolute; inset: 0; z-index: 6; pointer-events: none; }

/* the velvet swag the garland hangs from */
.proscenium .swag {
  position: absolute; left: -6%; right: -6%; top: -14%; height: 46%;
  background:
    radial-gradient(60% 100% at 50% 100%, rgba(122, 36, 54, 0.5), transparent 70%),
    radial-gradient(40% 80% at 12% 100%, rgba(87, 21, 34, 0.55), transparent 72%),
    radial-gradient(40% 80% at 88% 100%, rgba(87, 21, 34, 0.55), transparent 72%);
  filter: blur(6px);
}

/* Outer span = the arrival (drops in, fans out, bounces, settles — plays once).
   Inner span = the life afterwards (sway, twinkle — starts only once landed).
   Two layers so the arrival and the flicker never fight over the same property. */
/* At this density (~2,400 pieces) the cheap path matters: almost every piece is
   ONE span with a single run-once animation, no filter and no will-change. Only
   the ~5% marked `.live` — bulbs and lanterns — keep an inner layer that
   flickers after landing. */
.motif {
  position: absolute; width: var(--sz); height: var(--sz);
  margin-left: calc(var(--sz) / -2); margin-top: calc(var(--sz) / -2);
  animation: bloom-open var(--fdur) cubic-bezier(.2, 1.5, .4, 1) var(--fd) both;
  transform: rotate(var(--rot)) scale(var(--arx), var(--ary));
}
.motif.live { will-change: transform; }
/* The finished frame is a still graphic: nothing sways, nothing drifts. The only
   survivors are a scattering of bulbs and lanterns that keep a slow flicker —
   they are lights, and the Green Room frame behind them flickers the same way. */
.motif-in {
  display: block; width: 100%; height: 100%;
  animation: bulb-twinkle var(--t) ease-in-out calc(var(--fd) + var(--fdur)) infinite alternate;
}
.motif svg { width: 100%; height: 100%; display: block; }

/* palette per motif family — vivid, but all drawn from the house colours */
/* Colour is free; drop-shadow is not. Only the living garland pieces get a
   shadow — on three thousand spans it is the single most expensive property
   here, and invisible on a 9px petal buried in a bank anyway. */
.motif.marigold { color: #e8a33a; }
.motif.bloom    { color: #d9556f; }
.motif.rose     { color: #c62f4b; }
.motif.leaf     { color: #5c8a4a; }
.motif.mask     { color: var(--ivory); }
.motif.prop     { color: var(--brass); }
.motif.ticket   { color: #e8cd8a; }
.motif.star     { color: #f0d98c; }
.motif.tassel   { color: #a02840; }
.motif.lantern  { color: #d4633f; }
.motif.beam     { color: #f3e9d6; }
/* banks and per-family shadows retired in v7.6 — everything rests on the floor now. */

/* Colour now rides inline per piece (see VIVID in stageDecorHTML), so the only
   thing left here is the glow on the few pieces that are literally lights. */
.motif.live .motif-in {
  filter: drop-shadow(0 0 9px rgba(255, 217, 138, 0.8)) drop-shadow(0 0 20px rgba(255, 190, 90, 0.45));
}
.motif.floor { opacity: 1; }
/* the few that stand out of the bed sit above their neighbours */
.motif.proud { z-index: 2; }
.motif.live { z-index: 3; }

/* The descent, written to read like something suspended in a thick liquid.

   No hard bounce anywhere: the bloom drifts down at an even, unhurried rate,
   squashes softly against the lid instead of rebounding, slides out to the
   nearer edge of the window, oozes down that edge, then eases into the bed. The
   timing function is deliberately near-linear through the middle so nothing
   accelerates the way a falling object would — that constant, slightly resisted
   speed is what sells the viscosity, more than any single keyframe does. */
/* A flower opens where it already sits on the vine. Its delay is its distance
   along that vine, so the crop breaks open just behind the growing tip rather
   than all at once — that lag is what makes the vine look alive rather than
   pasted on. The overshoot in the easing is the bloom springing open. */
@keyframes bloom-open {
  0%   { transform: rotate(calc(var(--rot) - 40deg)) scale(0, 0); opacity: 0; }
  60%  { opacity: 1; }
  100% { transform: rotate(var(--rot)) scale(var(--arx), var(--ary)); opacity: 1; }
}

/* The woody stem, drawn on by running a dash the length of the path. --len is
   generous on purpose: it only has to exceed the true path length. */
.vine-layer {
  position: absolute; inset: 0; width: 100%; height: 100%;
  overflow: visible; pointer-events: none;
}
.vine-stroke {
  fill: none;
  stroke: #4f7a3a;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .85;
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  animation: vine-grow var(--fdur) cubic-bezier(.36, .5, .3, 1) var(--fd) both;
}
@keyframes vine-grow {
  from { stroke-dashoffset: var(--len); }
  to   { stroke-dashoffset: 0; }
}
@keyframes bulb-twinkle {
  from { opacity: 0.55; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .motif, .motif-in, .vine-stroke, .firefly, .firefly i { animation: none; }
  .motif { transform: rotate(var(--rot)) scale(var(--arx), var(--ary)); opacity: 1; }  /* straight to the settled frame */
  .vine-stroke { animation: none; stroke-dashoffset: 0; }
}

/* Once the arrival is over, the animations are dead weight: a finished CSS
   animation still keeps its element in the browser's animation bookkeeping for
   as long as the page lives, which on a few thousand flowers is a permanent tax
   on every frame. `.settled` is added a beat after the last bloom opens and
   pins everything to exactly the frame it landed on. The fireflies are spared —
   they are the one thing still meant to be moving. */
.proscenium.settled .motif { animation: none; opacity: 1; transform: rotate(var(--rot)) scale(var(--arx), var(--ary)); }
.proscenium.settled .motif-in { animation: none; }
.proscenium.settled .vine-stroke { animation: none; stroke-dashoffset: 0; }

/* the invite-only gate under the login card */
.invite-gate { max-width: 420px; margin: 22px auto 0; text-align: center; }
.invite-gate-rule {
  display: flex; align-items: center; gap: 12px;
  color: var(--smoke); font-size: 11px; letter-spacing: 0.28em; text-transform: uppercase;
  margin-bottom: 10px;
}
.invite-gate-rule::before, .invite-gate-rule::after {
  content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, var(--line), transparent);
}
.invite-gate p { color: var(--smoke); font-size: 13px; line-height: 1.55; margin-bottom: 12px; }
.invite-gate .btn { width: 100%; justify-content: center; }
.invite-gate .btn.small { margin-top: 8px; background: transparent; border-color: transparent; color: var(--smoke); }
.invite-gate .btn.small:hover { color: var(--brass-bright); }

/* A phone carries roughly a third of the carpet: it still reads as a strewn
   floor, but 2,400 spans on a mobile GPU does not. */
@media (max-width: 620px) {
  .motif { --sz: calc(var(--sz) * 0.78); }
  .proscenium .motif:nth-of-type(3n), .proscenium .motif:nth-of-type(3n+1) { display: none; }
  .firefly:nth-of-type(2n) { display: none; }
}
/* A phone used to build the full desktop arrangement and then hide half of it
   with nth-of-type — which paid for every node and threw the work away. The
   bloom budget now generates fewer in the first place, so nothing is wasted. */

/* invite request cards & the outcome note */
.ir-specs { margin-top: 6px; }
.ir-specs .spec dt { min-width: 78px; }
.ir-card .chip { margin: 2px 4px 2px 0; }
.house-verdict {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-top: 1px solid var(--line-soft);
}
.invite-outcome { text-align: center; padding: 18px 10px 6px; }
.invite-outcome-mark { font-size: 40px; line-height: 1; margin-bottom: 10px; }
.invite-outcome p { color: var(--ivory); font-size: 15px; line-height: 1.6; }
.invite-outcome.is-rejected p { color: var(--smoke); }
.invite-outcome.is-approved p { color: var(--brass-bright); }
.field label .opt {
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--smoke); font-weight: 400; margin-left: 6px;
}

/* ---------- fireflies ----------------------------------------------------------
   Outer span drifts on X, inner on Y, each with its own period — the mismatch
   traces a slow wandering loop that reads like an insect rather than a track. */
.fireflies { position: absolute; inset: 0; pointer-events: none; }
/* The walk itself is a generated @keyframes (ff-w0…ff-w11) picked per insect and
   scaled by --a, so no two share a path or a period. */
.firefly {
  position: absolute; width: 0; height: 0;
  animation-duration: var(--tw);
  animation-timing-function: linear;
  animation-delay: calc(var(--fd) * -1);   /* negative → they're already mid-flight on load */
  animation-iteration-count: infinite;
}
.firefly i {
  display: block; width: var(--fsz); height: var(--fsz); border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #fffdf0 0%, #ffe9a8 45%, rgba(232, 205, 138, 0) 100%);
  box-shadow: 0 0 7px 2px rgba(255, 224, 150, var(--glow)),
              0 0 16px 5px rgba(232, 190, 110, calc(var(--glow) * 0.45));
  animation: ff-pulse calc(var(--tw) / 7) ease-in-out var(--fd) infinite alternate;
}
@keyframes ff-pulse {
  0%   { opacity: 0.15; }
  45%  { opacity: 1; }
  100% { opacity: 0.3; }
}

/* =========================================================================
   THE SAKURA GROVE — the margins either side of the ledger
   Two trees leaning inward, grown fresh on every load. They live in the space
   .content already leaves empty (max-width 1280px, auto margins), so they never
   take a pixel from the ledger itself, and they vanish entirely once the window
   is too narrow to spare the room.

   No colour is declared here that isn't already the theme's. Bark borrows the
   smoke tone, blossom the curtain and the two brasses — so each theme grows its
   own trees, and a new theme needs no work to be planted.
   ========================================================================= */
.sakura-grove { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; }
/* The flanks claim the whole margin the ledger leaves free, and the trees inside
   them run the full height of the viewport rather than hugging the floor. The
   1180px subtrahend is the ledger's own width, so the grove still never steals a
   pixel from the content; only the empty margin grows. This box is also what
   growSakura() MEASURES: the tree is drawn to these exact pixels (see the v7.15
   note in app.js), so the canopy can no longer be cropped off the top. */
.sakura-side {
  position: absolute; top: 0; bottom: 0;
  width: calc((100vw - 1180px) / 2);
  max-width: 460px; min-width: 0;
  overflow: hidden;
}
.sakura-side.left { left: 0; }
.sakura-side.right { right: 0; }
/* The viewBox is generated to match this box 1:1, so height:100% simply means
   the tree stands the full height of the window: trunk rooted below the bottom
   edge, canopy up level with the masthead. Blossom carries more weight than the
   bark now — v7.14 painted the bloom at an effective 25% alpha, which read as
   bare branches at a glance. */
.sakura-tree { position: absolute; inset: 0; width: 100%; height: 100%; opacity: .68; }
.sakura-tree .bark { stroke: var(--smoke); opacity: .5; }
.sakura-tree .bloom .p1 { fill: var(--curtain); opacity: .78; }
.sakura-tree .bloom .p2 { fill: var(--brass); opacity: .68; }
.sakura-tree .bloom .p3 { fill: var(--brass-bright); opacity: .56; }

/* A handful of petals let go and drift down — seven a side, not seven hundred. */
.sakura-side .petal {
  position: absolute; top: -20px;
  width: var(--ps); height: var(--ps); border-radius: 60% 40% 55% 45%;
  opacity: 0; animation: sakura-fall var(--pt) linear var(--pd) infinite;
}
.sakura-side .petal.p1 { background: var(--curtain); }
.sakura-side .petal.p2 { background: var(--brass); }
.sakura-side .petal.p3 { background: var(--brass-bright); }
@keyframes sakura-fall {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 0; }
  8%   { opacity: .5; }
  85%  { opacity: .35; }
  100% { transform: translate(var(--px), 100vh) rotate(420deg); opacity: 0; }
}

/* The ledger and the demo strip sit above the grove.
   THE BUG OF v7.14, AND WHY THE MASTHEAD IS NOT IN THIS LIST: it used to read
   `.content, .masthead, .demo-banner { position: relative; z-index: 1 }`. That
   line sits BELOW the shell block, so for `.masthead` — same specificity, later
   in the file — it silently won, replacing `position: sticky; z-index: 40` with
   `relative; z-index: 1`. Two things broke at once: the masthead stopped
   sticking, and it ended up TIED with .content at layer 1. A tie is settled by
   document order, .content comes later, so .content painted on top — and with
   it every drop-down that hangs out of the masthead over the ledger. The
   Colours menu and the account menu were cut off at the masthead's edge and
   their buttons swallowed the clicks, because the ledger was physically in
   front of them.
   So the masthead keeps its own sticky/40 (see "portal shell" above), and it is
   restated here so that a future rule appended to the end of this file cannot
   quietly demote it a second time. Anything that must clear the grove and the
   ledger both belongs at 40+, not at 1. */
.content { position: relative; z-index: 1; }
.demo-banner { position: relative; z-index: 2; }
.masthead { position: sticky; z-index: 40; }

/* Below this width the margins are too thin to hold a tree, so the grove goes
   entirely rather than showing a sliver of trunk against the ledger edge. */
@media (max-width: 1420px) { .sakura-grove { display: none; } }
@media (prefers-reduced-motion: reduce) { .sakura-side .petal { animation: none; opacity: .4; } }
