/* StoryCodex MVC front-end — theme + responsive shell.
   Dark-first palette layered over Bootstrap 5 CSS variables, the Inter typeface, and an app shell
   (sticky frosted app bar + offcanvas sidebar) that collapses to a drawer on tablets/phones. */

/* ----- Palette ------------------------------------------------------------------ */
:root {
	--bs-primary: #5B4BD6;
	--bs-primary-rgb: 91, 75, 214;
	--bs-secondary: #5A5B73;
	--bs-secondary-rgb: 90, 91, 115;
	--bs-success: #16A34A;
	--bs-success-rgb: 22, 163, 74;
	--bs-info: #3B82F6;
	--bs-info-rgb: 59, 130, 246;
	--bs-warning: #F59E0B;
	--bs-warning-rgb: 245, 158, 11;
	--bs-danger: #EF4444;
	--bs-danger-rgb: 239, 68, 68;
	--sc-tertiary: #E0457B;
	--bs-link-color: #5B4BD6;
	--bs-link-hover-color: #4536b8;
	--bs-border-radius: 0.6rem;
	--sc-surface: #ffffff;
	--sc-surface-2: #f1f2f8;
	--sc-border: rgba(20, 22, 40, 0.12);
	--sc-appbar-bg: rgba(255, 255, 255, 0.78);
	--sc-nav-active-bg: rgba(91, 75, 214, 0.12);
	--bs-body-bg: #f6f7fb;
	--bs-body-font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

[data-bs-theme="dark"] {
	--bs-primary: #8C7DFF;
	--bs-primary-rgb: 140, 125, 255;
	--bs-secondary: #8B8CA7;
	--bs-secondary-rgb: 139, 140, 167;
	--bs-success: #34D399;
	--bs-success-rgb: 52, 211, 153;
	--bs-info: #60A5FA;
	--bs-info-rgb: 96, 165, 250;
	--bs-warning: #FBBF24;
	--bs-warning-rgb: 251, 191, 36;
	--bs-danger: #F87171;
	--bs-danger-rgb: 248, 113, 113;
	--sc-tertiary: #FF6FA3;
	--bs-link-color: #9b8dff;
	--bs-link-hover-color: #b3a8ff;
	--sc-surface: #161826;
	--sc-surface-2: #1e2133;
	--sc-border: rgba(255, 255, 255, 0.10);
	--sc-appbar-bg: rgba(14, 15, 26, 0.72);
	--sc-nav-active-bg: rgba(140, 125, 255, 0.18);
	--bs-body-bg: #0E0F1A;
	--bs-body-color: #e6e7ef;
	--bs-secondary-color: rgba(230, 231, 239, 0.65);
	--bs-emphasis-color: #ffffff;
}

html {
	font-size: 15px;
}

@media (min-width: 768px) {
	html {
		font-size: 16px;
	}
}

/* Hide Alpine-controlled regions until Alpine initialises (avoids a flash of the hidden content). */
[x-cloak] {
	display: none !important;
}

body {
	font-family: var(--bs-body-font-family);
}

.text-tertiary {
	color: var(--sc-tertiary) !important;
}

.sc-hero-logo {
	display: block;
}

.sc-wordmark {
	font-weight: 700;
	letter-spacing: -0.01em;
}

a {
	text-decoration: none;
}

	a:hover {
		text-decoration: underline;
	}
	/* Anchors styled as buttons never underline (Bootstrap sets none; the a:hover rule above would re-add it). */
	a.btn,
	a.btn:hover {
		text-decoration: none;
	}

/* The logo in the app-bar. */
.sc-appbar-logo {
	width: 1.5rem;
	height: 1.5rem;
}

/* ----- Buttons (MudBlazor-derived palette) --------------------------------------
   Bootstrap's .btn-* classes hard-code their own --bs-btn-bg (e.g. #0d6efd) rather than
   reading --bs-primary, so the theme palette alone leaves them stock-blue/green/etc. Drive
   each variant's button variables from the semantic tokens above; hover/active shades are
   derived with color-mix so they track the per-theme colour automatically. */
.btn-primary {
	--bs-btn-bg: var(--bs-primary);
	--bs-btn-border-color: var(--bs-primary);
	--bs-btn-hover-bg: color-mix(in srgb, var(--bs-primary) 88%, #000);
	--bs-btn-hover-border-color: color-mix(in srgb, var(--bs-primary) 85%, #000);
	--bs-btn-active-bg: color-mix(in srgb, var(--bs-primary) 78%, #000);
	--bs-btn-active-border-color: color-mix(in srgb, var(--bs-primary) 75%, #000);
	--bs-btn-disabled-bg: var(--bs-primary);
	--bs-btn-disabled-border-color: var(--bs-primary);
	--bs-btn-color: #fff;
	--bs-btn-hover-color: #fff;
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: #fff;
}

.btn-success {
	--bs-btn-bg: var(--bs-success);
	--bs-btn-border-color: var(--bs-success);
	--bs-btn-hover-bg: color-mix(in srgb, var(--bs-success) 88%, #000);
	--bs-btn-hover-border-color: color-mix(in srgb, var(--bs-success) 85%, #000);
	--bs-btn-active-bg: color-mix(in srgb, var(--bs-success) 78%, #000);
	--bs-btn-active-border-color: color-mix(in srgb, var(--bs-success) 75%, #000);
	--bs-btn-disabled-bg: var(--bs-success);
	--bs-btn-disabled-border-color: var(--bs-success);
	--bs-btn-color: #fff;
	--bs-btn-hover-color: #fff;
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: #fff;
}

.btn-info {
	--bs-btn-bg: var(--bs-info);
	--bs-btn-border-color: var(--bs-info);
	--bs-btn-hover-bg: color-mix(in srgb, var(--bs-info) 88%, #000);
	--bs-btn-hover-border-color: color-mix(in srgb, var(--bs-info) 85%, #000);
	--bs-btn-active-bg: color-mix(in srgb, var(--bs-info) 78%, #000);
	--bs-btn-active-border-color: color-mix(in srgb, var(--bs-info) 75%, #000);
	--bs-btn-disabled-bg: var(--bs-info);
	--bs-btn-disabled-border-color: var(--bs-info);
	--bs-btn-color: #fff;
	--bs-btn-hover-color: #fff;
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: #fff;
}

.btn-warning {
	--bs-btn-bg: var(--bs-warning);
	--bs-btn-border-color: var(--bs-warning);
	--bs-btn-hover-bg: color-mix(in srgb, var(--bs-warning) 88%, #000);
	--bs-btn-hover-border-color: color-mix(in srgb, var(--bs-warning) 85%, #000);
	--bs-btn-active-bg: color-mix(in srgb, var(--bs-warning) 78%, #000);
	--bs-btn-active-border-color: color-mix(in srgb, var(--bs-warning) 75%, #000);
	--bs-btn-disabled-bg: var(--bs-warning);
	--bs-btn-disabled-border-color: var(--bs-warning);
	--bs-btn-color: #000;
	--bs-btn-hover-color: #000;
	--bs-btn-active-color: #000;
	--bs-btn-disabled-color: #000;
}

.btn-danger {
	--bs-btn-bg: var(--bs-danger);
	--bs-btn-border-color: var(--bs-danger);
	--bs-btn-hover-bg: color-mix(in srgb, var(--bs-danger) 88%, #000);
	--bs-btn-hover-border-color: color-mix(in srgb, var(--bs-danger) 85%, #000);
	--bs-btn-active-bg: color-mix(in srgb, var(--bs-danger) 78%, #000);
	--bs-btn-active-border-color: color-mix(in srgb, var(--bs-danger) 75%, #000);
	--bs-btn-disabled-bg: var(--bs-danger);
	--bs-btn-disabled-border-color: var(--bs-danger);
	--bs-btn-color: #fff;
	--bs-btn-hover-color: #fff;
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: #fff;
}

/* Outline buttons: the colour fills on hover/active (and on a checked btn-check, e.g. the
   build-sheet "pick existing / create new" toggle). */
.btn-outline-primary {
	--bs-btn-color: var(--bs-primary);
	--bs-btn-border-color: var(--bs-primary);
	--bs-btn-hover-bg: var(--bs-primary);
	--bs-btn-hover-border-color: var(--bs-primary);
	--bs-btn-hover-color: #fff;
	--bs-btn-active-bg: var(--bs-primary);
	--bs-btn-active-border-color: var(--bs-primary);
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: var(--bs-primary);
	--bs-btn-disabled-border-color: var(--bs-primary);
}

.btn-outline-secondary {
	--bs-btn-color: var(--bs-secondary);
	--bs-btn-border-color: var(--bs-secondary);
	--bs-btn-hover-bg: var(--bs-secondary);
	--bs-btn-hover-border-color: var(--bs-secondary);
	--bs-btn-hover-color: #fff;
	--bs-btn-active-bg: var(--bs-secondary);
	--bs-btn-active-border-color: var(--bs-secondary);
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: var(--bs-secondary);
	--bs-btn-disabled-border-color: var(--bs-secondary);
}

.btn-outline-danger {
	--bs-btn-color: var(--bs-danger);
	--bs-btn-border-color: var(--bs-danger);
	--bs-btn-hover-bg: var(--bs-danger);
	--bs-btn-hover-border-color: var(--bs-danger);
	--bs-btn-hover-color: #fff;
	--bs-btn-active-bg: var(--bs-danger);
	--bs-btn-active-border-color: var(--bs-danger);
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: var(--bs-danger);
	--bs-btn-disabled-border-color: var(--bs-danger);
}

.btn-outline-success {
	--bs-btn-color: var(--bs-success);
	--bs-btn-border-color: var(--bs-success);
	--bs-btn-hover-bg: var(--bs-success);
	--bs-btn-hover-border-color: var(--bs-success);
	--bs-btn-hover-color: #fff;
	--bs-btn-active-bg: var(--bs-success);
	--bs-btn-active-border-color: var(--bs-success);
	--bs-btn-active-color: #fff;
	--bs-btn-disabled-color: var(--bs-success);
	--bs-btn-disabled-border-color: var(--bs-success);
}

.text-small {
	font-size: .7em;
}

/* ----- Toasts -------------------------------------------------------------------- */
/* Bootstrap's .text-bg-* utilities bake in a white foreground (color-contrast against
   its darker default theme colours), but our dark palette overrides those backgrounds to
   light pastels (e.g. --bs-success becomes mint). White text then fails contrast on the
   light toast, so force dark text + a dark close button on the light variants for WCAG-AA
   readability. The grey secondary fallback isn't overridden, so it keeps its light text. */
[data-bs-theme="dark"] .toast.text-bg-success,
[data-bs-theme="dark"] .toast.text-bg-primary,
[data-bs-theme="dark"] .toast.text-bg-warning,
[data-bs-theme="dark"] .toast.text-bg-danger {
	color: #000 !important;
}

	[data-bs-theme="dark"] .toast.text-bg-success .btn-close,
	[data-bs-theme="dark"] .toast.text-bg-primary .btn-close,
	[data-bs-theme="dark"] .toast.text-bg-warning .btn-close,
	[data-bs-theme="dark"] .toast.text-bg-danger .btn-close {
		filter: none; /* undo .btn-close-white so the × reads dark on the light background */
	}

/* ----- Badges -------------------------------------------------------------------- */
/* Same root cause as the toasts above: Bootstrap bakes color:#fff into these .text-bg-* variants,
   but our dark palette re-tints their backgrounds to lighter colours (mint success, salmon danger,
   lilac primary, grey secondary), so the white text fails contrast. Force dark text on the badges
   for AA readability. (info/warning already bake #000, so they're not in this list.) */
[data-bs-theme="dark"] .badge.text-bg-success,
[data-bs-theme="dark"] .badge.text-bg-danger,
[data-bs-theme="dark"] .badge.text-bg-primary,
[data-bs-theme="dark"] .badge.text-bg-secondary {
	color: #000 !important;
}

/* Inverse case in light mode: Bootstrap bakes color:#000 into .text-bg-info, which reads
   muddy on light mode's saturated --bs-info blue — white is cleaner. Dark mode uses a lighter
   info blue where the baked black reads well, so this is light mode only. */
[data-bs-theme="light"] .badge.text-bg-info {
	color: #fff !important;
}

/* ----- Text utilities ------------------------------------------------------------ */
/* .text-warning renders --bs-warning (amber) as a text colour. In light mode that amber is
   too pale against the near-white background, so darken it in light mode only — dark mode's
   brighter amber on the dark background already reads well. Scoped to the utility (not the
   --bs-warning token) so warning badges/borders/buttons keep their amber. */
[data-bs-theme="light"] .text-warning {
	color: #B45309 !important;
}

/* ----- App shell ---------------------------------------------------------------- */
.sc-shell {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

.sc-appbar {
	position: sticky;
	top: 0;
	z-index: 1035;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	height: 58px;
	padding: 0 0.75rem;
	background: var(--sc-appbar-bg);
	backdrop-filter: saturate(150%) blur(12px);
	-webkit-backdrop-filter: saturate(150%) blur(12px);
	border-bottom: 1px solid var(--sc-border);
}

.sc-brand {
	display: inline-flex;
	align-items: center;
	gap: 0.55rem;
	font-weight: 700;
	font-size: 1.1rem;
	color: var(--bs-emphasis-color);
}

	.sc-brand:hover {
		text-decoration: none;
	}

	.sc-brand .bi {
		color: var(--bs-primary);
		font-size: 1.25rem;
	}

/* Below md the app bar has no room for the wordmark: the hamburger + logo + collection pill + search /
   theme / avatar already fill a phone's width, and the overflow made Chrome shrink-to-fit the whole
   page. Show the logo alone and let the pill (min-width: 0, above) truncate. Scoped to .sc-appbar so
   the public shell's header — which carries the same .sc-brand-text but only a Sign in / Sign up
   beside it — keeps the wordmark on phones, where it's the marketing front door's branding. */
@media (max-width: 767.98px) {
	.sc-appbar .sc-brand-text {
		display: none;
	}
}

.sc-collection-pill {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	max-width: 14rem;
	min-width: 0; /* let the pill shrink so its text-truncate span can ellipsis instead of widening the app bar */
	margin-left: 0.5rem;
	padding: 0.3rem 0.7rem;
	border: 1px solid var(--sc-border);
	border-radius: 2rem;
	background: var(--sc-surface);
	color: var(--bs-body-color);
	font-size: 0.85rem;
}

	.sc-collection-pill:hover {
		text-decoration: none;
		border-color: var(--bs-primary);
	}

.btn-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	padding: 0;
	border-radius: 0.5rem;
	color: var(--bs-body-color);
}

	.btn-icon:hover {
		background: var(--sc-surface-2);
	}

.sc-avatar {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	padding: 0;
	border-radius: 50%;
	background: var(--bs-primary);
	color: #fff;
	font-weight: 600;
	font-size: 0.8rem;
}

/* Character avatar circle — an uploaded image or the character's initials (list rows + detail header). */
.sc-char-avatar {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	border-radius: 50%;
	background: var(--bs-primary);
	color: #fff;
	font-weight: 600;
	line-height: 1;
	overflow: hidden;
	-webkit-user-select: none;
	user-select: none;
}

	.sc-char-avatar img {
		display: block;
		width: 100%;
		height: 100%;
		object-fit: cover;
	}

.sc-char-avatar-sm {
	width: 36px;
	height: 36px;
	font-size: 0.8rem;
}

.sc-char-avatar-lg {
	width: 64px;
	height: 64px;
	font-size: 1.5rem;
}

/* Clickable header avatar: a button revealing a camera "edit" overlay on hover/focus. */
button.sc-char-avatar-button {
	padding: 0;
	border: 0;
	cursor: pointer;
	appearance: none;
}

.sc-char-avatar-edit {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(0, 0, 0, 0.45);
	color: #fff;
	font-size: 1rem;
	opacity: 0;
	transition: opacity 0.15s ease-in-out;
}

.sc-char-avatar-button:hover .sc-char-avatar-edit,
.sc-char-avatar-button:focus-visible .sc-char-avatar-edit {
	opacity: 1;
}

/* Avatar crop stage (Cropper.js) — bound the height so a large image fits the modal, and round the crop
   preview so it hints the circular avatar the square becomes. */
.sc-avatar-crop {
	margin-inline: auto;
}

#sc-avatar-crop-image {
	display: block;
	max-width: 100%;
	max-height: 320px;
}

.sc-avatar-crop .cropper-view-box,
.sc-avatar-crop .cropper-face {
	border-radius: 50%;
}

.sc-body {
	display: flex;
	flex: 1 1 auto;
	min-height: 0;
}

.sc-sidebar {
	--bs-offcanvas-width: 264px;
	width: 264px;
	flex-shrink: 0;
	border-right: 1px solid var(--sc-border);
	background: var(--bs-body-bg);
}

@media (min-width: 992px) {
	.sc-sidebar {
		position: sticky;
		top: 58px;
		height: calc(100vh - 58px);
		overflow-y: auto;
	}
}

.sc-sidebar-body {
	padding: 0.75rem;
}

.sc-main {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

.sc-content {
	flex: 1 1 auto;
	padding: 1.5rem;
}

@media (max-width: 575px) {
	.sc-content {
		padding: 1rem;
	}
}

/* ----- Navigation --------------------------------------------------------------- */
.sc-nav {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
}

.sc-nav-link {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	padding: 0.5rem 0.7rem;
	border-radius: 0.55rem;
	color: var(--bs-body-color);
	font-size: 0.92rem;
}

	.sc-nav-link:hover {
		background: var(--sc-surface-2);
		text-decoration: none;
	}

	.sc-nav-link.active {
		background: var(--sc-nav-active-bg);
		color: var(--bs-primary);
		font-weight: 600;
	}

	.sc-nav-link .bi {
		font-size: 1.05rem;
		width: 1.2rem;
		text-align: center;
	}

.sc-nav-group {
	margin: 0.9rem 0.7rem 0.25rem;
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--bs-secondary-color);
}

/* A collapsible group's header is a button, so it resets the button chrome but keeps the .sc-nav-group label
   look. No width is set: .sc-nav is a flex column, so it already stretches to the sidebar minus its margins. */
.sc-nav-group-toggle {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0;
	background: none;
	border: 0;
	text-align: left;
}

	.sc-nav-group-toggle:hover {
		color: var(--bs-body-color);
	}

.sc-nav-chevron {
	font-size: 0.7rem;
	transition: transform 0.15s ease;
}

	.sc-nav-chevron.sc-nav-chevron-open {
		transform: rotate(90deg);
	}

/* Links are nested inside a section now, so the gap lives here rather than only on .sc-nav. */
.sc-nav-section-body {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
}

.sc-nav-hint {
	padding: 0.75rem 0.7rem;
	font-size: 0.8rem;
	color: var(--bs-secondary-color);
}

.sc-nav-divider {
	margin: 0.75rem 0.3rem;
	border-color: var(--sc-border);
}

/* ----- Footer ------------------------------------------------------------------- */
.sc-footer {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1rem;
	align-items: center;
	justify-content: space-between;
	padding: 1rem 1.5rem;
	border-top: 1px solid var(--sc-border);
	color: var(--bs-secondary-color);
	font-size: 0.85rem;
}

.sc-footer-links {
	display: flex;
	gap: 1rem;
}

/* ----- Cards / surfaces --------------------------------------------------------- */
.sc-card {
	background: var(--sc-surface);
	border: 1px solid var(--sc-border);
	border-radius: var(--bs-border-radius);
	transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}

	.sc-card:hover {
		border-color: rgba(var(--bs-primary-rgb), 0.6);
	}

/* Card watermark — a card wears its own subject as a faded glyph on its right, so a shelf of cards
   separates at a glance without a further line of text. Introduced for the collection picker's TYPE
   (WI 537) and extended to the workspace count tiles (WI 548); it is ONE treatment on purpose, because
   two copies of a wash this subtle drift apart on the first tweak and nobody sees it happen.

   The card is the positioning context; its own children are lifted above the glyph, because an
   absolutely positioned child paints over static content whatever the source order says. `overflow` is
   the backstop for a card shorter than the glyph, not the shape of the design — the glyph sits WHOLLY
   inside the card, because a clipped one reads as a mistake. */
.sc-watermark-card {
	position: relative;
	overflow: hidden;
}

	.sc-watermark-card > *:not(.sc-card-watermark) {
		position: relative;
		z-index: 1;
	}

/* Everything EXCEPT the vertical anchor, which each page supplies below — the anchor is a statement
   about what the glyph has to keep clear of, and that is the one thing the two pages genuinely differ on. */
.sc-card-watermark {
	position: absolute;
	right: 0.1em;
	font-size: 5rem;
	line-height: 1;
	color: var(--bs-primary);
	/* One alpha for both themes, which is measured rather than assumed: the dark palette's primary over the
	   dark surface and the light one over white both land at ~1.23:1 against the card at this value — a shade
	   softer than the card's own border, so the glyph never competes with the description it sits behind. */
	opacity: 0.14;
	/* The glyph spans the card, so it must never intercept a click meant for Open, the gear or the bin. */
	pointer-events: none;
	transition: opacity 0.12s ease;
}

	.sc-card:hover .sc-card-watermark {
		opacity: 0.22;
	}

	/* Muted text that can cross the glyph is lifted a shade, in DARK THEME ONLY — the wash is symmetric
	   across the themes (measured above) but the text over it is not: light's secondary lands at 5.38:1
	   over the resting wash and 4.75:1 over the hover wash, while dark's #8B8CA7 lands at 4.43 and 3.88 —
	   under AA's 4.5:1 in both states, and the HOVER state is the one a first measurement misses. Sizing
	   can't fix it (the labels are author-configurable nomenclature, so no glyph size guarantees
	   clearance), and thinning the wash instead would gut the watermark: even at 0.08 the resting label
	   only reaches 4.84 and hover still fails. This value is chosen to land dark where light already is —
	   4.75 hover / 5.42 rest — while keeping 2.2:1 of separation from body text so the hierarchy still
	   reads muted. Scoped to the watermark cards via Bootstrap's own variable (`.text-secondary` resolves
	   `--bs-secondary-rgb`), so ordinary cards keep the palette's secondary and no `!important` is needed. */
	[data-bs-theme="dark"] .sc-watermark-card {
		--bs-secondary-rgb: 155, 156, 185;
	}

/* Collection picker (/collections): anchored ABOVE THE BUTTON ROW rather than centred in the card.
   Centring couples the glyph to the card's height at half rate, so holding a centred glyph clear of the
   buttons costs ~45px of card growth, where anchoring holds the same gap for free and at any height.
   3.75rem is the row, the card's own p-3 and ~6px of daylight. The glyph still passes behind the lower
   half of the name row — 5rem of glyph will not fit between a 161px card's header and its buttons, and
   behind the name is the right place for it to lose. */
.sc-collection-card .sc-card-watermark {
	bottom: 3.75rem;
}

/* The whole picker card is a click target for Open (WI 560) — the pointer is the visible promise, and it
   keys on the SAME attribute site.js delegates on, so removing the behavior from the view retires the
   promise with it. .sc-card:hover's border shift already supplies the rest of the affordance, exactly as
   it does for the count tiles this matches. */
[data-sc-open-card] {
	cursor: pointer;
}

/* Workspace count tiles (/workspace) — the same glyph at the same 5rem (WI 548), but CENTRED rather than
   anchored, because a tile carries no action row and so has nothing at its foot to keep clear. Centring is
   what the collection card could not afford; here it is the cheaper option, and it also self-corrects — a
   tile whose label wraps to two lines grows, and a centred glyph stays balanced in it where a bottom anchor
   would drift. Both lengths are in rem so the glyph and the box that must hold it scale together on zoom. */
.sc-count-card {
	/* The floor exists because the glyph is TALLER THAN THE TILE'S OWN CONTENT: a count and a one-word label
	   come to ~57px, so without it a 5rem glyph would be the thing setting the height and `overflow` would
	   clip it. 7rem leaves ~15px of daylight above and below the ink. */
	min-height: 7rem;
}

	.sc-count-card .sc-card-watermark {
		top: 50%;
		transform: translateY(-50%);
	}

/* Collection wizard info cards (/wizard/*) — each step's teaching card wears its subject (WI 556), and the
   subject is the collection's own context where it has one: the create, what-we-set-up and finish cards wear
   the type glyph, and the work and section cards wear the type's word for the thing being made, so a games
   collection walks through dice and ladders where a book series walks through books and bookmarks. CENTRED,
   the count tiles' reasoning: a prose card has no action row at its foot, so there is nothing for centring to
   fight, and a card that grows a paragraph keeps the glyph balanced where a bottom anchor would drift. The
   floor is for the two one-line cards (the whats-ready intro and the finish tip) — everywhere else the prose
   is taller than the glyph, but a 5rem glyph must never be the thing that meets `overflow: hidden`. */
.sc-wizard-card {
	min-height: 7rem;
}

	.sc-wizard-card .sc-card-watermark {
		top: 50%;
		transform: translateY(-50%);
	}

/* Collection setup hub (/setup) — a card per reference-data page. The card is a link, so it opts out of the
   link colour and lets the icon carry the accent; .sc-card:hover supplies the affordance. */
.sc-setup-card {
	color: inherit;
}

/* Recent-activity feed (dashboard) — divider-separated rows with a hover affordance. */
.sc-activity-feed > li + li {
	border-top: var(--bs-border-width) solid var(--bs-border-color);
}

.sc-activity-item {
	color: inherit;
	border-radius: var(--bs-border-radius);
	transition: background-color 0.12s ease;
}

	.sc-activity-item:hover {
		background-color: var(--sc-surface-2);
	}

/* ----- Breadcrumbs (WI 508) ------------------------------------------------------
   Rendered by the layout above every workspace page's header, so a page joins the scheme
   by existing. Deliberately muted: it is the way back, not a heading, and it sits directly
   above the h1 that is. */
.sc-breadcrumb {
	margin-bottom: 0.6rem;
	font-size: 0.85rem;
	line-height: 1.5;
}

	.sc-breadcrumb ol {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 0.1rem 0.4rem;
		margin: 0;
		padding: 0;
		list-style: none;
	}

	.sc-breadcrumb li {
		display: flex;
		align-items: center;
		min-width: 0;
	}

		/* The separator belongs to the crumb that follows it, so a trail that wraps breaks
		   before a crumb rather than leaving a chevron stranded at the end of a line. */
		.sc-breadcrumb li + li::before {
			content: "\f285"; /* bi-chevron-right */
			font-family: bootstrap-icons;
			font-size: 0.7em;
			margin-right: 0.4rem;
			color: var(--bs-secondary-color);
			opacity: 0.65;
		}

	.sc-breadcrumb a,
	.sc-breadcrumb .sc-breadcrumb-current {
		display: inline-flex;
		align-items: center;
		gap: 0.3rem;
		min-width: 0;
	}

	.sc-breadcrumb a {
		color: var(--bs-secondary-color);
		text-decoration: none;
	}

		.sc-breadcrumb a:hover,
		.sc-breadcrumb a:focus-visible {
			color: var(--bs-body-color);
			text-decoration: underline;
		}

	.sc-breadcrumb .sc-breadcrumb-current {
		color: var(--bs-body-color);
		font-weight: 500;
	}

	/* A crumb is a record's own name, which can be long. Truncate rather than wrap inside a
	   crumb: at 320px a four-deep trail otherwise becomes a paragraph above the heading. */
	.sc-breadcrumb-label {
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		max-width: 14rem;
	}

@media (max-width: 575px) {
	.sc-breadcrumb-label {
		max-width: 8.5rem;
	}
}

.sc-page-header {
	margin-bottom: 1.25rem;
}

	.sc-page-header h1 {
		font-size: 1.6rem;
		font-weight: 700;
		margin-bottom: 0.15rem;
	}

/* Build sheet (progression detail): on desktop (≥ lg, where the two-column
   layout lives), keep the back/prev/next row + page header pinned below the app
   bar as the page scrolls, with the same frosted translucency as the app bar
   (--sc-appbar-bg + backdrop blur) so scrolling content shows through softly.
   The top padding (offset by the negative margin so the initial layout is
   unchanged) gives breathing room when stuck; JS on the page publishes this
   bar's height into --sc-bsheet-header-h so the sticky stat sheet clears it.
   Below lg the columns stack, so the wrapper is a plain (non-sticky) block. */
@media (min-width: 992px) {
	.sc-build-sheet-header {
		position: sticky;
		top: 58px;
		z-index: 1020;
		background: var(--sc-appbar-bg);
		backdrop-filter: saturate(150%) blur(12px);
		-webkit-backdrop-filter: saturate(150%) blur(12px);
		padding-top: 0.75rem;
		margin-top: -0.75rem;
		padding-bottom: 0.75rem;
		margin-bottom: 1.25rem;
		border-bottom: 1px solid var(--sc-border);
	}

		.sc-build-sheet-header .sc-page-header {
			margin-bottom: 0;
		}
}

.sc-page-subtitle {
	color: var(--bs-secondary-color);
	margin: 0;
}

.sc-clamp-2 {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* ----- Tables ------------------------------------------------------------------- */
/* Every .sc-table in the app is also a Bootstrap .table-responsive, whose whole job is `overflow-x: auto`.
   A blanket `overflow: hidden` here won the cascade and silently took that away: a table wider than its card
   was clipped with no scrollbar and no touch panning, so the right-hand columns - including the row actions -
   were simply unreachable on a narrow screen. The AI-tokens card lost 233px and its Revoke button at 320px.

   Both axes are named deliberately. `overflow-x: auto` restores the scrolling; `overflow-y: hidden` is what
   still clips children to the rounded corners, which is what the original rule was actually for. Leaving
   overflow-y at its `visible` default would not do: CSS computes `visible` to `auto` when the other axis is
   not visible, so the corners would stop clipping and a stray vertical scrollbar could appear.

   `auto` shows no scrollbar when the table already fits, so nothing changes on a desktop-width grid. */
.sc-table {
	background: var(--sc-surface);
	border: 1px solid var(--sc-border);
	border-radius: var(--bs-border-radius);
	overflow-x: auto;
	overflow-y: hidden;
}

	.sc-table .table {
		margin-bottom: 0;
	}

	.sc-table thead th {
		background: var(--sc-surface-2);
		font-weight: 600;
		font-size: 0.82rem;
		text-transform: uppercase;
		letter-spacing: 0.03em;
	}

	.sc-table tbody tr:last-child td {
		border-bottom: 0;
	}

	.sc-table tfoot td {
		background: var(--sc-surface-2);
		font-weight: 400;
		font-size: 0.82rem;
		letter-spacing: 0.03em;
		/* The last tbody row has its border-bottom zeroed above, so draw the divider on
		   the footer's top edge — mirrors how thead th gets its bottom border from
		   Bootstrap (same width/colour vars, so it tracks the light/dark theme). */
		border-top: var(--bs-border-width) solid var(--bs-border-color);
		border-bottom: 0;
	}

/* ----- Grid sorting & paging ----------------------------------------------------- */
/* A sortable column heading. Inherits the thead's uppercase treatment so a sortable column
   reads as a heading first and a control second. */
.sc-sort-header {
	color: inherit;
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	white-space: nowrap;
}

	.sc-sort-header:hover {
		color: var(--bs-primary);
	}

	/* The caret is a hint until the column is the active sort, then it carries the answer. */
	.sc-sort-header .bi {
		opacity: 0.35;
		font-size: 0.75em;
	}

	.sc-sort-header.sc-sort-active,
	.sc-sort-header:hover .bi {
		opacity: 1;
	}

	.sc-sort-header.sc-sort-active {
		color: var(--bs-primary);
	}

/* With no <tfoot> to cap it, the table's rounded bottom would meet the pager's square top and show a
   seam. The pager becomes the cap instead. :has() rather than a Razor-set class, so a grid gets this
   purely by rendering a pager. */
.sc-table:has(+ .sc-pager) {
	border-bottom-left-radius: 0;
	border-bottom-right-radius: 0;
	border-bottom: 0;
}

.sc-pager {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem 1rem;
	padding: 0.6rem 0.75rem;
	background: var(--sc-surface-2);
	border: 1px solid var(--sc-border);
	border-top: 0;
	border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius);
}

.sc-pager-pages {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.25rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.sc-pager-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2rem;
	padding: 0.2rem 0.45rem;
	border: 1px solid var(--sc-border);
	border-radius: var(--bs-border-radius-sm);
	color: var(--bs-body-color);
	text-decoration: none;
	font-size: 0.85rem;
	line-height: 1.4;
}

	.sc-pager-link:hover:not(.disabled):not(.sc-pager-current) {
		background: var(--sc-surface);
		color: var(--bs-primary);
		border-color: var(--bs-primary);
	}

	.sc-pager-link.sc-pager-current {
		background: var(--bs-primary);
		border-color: var(--bs-primary);
		color: #fff;
		font-weight: 600;
	}

	.sc-pager-link.disabled {
		opacity: 0.4;
		pointer-events: none;
	}

.sc-pager-gap {
	padding: 0 0.15rem;
	color: var(--bs-secondary-color);
}

/* Handles are hidden rather than removed while sorted/paged, so the column keeps its width
   and the rows don't jump as you sort. */
.sc-drag-col-inert .sc-drag-handle {
	visibility: hidden;
}

.sc-actions {
	text-align: right;
	white-space: nowrap;
}

/* Drag-to-reorder grids (SortableJS) — a narrow grip-handle column before the first data column. */
.sc-drag-col {
	width: 2.25rem;
	text-align: center;
	padding-left: 0.35rem;
	padding-right: 0.35rem;
}

.sc-drag-handle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var(--bs-secondary-color);
	cursor: grab;
	line-height: 1;
	/* Let SortableJS own the touch drag gesture instead of the browser scrolling the page. */
	touch-action: none;
}

	.sc-drag-handle:hover {
		color: var(--bs-body-color);
	}

	.sc-drag-handle:active {
		cursor: grabbing;
	}

/* The placeholder gap left where the dragged row will drop, and the row being dragged. */
.sc-sortable-ghost {
	opacity: 0.5;
	background: var(--sc-surface-2);
}

.sc-sortable-chosen {
	background: var(--sc-surface-2);
}

/* Inline-edit inputs inside a grid (the build sheet's Free Points values): Bootstrap's light-mode
   --bs-border-color (#dee2e6) barely separates the textbox from the table surface, so darken the
   border in light mode only — dark mode's border already contrasts well against the dark rows. */
[data-bs-theme="light"] .sc-inline-value {
	border-color: var(--bs-gray-500, #adb5bd);
}

/* ----- Grade / rarity colour badge ---------------------------------------------- */
.sc-color-badge {
	display: inline-flex;
	align-items: center;
	padding: 0.15rem 0.6rem;
	border-radius: 1rem;
	font-size: 0.78rem;
	font-weight: 600;
	line-height: 1.4;
	/* Dark-first default. BadgeTagHelper emits both theme colour pairs as custom properties; this rule uses the
	   dark pair and the [data-bs-theme="light"] rule below swaps to the light pair. Falls back to a neutral surface. */
	background: var(--sc-badge-bg-dark, var(--sc-surface-2));
	color: var(--sc-badge-fg-dark, inherit);
}

[data-bs-theme="light"] .sc-color-badge {
	/* Light theme: use the light pair, falling back to the dark pair (mirror-dark) then a neutral surface. */
	background: var(--sc-badge-bg-light, var(--sc-badge-bg-dark, var(--sc-surface-2)));
	color: var(--sc-badge-fg-light, var(--sc-badge-fg-dark, inherit));
}

.sc-color-badge-outlined {
	display: inline-flex;
	align-items: center;
	padding: 0.15rem 0.6rem;
	border-radius: 1rem;
	font-size: 0.78rem;
	font-weight: 600;
	line-height: 1.4;
	/* Dark-first default. BadgeTagHelper emits both theme colour pairs as custom properties; this rule uses the
	   dark pair and the [data-bs-theme="light"] rule below swaps to the light pair. Falls back to a neutral surface. */
	border-width: thin;
	border-style: solid;
	border-color: var(--sc-badge-bg-dark, var(--sc-surface-2));
	color: var(--sc-badge-fg-dark, inherit);
}

[data-bs-theme="light"] .sc-color-badge-outlined {
	/* Light theme: use the light pair, falling back to the dark pair (mirror-dark) then a neutral surface. */
	border-color: var(--sc-badge-bg-light, var(--sc-badge-bg-dark, var(--sc-surface-2)));
	color: var(--sc-badge-fg-light, var(--sc-badge-fg-dark, inherit));
}

/* ----- Tag chips ---------------------------------------------------------------- */
/* A tag's colour is applied inline (background + a contrast-derived text colour) by TagColors.ChipStyle; this
   class supplies the shape + the neutral fallback when a tag has no colour. */
.sc-tag-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	padding: 0.1rem 0.55rem;
	border-radius: 1rem;
	border: 1px solid var(--bs-border-color);
	background: var(--sc-surface-2);
	color: var(--bs-body-color);
	font-size: 0.75rem;
	font-weight: 600;
	line-height: 1.35;
	white-space: nowrap;
}

.sc-tag-chip-list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem;
	align-items: center;
}

/* The "manage tags" affordance rendered alongside a record's chips. */
.sc-tag-manage-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.2rem;
	padding: 0.05rem 0.45rem;
	border-radius: 1rem;
	border: 1px dashed var(--bs-border-color);
	background: transparent;
	color: var(--bs-secondary-color);
	font-size: 0.72rem;
	line-height: 1.35;
}

	.sc-tag-manage-btn:hover {
		border-color: var(--bs-primary);
		color: var(--bs-primary);
	}

/* The manage-tags modal checklist. */
.sc-tag-checklist {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	max-height: 45vh;
	overflow-y: auto;
}

.sc-tag-check {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	cursor: pointer;
	margin: 0;
}

	.sc-tag-check input {
		flex: 0 0 auto;
	}

/* ----- Change history (revision log) -------------------------------------------- */
.sc-revision-list {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}

.sc-revision {
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	overflow: hidden;
}

.sc-revision-head {
	padding: 0.4rem 0.75rem;
	background: var(--sc-surface-2);
	border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.sc-revision-body {
	padding: 0.6rem 0.75rem;
	max-height: 14rem;
	overflow-y: auto;
}

	/* The sanitized rich-text preview shouldn't carry big leading/trailing margins in the small box. */
	.sc-revision-body :first-child {
		margin-top: 0;
	}

	.sc-revision-body :last-child {
		margin-bottom: 0;
	}

/* ----- Login history ------------------------------------------------------------ */
/* A user agent is one long unbroken token, so it must wrap inside the cell rather than widen the table. */
.sc-login-agent {
	max-width: 22rem;
	overflow-wrap: anywhere;
}

/* ----- Error reports ------------------------------------------------------------ */
/* A request path is an unbroken token like a user agent, so it wraps rather than widening the grid. */
.sc-error-path {
	max-width: 18rem;
	overflow-wrap: anywhere;
}

.sc-error-value {
	overflow-wrap: anywhere;
}

/* A stack trace is wide and long: scroll it inside its own box instead of stretching the page. */
.sc-error-detail {
	max-height: 32rem;
	overflow: auto;
	padding: 0.75rem;
	border-radius: var(--bs-border-radius);
	background: var(--sc-surface-2);
	font-size: 0.8125rem;
	line-height: 1.5;
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}

/* ----- API requests ------------------------------------------------------------- */
/* A route template reads as code, and it is what the eye scans down this column - so it gets a monospace
   face and wraps rather than widening the grid, like the error-report path above. */
.sc-apireq-route {
	max-width: 24rem;
	font-family: var(--bs-font-monospace);
	font-size: 0.8125rem;
	overflow-wrap: anywhere;
}

/* ----- Collaborator comments ---------------------------------------------------- */
/* The count badge sits in the corner of the comment button. */
.sc-comment-btn {
	overflow: visible;
}

.sc-comment-count {
	position: absolute;
	top: -0.15rem;
	right: -0.15rem;
	min-width: 1rem;
	height: 1rem;
	padding: 0 0.22rem;
	border-radius: 1rem;
	background: var(--bs-primary);
	color: #fff;
	font-size: 0.62rem;
	font-weight: 700;
	line-height: 1rem;
	text-align: center;
}

.sc-comment-list {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	margin-bottom: 1rem;
}

.sc-comment {
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	padding: 0.5rem 0.75rem;
}

.sc-comment-head {
	margin-bottom: 0.35rem;
}

.sc-comment-body :first-child {
	margin-top: 0;
}

.sc-comment-body :last-child {
	margin-bottom: 0;
}

.sc-comment-add {
	border-top: var(--bs-border-width) solid var(--bs-border-color);
	padding-top: 0.75rem;
}

/* ----- Rich text ---------------------------------------------------------------- */
.sc-rich-text :first-child {
	margin-top: 0;
}

.sc-rich-text :last-child {
	margin-bottom: 0;
}

/* Trumbowyg ships a light skin; re-skin it for dark mode so the editor meshes with the theme. */
[data-bs-theme="dark"] .trumbowyg-box,
[data-bs-theme="dark"] .trumbowyg-editor {
	background: var(--sc-surface);
	color: var(--bs-body-color);
	border-color: var(--sc-border);
}

	[data-bs-theme="dark"] .trumbowyg-box.trumbowyg-fullscreen {
		background: var(--bs-body-bg);
	}

	[data-bs-theme="dark"] .trumbowyg-editor[contenteditable="true"]:empty::before {
		color: var(--bs-secondary-color);
	}

[data-bs-theme="dark"] .trumbowyg-button-pane {
	background: var(--sc-surface-2);
	border-bottom-color: var(--sc-border);
}

	[data-bs-theme="dark"] .trumbowyg-button-pane::after {
		background: var(--sc-border);
	}

	[data-bs-theme="dark"] .trumbowyg-button-pane .trumbowyg-button-group::after {
		background: var(--sc-border);
	}
	/* The toolbar icons are a dark monochrome sprite; invert them to read on the dark toolbar. */
	[data-bs-theme="dark"] .trumbowyg-button-pane button svg {
		filter: invert(0.9);
	}

[data-bs-theme="dark"] .trumbowyg button:not(.trumbowyg-disable):hover,
[data-bs-theme="dark"] .trumbowyg button:not(.trumbowyg-disable):focus {
	background-color: rgba(255, 255, 255, 0.08);
}

[data-bs-theme="dark"] .trumbowyg button.trumbowyg-active,
[data-bs-theme="dark"] .trumbowyg-button-pane .trumbowyg-button-group .trumbowyg-active:hover {
	background-color: rgba(255, 255, 255, 0.14);
}

[data-bs-theme="dark"] .trumbowyg-dropdown {
	background: var(--sc-surface);
	border-color: var(--sc-border);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32);
}

	[data-bs-theme="dark"] .trumbowyg-dropdown button {
		background: var(--sc-surface);
		color: var(--bs-body-color);
	}

		[data-bs-theme="dark"] .trumbowyg-dropdown button svg {
			filter: invert(0.9);
		}

		[data-bs-theme="dark"] .trumbowyg-dropdown button:hover,
		[data-bs-theme="dark"] .trumbowyg-dropdown button:focus {
			background: var(--sc-surface-2);
		}

[data-bs-theme="dark"] .trumbowyg-modal-box {
	background: var(--sc-surface);
	color: var(--bs-body-color);
}

	[data-bs-theme="dark"] .trumbowyg-modal-box .trumbowyg-modal-title {
		background: var(--sc-surface-2);
		color: var(--bs-body-color);
		border-bottom-color: var(--sc-border);
	}

	[data-bs-theme="dark"] .trumbowyg-modal-box input {
		background: var(--bs-body-bg);
		color: var(--bs-body-color);
		border-color: var(--sc-border);
	}

	[data-bs-theme="dark"] .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset {
		color: var(--bs-body-color);
	}

/* ----- Getting Started checklist ------------------------------------------------ */
.sc-checklist {
	display: flex;
	flex-direction: column;
}

.sc-checklist-row {
	padding: 0.5rem 0.5rem;
	border-radius: 0.5rem;
	color: var(--bs-body-color);
}

	.sc-checklist-row:hover {
		background: var(--sc-surface-2);
	}

/* ----- Build sheet / stat sheet ------------------------------------------------- */
.sc-resource-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
	gap: 0.6rem;
}

.sc-resource-card {
	background: var(--sc-surface-2);
	border: 1px solid var(--sc-border);
	border-left: 3px solid var(--bs-primary);
	border-radius: 0.5rem;
	padding: 0.5rem 0.7rem;
}

.sc-resource-card-special {
	border-left-color: #b07cff;
}

.sc-resource-label {
	font-size: 0.72rem;
	color: var(--bs-secondary-color);
	text-transform: uppercase;
	letter-spacing: 0.03em;
}

.sc-resource-value {
	font-size: 1.25rem;
	font-weight: 600;
	line-height: 1.2;
}

.sc-stat-head {
	display: flex;
	align-items: center;
	font-size: 0.7rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--bs-secondary-color);
}

.sc-stat-head-spacer {
	flex: 1 1 auto;
}

.sc-stat-col {
	width: 4.5rem;
	text-align: right;
}

.sc-stat-line {
	display: flex;
	align-items: baseline;
}

.sc-stat-line-name {
	flex: 1 1 auto;
	font-size: 0.9rem;
}

.sc-stat-num {
	width: 4.5rem;
	text-align: right;
	font-variant-numeric: tabular-nums;
}

.sc-stat-num-pre {
	color: var(--bs-secondary-color);
}

.sc-stat-num-total {
	font-weight: 700;
}

.sc-stat-breakdown {
	word-break: break-word;
}

@media (min-width: 992px) {
	.sc-build-sheet-sticky {
		position: sticky;
		/* clear the sticky build-sheet header (app bar 58px + its measured height + a small gap) */
		top: calc(58px + var(--sc-bsheet-header-h, 121px) + 0.75rem);
	}
}

/* A lazily-loaded card's placeholder body (the build sheet's WI 258 skeletons): a quiet centred spinner
   with enough height that the card doesn't collapse and reflow the column when the content arrives. */
.sc-card-loading {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	min-height: 6rem;
	color: var(--bs-secondary-color);
}

/* ----- Empty state -------------------------------------------------------------- */
.sc-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	padding: 3rem 1.5rem;
	color: var(--bs-secondary-color);
	background: var(--sc-surface);
	border: 1px dashed var(--sc-border);
	border-radius: var(--bs-border-radius);
}

	.sc-empty .bi {
		font-size: 2rem;
		margin-bottom: 0.5rem;
	}

/* ----- Public (marketing / auth) shell ------------------------------------------ */
.sc-public-shell {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

.sc-public-header {
	display: flex;
	align-items: center;
	padding: 1rem 1.5rem;
}

.sc-public-main {
	flex: 1 1 auto;
}

.sc-hero {
	max-width: 56rem;
	margin: 0 auto;
	padding: 4rem 1.5rem;
	text-align: center;
}

	.sc-hero h1 {
		font-size: clamp(2rem, 5vw, 3.2rem);
		font-weight: 700;
		line-height: 1.1;
	}

	.sc-hero p.lead {
		color: var(--bs-secondary-color);
		max-width: 38rem;
		margin: 1rem auto 2rem;
	}

.sc-feature-grid {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.sc-auth-card {
	max-width: 25rem;
	margin: 3rem auto;
}

/* ----- Cookie consent banner ---------------------------------------------------- */
.sc-cookie-consent {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 1080;
	padding: 0.75rem 1rem;
	background: var(--sc-surface);
	border-top: 1px solid var(--sc-border);
	box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.18);
}

	.sc-cookie-consent[hidden] {
		display: none;
	}

.sc-cookie-consent-inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem 1.5rem;
	max-width: 70rem;
	margin: 0 auto;
}

.sc-cookie-consent-text {
	font-size: 0.85rem;
	color: var(--bs-body-color);
	flex: 1 1 18rem;
}

.sc-cookie-consent-actions {
	display: flex;
	gap: 0.5rem;
}

/* ----- Modal polish ------------------------------------------------------------- */
.modal-content {
	background: var(--sc-surface);
	border: 1px solid var(--sc-border);
}

/* A mobile browser resolves 100vh — and the 100% Bootstrap sizes .modal with — against the *large*
   viewport: the height with the retractable address bar hidden. So while that bar is showing, the modal
   is taller than the screen by exactly its height, and the footer pinned to the bottom of the modal (the
   Save button) sits below the fold, reachable only by scrolling. dvh instead tracks the viewport actually
   on screen. Pin .modal to it and the dialog/content — sized off 100% of it — follow, so the body takes
   the squeeze and the footer stays put. Browsers without dvh keep Bootstrap's 100%. The modal locks body
   scroll while open, so the address bar can't retract underneath it and resize this mid-edit. */
.modal {
	height: 100dvh;
}

/* Our form partials wrap .modal-body + .modal-footer in a <form>, so that <form> — not the body/
   footer — is the flex child of .modal-content. That extra block defeats .modal-dialog-scrollable:
   the body never gets a bounded height, so a tall form overflows and .modal-content's overflow:hidden
   clips the footer (the Save button) off-screen on short viewports (e.g. an iPad). Make the <form>
   itself the flex column so .modal-body scrolls and the header/footer stay pinned on screen. */
#sc-modal-content > form {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-height: 0; /* let the form shrink below its content height so the body can scroll */
	overflow: hidden;
}

@media (max-width: 575px) {
	.modal-dialog {
		margin: 0;
		min-height: 100%;
	}

	.modal-dialog-centered {
		align-items: stretch;
	}

	.modal-content {
		border-radius: 0;
		min-height: 100vh; /* fallback: browsers without dvh keep the previous full-screen sheet */
		min-height: 100dvh;
	}
}

/* ----- reCAPTCHA ---------------------------------------------------------------- */
/* Hide the floating v3 badge — the Contact form shows the required text disclosure instead (Google ToS). */
.grecaptcha-badge {
	visibility: hidden;
}

/* ----- Timeline (/timeline) ----------------------------------------------------- */
/* Vertical "list" view: a continuous rail with a node per event. */
.sc-timeline-list {
	position: relative;
	margin-top: 0.25rem;
}

.sc-timeline-year {
	font-weight: 600;
	color: var(--bs-secondary-color);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	font-size: 0.78rem;
	margin: 1.1rem 0 0.5rem 2rem;
}

.sc-timeline-item {
	position: relative;
	padding-left: 2rem;
	padding-bottom: 0.75rem;
}

	.sc-timeline-item::before {
		content: "";
		position: absolute;
		left: 0.4rem;
		top: 0;
		bottom: 0;
		width: 2px;
		background: var(--bs-border-color);
	}

.sc-timeline-node {
	position: absolute;
	left: 0.01rem;
	top: 0.95rem;
	width: 0.8rem;
	height: 0.8rem;
	border-radius: 50%;
	background: var(--bs-primary);
	border: 2px solid var(--sc-surface-2);
	z-index: 1;
}

.sc-timeline-card {
	padding: 0.75rem 1rem;
}

.sc-timeline-chip {
	background: var(--sc-surface-2);
	color: var(--bs-body-color);
	border: 1px solid var(--bs-border-color);
	font-weight: 500;
}

.sc-timeline-desc > :last-child {
	margin-bottom: 0;
}

/* Horizontal "axis" view: events placed along a scrollable line, spacing proportional to elapsed time. */
.sc-timeline-axis {
	overflow-x: auto;
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	background: var(--sc-surface-2);
	padding: 0.5rem 0;
}

.sc-timeline-axis-track {
	position: relative;
	height: 360px;
}

.sc-timeline-axis-inner {
	position: relative;
	height: 100%;
	margin: 0 5rem;
}

.sc-timeline-axis-line {
	position: absolute;
	top: 50%;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--bs-border-color);
}

.sc-timeline-axis-point {
	position: absolute;
	top: 0;
	height: 100%;
	width: 172px;
	transform: translateX(-50%);
}

.sc-timeline-axis-dot {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 12px;
	height: 12px;
	border-radius: 50%;
	background: var(--bs-primary);
	border: 2px solid var(--sc-surface-2);
	z-index: 2;
}

.sc-timeline-axis-card {
	position: absolute;
	left: 0;
	right: 0;
	padding: 0.45rem 0.6rem;
}

.sc-timeline-axis-point.is-above .sc-timeline-axis-card {
	bottom: calc(50% + 16px);
}

.sc-timeline-axis-point.is-below .sc-timeline-axis-card {
	top: calc(50% + 16px);
}

.sc-timeline-axis-date {
	font-size: 0.75rem;
}

/* ----- Relationship graph ------------------------------------------------------- */
/* Container for the vis-network canvas on /relationship-graph. Fixed, responsive height so the
   force-directed layout has room; theme-aware surface + border like the other cards. */
.sc-relationship-graph {
	height: min(72vh, 760px);
	min-height: 420px;
	width: 100%;
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	background: var(--sc-surface-2);
	/* Let vis-network own the drag/zoom gestures instead of the browser scrolling the page. */
	touch-action: none;
}

/* Legend chips (gender → colour), populated by relationshipgraph.js. */
.sc-graph-legend-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	color: var(--bs-secondary-color);
}

.sc-graph-legend-dot {
	width: 0.75rem;
	height: 0.75rem;
	border-radius: 50%;
	display: inline-block;
	flex: 0 0 auto;
	border: 1px solid rgba(0, 0, 0, 0.15);
}

/* vis-network hover tooltip (name · gender · race). We don't load vis-network's stylesheet, so style its
   tooltip element here to match the theme. It's appended to <body>, so this is a plain (unscoped) rule. */
.vis-tooltip {
	position: absolute;
	padding: 0.35rem 0.55rem;
	font-family: inherit;
	font-size: 0.8125rem;
	color: var(--bs-body-color);
	background: var(--sc-surface-2);
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.25);
	pointer-events: none;
	white-space: nowrap;
	z-index: 1080;
}

/* ----- Progression charts (/characters/{id}/charts) ----------------------------- */
/* Container for a Chart.js canvas — a fixed, responsive height (Chart.js fills it with
   maintainAspectRatio:false). */
.sc-chart {
	position: relative;
	height: min(58vh, 420px);
	min-height: 260px;
	width: 100%;
}

/* ----- Global search command palette (Ctrl/Cmd+K) ------------------------------- */
/* App-bar trigger: a search "pill" that collapses to an icon on small screens. */
.sc-search-trigger {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	height: 38px;
	padding: 0 0.6rem;
	border: 1px solid var(--sc-border);
	border-radius: 0.5rem;
	background: var(--sc-surface);
	color: var(--bs-secondary-color);
	font-size: 0.85rem;
}

	.sc-search-trigger:hover {
		border-color: var(--bs-primary);
		color: var(--bs-body-color);
	}

.sc-search-trigger-label {
	white-space: nowrap;
}

.sc-search-trigger-kbd {
	font-size: 0.7rem;
	padding: 0.05rem 0.35rem;
	border-radius: 0.3rem;
	background: var(--sc-surface-2);
	color: var(--bs-secondary-color);
}

@media (max-width: 575.98px) {
	.sc-search-trigger-label,
	.sc-search-trigger-kbd {
		display: none;
	}
}

/* Palette dialog: near the top, a touch wider than default so results have room. */
.sc-search-dialog {
	max-width: 640px;
	margin-top: 4.5rem;
}

.sc-search-content {
	overflow: hidden;
}

.sc-search-inputrow {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.75rem 1rem;
	border-bottom: 1px solid var(--sc-border);
}

.sc-search-inputicon {
	color: var(--bs-secondary-color);
}

.sc-search-input {
	border: 0;
	box-shadow: none !important;
	padding: 0;
	font-size: 1.05rem;
	background: transparent;
}

	.sc-search-input:focus {
		outline: none;
	}

.sc-search-esc {
	font-size: 0.7rem;
	padding: 0.1rem 0.4rem;
	border-radius: 0.3rem;
	background: var(--sc-surface-2);
	color: var(--bs-secondary-color);
}

.sc-search-results {
	max-height: min(60vh, 26rem);
	overflow-y: auto;
	padding: 0.4rem;
}

.sc-search-hint {
	padding: 1.4rem 1rem;
	text-align: center;
	color: var(--bs-secondary-color);
	font-size: 0.9rem;
}

.sc-search-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.sc-search-group {
	padding: 0.5rem 0.6rem 0.25rem;
	font-size: 0.72rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--bs-secondary-color);
}

.sc-search-item {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.5rem 0.6rem;
	border-radius: 0.5rem;
	color: var(--bs-body-color);
	text-decoration: none;
}

	.sc-search-item:hover,
	.sc-search-item.sc-search-active {
		background: var(--sc-nav-active-bg);
		text-decoration: none;
	}

.sc-search-item-icon {
	color: var(--bs-primary);
	flex: 0 0 auto;
}

.sc-search-item-title {
	flex: 1 1 auto;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.sc-search-item-sub {
	flex: 0 0 auto;
	font-size: 0.8rem;
	color: var(--bs-secondary-color);
	max-width: 40%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* ----- Plot threads & storylines ------------------------------------------------ */
/* Beat-kind colours: Introduced (start) → Developed (advance) → Resolved (payoff), plus Referenced. */
.sc-beat-introduced {
	--sc-beat-color: #0d6efd;
}

.sc-beat-developed {
	--sc-beat-color: #fd7e14;
}

.sc-beat-resolved {
	--sc-beat-color: #198754;
}

.sc-beat-referenced {
	--sc-beat-color: #6c757d;
}

/* A labelled pill (grids) and a bare dot (the board). */
.sc-beat-kind {
	display: inline-block;
	padding: 0.15rem 0.5rem;
	border-radius: 2rem;
	font-size: 0.75rem;
	font-weight: 600;
	color: #fff;
	background: var(--sc-beat-color, #6c757d);
	white-space: nowrap;
}

.sc-beat-dot {
	display: inline-block;
	width: 0.7rem;
	height: 0.7rem;
	margin: 0.1rem;
	border-radius: 50%;
	background: var(--sc-beat-color, #6c757d);
	vertical-align: middle;
}

/* The Storylines board: a threads × sections grid; the thread column is sticky while sections scroll. */
.sc-storyline {
	border: 1px solid var(--sc-border);
	border-radius: 0.5rem;
	overflow: auto;
	max-height: 72vh;
}

.sc-storyline-table {
	border-collapse: separate;
	border-spacing: 0;
	width: max-content;
	min-width: 100%;
}

	.sc-storyline-table th,
	.sc-storyline-table td {
		border-bottom: 1px solid var(--sc-border);
		border-right: 1px solid var(--sc-border);
	}

.sc-storyline-corner,
.sc-storyline-thread {
	position: sticky;
	left: 0;
	z-index: 2;
	background: var(--sc-surface-2);
	min-width: 12rem;
	max-width: 16rem;
	padding: 0.5rem 0.75rem;
	text-align: left;
	vertical-align: middle;
}

.sc-storyline-thread {
	background: var(--sc-surface);
	font-weight: 500;
}

.sc-storyline-corner {
	top: 0;
	z-index: 4;
}

.sc-storyline-table thead th {
	position: sticky;
	top: 0;
	z-index: 1;
	background: var(--sc-surface-2);
}

.sc-storyline-sectionhead {
	min-width: 3rem;
	padding: 0.4rem 0.5rem;
	text-align: center;
	font-size: 0.8rem;
	font-weight: 500;
	white-space: nowrap;
}

.sc-storyline-work {
	display: block;
	font-size: 0.7rem;
	font-weight: 600;
	color: var(--bs-primary);
	text-overflow: ellipsis;
	overflow: hidden;
	max-width: 8rem;
}

.sc-storyline-section {
	color: var(--bs-secondary-color);
}

.sc-storyline-cell {
	padding: 0.4rem 0.5rem;
	text-align: center;
	min-width: 3rem;
}

.sc-storyline-workstart {
	border-left: 2px solid var(--bs-primary);
}

/* ----- Inventory over time (a character's assets across sections) ---------------- */
.sc-inv-dot {
	display: inline-block;
	width: 0.7rem;
	height: 0.7rem;
	border-radius: 50%;
	vertical-align: middle;
	margin-right: 0.15rem;
}

	.sc-inv-dot.sc-inv-gained {
		background: var(--bs-success);
	}

	.sc-inv-dot.sc-inv-lost {
		background: var(--bs-danger);
	}

	.sc-inv-dot.sc-inv-held {
		background: var(--bs-primary);
	}

.sc-inv-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	padding: 0.1rem 0.5rem;
	margin: 0.15rem 0.15rem 0 0;
	border: 1px solid var(--bs-border-color);
	border-radius: 1rem;
	background: var(--sc-surface-2);
	font-size: 0.8rem;
}

.sc-inv-change {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.15rem;
}

.sc-inv-tag {
	display: inline-block;
	padding: 0.05rem 0.5rem;
	border-radius: 1rem;
	font-size: 0.68rem;
	font-weight: 600;
	margin-right: 0.35rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: #fff;
}

	.sc-inv-tag.sc-inv-gained {
		background: var(--bs-success);
	}

	.sc-inv-tag.sc-inv-lost {
		background: var(--bs-danger);
	}

.sc-inv-lost-item {
	text-decoration: line-through;
	opacity: 0.7;
}

.sc-inv-matrix-wrap {
	overflow-x: auto;
	border: 1px solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
}

.sc-inv-matrix {
	border-collapse: collapse;
	width: auto;
	font-size: 0.85rem;
}

	.sc-inv-matrix th,
	.sc-inv-matrix td {
		border-bottom: 1px solid var(--bs-border-color);
	}

	.sc-inv-matrix thead th {
		position: sticky;
		top: 0;
		z-index: 1;
		background: var(--sc-surface-2);
		padding: 0.35rem 0.5rem;
	}

.sc-inv-section-col {
	text-align: center;
	min-width: 2.2rem;
	font-weight: 500;
	color: var(--bs-secondary-color);
}

.sc-inv-item-col {
	position: sticky;
	left: 0;
	z-index: 1;
	background: var(--bs-body-bg);
	min-width: 11rem;
	max-width: 16rem;
	padding: 0.3rem 0.6rem;
	white-space: nowrap;
}

.sc-inv-matrix thead .sc-inv-item-col {
	z-index: 2;
	background: var(--sc-surface-2);
}

.sc-inv-cell {
	text-align: center;
	min-width: 2.2rem;
	padding: 0.3rem 0.4rem;
	color: var(--bs-secondary-color);
}

	.sc-inv-cell.sc-inv-gained {
		background: color-mix(in srgb, var(--bs-success) 22%, transparent);
		color: var(--bs-success);
		font-weight: 700;
	}

	.sc-inv-cell.sc-inv-lost {
		background: color-mix(in srgb, var(--bs-danger) 22%, transparent);
		color: var(--bs-danger);
		font-weight: 700;
	}

	.sc-inv-cell.sc-inv-held {
		background: color-mix(in srgb, var(--bs-primary) 12%, transparent);
		color: var(--bs-primary);
	}

/* ----- Scene & beat board (kanban) ---------------------------------------------- */
.sc-kanban {
	display: flex;
	gap: 1rem;
	align-items: flex-start;
	overflow-x: auto;
	padding-bottom: 0.5rem;
}

.sc-kanban-col {
	flex: 0 0 17rem;
	max-width: 17rem;
	background: var(--sc-surface-2);
	border: 1px solid var(--sc-border);
	border-radius: 0.6rem;
	display: flex;
	flex-direction: column;
	max-height: 76vh;
}

.sc-kanban-col-head {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.5rem 0.6rem;
	border-bottom: 1px solid var(--sc-border);
}

.sc-kanban-col-grip {
	cursor: grab;
	color: var(--bs-secondary-color);
}

.sc-kanban-col-title {
	flex: 1 1 auto;
	font-weight: 600;
	font-size: 0.9rem;
}

.sc-kanban-col-actions {
	display: inline-flex;
	opacity: 0;
	transition: opacity 0.12s ease-in-out;
}

.sc-kanban-col-head:hover .sc-kanban-col-actions {
	opacity: 1;
}

.sc-kanban-cards {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 0.5rem;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	min-height: 3rem;
}

.sc-kanban-card {
	background: var(--sc-surface);
	border: 1px solid var(--sc-border);
	border-radius: 0.5rem;
	padding: 0.55rem 0.6rem;
	cursor: grab;
	position: relative;
}

	.sc-kanban-card:hover {
		border-color: var(--bs-primary);
	}

.sc-kanban-card-title {
	font-weight: 500;
	font-size: 0.9rem;
	margin-bottom: 0.35rem;
	padding-right: 2.5rem;
}

.sc-kanban-card-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.35rem;
}

.sc-kanban-card-section {
	font-size: 0.75rem;
	color: var(--bs-secondary-color);
	text-decoration: none;
}

	.sc-kanban-card-section:hover {
		color: var(--bs-primary);
	}

.sc-kanban-card-desc {
	margin-top: 0.35rem;
	font-size: 0.8rem;
	color: var(--bs-secondary-color);
}

.sc-kanban-card-actions {
	position: absolute;
	top: 0.3rem;
	right: 0.3rem;
	display: inline-flex;
	opacity: 0;
	transition: opacity 0.12s ease-in-out;
}

.sc-kanban-card:hover .sc-kanban-card-actions {
	opacity: 1;
}

.sc-kanban-add {
	margin: 0.5rem;
	padding: 0.35rem;
	border: 1px dashed var(--sc-border);
	border-radius: 0.5rem;
	background: transparent;
	color: var(--bs-secondary-color);
	font-size: 0.85rem;
}

	.sc-kanban-add:hover {
		border-color: var(--bs-primary);
		color: var(--bs-primary);
	}

.sc-kanban-card-ghost,
.sc-kanban-col-ghost {
	opacity: 0.5;
}

/* Scene writing-progress status chips: Idea -> Outlined -> Drafted -> Revised -> Done. */
.sc-scene-status {
	display: inline-block;
	padding: 0.1rem 0.45rem;
	border-radius: 2rem;
	font-size: 0.7rem;
	font-weight: 600;
	color: #fff;
	background: var(--sc-scene-color, #6c757d);
}

.sc-scene-idea {
	--sc-scene-color: #6c757d;
}

.sc-scene-outlined {
	--sc-scene-color: #0d6efd;
}

.sc-scene-drafted {
	--sc-scene-color: #fd7e14;
}

.sc-scene-revised {
	--sc-scene-color: #6f42c1;
}

.sc-scene-done {
	--sc-scene-color: #198754;
}

/* ----- Quests & arcs ------------------------------------------------------------ */
/* Quest status chips: Available -> Active -> Completed, plus Failed. */
.sc-quest-status {
	display: inline-block;
	padding: 0.15rem 0.5rem;
	border-radius: 2rem;
	font-size: 0.72rem;
	font-weight: 600;
	color: #fff;
	background: var(--sc-quest-color, #6c757d);
	white-space: nowrap;
}

.sc-quest-available {
	--sc-quest-color: #6c757d;
}

.sc-quest-active {
	--sc-quest-color: #0d6efd;
}

.sc-quest-completed {
	--sc-quest-color: #198754;
}

.sc-quest-failed {
	--sc-quest-color: #dc3545;
}

/* Reward type chips: Title / Skill / Item. */
.sc-reward-type {
	display: inline-block;
	padding: 0.1rem 0.45rem;
	border-radius: 2rem;
	font-size: 0.7rem;
	font-weight: 600;
	color: #fff;
	background: var(--sc-reward-color, #6c757d);
}

.sc-reward-title {
	--sc-reward-color: #6f42c1;
}

.sc-reward-skill {
	--sc-reward-color: #0d6efd;
}

.sc-reward-item {
	--sc-reward-color: #fd7e14;
}

.sc-quest-objective-check {
	cursor: pointer;
}

/* ----- Skill/spell prerequisite trees ------------------------------------------- */
.sc-skill-tree {
	height: min(66vh, 640px);
	min-height: 380px;
	width: 100%;
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	background: var(--sc-surface-2);
	touch-action: none;
}

/* Ability kind chips (Skill / Spell) on the prerequisites list. */
.sc-ability-kind {
	display: inline-block;
	padding: 0.1rem 0.45rem;
	border-radius: 2rem;
	font-size: 0.7rem;
	font-weight: 600;
	color: #fff;
	background: var(--sc-ability-color, #6c757d);
}

.sc-ability-skill {
	--sc-ability-color: #5b8def;
}

.sc-ability-spell {
	--sc-ability-color: #9b6cd8;
}

.sc-ability-freetext {
	--sc-ability-color: #6c757d;
}

/* ----- Bestiary stat-block kind chips -------------------------------------------- */
.sc-statblock-kind {
	display: inline-block;
	padding: 0.1rem 0.5rem;
	border-radius: 2rem;
	font-size: 0.7rem;
	font-weight: 600;
	color: #fff;
	background: var(--sc-statblock-color, #6c757d);
}

.sc-statblock-npc {
	--sc-statblock-color: #0d9488;
}

.sc-statblock-monster {
	--sc-statblock-color: #b45309;
}

.sc-statblock-antagonist {
	--sc-statblock-color: #b91c1c;
}

.sc-statblock-boss {
	--sc-statblock-color: #7e22ce;
}

/* ----- Stat comparison & power-scaling ------------------------------------------- */
.sc-compare-table th,
.sc-compare-table td {
	text-align: center;
	vertical-align: top;
}

/* The stat-name column stays put while the value columns scroll. */
.sc-compare-rowhead {
	text-align: left !important;
	position: sticky;
	left: 0;
	background: var(--sc-surface);
	z-index: 1;
	white-space: nowrap;
}

.sc-compare-col {
	min-width: 9.5rem;
}

.sc-compare-baseline {
	background: var(--sc-surface-2);
}

.sc-compare-section th {
	text-align: left !important;
	background: var(--sc-surface-2);
	font-size: 0.72rem;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--bs-secondary-color);
}

.sc-compare-value {
	font-weight: 600;
	font-size: 1.05rem;
	line-height: 1.1;
}

/* Relative-magnitude bar: width is the cell's value ÷ the row's largest value. */
.sc-compare-bar {
	height: 4px;
	border-radius: 2px;
	background: var(--sc-surface-2);
	margin: 4px auto 2px;
	overflow: hidden;
}

	.sc-compare-bar > span {
		display: block;
		height: 100%;
		background: var(--bs-primary);
		border-radius: 2px;
	}

.sc-compare-delta {
	font-size: 0.72rem;
	display: flex;
	gap: 0.35rem;
	justify-content: center;
}

.sc-delta-pos {
	color: #16a34a;
	font-weight: 600;
}

.sc-delta-neg {
	color: #dc2626;
	font-weight: 600;
}

.sc-compare-ratio {
	color: var(--bs-secondary-color);
}

/* ----- Writing progress & goals -------------------------------------------------- */
.sc-progress-bar {
	height: 8px;
	border-radius: 4px;
	background: var(--sc-surface-2);
	overflow: hidden;
}

	.sc-progress-bar > span {
		display: block;
		height: 100%;
		background: var(--bs-primary);
		border-radius: 4px;
		transition: width 0.3s ease;
	}

/* --- Place hierarchy + map pins (WI59) --------------------------------------------------- */
.sc-link-plain {
	color: inherit;
	text-decoration: none;
}

	.sc-link-plain:hover {
		color: var(--bs-primary);
		text-decoration: underline;
	}

/* Nested-tree indentation in the Places grid (one step per depth level). */
.sc-tree-indent {
	display: inline-block;
	width: calc(var(--sc-tree-depth, 0) * 1.25rem);
}

/* The map image frame: pins are absolutely positioned as a percentage of the image. */
.sc-map-frame {
	position: relative;
	display: inline-block;
	max-width: 100%;
	line-height: 0;
	touch-action: none;
}

	.sc-map-frame[data-mode="arrange"] {
		cursor: crosshair;
	}

.sc-map-image {
	display: block;
	max-width: 100%;
	height: auto;
	border-radius: 8px;
	border: var(--bs-border-width) solid var(--bs-border-color);
}

.sc-map-preview {
	max-width: 100%;
	max-height: 240px;
	border-radius: 8px;
	border: var(--bs-border-width) solid var(--bs-border-color);
}

/* A pin: the icon tip sits on the (X, Y) coordinate. */
.sc-map-pin {
	position: absolute;
	transform: translate(-50%, -100%);
	line-height: 1;
	cursor: pointer;
	z-index: 2;
}

.sc-map-frame[data-mode="arrange"] .sc-map-pin {
	cursor: move;
}

.sc-map-pin.sc-map-pin-dragging {
	z-index: 5;
	opacity: 0.85;
}

.sc-map-pin-icon {
	font-size: 1.5rem;
	color: var(--bs-primary);
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}

/* The label bubble — hidden until hover so a dense map stays readable. */
.sc-map-pin-label {
	position: absolute;
	bottom: 100%;
	left: 50%;
	transform: translateX(-50%);
	margin-bottom: 2px;
	padding: 1px 8px;
	white-space: nowrap;
	font-size: 0.75rem;
	line-height: 1.4;
	color: var(--bs-body-color);
	background: var(--sc-surface-2, var(--bs-tertiary-bg));
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: 999px;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
	display: none;
}

.sc-map-pin:hover .sc-map-pin-label {
	display: block;
}

/* The delete affordance (shown only in arrange mode via Alpine x-show). */
.sc-map-pin-delete {
	position: absolute;
	top: -6px;
	right: -10px;
	width: 18px;
	height: 18px;
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: 0.6rem;
	line-height: 1;
	color: #fff;
	background: var(--bs-danger);
	border: 1px solid #fff;
	border-radius: 50%;
	cursor: pointer;
	z-index: 3;
}
/* --- Wiki-style [[mentions]] + backlinks (WI53) ------------------------------------------ */
/* An inline cross-link rendered from a [[Type:Name]] mention in a rich-text body. */
.sc-mention {
	color: var(--bs-primary);
	text-decoration: none;
	font-weight: 500;
	border-bottom: 1px dotted currentColor;
}

	.sc-mention:hover {
		text-decoration: none;
		border-bottom-style: solid;
	}

/* A mention that didn't resolve to a record — muted, not a link. */
.sc-mention-broken {
	color: var(--bs-secondary-color, var(--bs-secondary));
	font-weight: 500;
	border-bottom: 1px dashed var(--bs-danger);
	cursor: help;
}

/* The "Mentioned in" backlinks panel on a detail page. */
.sc-backlinks-item {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	padding: 0.2rem 0.6rem;
	margin: 0 0.35rem 0.35rem 0;
	font-size: 0.85rem;
	color: var(--bs-body-color);
	text-decoration: none;
	background: var(--sc-surface-2, var(--bs-tertiary-bg));
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: 999px;
}

	.sc-backlinks-item:hover {
		border-color: var(--bs-primary);
		color: var(--bs-primary);
	}

	.sc-backlinks-item .sc-backlinks-kind {
		font-size: 0.7rem;
		text-transform: uppercase;
		letter-spacing: 0.03em;
		color: var(--bs-secondary-color, var(--bs-secondary));
	}

/* The [[ mention autocomplete dropdown (appended to <body>, positioned at the caret). */
.sc-mention-dropdown {
	position: absolute;
	z-index: 2000;
	min-width: 220px;
	max-width: 340px;
	max-height: 260px;
	overflow-y: auto;
	padding: 0.25rem;
	background: var(--bs-body-bg);
	border: var(--bs-border-width) solid var(--bs-border-color);
	border-radius: 8px;
	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}

.sc-mention-option {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.75rem;
	width: 100%;
	padding: 0.3rem 0.55rem;
	text-align: left;
	background: transparent;
	border: 0;
	border-radius: 6px;
	color: var(--bs-body-color);
	cursor: pointer;
}

	.sc-mention-option:hover,
	.sc-mention-option.sc-mention-active {
		background: var(--bs-primary);
		color: #fff;
	}

.sc-mention-option-name {
	font-weight: 500;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.sc-mention-option-kind {
	flex-shrink: 0;
	font-size: 0.7rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	opacity: 0.7;
}

/* --- Release announcements & change log ---------------------------------------------------------------- */
/* The version pill on the change log, the admin grid and the announcement modal. */
.sc-release-version {
	display: inline-block;
	padding: 0.1rem 0.5rem;
	border-radius: 0.35rem;
	font-family: var(--bs-font-monospace);
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--bs-primary);
	background: color-mix(in srgb, var(--bs-primary) 14%, transparent);
	border: var(--bs-border-width) solid color-mix(in srgb, var(--bs-primary) 30%, transparent);
}

/* A change-log group's heading chip (Added / Changed / Fixed / Removed). */
.sc-release-kind {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	padding: 0.1rem 0.5rem;
	border-radius: 2rem;
	font-size: 0.7rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: #fff;
	background: var(--sc-release-kind-color, #6c757d);
}

.sc-release-kind-added {
	--sc-release-kind-color: #16a34a;
}

.sc-release-kind-changed {
	--sc-release-kind-color: #2563eb;
}

.sc-release-kind-fixed {
	--sc-release-kind-color: #d97706;
}

.sc-release-kind-removed {
	--sc-release-kind-color: #dc2626;
}

.sc-release-group {
	margin-top: 1rem;
}

.sc-release-items {
	margin: 0.5rem 0 0;
	padding-left: 1.25rem;
}

.sc-release-items li {
	margin-bottom: 0.25rem;
}

/* The public change log stacks one card per release. */
.sc-release-log {
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
}

/* Inside the announcement modal each release is a section, divided from the next. */
.modal-body > .sc-release-entry + .sc-release-entry {
	margin-top: 1.5rem;
	padding-top: 1.5rem;
	border-top: var(--bs-border-width) solid var(--bs-border-color);
}

/* ----- Status page (/error/404) -------------------------------------------------- */
/* The hero status code. Muted rather than loud so the heading below it still leads, and sized off the token
   Bootstrap already recolours per theme. It clamps because three digits at a fixed 4.5rem would overflow a
   320px phone — the app bar's lesson, applied before it can bite. */
.sc-status-code {
	font-size: clamp(3rem, 11vw, 4.5rem);
	font-weight: 700;
	line-height: 1.1;
	letter-spacing: -0.03em;
	color: var(--bs-secondary-color);
	opacity: 0.6;
}

/* --- Account utilization report (WI111) ------------------------------------------------- */
/* A compact score cell: points, percentage and a thin magnitude bar, sized so seven columns
   still fit a laptop before the responsive wrapper has to scroll. */
.sc-util-cell {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 5.5rem;
}

.sc-util-score {
	font-variant-numeric: tabular-nums;
	line-height: 1.2;
}

.sc-util-percent {
	font-size: 0.8125rem;
	color: var(--bs-secondary-color);
	font-variant-numeric: tabular-nums;
	line-height: 1.2;
}

/* Thinner than the writing-progress bar it borrows its look from — this one sits inside a table row. */
.sc-util-bar {
	height: 4px;
	margin-top: 0.15rem;
}

/* --- Help system (WI 161) ------------------------------------------------------------------ */
/* The field-help icon the HelpLabelTagHelper appends after a bound label — a quiet affordance that
   only exists when a topic is authored, so it must read as "available", never as noise. */
.sc-help-icon {
	border: 0;
	background: transparent;
	padding: 0 0.15rem;
	margin-left: 0.15rem;
	color: var(--bs-secondary-color);
	font-size: 0.85em;
	line-height: 1;
	vertical-align: baseline;
	cursor: help;
}

.sc-help-icon:hover,
.sc-help-icon:focus-visible {
	color: var(--bs-primary);
}

/* The popover body is admin-authored rich text — cap its footprint so a long note scrolls instead of
   covering the form. */
.sc-help-popover {
	max-width: 320px;
}

.sc-help-popover .popover-body {
	max-height: 45vh;
	overflow-y: auto;
}

.sc-help-popover .popover-body :last-child {
	margin-bottom: 0;
}

/* The page-help offcanvas — a reading pane, so give prose a comfortable measure on wide screens. */
.sc-help-panel {
	--bs-offcanvas-width: 420px;
}

/* Dialog help (WI 181): an authored Dialog topic's blurb, prepended to a modal's body before the fields
   by the HelpDialogTagHelper. A quiet intro strip on the surface tokens, so it reads as guidance rather
   than an alert, in both themes. */
.sc-dialog-help {
	background: var(--sc-surface-2);
	border-left: 3px solid var(--bs-primary);
	border-radius: var(--bs-border-radius);
	padding: 0.625rem 0.75rem;
	margin-bottom: 1rem;
	font-size: 0.875rem;
	color: var(--bs-secondary-color);
}

.sc-dialog-help :last-child {
	margin-bottom: 0;
}

/* ----- Unsubscribe page ---------------------------------------------------------- */
/* An email address is one long unbroken token. Without this an 80-character address widens the card past a
   320px viewport, and mobile Chrome answers by shrink-to-fitting the whole page (see the app-bar note). */
.sc-break-anywhere {
	overflow-wrap: anywhere;
}

/* ---- New collection wizard (WI 348) ------------------------------------------------------------
   The progress track. Circles on a connecting line rather than labelled pills: the labelled version
   wrapped onto three rows below xl, and the step's name is already the <h1> right beneath it. The
   connector is a pseudo-element on every item except the first, so the track needs no extra markup
   and cannot end with a line pointing at nothing. */
.sc-wizard-rail-item {
	display: flex;
	align-items: center;
}

	.sc-wizard-rail-item + .sc-wizard-rail-item::before {
		content: "";
		display: block;
		width: 1.25rem;
		height: 2px;
		background-color: var(--bs-border-color);
	}

	.sc-wizard-rail-item.is-complete + .sc-wizard-rail-item::before,
	.sc-wizard-rail-item.is-current + .sc-wizard-rail-item::before {
		background-color: var(--bs-primary);
	}

.sc-wizard-rail-bubble {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 1.75rem;
	height: 1.75rem;
	border-radius: 50%;
	border: 2px solid var(--bs-border-color);
	background-color: var(--bs-body-bg);
	color: var(--bs-secondary-color);
	font-size: .8125rem;
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
}

a.sc-wizard-rail-bubble:hover,
a.sc-wizard-rail-bubble:focus-visible {
	transform: scale(1.12);
	color: #fff;
}

.sc-wizard-rail-item.is-complete .sc-wizard-rail-bubble {
	background-color: var(--bs-primary);
	border-color: var(--bs-primary);
	color: #fff;
}

.sc-wizard-rail-item.is-current .sc-wizard-rail-bubble {
	border-color: var(--bs-primary);
	color: var(--bs-primary);
	/* The ring is what makes "you are here" read at a glance once the labels are gone. */
	box-shadow: 0 0 0 3px var(--bs-primary-bg-subtle);
}

/* Eight bubbles plus seven connectors comes to ~364px, which overflows a 320px phone once the
   container's padding is taken out - so the track tightens rather than wrapping. Measured, not
   guessed: the full-size track was 341px inside a 356px viewport with nothing to spare. */
@media (max-width: 575.98px) {
	.sc-wizard-rail-bubble {
		width: 1.5rem;
		height: 1.5rem;
		font-size: .6875rem;
	}

	.sc-wizard-rail-item + .sc-wizard-rail-item::before {
		width: .5rem;
	}
}

/* A page that hides the navigation (ViewData["HideNav"]) would otherwise hand its content the
   sidebar's 264px, stretching every line of the wizard's teaching copy. Centre it at about the
   measure it had with the sidebar present, so hiding the nav changes what is on screen and not how
   it reads. */
.sc-body-no-nav .sc-content {
	width: 100%;
	max-width: 1040px;
	margin-inline: auto;
}
