/* ============================================================================
   delver/editor/src/styles.css — the editor's single stylesheet
   Dark, dense, readable. No framework; class names come from ui.js + views.
   ============================================================================ */

:root {
	--bg: #14161c;
	--bg-panel: #1c1f27;
	--bg-card: #23262f;
	--bg-hover: #2b2f3a;
	--border: #343846;
	--text: #e6e8ee;
	--text-dim: #9aa0ae;
	--accent: #7aa2f7;
	--good: #4caf7d;
	--warn: #e0af68;
	--bad: #f7768e;
	--concept: #e0af68;
	--confirmed: #4caf7d;
	--complete: #7dcfff;
	--cut: #6b7089;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
	background: var(--bg);
	color: var(--text);
	font: 14px/1.5 system-ui, -apple-system, 'Segoe UI', sans-serif;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { margin: 0.2em 0 0.5em; line-height: 1.2; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.1rem; }
button {
	background: var(--bg-hover);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: 6px 14px;
	cursor: pointer;
	font: inherit;
}
button:hover { border-color: var(--accent); }
button:disabled { opacity: 0.5; cursor: default; }
button.save { background: #2d4a75; border-color: #3d5f95; }
button.danger { background: #5a2733; border-color: #7a3745; }
input, textarea, select {
	background: var(--bg);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: 6px 10px;
	font: inherit;
	width: 100%;
}
input:focus, textarea:focus, select:focus { outline: 1px solid var(--accent); }
pre { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 10px; overflow: auto; }

/* --- shell ---------------------------------------------------------------- */
.shell { display: flex; min-height: 100vh; min-height: 100dvh; }
.sidebar {
	width: 220px;
	flex-shrink: 0;
	background: var(--bg-panel);
	border-right: 1px solid var(--border);
	padding: 14px;
	display: flex;
	flex-direction: column;
	gap: 14px;
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100dvh;
	overflow-y: auto;
}
.topbar { display: none; }
.nav-backdrop { display: none; }
.brand { font-size: 1.2rem; font-weight: 700; cursor: pointer; }
.brand-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.nav-collapse {
	background: none; border: 1px solid transparent; color: var(--text-dim);
	font-size: 1rem; padding: 3px 9px; cursor: pointer; border-radius: 6px; flex-shrink: 0;
}
.nav-collapse:hover { background: var(--bg-hover); color: var(--text); }
/* Collapsed: the sidebar becomes a slim rail — one click brings it back.
   Wide screens only; narrow screens already have the drawer + top bar. */
@media (min-width: 821px) {
	body.nav-collapsed .sidebar { width: 42px; padding: 10px 5px; align-items: center; }
	body.nav-collapsed .sidebar > :not(.brand-row) { display: none; }
	body.nav-collapsed .brand-row .brand { display: none; }
}
@media (max-width: 820px) {
	.nav-collapse { display: none; }
}
.nav-group { display: flex; flex-direction: column; gap: 2px; }
.nav-group h4 { color: var(--text-dim); text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.08em; margin: 0 0 4px; }
.nav-group a { padding: 5px 8px; border-radius: 6px; color: var(--text); }
.nav-group a:hover { background: var(--bg-hover); text-decoration: none; }
.nav-group a.active { background: var(--bg-card); color: var(--accent); }
.nav-search { margin-top: 2px; }
.whoami { display: flex; gap: 8px; align-items: center; color: var(--text-dim); font-size: 0.85rem; flex-wrap: wrap; }

/* --- who is online (the markers above the username) ------------------------------ */
.presence-footer { margin-top: auto; display: flex; flex-direction: column; gap: 6px; }
.online-row { display: flex; gap: 5px; align-items: center; flex-wrap: wrap; min-height: 20px; }
.online-label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); margin-right: 2px; }
.online-marker {
	width: 20px; height: 20px; border-radius: 50%;
	display: inline-flex; align-items: center; justify-content: center;
	color: #10131a; font-size: 10px; font-weight: 700;
	border: 1.5px solid rgba(255, 255, 255, 0.55);
	box-shadow: 0 0 0 2px var(--bg-panel);
}
.online-marker.me { border-color: #fff; }
/* Your color: the marker doubles as the picker toggle. */
button.online-marker { cursor: pointer; padding: 0; }
.color-pop { display: flex; gap: 5px; flex-wrap: wrap; padding: 6px 0 2px; }
.color-pop .map-swatch { border-radius: 50%; }
.view { flex: 1; padding: 22px 26px; min-width: 0; max-width: 1200px; }
.read-only-banner { background: var(--bad); color: #1b1b1b; padding: 8px 14px; font-weight: 600; }
/* The dev client is pointed at the REAL world — impossible to miss on purpose. */
.live-data-banner {
	background: var(--warn); color: #1b1b1b; padding: 8px 14px; font-weight: 700;
	display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.live-data-banner button { background: #1b1b1b; color: #fff; border-color: #1b1b1b; padding: 4px 12px; min-height: 0; }

/* --- data-source switch (dev hosts only) ----------------------------------------- */
.datasource { display: flex; flex-direction: column; gap: 4px; }
.datasource-label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); }
.datasource-row { display: flex; gap: 4px; }
.datasource-opt { flex: 1; padding: 5px 8px; font-size: 0.74rem; min-height: 0; }
.datasource-opt.on { background: var(--accent); color: #10131a; border-color: var(--accent); font-weight: 700; }

/* --- login ---------------------------------------------------------------- */
.login { max-width: 460px; margin: 12vh auto; display: flex; flex-direction: column; gap: 12px; padding: 0 16px; }
.login .hint { color: var(--text-dim); font-size: 0.9rem; }
.login form { display: flex; gap: 8px; }

/* --- cards + sections ------------------------------------------------------ */
.card, .section {
	background: var(--bg-card);
	border: 1px solid var(--border);
	border-radius: 10px;
	padding: 14px 16px;
	margin-bottom: 16px;
}
.section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.section-head h3 { margin: 0; }
.section-actions { display: flex; align-items: center; gap: 10px; }
.save-status { color: var(--text-dim); font-size: 0.85rem; }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 14px; flex-wrap: wrap; }
/* Wide screens: keep the actions row (Delete, status) clear of the floating
   Undo button pinned to the screen's top-right corner. (On phones the Undo
   button sits over the top bar, never the content.) */
@media (min-width: 821px) {
	.page-head { padding-right: 96px; }
}
.page-head .titles { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.entity-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* --- fields ---------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.field.inline { flex-direction: row; align-items: center; gap: 8px; }
.field.inline input[type=checkbox] { width: auto; }
.field-label { color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
.field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.field-row .field { flex: 1 1 180px; }

/* --- badges + links --------------------------------------------------------- */
.badge {
	display: inline-block;
	font-size: 0.7rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	border-radius: 10px;
	padding: 1px 8px;
	background: var(--bg-hover);
	color: var(--text-dim);
	vertical-align: middle;
}
.badge.status-concept { background: #4a3d22; color: var(--concept); }
.badge.status-confirmed { background: #22402f; color: var(--confirmed); }
.badge.status-complete { background: #1d3348; color: var(--complete); }
.badge.status-cut { background: #2c2e3b; color: var(--cut); }
.badge.deleted { background: #4a2230; color: var(--bad); }
.entity-link { display: inline-flex; gap: 6px; align-items: center; }
.entity-link.cut { color: var(--cut); text-decoration: line-through; }
.missing { color: var(--bad); font-style: italic; }

/* --- presence --------------------------------------------------------------- */
.presence { display: flex; gap: 6px; flex-wrap: wrap; }
.presence-chip {
	font-size: 0.8rem;
	background: var(--bg-hover);
	border: 1px solid var(--border);
	border-radius: 12px;
	padding: 2px 10px;
}
.presence-chip.editing { border-color: var(--warn); color: var(--warn); }
.presence-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--warn); margin-left: 6px; }

/* --- conflict --------------------------------------------------------------- */
.conflict { border: 1px solid var(--warn); border-radius: 8px; padding: 12px; margin-bottom: 12px; background: #33301f; }
.conflict-actions { display: flex; gap: 10px; margin-top: 8px; flex-wrap: wrap; }

/* --- meta footer ------------------------------------------------------------ */
.meta-footer { display: flex; gap: 16px; flex-wrap: wrap; color: var(--text-dim); font-size: 0.78rem; margin-top: 6px; }

/* --- lists ------------------------------------------------------------------ */
.list-controls { display: flex; gap: 10px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.list-controls input[type=search] { max-width: 260px; }
table.entity-table { width: 100%; border-collapse: collapse; }
table.entity-table th { text-align: left; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; padding: 6px 10px; border-bottom: 1px solid var(--border); }
table.entity-table td { padding: 7px 10px; border-bottom: 1px solid var(--border); }
table.entity-table tr:hover td { background: var(--bg-hover); }

/* --- schedule grid ----------------------------------------------------------- */
/* minmax floors the day columns so narrow screens scroll sideways instead of crushing them */
.schedule-grid { display: grid; grid-template-columns: 80px repeat(7, minmax(130px, 1fr)); gap: 4px; overflow-x: auto; }
.schedule-grid .head { color: var(--text-dim); font-size: 0.75rem; text-transform: uppercase; padding: 4px; text-align: center; }
.schedule-cell {
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: 6px;
	min-height: 54px;
	padding: 4px;
	font-size: 0.8rem;
	display: flex;
	flex-direction: column;
	gap: 3px;
}
.schedule-cell.empty { border-style: dashed; }
.schedule-cell .entry { background: var(--bg-hover); border-radius: 4px; padding: 2px 6px; display: flex; justify-content: space-between; gap: 4px; align-items: center; }
.schedule-cell .entry.overridden { outline: 1px solid var(--warn); }
.schedule-cell .entry .x { cursor: pointer; color: var(--text-dim); }
.schedule-cell .add { color: var(--text-dim); cursor: pointer; font-size: 0.75rem; }
.schedule-cell .add:hover { color: var(--accent); }

/* --- graphs (plotlines) ------------------------------------------------------ */
.graph-wrap { overflow: auto; background: var(--bg); border: 1px solid var(--border); border-radius: 10px; }
svg.plotgraph text { fill: var(--text); font: 12px system-ui; }
svg.plotgraph .node rect { fill: var(--bg-card); stroke: var(--border); rx: 8px; }
svg.plotgraph .node.concept rect { stroke: var(--concept); }
svg.plotgraph .node.confirmed rect { stroke: var(--confirmed); }
svg.plotgraph .node.core rect { stroke-width: 2.5; }
svg.plotgraph .edge { stroke: var(--text-dim); fill: none; marker-end: url(#arrow); }
svg.plotgraph .node { cursor: pointer; }

/* --- timetable ---------------------------------------------------------------- */
.timetable-controls { display: flex; gap: 10px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.timetable-controls select { width: auto; }
.tt-location { margin-bottom: 10px; }
.tt-location .who { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.tt-chip { background: var(--bg-hover); border-radius: 12px; padding: 2px 10px; font-size: 0.85rem; }
.tt-chip.via { border: 1px solid var(--warn); }

/* --- lint + logbook ----------------------------------------------------------- */
.lint-finding { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.sev { font-size: 0.7rem; font-weight: 700; padding: 1px 8px; border-radius: 10px; text-transform: uppercase; }
.sev.error { background: #4a2230; color: var(--bad); }
.sev.warning { background: #4a3d22; color: var(--warn); }
.sev.info { background: #22334a; color: var(--accent); }
.log-entry { padding: 8px 0; border-bottom: 1px solid var(--border); }
.log-entry .when { color: var(--text-dim); font-size: 0.8rem; }
.log-entry .diff { font-size: 0.82rem; color: var(--text-dim); margin-top: 3px; white-space: pre-wrap; word-break: break-word; }

/* --- comments ------------------------------------------------------------------ */
.comment { padding: 8px 0 4px; border-bottom: 1px solid var(--border); }
.comment.reply { margin-left: 28px; border-bottom: none; border-left: 2px solid var(--border); padding-left: 12px; margin-top: 6px; }
.comment-head { display: flex; align-items: baseline; gap: 10px; }
.comment-when { color: var(--text-dim); font-size: 0.75rem; }
.comment-text { white-space: pre-wrap; word-break: break-word; margin: 3px 0 4px; }
.comment-text.deleted { color: var(--text-dim); font-style: italic; }
.comment-x { background: none; border: none; color: var(--text-dim); padding: 0 4px; font-size: 0.8rem; margin-left: auto; }
.comment-x:hover { color: var(--bad); }
.comment-reply-btn { background: none; border: none; color: var(--accent); padding: 0; font-size: 0.8rem; }
.comment-composer { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.comment-composer-actions { display: flex; justify-content: flex-end; }

/* --- portraits ---------------------------------------------------------------- */
.portrait-box { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.portrait-actions { display: flex; gap: 8px; }
img.portrait { max-width: 220px; max-height: 220px; border-radius: 10px; border: 1px solid var(--border); }
.portrait.placeholder {
	width: 160px; height: 160px; border: 1px dashed var(--border); border-radius: 10px;
	display: flex; align-items: center; justify-content: center; color: var(--text-dim);
}

/* --- the crop tool (portraits) ------------------------------------------------ */
.crop-overlay {
	position: fixed; inset: 0; z-index: 200; background: rgba(8, 10, 14, 0.8);
	display: flex; flex-direction: column; align-items: center; justify-content: center;
	gap: 14px; padding: 16px;
}
.crop-stage { position: relative; overflow: hidden; border-radius: 8px; touch-action: none; user-select: none; -webkit-user-select: none; }
.crop-stage canvas { display: block; }
.crop-box {
	position: absolute; cursor: move; border: 1.5px solid var(--accent); border-radius: 4px;
	/* the giant shadow dims everything OUTSIDE the selection */
	box-shadow: 0 0 0 9999px rgba(8, 10, 14, 0.62);
}
.crop-h { position: absolute; width: 22px; height: 22px; background: var(--bg-card); border: 1.5px solid var(--accent); border-radius: 50%; }
.crop-h.nw { left: -11px; top: -11px; cursor: nwse-resize; }
.crop-h.ne { right: -11px; top: -11px; cursor: nesw-resize; }
.crop-h.sw { left: -11px; bottom: -11px; cursor: nesw-resize; }
.crop-h.se { right: -11px; bottom: -11px; cursor: nwse-resize; }
.crop-actions { display: flex; gap: 10px; }
@media (pointer: coarse) {
	.crop-h { width: 30px; height: 30px; }
	.crop-h.nw { left: -15px; top: -15px; }
	.crop-h.ne { right: -15px; top: -15px; }
	.crop-h.sw { left: -15px; bottom: -15px; }
	.crop-h.se { right: -15px; bottom: -15px; }
}

/* Publish build tags (history table) */
.badge.build-testing { background: rgba(224, 175, 104, 0.16); color: var(--warn); }
.badge.build-finished { background: rgba(125, 207, 255, 0.16); color: var(--complete); }

/* --- dashboard ---------------------------------------------------------------- */
.stat-row { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.stat { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 12px 18px; min-width: 130px; }
.stat .n { font-size: 1.6rem; font-weight: 700; }
.stat .label { color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 900px) { .two-col { grid-template-columns: 1fr; } .sidebar { width: 170px; } }

/* --- relationship editor -------------------------------------------------------- */
.rel-row { display: flex; gap: 8px; align-items: center; padding: 6px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.rel-row select { width: auto; }
.rel-kind-family { color: var(--warn); }
.rel-kind-friend { color: var(--good); }
.rel-kind-foe { color: var(--bad); }

/* --- scene helpers ---------------------------------------------------------------- */
.pill-grid { display: flex; gap: 6px; flex-wrap: wrap; }
.pill { background: var(--bg-hover); border: 1px solid var(--border); border-radius: 12px; padding: 2px 10px; font-size: 0.82rem; cursor: pointer; user-select: none; }
.pill.on { border-color: var(--accent); color: var(--accent); }
.mod-card { border: 1px solid var(--border); border-radius: 8px; padding: 10px; margin-bottom: 10px; background: var(--bg); }
.mod-card .mod-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.req-row { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; flex-wrap: wrap; }
.req-row select, .req-row input { width: auto; max-width: 100%; }

/* --- world map (the main page) --------------------------------------------------- */
/* SPACE-EFFICIENT (owner decision): no page title, slim padding, and the view
   pins itself to exactly one viewport tall so the canvas takes every pixel the
   toolbar leaves over. The right edge of the toolbar stays clear of the
   floating Undo button. DIRECT-CHILD selectors on purpose: entity pages embed
   their own nested .map-body (the per-entity canvas) and must keep scrolling. */
.view:has(> .map-body) {
	max-width: none; display: flex; flex-direction: column;
	padding: 10px 12px; height: 100vh; height: 100dvh; overflow: hidden;
}
.view:has(> .map-body) > .map-body { flex: 1 1 auto; min-height: 0; height: auto; }
.view:has(> .map-body) .map-toolbar { padding-right: 104px; }
.map-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.map-toolbar select { width: auto; }
.map-pill { border-radius: 999px; padding: 6px 14px; }
.map-pill.on { background: var(--accent); color: #10131a; border-color: var(--accent); font-weight: 600; }
.map-mode-note { color: var(--text-dim); font-size: 0.8rem; }
.map-toolbar-spacer { flex: 1; }

.map-body { display: flex; gap: 10px; min-height: 260px; position: relative; }
.map-tree { width: 235px; flex-shrink: 0; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 8px; overflow-y: auto; padding: 8px 6px; }
/* Wide screens: the tree is an inline panel the ☰ List pill can put away —
   closed, the canvas gets its 235px too. (Narrow: overlay drawer below.) */
@media (min-width: 841px) {
	.map-tree:not(.open) { display: none; }
}
.map-tree-head { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); padding: 4px 8px 6px; }
.map-tree-head.sub { margin-top: 10px; border-top: 1px solid var(--border); padding-top: 10px; }
.map-tree-row { display: flex; align-items: center; gap: 6px; padding: 3px 6px 3px 0; border-radius: 6px; color: var(--text); font-size: 0.86rem; }
.map-tree-row:hover { background: var(--bg-hover); text-decoration: none; }
.map-tree-row.character { color: var(--text-dim); font-size: 0.8rem; }
.map-tree-row .badge { flex-shrink: 0; }
.map-tree-name { cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.map-tree-caret { background: none; border: none; padding: 0; color: var(--text-dim); cursor: pointer; width: 18px; flex-shrink: 0; text-align: center; }
span.map-tree-caret { cursor: default; }
.map-tree-count { background: var(--bg-hover); border-radius: 8px; padding: 0 6px; font-size: 0.72rem; color: var(--text-dim); flex-shrink: 0; }

.map-viewport { position: relative; flex: 1; min-width: 0; overflow: hidden; border: 1px solid var(--border); border-radius: 8px; cursor: grab; touch-action: none;
	background: radial-gradient(circle, #252a36 1px, transparent 1px) 0 0 / 26px 26px, var(--bg); }
/* While snapping, the SNAP grid is the only grid — the decorative static
   dots would double up against it (they neither pan nor share its pitch). */
.map-viewport.snapping { background-image: none; }
.map-viewport.panning { cursor: grabbing; }
.map-surface { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
/* Snap grid: 20px world-space dots, offsets kept at multiples of 20 so the
   dots land exactly where snapped objects do. First child = behind shapes. */
.map-grid-layer {
	position: absolute; left: -20000px; top: -20000px; width: 40000px; height: 40000px;
	pointer-events: none;
	/* -10px shift: dot CENTERS (mid-tile) land on multiples of 20, where
	   snapped corners actually go. */
	background: radial-gradient(circle, rgba(140, 156, 192, 0.28) 1.2px, transparent 1.4px) -10px -10px / 20px 20px;
}

.map-node { position: absolute; width: 290px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35); }
.map-node-head { display: flex; align-items: center; gap: 7px; padding: 8px 10px; border-bottom: 1px solid var(--border); cursor: grab; user-select: none; background: var(--bg-hover); border-radius: 10px 10px 0 0; }
.map-node-head:active { cursor: grabbing; }
.map-node-head .badge { flex-shrink: 0; }
.map-grip { color: var(--text-dim); font-size: 0.8rem; }
.map-loc-name { color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.map-node-body { padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.map-sub { border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; background: rgba(0, 0, 0, 0.16); display: flex; flex-direction: column; gap: 6px; }
.map-sub-head { display: flex; gap: 6px; align-items: center; }
.map-sub-head .map-loc-name { font-weight: 500; font-size: 0.86rem; }

.map-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.map-chip { display: inline-flex; align-items: center; gap: 5px; background: var(--bg-hover); border-radius: 999px; padding: 2px 8px 2px 3px; font-size: 0.78rem; color: var(--text); }
.map-chip:hover { text-decoration: none; outline: 1px solid var(--accent); }
.map-chip.via { outline: 1px dashed var(--accent); }
.map-chip-name { white-space: nowrap; }
.map-avatar { width: 18px; height: 18px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.map-avatar.initials { background: var(--accent); color: #10131a; display: inline-flex; align-items: center; justify-content: center; font-size: 0.6rem; font-weight: 700; }
.map-chip-multi { color: var(--text-dim); font-size: 0.68rem; }

.map-tray { position: absolute; left: 10px; right: 10px; bottom: 10px; background: rgba(28, 31, 39, 0.94); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; display: flex; flex-direction: column; gap: 6px; max-height: 38%; overflow-y: auto; }
.map-tray-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.map-tray-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); margin-right: 4px; }
.map-empty { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 20px; text-align: center; color: var(--text-dim); overflow-y: auto; }

.map-node.flash, .map-sub.flash { animation: map-flash 1.4s ease-out; }
@keyframes map-flash {
	0%, 55% { outline: 2px solid var(--accent); outline-offset: 3px; }
	100% { outline: 2px solid transparent; outline-offset: 3px; }
}

/* --- world map: shape annotations (drawn behind the data cards) ------------------ */
.map-shapes { position: absolute; left: 0; top: 0; width: 1px; height: 1px; overflow: visible; pointer-events: none; }
.map-shapes.editing .map-shape, .map-shapes.editing .map-shape-hit, .map-shapes.editing .map-handle { pointer-events: auto; }
.map-shapes.editing .map-shape, .map-shapes.editing .map-shape-hit { cursor: move; }
/* Reference images (pasted): rounded like every card; the invisible rect in
   the same group is the pointer target, so the img itself never eats events. */
.map-image-fo { pointer-events: none; }
.map-image-holder { width: 100%; height: 100%; }
/* No own background: transparent pixels show the group's canvas-colored
   backing rect, so decals sit seamlessly and the grid never bleeds through. */
.map-image { width: 100%; height: 100%; display: block; border-radius: 10px; object-fit: fill; }

/* --- asset loading feedback ------------------------------------------------- */
/* Anything whose pixels are still in flight SHIMMERS instead of sitting blank:
   canvas reference images (below) and authed <img>s app-wide (.img-loading). */
@keyframes asset-shimmer {
	to { background-position: -200% 0; }
}
.map-image-holder.loading, img.img-loading {
	background: linear-gradient(100deg, #1b1e27 40%, #2a3040 50%, #1b1e27 60%) 0 0 / 200% 100%;
	animation: asset-shimmer 1.1s linear infinite;
}
.map-image-holder.loading { border-radius: 10px; } /* imgs keep their own radius */
/* An empty <img> has no size — give loading portraits their frame. */
img.portrait.img-loading { width: 220px; height: 220px; }

/* The floating "Adding image…" pill while a paste converts + uploads. */
.asset-toast {
	position: fixed; top: 56px; right: 12px; z-index: 70;
	background: var(--bg-card); border: 1px solid var(--border); border-radius: 999px;
	padding: 7px 16px; font-weight: 600; color: var(--text);
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
	animation: asset-toast-pulse 1.2s ease-in-out infinite;
}
@keyframes asset-toast-pulse {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.6; }
}
.map-handle { fill: var(--bg-card); stroke: var(--accent); stroke-width: 1.5; }
.map-selection-box { fill: none; stroke: var(--accent); stroke-width: 1; stroke-dasharray: 5 4; opacity: 0.8; pointer-events: none; }
.map-viewport.drawing { cursor: crosshair; }

.map-shape-panel { position: absolute; top: 10px; right: 10px; background: rgba(28, 31, 39, 0.96); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; max-width: 400px; }
.map-panel-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.map-panel-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); width: 46px; flex-shrink: 0; }
.map-panel-hint { color: var(--text-dim); font-size: 0.78rem; }
.map-swatches { display: flex; gap: 5px; flex-wrap: wrap; }
.map-swatch { width: 22px; height: 22px; border-radius: 6px; border: 1px solid var(--border); cursor: pointer; padding: 0; }
.map-swatch:hover { border-color: var(--accent); }
.map-swatch.on { outline: 2px solid var(--accent); outline-offset: 1px; }
.map-swatch.none { background: var(--bg); color: var(--text-dim); font-size: 0.8rem; line-height: 1; }

/* --- world map: notepads, comment popovers, shapes-mode focus -------------------- */
.map-viewport.shapes-editing .map-node { pointer-events: none; opacity: 0.68; }
.map-note-fo, .map-note-fo * { pointer-events: none; }
.map-shapes.editing .map-note-text { pointer-events: auto; cursor: move; }
.map-note-text { color: var(--text); font-size: 12.5px; line-height: 1.45; white-space: pre-wrap; word-break: break-word; overflow: hidden; height: 100%; user-select: none; font-family: inherit; }
.map-note-title { font-weight: 700; font-size: 13px; margin-bottom: 4px; }
.map-note-block { margin: 0 0 6px; }
.map-note-block:last-child { margin-bottom: 0; }
.map-note-bullets { margin: 0 0 6px; padding-left: 16px; list-style: disc; }
.map-note-bullets li { margin: 1px 0; }
/* URLs in notes are REAL links (new tab) — clickable even though the shapes
   layer (and the note fo subtree) is pointer-inert; noteLink() stops the
   pointerdown so a click never starts a shape drag. */
.map-note-link { color: var(--accent); text-decoration: underline; }
.map-note-fo a.map-note-link { pointer-events: auto; }

/* --- the note editor (panel): title row + the growing column of blocks --------- */
.map-note-editor { display: flex; flex-direction: column; gap: 6px; }
.map-note-title-input { flex: 1; font-size: 0.85rem; }
.map-note-block-row { display: flex; gap: 6px; align-items: stretch; }
.map-note-block-row textarea { flex: 1; font-size: 0.85rem; }
.map-note-block-side { display: flex; flex-direction: column; gap: 4px; justify-content: flex-start; }
.map-pill.small, button.danger.small { padding: 2px 8px; font-size: 0.78rem; line-height: 1.4; }

/* --- marquee selection ---------------------------------------------------------- */
.map-marquee {
	position: absolute; z-index: 8; pointer-events: none;
	border: 1.5px dashed var(--accent); border-radius: 3px;
	background: rgba(122, 162, 247, 0.08);
}

/* --- live cursors (teammates on the same canvas) -------------------------------- */
.map-cursor-layer { position: absolute; left: 0; top: 0; width: 1px; height: 1px; overflow: visible; pointer-events: none; }
.map-cursor {
	position: absolute; left: 0; top: 0; pointer-events: none;
	transform-origin: 0 0;
	/* THE lag tween: each ~90ms packet glides instead of teleporting. */
	transition: transform 0.13s linear;
	will-change: transform;
	z-index: 9;
}
.map-cursor-badge {
	display: flex; align-items: center; justify-content: center;
	width: 22px; height: 22px;
	border-radius: 2px 50% 50% 50%; /* sharp top-left corner = the pointer tip */
	color: #10131a; font-size: 11px; font-weight: 700;
	border: 1.5px solid rgba(255, 255, 255, 0.85);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
}
.map-remote-sel {
	position: absolute; pointer-events: none; z-index: 7;
	border: 1.5px solid transparent; border-radius: 4px; opacity: 0.85;
}

/* --- per-entity canvases (character/location pages) ------------------------------ */
.entity-canvas .map-body { height: 60vh; min-height: 320px; }
.entity-canvas .map-toolbar { margin-bottom: 6px; }
.map-toolbar.entity .map-mode-note { font-size: 0.74rem; }
.map-viewport.space-pan { cursor: grab; }
.map-empty.passive { pointer-events: none; }

/* --- publish: release notes draft ------------------------------------------------ */
.notes-output { width: 100%; font-family: inherit; font-size: 0.88rem; line-height: 1.5; }

.map-comment-badge { background: none; border: none; color: var(--text-dim); font-size: 0.72rem; padding: 0 2px; cursor: pointer; margin-left: auto; flex-shrink: 0; }
.map-comment-badge:hover { color: var(--accent); }
.map-sub { position: relative; }
.map-node.pop-open { z-index: 5; }
.map-comment-pop { position: absolute; left: 6px; right: 6px; top: 36px; z-index: 6; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; max-height: 280px; overflow-y: auto; box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5); }
.map-sub .map-comment-pop { top: 26px; }
.map-pop-title { display: flex; gap: 10px; align-items: baseline; font-weight: 600; font-size: 0.85rem; margin-bottom: 4px; }
.map-pop-title a { margin-left: auto; font-weight: 400; font-size: 0.76rem; flex-shrink: 0; }
.map-pop-comment { padding: 7px 0 4px; border-top: 1px solid var(--border); }
.map-pop-comment.reply { margin-left: 14px; border-top: none; border-left: 2px solid var(--border); padding-left: 10px; margin-top: 4px; }
.map-pop-head { display: flex; gap: 8px; align-items: baseline; font-size: 0.8rem; }
.map-pop-when { color: var(--text-dim); font-size: 0.7rem; }
.map-pop-text { white-space: pre-wrap; word-break: break-word; font-size: 0.85rem; line-height: 1.5; margin-top: 2px; }
.map-pop-text.deleted { color: var(--text-dim); font-style: italic; }

/* Comment threads everywhere: a touch more air for readability. */
.comment-text { font-size: 0.92rem; line-height: 1.55; }

/* ================================================================================
   MOBILE — phones and tablets are first-class editors, not viewers.
   Three layers: a narrow-screen shell (drawer nav under a top bar), a
   narrow-screen map layout (tree as an overlay drawer, bottom-sheet shape
   panel), and a coarse-pointer layer (bigger targets, 16px inputs so iOS
   never auto-zooms, long-press peek bubble for hover-only info).
   ================================================================================ */

/* --- misc shared pieces --------------------------------------------------------- */
.table-scroll { overflow-x: auto; }
.table-scroll table { min-width: 560px; }
.peek-bubble {
	position: fixed; z-index: 300; max-width: min(340px, calc(100vw - 20px));
	background: var(--bg-panel); border: 1px solid var(--accent); border-radius: 8px;
	padding: 8px 12px; font-size: 0.85rem; line-height: 1.5; white-space: pre-wrap;
	box-shadow: 0 10px 26px rgba(0, 0, 0, 0.55); pointer-events: none;
}

/* --- narrow shell: top bar + off-canvas nav drawer ------------------------------- */
@media (max-width: 820px) {
	.topbar {
		display: flex; align-items: center; gap: 10px; padding: 8px 12px;
		background: var(--bg-panel); border-bottom: 1px solid var(--border);
		position: sticky; top: 0; z-index: 30;
	}
	.nav-toggle { font-size: 1.1rem; padding: 8px 14px; min-height: 42px; }
	.shell { display: block; }
	.sidebar {
		position: fixed; top: 0; left: 0; bottom: 0; width: min(280px, 84vw);
		height: 100vh; height: 100dvh; z-index: 50;
		transform: translateX(-105%); transition: transform 0.2s ease;
		box-shadow: 6px 0 30px rgba(0, 0, 0, 0.5);
	}
	body.nav-open .sidebar { transform: none; }
	body.nav-open .nav-backdrop { display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.55); z-index: 40; }
	.view { padding: 12px; max-width: none; }
	/* THE MAP IS THE PAGE on a phone: a FIXED layer filling everything under
	   the sticky top bar. Fixed positioning (rather than a `calc(100dvh - …)`
	   height in normal flow) is deliberate — it is immune to the mobile
	   URL-bar dance, to the page scrolling, and to the toolbar's own height,
	   all of which previously conspired to squeeze the canvas down to its
	   260px floor and push its contents off the bottom of the screen. (The
	   old rule also silently lost the cascade: media queries add no
	   specificity, so the base `.view:has(> .map-body) > .map-body` rule beat
	   it outright.) The toolbar keeps its natural height; the canvas takes
	   every remaining pixel. */
	.view:has(> .map-body) {
		position: fixed; left: 0; right: 0; top: 59px; bottom: 0;
		height: auto; max-width: none; padding: 6px; overflow: hidden;
	}
	.view:has(> .map-body) > .map-body { flex: 1 1 auto; min-height: 0; height: auto; }
	/* A tall canvas must never center its empty state off the bottom edge. */
	.map-empty { justify-content: flex-start; padding-top: 28px; }
}

/* --- narrow map: the tree becomes an overlay drawer over the canvas -------------- */
@media (max-width: 840px) {
	.map-tree {
		position: absolute; top: 0; left: 0; bottom: 0; z-index: 20;
		width: min(280px, 82vw); transform: translateX(-108%);
		transition: transform 0.2s ease; box-shadow: 6px 0 26px rgba(0, 0, 0, 0.5);
	}
	.map-tree.open { transform: none; }
}

/* --- phone map: one icon row + bottom sheets ------------------------------------- */
/* Every control that is not zoom / snap / draw moves into a sheet, because on a
   420px screen a wrapped toolbar costs the canvas more than those controls are
   worth. The row never wraps; it scrolls sideways if a language or font makes
   it overflow. */
.map-toolbar.compact { flex-wrap: nowrap; gap: 6px; margin-bottom: 6px; overflow-x: auto; scrollbar-width: none; }
.map-toolbar.compact::-webkit-scrollbar { display: none; }
.map-icon {
	flex-shrink: 0; min-width: 44px; min-height: 44px; padding: 0 10px;
	display: inline-flex; align-items: center; justify-content: center;
	font-size: 1.05rem; line-height: 1;
}
.map-icon.on, .map-chip-filter.on { background: var(--accent); color: #10131a; border-color: var(--accent); }
.map-chip-filter {
	flex: 1 1 auto; min-width: 0; min-height: 44px; border-radius: 999px;
	padding: 0 14px; font-weight: 600; white-space: nowrap;
	overflow: hidden; text-overflow: ellipsis;
}
.map-sheet {
	position: absolute; left: 0; right: 0; bottom: 0; z-index: 24;
	background: rgba(28, 31, 39, 0.98); border-top: 1px solid var(--border);
	border-radius: 12px 12px 0 0; padding: 10px 12px 14px;
	display: flex; flex-direction: column; gap: 8px;
	max-height: 62%; overflow-y: auto;
	box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.55);
}
.map-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.map-sheet-note { color: var(--text-dim); font-size: 0.78rem; margin: 0; }
.map-sheet select { width: auto; flex: 1; }

@media (max-width: 700px) {
	.map-shape-panel {
		top: auto; bottom: 0; left: 0; right: 0; max-width: none;
		border-radius: 12px 12px 0 0; max-height: 46%; overflow-y: auto;
	}
	.shapes-editing .map-tray { display: none; } /* the sheet owns the bottom edge */
	.map-tray { max-height: 26%; }
	.map-node { width: 250px; }
	.map-toolbar { gap: 6px; }
	.map-mode-note { flex-basis: 100%; order: 9; } /* full-width caption, no squeeze */
}

/* --- coarse pointers (any touch device): bigger everything ----------------------- */
@media (pointer: coarse) {
	button, select { min-height: 42px; }
	input:not([type=checkbox]), select, textarea { font-size: 16px; } /* iOS: no focus auto-zoom */
	input[type=checkbox] { width: 20px; height: 20px; }
	.nav-group a { padding: 11px 10px; }
	.pill { padding: 8px 14px; font-size: 0.9rem; }
	.map-pill { padding: 8px 16px; }
	.map-chip { padding: 5px 11px 5px 5px; font-size: 0.85rem; }
	.map-avatar { width: 22px; height: 22px; }
	.map-tree-row { padding: 8px 6px 8px 0; }
	.map-tree-caret { width: 32px; font-size: 1rem; padding: 4px 0; min-height: 32px; }
	.map-comment-badge { font-size: 0.85rem; padding: 6px 8px; margin: -4px 0; }
	.map-swatch { width: 32px; height: 32px; border-radius: 8px; }
	.map-grip { font-size: 1rem; padding: 4px 6px; margin: -4px 0; }
	.tt-chip { padding: 7px 12px; }
	.schedule-cell .entry .x { padding: 4px 9px; font-size: 1rem; }
	.schedule-cell .add { padding: 7px 0; font-size: 0.85rem; }
	.comment-x { padding: 8px 12px; font-size: 1rem; }
	.comment-reply-btn { padding: 9px 4px; }
	.map-note-text { user-select: none; -webkit-user-select: none; }
	.map-node-head { padding: 11px 10px; }
	.map-sub-head { min-height: 30px; }
}
.map-tree-toggle.on { border-color: var(--accent); color: var(--accent); }

/* --- universal undo + autosave --------------------------------------------------- */
.undo-btn {
	position: fixed; top: 9px; right: 12px; z-index: 60;
	background: var(--bg-card); border: 1px solid var(--border); border-radius: 999px;
	padding: 7px 16px; font-weight: 600; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}
.undo-btn:not(:disabled):hover { border-color: var(--accent); color: var(--accent); }
.undo-btn:disabled { opacity: 0.45; }
.undo-toast {
	position: fixed; top: 54px; right: 12px; z-index: 60;
	background: var(--bg-panel); border: 1px solid var(--accent); border-radius: 8px;
	padding: 9px 14px; font-size: 0.88rem; max-width: min(360px, calc(100vw - 24px));
	box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
}

/* --- schedule, day-per-row --------------------------------------------------------
   Each row reads like a day: Monday → morning / day / evening / night. */
.schedule-grid.day-rows { grid-template-columns: 150px repeat(4, minmax(150px, 1fr)); }
.schedule-grid .day-label { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; text-align: left; padding: 6px 4px; }
.schedule-grid .day-label .day-name { font-weight: 700; color: var(--text); font-size: 0.85rem; }
select.copy-day { width: 100%; min-height: 0; padding: 3px 6px; font-size: 0.72rem; color: var(--text-dim); background: var(--bg); }
.schedule-cell.pending { border-color: var(--accent); border-style: solid; }
.schedule-cell .entry { align-items: center; }
.entry-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.entry-loc { font-weight: 600; font-size: 0.8rem; }
.entry-act { color: var(--text-dim); font-size: 0.74rem; }
.entry-weight { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 0 6px; font-size: 0.7rem; color: var(--warn); flex-shrink: 0; }
button.entry-x { background: none; border: none; color: var(--text-dim); cursor: pointer; padding: 2px 7px; min-height: 0; font-size: 0.95rem; flex-shrink: 0; }
button.entry-x:hover { color: var(--bad); }
.schedule-cell button.add { background: none; border: 1px dashed transparent; color: var(--text-dim); cursor: pointer; font-size: 0.75rem; padding: 4px 2px; min-height: 0; text-align: left; }
.schedule-cell button.add:hover { color: var(--accent); border-color: var(--border); }
.schedule-add { border: 1px solid var(--accent); border-radius: 10px; padding: 12px 14px; margin-top: 12px; background: var(--bg); }
.schedule-add-title { font-weight: 700; margin-bottom: 8px; }
.schedule-add-hint { color: var(--text-dim); font-size: 0.78rem; margin: 2px 0 8px; }

@media (pointer: coarse) {
	.undo-btn { padding: 10px 18px; }
	select.copy-day { min-height: 34px; font-size: 0.8rem; }
	button.entry-x { padding: 6px 10px; }
}

/* --- character identity ----------------------------------------------------------- */
input.ref-name { text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em; }

/* --- login: Discord ---------------------------------------------------------------- */
a.discord-btn {
	display: block; text-align: center; background: #5865f2; color: #fff;
	font-weight: 700; font-size: 1rem; border-radius: 8px; padding: 13px 18px;
}
a.discord-btn:hover { background: #4752c4; text-decoration: none; }
