/* ============================================================================
   play-polish.css — Game-feel pass (P0 sweep from docs/audit/website-game-feel-audit.md)
   Loaded AFTER play.css so equal-specificity rules win. Scoped to body.play-app
   so the marketing site / wiki are untouched.
   Sections:
     1. Design tokens (fonts, surfaces, gold)
     2. Typography — give titles & numbers a voice
     3. Themed card surfaces — depth + category accents
     4. Button system — juicy primary verbs + tactile secondary
     5. HUD header — currency chip, mode toggle, nav tabs
     6. POV stage — make it feel like a screen
   ============================================================================ */

/* ---- 1. TOKENS ---------------------------------------------------------- */
/* Owned-accent + display-font tokens (--gold-bright/-grad/-grad-soft/-glow,
   --font-display/-numeric) now live in the shared styles.css :root, so the look
   stays in sync across site / wiki / play. Only play-specific surface + category
   tokens are defined here. */
body.play-app {
	/* Surfaces with real material: top highlight + body gradient + drop shadow */
	--surface-card: linear-gradient(168deg, #1b2133 0%, #151a29 58%, #11151f 100%);
	--surface-edge: inset 0 1px 0 rgba(255, 255, 255, 0.06), inset 0 0 0 1px rgba(255, 255, 255, 0.02);
	--panel-shadow: 0 22px 48px -22px rgba(0, 0, 0, 0.85), 0 3px 10px -4px rgba(0, 0, 0, 0.55);

	/* Category accents (reuse base palette) */
	--cat-shop: #f1c40f;
	--cat-raid: #b06bd6;
	--cat-quest: #2ecc71;
	--cat-thrill: #ff6a4d;
}

/* ---- 2. TYPOGRAPHY ------------------------------------------------------ */
/* Titles get the playful display face; numbers get a consistent tabular feel. */
body.play-app h1,
body.play-app h2,
body.play-app h3,
body.play-app .play-card h2,
body.play-app .vv-hub-panel-title,
body.play-app .play-hub-panel-title,
body.play-app .rpg-panel-head,
body.play-app .play-queue-title,
body.play-app .vv-hub-idle-title {
	font-family: var(--font-display);
	letter-spacing: -0.005em;
}

body.play-app .vv-hub-panel-title,
body.play-app .play-hub-panel-title {
	font-size: 1.15rem;
	letter-spacing: 0.01em;
}

/* All game numbers: tabular, display face, slightly tighter. */
body.play-app .profile-stat .val,
body.play-app .play-gold-val,
body.play-app .vv-ride-gear,
body.play-app .play-ready {
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
}

body.play-app .profile-stat .val {
	font-size: 1.35rem;
	font-weight: 700;
	color: var(--text);
}

/* Stat labels read as a HUD legend, not form labels. */
body.play-app .profile-stat .label {
	font-weight: 700;
	letter-spacing: 0.09em;
	color: rgba(154, 163, 181, 0.85);
}

/* ---- 3. THEMED CARD SURFACES ------------------------------------------- */
body.play-app .play-card,
body.play-app .profile-stat,
body.play-app .vv-hub-panel {
	background-image: var(--surface-card);
	box-shadow: var(--surface-edge), var(--panel-shadow);
}

body.play-app .profile-stat {
	background-image: linear-gradient(168deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.015));
	box-shadow: var(--surface-edge);
	position: relative;
	overflow: hidden;
}
/* A thin accent strip on each stat tile — turns a form into a character sheet.
   Each stat carries its own identity color (set via [data-stat]). */
body.play-app .profile-stat {
	--stat-color: var(--gold-bright);
}
body.play-app .profile-stat[data-stat="stm"] { --stat-color: #2ecc71; }
body.play-app .profile-stat[data-stat="eff"] { --stat-color: #74b9ff; }
body.play-app .profile-stat[data-stat="cha"] { --stat-color: #c56bd6; }
body.play-app .profile-stat[data-stat="ap"]  { --stat-color: var(--gold-bright); }
body.play-app .profile-stat::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	width: 3px;
	background: linear-gradient(180deg, var(--stat-color), color-mix(in srgb, var(--stat-color) 25%, transparent));
	opacity: 0.9;
}
/* Stat label icon — consistent inline-SVG glyph, tinted to the stat's color. */
body.play-app .profile-stat .label {
	display: inline-flex;
	align-items: center;
	gap: 0.32rem;
}
body.play-app .profile-stat-ic {
	display: inline-flex;
	color: var(--stat-color);
	filter: drop-shadow(0 0 6px color-mix(in srgb, var(--stat-color) 45%, transparent));
}

/* Modal/route panels (Emporium, Profile, Bounties…) get a subtle header rule. */
body.play-app .vv-hub-panel-head {
	padding-bottom: 0.7rem;
	border-bottom: 1px solid rgba(255, 255, 255, 0.07);
	position: relative;
}

/* Close button — a real round control with hover lift. */
body.play-app .vv-hub-panel-close {
	transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
body.play-app .vv-hub-panel-close:hover {
	transform: scale(1.06);
	background: rgba(176, 107, 214, 0.18);
}

/* The queue card already has a gold edge — deepen its glow. */
body.play-app .play-queue-card {
	box-shadow: var(--surface-edge), var(--panel-shadow), 0 0 24px -10px rgba(241, 196, 15, 0.45);
}

/* ---- 4. BUTTON SYSTEM --------------------------------------------------- */
/* Secondary / list buttons: tactile, with a real press. */
body.play-app .play-action-btn,
body.play-app .play-park-btn {
	border-radius: 12px;
	background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 2px 6px -3px rgba(0, 0, 0, 0.6);
	transition: transform 0.12s ease, border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
body.play-app .play-action-btn:hover,
body.play-app .play-park-btn:hover {
	transform: translateY(-1px);
	border-color: rgba(241, 196, 15, 0.45);
}
body.play-app .play-action-btn:active,
body.play-app .play-park-btn:active {
	transform: translateY(1px) scale(0.985);
	box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.45);
	transition-duration: 0.04s;
}

/* PRIMARY VERBS — Queue / Buy / Dungeon. These are the fun; make them pop gold. */
body.play-app .play-action-btn[data-ride],
body.play-app .play-action-btn[data-dung],
body.play-app .play-action-btn[data-shop]:not(:disabled) {
	background-image: var(--gold-grad);
	color: #2a1d03;
	font-weight: 800;
	border: 1px solid rgba(255, 224, 122, 0.7);
	text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
	box-shadow: var(--gold-glow);
	/* Comfortable touch target on mobile ride lists. */
	min-height: 2.6rem;
	padding: 0.5rem 1.05rem;
}
body.play-app .play-action-btn[data-ride]:hover,
body.play-app .play-action-btn[data-dung]:hover,
body.play-app .play-action-btn[data-shop]:not(:disabled):hover {
	transform: translateY(-1px);
	border-color: #ffe89a;
	box-shadow: 0 10px 24px -8px rgba(241, 196, 15, 0.75), 0 0 0 1px rgba(255, 224, 122, 0.6);
	filter: saturate(1.08);
}
body.play-app .play-action-btn[data-ride]:active,
body.play-app .play-action-btn[data-dung]:active,
body.play-app .play-action-btn[data-shop]:not(:disabled):active {
	transform: translateY(1px) scale(0.97);
	box-shadow: inset 0 2px 6px rgba(120, 80, 0, 0.5);
}
/* Bigger tap row in ride lists. */
body.play-app .play-ride-list li {
	padding: 0.7rem 0;
}
body.play-app .play-ride-list button {
	padding: 0.5rem 1.05rem;
	font-size: 0.85rem;
}

/* ---- 5. HUD HEADER ------------------------------------------------------ */
body.play-app .play-header {
	background:
		linear-gradient(180deg, rgba(20, 16, 34, 0.92), rgba(12, 14, 20, 0.92));
	border-bottom: 1px solid rgba(241, 196, 15, 0.12);
	box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04), 0 8px 24px -16px rgba(0, 0, 0, 0.9);
}

/* Brand wordmark — a touch of arcade glow. */
body.play-app .play-logo {
	font-size: 1.12rem;
	text-shadow: 0 0 18px rgba(241, 196, 15, 0.18);
}
body.play-app .play-logo span {
	text-shadow: 0 0 14px rgba(241, 196, 15, 0.55);
}

/* Section nav as pill tabs. */
body.play-app .play-nav a {
	padding: 0.25rem 0.6rem;
	border-radius: 999px;
	font-weight: 700;
	transition: color 0.12s ease, background 0.12s ease;
}
body.play-app .play-nav a.active {
	background: var(--gold-grad-soft);
	color: var(--gold-bright);
}

/* Currency chip — the HUD's centerpiece. */
body.play-app .play-gold {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	padding: 0.2rem 0.6rem 0.2rem 0.45rem;
	border-radius: 999px;
	background: var(--gold-grad-soft);
	border: 1px solid rgba(241, 196, 15, 0.4);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
	line-height: 1;
	vertical-align: middle;
}
body.play-app .play-gold-coin {
	font-size: 0.95rem;
	filter: drop-shadow(0 1px 3px rgba(241, 196, 15, 0.6));
}
body.play-app .play-gold-val {
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
	font-weight: 800;
	font-size: 0.95rem;
	color: var(--gold-bright);
}
/* Coin-pop when the balance changes (class toggled in app-shell.js). */
body.play-app .play-gold--bump {
	animation: tpq-gold-bump 0.5s cubic-bezier(0.2, 1.4, 0.4, 1);
}
@keyframes tpq-gold-bump {
	0% { transform: scale(1); }
	35% { transform: scale(1.18); box-shadow: 0 0 0 4px rgba(241, 196, 15, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.08); }
	100% { transform: scale(1); }
}

/* Offline / test badge — a HUD status chip, not a form label. */
body.play-app .play-offline-badge {
	border-radius: 999px;
	padding: 0.2rem 0.55rem;
	border: 1px solid rgba(46, 204, 113, 0.35);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* Mode toggle — a deliberate game-mode switch, not a settings control. */
body.play-app .play-mode-toggle {
	border-color: rgba(176, 107, 214, 0.4);
	background: rgba(0, 0, 0, 0.35);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
	padding: 2px;
	gap: 2px;
}
body.play-app .play-mode-opt {
	border-radius: 999px;
	padding: 0.34rem 0.8rem;
	transition: color 0.12s ease, background 0.12s ease;
}
body.play-app .play-mode-opt.active {
	background: linear-gradient(180deg, rgba(176, 107, 214, 0.55), rgba(124, 58, 173, 0.45));
	color: #fff;
	box-shadow: 0 2px 10px -3px rgba(155, 89, 182, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

/* ---- 6. POV STAGE ------------------------------------------------------- */
/* The stage panel wears a red "LIVE" breathing border meant for stream-follow.
   In own-POV mode that reads as an error — retheme it to the stage's purple. */
body.play-app .vv-hub--stage:not(.vv-hub--stream-mode) .vv-livestream-panel,
body.play-app .vv-hub--stage:not(.vv-hub--stream-mode) .vv-livestream-panel--active {
	border-color: rgba(176, 107, 214, 0.4);
	background:
		linear-gradient(135deg, rgba(176, 107, 214, 0.08), transparent 55%),
		rgba(14, 16, 24, 0.95);
	animation: none;
}

/* Make the own-POV frame read like a glowing screen with a bezel, not a void. */
body.play-app .vv-hub--stage:not(.vv-hub--stream-mode) .vv-livestream-embed-wrap {
	border: 1px solid rgba(176, 107, 214, 0.45);
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, 0.04),
		inset 0 0 40px rgba(176, 107, 214, 0.12),
		0 0 32px -6px rgba(155, 89, 182, 0.45),
		0 18px 44px -20px rgba(0, 0, 0, 0.85);
	background:
		radial-gradient(ellipse 90% 70% at 50% 0%, rgba(176, 107, 214, 0.16), transparent),
		#07080d;
}

/* Idle "pick a ride" prompt — inviting, with a soft pulsing play cue. */
body.play-app .vv-stage-pov-host:not(.vv-stage-pov-host--player) {
	background:
		radial-gradient(ellipse 80% 60% at 50% 18%, rgba(176, 107, 214, 0.22), transparent),
		linear-gradient(160deg, rgba(26, 22, 42, 0.96), rgba(10, 9, 16, 0.99));
}
body.play-app .vv-stage-pov-hint {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	font-family: var(--font-display);
	font-size: 1.02rem;
	color: rgba(255, 255, 255, 0.92);
	max-width: 16rem;
}
body.play-app .vv-stage-pov-hint::before {
	content: "▶";
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	border-radius: 999px;
	font-size: 1.05rem;
	color: #fff;
	padding-left: 3px;
	background: linear-gradient(180deg, rgba(176, 107, 214, 0.75), rgba(124, 58, 173, 0.6));
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18), 0 0 26px rgba(155, 89, 182, 0.6);
	animation: tpq-stage-pulse 2.4s ease-in-out infinite;
}
@keyframes tpq-stage-pulse {
	0%, 100% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18), 0 0 22px rgba(155, 89, 182, 0.45); }
	50% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.28), 0 0 34px rgba(155, 89, 182, 0.8); }
}

/* ---- 7. REWARD CELEBRATION --------------------------------------------- */
/* The daily check-in is the game's best dopamine moment — make it feel earned.
   (Appended to <body>, so these are global, not under body.play-app.) */
.play-daily-toast.play-reward {
	gap: 0.45rem;
	padding: 1.1rem 1.35rem 1rem;
	overflow: visible;
	background:
		radial-gradient(ellipse 90% 70% at 50% 0%, rgba(241, 196, 15, 0.22), transparent),
		linear-gradient(165deg, rgba(32, 28, 18, 0.98), rgba(18, 16, 12, 0.98));
	border: 1px solid rgba(241, 196, 15, 0.55);
	box-shadow:
		0 18px 44px rgba(0, 0, 0, 0.55),
		0 0 30px -6px rgba(241, 196, 15, 0.5),
		inset 0 1px 0 rgba(255, 255, 255, 0.12);
	color: #fff7e2;
}

.play-reward-medal {
	width: 3.1rem;
	height: 3.1rem;
	display: grid;
	place-items: center;
	margin: 0 auto;
	border-radius: 999px;
	font-size: 1.5rem;
	background: linear-gradient(180deg, #ffe07a, #f5c518 55%, #d99e06);
	box-shadow:
		0 0 0 3px rgba(241, 196, 15, 0.22),
		0 6px 18px -4px rgba(241, 196, 15, 0.7),
		inset 0 2px 3px rgba(255, 255, 255, 0.5);
	animation: tpq-medal-pop 0.6s cubic-bezier(0.2, 1.5, 0.4, 1) both;
}
@keyframes tpq-medal-pop {
	0% { transform: scale(0) rotate(-25deg); }
	60% { transform: scale(1.16) rotate(7deg); }
	100% { transform: scale(1) rotate(0); }
}

.play-reward-title {
	font-family: "Fredoka", system-ui, sans-serif;
	font-size: 1.18rem !important;
	letter-spacing: 0.01em;
	color: var(--gold-bright, #ffd75e);
	text-shadow: 0 1px 10px rgba(241, 196, 15, 0.4);
}

.play-reward-chips {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.4rem;
}
.play-reward-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	padding: 0.22rem 0.6rem;
	border-radius: 999px;
	font-weight: 800;
	font-size: 0.85rem;
	font-variant-numeric: tabular-nums;
	background: rgba(0, 0, 0, 0.3);
	border: 1px solid rgba(255, 255, 255, 0.14);
}
.play-reward-chip--gold { color: #ffe07a; border-color: rgba(241, 196, 15, 0.5); }
.play-reward-chip--xp { color: #b9e6ff; border-color: rgba(116, 185, 255, 0.45); }
.play-reward-chip--bonus { color: #ffd0f0; border-color: rgba(255, 140, 220, 0.45); }

.play-reward-best {
	font-weight: 800;
	font-size: 0.86rem;
	color: #ffe7a8;
}

/* Particle burst — coins/sparks fly out from the medallion on appear. */
.play-reward-burst {
	position: absolute;
	top: 1.35rem;
	left: 50%;
	width: 0;
	height: 0;
	pointer-events: none;
}
.play-reward-particle {
	position: absolute;
	top: 0;
	left: 0;
	font-size: 0.8rem;
	line-height: 1;
	opacity: 0;
	transform: translate(-50%, -50%) scale(0.2);
	animation: tpq-reward-particle 0.9s ease-out var(--d, 0s) forwards;
}
@keyframes tpq-reward-particle {
	0% { opacity: 0; transform: translate(-50%, -50%) scale(0.2); }
	18% { opacity: 1; }
	100% {
		opacity: 0;
		transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(1) rotate(40deg);
	}
}

/* ---- 8. EMPTY STATES ---------------------------------------------------- */
/* Dead ends become invitations: an icon, a line of voice, and what to do next. */
body.play-app .play-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 0.5rem;
	padding: 2.25rem 1.5rem;
	margin: 0.5rem auto;
	max-width: 22rem;
}
body.play-app .play-empty-icon {
	width: 3.6rem;
	height: 3.6rem;
	display: grid;
	place-items: center;
	font-size: 1.9rem;
	border-radius: 999px;
	background:
		radial-gradient(circle at 50% 35%, rgba(176, 107, 214, 0.3), transparent 70%),
		rgba(255, 255, 255, 0.03);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 0 24px -8px rgba(176, 107, 214, 0.6);
	filter: saturate(1.05);
}
body.play-app .play-empty-title {
	margin: 0;
	font-family: var(--font-display);
	font-size: 1.08rem;
	font-weight: 700;
	color: var(--text);
}
body.play-app .play-empty-text {
	margin: 0;
	font-size: 0.9rem;
	line-height: 1.45;
	color: rgba(154, 163, 181, 0.92);
}
body.play-app .play-empty--raid .play-empty-icon {
	background:
		radial-gradient(circle at 50% 35%, rgba(241, 196, 15, 0.32), transparent 70%),
		rgba(255, 255, 255, 0.03);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 0 26px -6px rgba(241, 196, 15, 0.55);
}

/* Existing profile "nothing here yet" lines — match the calmer empty voice. */
body.play-app .play-profile-settings-empty {
	text-align: center;
	padding: 1.4rem 1rem;
	color: rgba(154, 163, 181, 0.92);
	font-size: 0.9rem;
}

/* ---- 9. TACTILE SETTINGS ------------------------------------------------ */
/* On/Off + segmented controls should feel like a switch you flip, not a form. */
body.play-app .play-settings-segment {
	border-radius: 999px;
	padding: 2px;
	gap: 2px;
	border-color: rgba(255, 255, 255, 0.1);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
body.play-app .play-settings-segment-opt {
	border-radius: 999px;
	padding: 0.5rem 0.7rem;
}
body.play-app .play-settings-segment-opt.is-active {
	background: var(--gold-grad);
	color: #2a1d03;
	box-shadow: 0 2px 9px -3px rgba(241, 196, 15, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.35);
	text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
}

/* Section legends (SETTINGS, AUTO-ROLL…) read as HUD labels. */
body.play-app .play-profile-hub-settings-label,
body.play-app .play-profile-settings-head {
	font-family: var(--font-display);
	letter-spacing: 0.1em;
}

/* ---- 10. RHYTHM + LEGIBILITY ------------------------------------------- */
/* Panels read like a game UI, not an article: tighter leading, calmer paragraph
   gaps, and a small legibility nudge on the smallest secondary text. */
body.play-app .vv-hub-panel-body {
	line-height: 1.5;
}
body.play-app .vv-hub-panel-body > p,
body.play-app .play-profile-hub-section p {
	margin-top: 0.3rem;
	margin-bottom: 0.3rem;
}
body.play-app .play-meta {
	color: #aab3c5; /* perceptual lift for the smallest helper text */
}

/* ---- 11. LEVEL-UP CELEBRATION ------------------------------------------ */
/* The loot reveal already has a rarity spotlight + burst; the one flat spot was
   "Level up!" rendered as tiny text. Make leveling feel like an event. */
body.play-app .vv-loot-xp-levelup {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	font-size: 0.8rem;
	padding: 0.22rem 0.62rem 0.22rem 0.5rem;
	border-radius: 999px;
	color: #2a1d03;
	background: var(--gold-grad);
	box-shadow: 0 3px 14px -3px rgba(241, 196, 15, 0.85), inset 0 1px 0 rgba(255, 255, 255, 0.45);
	text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3);
	transform-origin: center;
	animation:
		tpq-levelup-pop 0.7s cubic-bezier(0.2, 1.5, 0.4, 1) both,
		tpq-levelup-glow 1.9s ease-in-out 0.7s infinite;
}
body.play-app .vv-loot-xp-levelup::before {
	content: "⭐";
	font-size: 0.85em;
	filter: drop-shadow(0 1px 2px rgba(180, 120, 0, 0.5));
}
/* The level number gets a quick sympathetic pop when you level up. */
body.play-app .vv-loot-xp-progress-head:has(.vv-loot-xp-levelup) .vv-loot-xp-level {
	color: var(--gold-bright);
	animation: tpq-levelup-num 0.7s cubic-bezier(0.2, 1.6, 0.4, 1) 0.1s both;
}
@keyframes tpq-levelup-pop {
	0% { transform: scale(0) rotate(-14deg); opacity: 0; }
	60% { transform: scale(1.22) rotate(6deg); opacity: 1; }
	100% { transform: scale(1) rotate(0); }
}
@keyframes tpq-levelup-glow {
	0%, 100% { box-shadow: 0 3px 14px -3px rgba(241, 196, 15, 0.65), inset 0 1px 0 rgba(255, 255, 255, 0.45); }
	50% { box-shadow: 0 3px 22px 0 rgba(241, 196, 15, 1), inset 0 1px 0 rgba(255, 255, 255, 0.55); }
}
@keyframes tpq-levelup-num {
	0% { transform: scale(1); }
	55% { transform: scale(1.35); }
	100% { transform: scale(1); }
}

/* ---- 12. FRIENDS LIST --------------------------------------------------- */
/* A console-style friends list: presence dots, class-colored avatars, expandable rows. */
body.play-app .play-friends {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	/* Fill the panel body so the status bar + tabs + action bar pin, and only the list scrolls. */
	flex: 1;
	min-height: 0;
}

/* ---- Status bar: "Tell your friends what you're doing" (your live presence). ---- */
body.play-app .friend-statusbar {
	flex: none;
	display: flex;
	align-items: center;
	gap: 0.65rem;
	padding: 0.5rem 0.65rem;
	border-radius: 12px;
	background-image: linear-gradient(168deg, rgba(0, 0, 0, 0.34), rgba(0, 0, 0, 0.18));
	box-shadow: var(--surface-edge), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
	border: 1px solid rgba(241, 196, 15, 0.22);
}
body.play-app .friend-statusbar-avatar {
	width: 2.1rem;
	height: 2.1rem;
	font-size: 1.05rem;
}
body.play-app .friend-statusbar-id {
	display: flex;
	flex-direction: column;
	gap: 0.05rem;
	min-width: 0;
	flex: 1;
}
body.play-app .friend-statusbar-name {
	font-weight: 700;
	font-size: 0.92rem;
	color: var(--text);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .friend-statusbar.magic .friend-statusbar-name { color: #c98fe0; }
body.play-app .friend-statusbar.thrill .friend-statusbar-name { color: #ef7d72; }
body.play-app .friend-statusbar.wayfinder .friend-statusbar-name { color: #5fd99a; }
body.play-app .friend-statusbar-status {
	font-size: 0.78rem;
	font-weight: 600;
	color: rgba(180, 188, 204, 0.9);
	/* Truncate long park names ("In Universal's Islands of Adventure") to one line instead of
	   letting the squeezed id column wrap them into a 5-line stack. */
	max-width: 100%;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .friend-statusbar-code {
	flex: none;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.05rem;
	padding: 0.28rem 0.6rem;
	border-radius: 10px;
	background: rgba(0, 0, 0, 0.32);
	border: 1px solid rgba(241, 196, 15, 0.34);
	cursor: pointer;
	transition: border-color 0.12s ease, transform 0.1s ease;
}
body.play-app .friend-statusbar-code:hover { border-color: rgba(241, 196, 15, 0.6); }
body.play-app .friend-statusbar-code:active { transform: translateY(1px); }
body.play-app .friend-statusbar-code.is-copied { border-color: #2ecc71; }
body.play-app .friend-statusbar-code-label {
	font-size: 0.56rem;
	font-weight: 800;
	letter-spacing: 0.12em;
	color: rgba(154, 163, 181, 0.8);
}
body.play-app .friend-statusbar-code-value {
	font-family: var(--font-display);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.1em;
	font-size: 0.88rem;
	font-weight: 700;
	color: var(--gold-bright);
}

/* ---- Tabs: Friends / Party / Pending. ---- */
body.play-app .friend-tabs {
	flex: none;
	display: flex;
	gap: 0.25rem;
	padding: 0.25rem;
	border-radius: 12px;
	background: rgba(0, 0, 0, 0.28);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
body.play-app .friend-tab {
	flex: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.35rem;
	min-height: 2.2rem;
	padding: 0.35rem 0.5rem;
	border: 0;
	border-radius: 9px;
	background: transparent;
	color: rgba(180, 188, 204, 0.85);
	font-family: var(--font-display);
	font-size: 0.82rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	cursor: pointer;
	transition: background 0.14s ease, color 0.14s ease;
}
body.play-app .friend-tab:hover { color: var(--text); background: rgba(255, 255, 255, 0.04); }
body.play-app .friend-tab.is-active {
	color: #1c1304;
	background-image: var(--gold-grad);
	box-shadow: 0 2px 10px -4px rgba(241, 196, 15, 0.6);
}
body.play-app .friend-tab-badge {
	display: inline-grid;
	place-items: center;
	min-width: 1.15rem;
	height: 1.15rem;
	padding: 0 0.3rem;
	border-radius: 999px;
	font-size: 0.68rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
	color: #fff;
	background: #e0506a;
}
body.play-app .friend-tab.is-active .friend-tab-badge { color: #fff; background: rgba(0, 0, 0, 0.45); }
body.play-app .friend-tabpanels { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto; }
body.play-app .friend-tabpanel { display: flex; flex-direction: column; gap: 0.4rem; }
body.play-app .friend-tabpanel[hidden] { display: none; }

/* Section divider between online/offline + incoming/sent. */
body.play-app .friend-divider {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	margin: 0.5rem 0 0.15rem;
	font-family: var(--font-display);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.8);
}
body.play-app .friend-divider::after {
	content: "";
	flex: 1;
	height: 1px;
	background: linear-gradient(90deg, rgba(255, 255, 255, 0.12), transparent);
}

/* Pinned bottom action bar. The status bar + tabs + this bar are flex:none, the list (tabpanels)
   is the only scroller — so Add Friend / Share-my-code stay parked at the panel bottom (clear of
   the HUD via the body's bottom padding) instead of scrolling off or clipping. */
body.play-app .friend-actionbar {
	flex: none;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	padding-top: 0.6rem;
	border-top: 1px solid rgba(255, 255, 255, 0.08);
}
body.play-app .friend-add-form {
	display: flex;
	gap: 0.5rem;
	width: 100%;
}
body.play-app .friend-add-form[hidden] { display: none; }
/* Input takes the row; the Add button stays a fixed, compact width (and doesn't grow). */
body.play-app .friend-add-form .rpg-field {
	flex: 1 1 auto;
	min-width: 0;
	width: auto;
}
body.play-app .friend-add-form #friendAddBtn {
	flex: 0 0 auto;
	width: auto;
	min-width: 4.5rem;
	padding-left: 1.1rem;
	padding-right: 1.1rem;
}
body.play-app .friend-actionbar-btn {
	flex: 1 1 auto;
	min-height: 2.4rem;
	padding: 0.45rem 0.8rem;
	border-radius: 11px;
	border: 1px solid rgba(241, 196, 15, 0.5);
	background-image: var(--gold-grad);
	color: #1c1304;
	font-family: var(--font-display);
	font-size: 0.88rem;
	font-weight: 800;
	letter-spacing: 0.02em;
	cursor: pointer;
	transition: filter 0.12s ease, transform 0.1s ease;
}
body.play-app .friend-actionbar-btn:hover { filter: brightness(1.06); }
body.play-app .friend-actionbar-btn:active { transform: translateY(1px); }
body.play-app .friend-actionbar-btn.is-open { filter: brightness(0.9); }
body.play-app .friend-actionbar-btn--ghost {
	background-image: none;
	background: rgba(0, 0, 0, 0.3);
	color: var(--gold-bright);
}

/* Sections. */
body.play-app .friends-section-head {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin: 0 0 0.5rem;
}
body.play-app .friends-section-title {
	font-family: var(--font-display);
	font-size: 0.82rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: rgba(180, 188, 204, 0.95);
}
body.play-app .friends-section-count {
	display: inline-grid;
	place-items: center;
	min-width: 1.3rem;
	height: 1.3rem;
	padding: 0 0.35rem;
	border-radius: 999px;
	font-size: 0.72rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
	color: #0c0e14;
	background: var(--gold-grad);
}
body.play-app .friends-section-body {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

/* Friend row. */
body.play-app .friend-row {
	border-radius: 12px;
	border: 1px solid var(--border);
	background-image: linear-gradient(168deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.012));
	box-shadow: var(--surface-edge);
	overflow: hidden;
	transition: border-color 0.15s ease, transform 0.12s ease;
}
body.play-app .friend-row--request {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.65rem;
	padding: 0.6rem 0.7rem;
}
body.play-app .friend-row--request .friend-row-id { flex: 1 1 7rem; }
/* Top row: the expandable toggle (avatar + id + chevron) and the inline quick action. */
body.play-app .friend-row-top {
	display: flex;
	align-items: stretch;
	gap: 0.4rem;
	padding-right: 0.6rem;
}
body.play-app .friend-row-main {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	flex: 1;
	min-width: 0;
	padding: 0.6rem 0.4rem 0.6rem 0.7rem;
	background: transparent;
	border: 0;
	color: inherit;
	cursor: pointer;
	text-align: left;
	font: inherit;
}
body.play-app .friend-row-main:hover {
	background: rgba(255, 255, 255, 0.03);
}
body.play-app .friend-chevron {
	flex: none;
	color: rgba(154, 163, 181, 0.65);
	font-size: 1.1rem;
	line-height: 1;
	transition: transform 0.16s ease, color 0.16s ease;
}
body.play-app .friend-row.is-expanded .friend-chevron {
	transform: rotate(90deg);
	color: var(--gold-bright);
}
/* Inline quick action (WoW's per-row "W" button). */
body.play-app .friend-quick {
	flex: none;
	align-self: center;
	min-width: 3.6rem;
	min-height: 2rem;
	padding: 0.3rem 0.7rem;
	border-radius: 999px;
	border: 1px solid var(--border);
	background: rgba(0, 0, 0, 0.28);
	color: var(--text);
	font-size: 0.78rem;
	font-weight: 700;
	cursor: pointer;
	transition: filter 0.12s ease, transform 0.1s ease, border-color 0.12s ease;
}
body.play-app .friend-quick:hover { border-color: rgba(241, 196, 15, 0.5); }
body.play-app .friend-quick:active { transform: translateY(1px); }
body.play-app .friend-quick--join {
	background-image: var(--gold-grad);
	color: #1c1304;
	border-color: rgba(255, 224, 122, 0.7);
}
body.play-app .friend-quick--join:hover { filter: brightness(1.06); }
body.play-app .friend-quick--inparty {
	display: inline-flex;
	align-items: center;
	color: var(--gold-bright);
	background: var(--gold-grad-soft);
	border: 1px solid rgba(241, 196, 15, 0.35);
	cursor: default;
}
body.play-app .friend-row.is-expanded {
	border-color: rgba(241, 196, 15, 0.35);
}

/* Class-colored avatar with a status dot. */
body.play-app .friend-avatar {
	position: relative;
	flex: none;
	width: 2.4rem;
	height: 2.4rem;
	display: grid;
	place-items: center;
	font-size: 1.2rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.3);
	box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.1);
}
body.play-app .friend-row.magic .friend-avatar { box-shadow: inset 0 0 0 2px rgba(155, 89, 182, 0.75), 0 0 12px -4px rgba(155, 89, 182, 0.6); }
body.play-app .friend-row.thrill .friend-avatar { box-shadow: inset 0 0 0 2px rgba(231, 76, 60, 0.75), 0 0 12px -4px rgba(231, 76, 60, 0.6); }
body.play-app .friend-row.wayfinder .friend-avatar { box-shadow: inset 0 0 0 2px rgba(46, 204, 113, 0.75), 0 0 12px -4px rgba(46, 204, 113, 0.6); }

body.play-app .friend-dot {
	position: absolute;
	right: -1px;
	bottom: -1px;
	width: 0.7rem;
	height: 0.7rem;
	border-radius: 999px;
	border: 2px solid #0c0e14;
	background: #6b7280;
}
body.play-app .friend-dot--online { background: #2ecc71; }
body.play-app .friend-dot--in_park { background: #43d17a; box-shadow: 0 0 8px rgba(46, 204, 113, 0.8); }
body.play-app .friend-dot--queuing { background: #f1c40f; }
body.play-app .friend-dot--in_raid {
	background: #c56bd6;
	animation: tpq-friend-raid 1.6s ease-in-out infinite;
}
@keyframes tpq-friend-raid {
	0%, 100% { box-shadow: 0 0 0 0 rgba(176, 107, 214, 0.7); }
	50% { box-shadow: 0 0 8px 2px rgba(176, 107, 214, 0.95); }
}

body.play-app .friend-row-id {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	min-width: 0;
	flex: 1;
}
/* Name + streak share one line; the name truncates, the 🔥 streak badge stays put. */
body.play-app .friend-name-line {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	min-width: 0;
}
body.play-app .friend-name {
	font-weight: 700;
	color: var(--text);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .friend-streak {
	flex: none;
	display: inline-flex;
	align-items: center;
	gap: 0.1rem;
	font-size: 0.74rem;
	font-weight: 800;
	color: #ffd0a0;
	padding: 0.02rem 0.4rem;
	border-radius: 999px;
	background: linear-gradient(180deg, rgba(255, 120, 40, 0.22), rgba(255, 90, 20, 0.08));
	border: 1px solid rgba(255, 130, 50, 0.45);
}
body.play-app .friend-row.magic .friend-name { color: #c98fe0; }
body.play-app .friend-row.thrill .friend-name { color: #ef7d72; }
body.play-app .friend-row.wayfinder .friend-name { color: #5fd99a; }
body.play-app .friend-sub {
	font-size: 0.78rem;
	color: rgba(154, 163, 181, 0.85);
}
body.play-app .friend-status {
	flex: none;
	font-size: 0.78rem;
	font-weight: 600;
	color: rgba(180, 188, 204, 0.9);
	text-align: left;
	max-width: 100%;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .friend-status--in_raid { color: #d6a6ea; }
body.play-app .friend-status--queuing { color: #f1c40f; }
body.play-app .friend-status--in_park { color: #5fd99a; }
body.play-app .friend-status--online { color: #5fd99a; }
body.play-app .friend-row--offline { opacity: 0.72; }
body.play-app .friend-row--offline .friend-avatar { filter: grayscale(0.4); }

/* ============================================================================
   Friends P0 game-feel: presence-visibility sigil toggle, location chip,
   guild badge, weekly-board ladder (friends-social-room-plan.md §5 P0 + PB1/PB2)
   ============================================================================ */

/* Let the status bar wrap so the visibility toggle drops to its own line when tight. */
body.play-app .friend-statusbar { flex-wrap: wrap; row-gap: 0.5rem; }

/* Presence-visibility: a segmented sigil toggle (reuses the .char-gender-toggle grammar)
   in place of the old web <select>. */
/* The toggle + its caption travel together as one flex item (pinned right on a wide bar,
   dropped to its own centered row on phones). The caption tells the user what it's FOR. */
body.play-app .friend-visibility-group {
	flex: none;
	margin-left: auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.16rem;
}
body.play-app .friend-visibility-caption {
	font-size: 0.58rem;
	font-weight: 700;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: rgba(170, 178, 196, 0.85);
}
body.play-app .friend-visibility-toggle {
	display: inline-flex;
	gap: 2px;
	padding: 2px;
	border-radius: 999px;
	border: 1px solid rgba(201, 162, 77, 0.32);
	background: rgba(0, 0, 0, 0.4);
}
body.play-app .friend-visibility-opt {
	appearance: none;
	border: 0;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 0.28rem;
	min-height: 2rem;
	padding: 0.26rem 0.55rem;
	border-radius: 999px;
	font-family: var(--font-display);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	color: #d8c9a6;
	background: transparent;
	transition: background 0.14s ease, color 0.14s ease;
}
body.play-app .friend-visibility-opt:hover:not(.is-active) { color: #fff; background: rgba(255, 255, 255, 0.06); }
body.play-app .friend-visibility-opt.is-active {
	color: #2a1d00;
	background: linear-gradient(180deg, #ffe07a, #d99e06);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
}
body.play-app .friend-visibility-opt:disabled { opacity: 0.6; cursor: default; }
body.play-app .friend-visibility-glyph { line-height: 1; font-size: 0.82rem; }
/* Phones: the status bar (avatar · name/park · code · captioned toggle) is too much for one row,
   so drop the visibility group to its own centered full-width row beneath — this is what was
   crushing the park-status into a 5-line stack. With its own row the caption + labels all fit. */
@media (max-width: 560px) {
	body.play-app .friend-visibility-group {
		flex: 1 0 100%;
		margin-left: 0;
		align-items: center;
	}
}
/* Very narrow: even the full row gets tight — inactive options collapse to their glyph. */
@media (max-width: 360px) {
	body.play-app .friend-visibility-opt:not(.is-active) .friend-visibility-lbl { display: none; }
}

/* Location chip: park crest + presence sigil + status — where this hero is right now. */
body.play-app .friend-loc-chip {
	flex: none;
	display: inline-flex;
	align-items: center;
	gap: 0.32rem;
	max-width: 100%;
	margin-top: 0.12rem;
	padding: 0.12rem 0.55rem 0.12rem 0.14rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.3);
	border: 1px solid rgba(255, 255, 255, 0.08);
	font-size: 0.76rem;
	font-weight: 600;
	color: rgba(180, 188, 204, 0.9);
	overflow: hidden;
}
body.play-app .friend-loc-text { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body.play-app .friend-loc-crest {
	flex: none;
	display: grid;
	place-items: center;
	width: 1.45rem;
	height: 1.45rem;
	border-radius: 999px;
	background: radial-gradient(70% 70% at 50% 38%, rgba(255, 236, 170, 0.25), rgba(10, 9, 16, 0.6) 75%);
	border: 1px solid rgba(231, 201, 122, 0.45);
}
body.play-app .friend-loc-crest img { width: 1.1rem; height: 1.1rem; object-fit: contain; }
body.play-app .friend-loc-sigil { flex: none; font-size: 0.82rem; line-height: 1; }
body.play-app .friend-loc-chip.friend-status--in_raid { border-color: rgba(197, 107, 214, 0.42); background: rgba(120, 60, 140, 0.18); }
body.play-app .friend-loc-chip.friend-status--queuing { border-color: rgba(241, 196, 15, 0.38); background: rgba(120, 96, 10, 0.16); }
body.play-app .friend-loc-chip.friend-status--in_park { border-color: rgba(46, 204, 113, 0.34); background: rgba(20, 90, 50, 0.16); }
body.play-app .friend-loc-chip.friend-status--offline { opacity: 0.85; }

/* Guild badge on the name line (PB1) — heraldic crest + small-caps tag. */
body.play-app .friend-guild-chip {
	flex: none;
	display: inline-flex;
	align-items: center;
	gap: 0.2rem;
	padding: 0.04rem 0.42rem 0.04rem 0.3rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.32);
	border: 1px solid rgba(201, 162, 77, 0.4);
	font-size: 0.68rem;
	font-weight: 800;
	letter-spacing: 0.02em;
	color: var(--gold-bright);
}
body.play-app .friend-guild-crest { font-size: 0.78rem; line-height: 1; }
body.play-app .friend-guild-tag { font-variant: small-caps; }

/* Weekly boards as a ladder: rank · name · gold fill rail · score (not bare <p> lines). */
body.play-app .board-week {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem 1.1rem;
	margin: 0.3rem 0 0.7rem;
}
body.play-app .board-week-col { flex: 1 1 13rem; min-width: 0; display: flex; flex-direction: column; gap: 0.26rem; }
body.play-app .board-week-title {
	margin: 0 0 0.1rem;
	font-family: var(--font-display);
	font-size: 0.78rem;
	font-weight: 800;
	letter-spacing: 0.02em;
	color: rgba(200, 208, 224, 0.95);
}
body.play-app .board-week-rank { color: var(--gold-bright); font-weight: 700; }
body.play-app .board-week-row {
	display: grid;
	grid-template-columns: 1.7rem minmax(0, 6rem) minmax(2rem, 1fr) 2.2rem;
	align-items: center;
	gap: 0.4rem;
	padding: 0.14rem 0.4rem;
	border-radius: 8px;
	font-size: 0.76rem;
}
body.play-app .board-week-row.is-you { background: rgba(241, 196, 15, 0.12); box-shadow: inset 0 0 0 1px rgba(241, 196, 15, 0.35); }
body.play-app .board-week-pos { font-variant-numeric: tabular-nums; font-weight: 800; color: rgba(154, 163, 181, 0.85); }
body.play-app .board-week-row.is-you .board-week-pos { color: var(--gold-bright); }
body.play-app .board-week-name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
body.play-app .board-week-bar {
	height: 0.42rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.45);
	overflow: hidden;
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}
body.play-app .board-week-fill { display: block; height: 100%; border-radius: inherit; background-image: var(--gold-grad); box-shadow: 0 0 6px rgba(241, 196, 15, 0.4); }
body.play-app .board-week-n { font-variant-numeric: tabular-nums; font-weight: 800; color: var(--text); text-align: right; }

/* Expandable drawer (view profile + actions). */
body.play-app .friend-drawer {
	padding: 0 0.7rem 0.7rem;
	border-top: 1px solid rgba(255, 255, 255, 0.05);
}
body.play-app .friend-card {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 0.3rem 0.9rem;
	padding: 0.6rem 0;
}
body.play-app .friend-card-row {
	display: flex;
	justify-content: space-between;
	gap: 0.5rem;
	font-size: 0.82rem;
}
body.play-app .friend-card-k { color: rgba(154, 163, 181, 0.8); }
body.play-app .friend-card-v { color: var(--text); font-weight: 600; text-align: right; }
body.play-app .friend-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}
body.play-app .friend-act {
	flex: 1 1 auto;
	min-height: 2.2rem;
	padding: 0.4rem 0.75rem;
	font-size: 0.82rem;
}
body.play-app .friend-act--primary {
	background-image: var(--gold-grad);
	color: #2a1d03;
	font-weight: 800;
	border-color: rgba(255, 224, 122, 0.7);
}
body.play-app .friend-act--danger.is-arming {
	background: rgba(231, 76, 60, 0.85);
	color: #fff;
	border-color: rgba(231, 76, 60, 0.9);
}
body.play-app .friend-inparty-badge,
body.play-app .friend-req-pending {
	display: inline-flex;
	align-items: center;
	padding: 0.3rem 0.6rem;
	border-radius: 999px;
	font-size: 0.74rem;
	font-weight: 700;
	color: var(--gold-bright);
	background: var(--gold-grad-soft);
	border: 1px solid rgba(241, 196, 15, 0.35);
}
body.play-app .friend-req-actions {
	display: flex;
	gap: 0.4rem;
	flex: 1 1 100%;
	align-items: center;
}
body.play-app .friend-req-actions .friend-act { flex: 1 1 auto; }
body.play-app .friend-req-actions .friend-req-pending { flex: 0 0 auto; }

/* "Your party" embed keeps the day-party UI but tucks it under a section header. */
body.play-app .friends-party-section .friends-party-mount {
	border-radius: 12px;
}

/* Party tab is for the party only: drop the friend Add bar + the day-party event log
   (the "Party queue / Waiting for <@…>" mirror of the Discord announcement). */
body.play-app .friend-actionbar[hidden] { display: none; }
body.play-app .friend-tabpanel--party .rpg-party-log { display: none; }

/* Roster height: the old 7.5rem cap (built for compact slots) only fits ~1.5 of the taller WoW
   frames before an inner scrollbar. Scale the cap to the viewport so many more members show, and
   in the friends Party tab drop the inner scroll entirely — the panel itself scrolls, so the
   roster grows naturally (one scroll, not a tiny nested box). Works on every screen size. */
body.play-app .play-dayparty-hub .dp-roster { max-height: min(62vh, 34rem); }
/* Only lift the scroll cap here — keep the box's padding so the "PARTY" header and the frames
   don't run into its border. */
body.play-app .friend-tabpanel--party .play-dayparty-hub .dp-roster {
	max-height: none;
	overflow: visible;
}

/* Stop full-width action buttons from stretching into giant bars on wide screens. The caps
   exceed a phone's width, so mobile is unchanged; on wide panels the buttons settle to a sensible
   size and centre instead of spanning edge to edge. */
body.play-app .play-dayparty-hub .play-dayparty-actions { justify-content: center; }
body.play-app .play-dayparty-hub .play-dayparty-actions .play-action-btn { max-width: 18rem; }
body.play-app .play-dayparty-hub .play-dayparty-join-row { max-width: 32rem; }
body.play-app .friend-actionbar { justify-content: center; }
body.play-app .friend-actionbar-btn { max-width: 18rem; }
body.play-app .friend-add-form { max-width: 32rem; }
body.play-app .friend-req-actions .friend-act { max-width: 14rem; }

/* ---- WoW-style party frames (Party tab + #/dayparty roster). --------------- */
body.play-app .dp-frames { display: flex; flex-direction: column; gap: 0.5rem; }
body.play-app .dp-frames .dp-roster-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin: 0;
}
body.play-app .dp-frames .dp-roster-title {
	font-family: var(--font-display);
	font-size: 0.8rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: rgba(180, 188, 204, 0.95);
}
body.play-app .dp-frames .dp-roster-count {
	font-size: 0.72rem;
	font-weight: 600;
	color: rgba(154, 163, 181, 0.85);
}
body.play-app .dp-frames-list { display: flex; flex-direction: column; gap: 0.4rem; }

body.play-app .dp-frame {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.45rem 0.65rem;
	border-radius: 12px;
	border: 1px solid var(--border);
	background-image: linear-gradient(168deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.012));
	box-shadow: var(--surface-edge);
}
body.play-app .dp-frame.magic { border-color: rgba(155, 89, 182, 0.4); }
body.play-app .dp-frame.thrill { border-color: rgba(231, 76, 60, 0.4); }
body.play-app .dp-frame.wayfinder { border-color: rgba(46, 204, 113, 0.4); }
body.play-app .dp-frame.is-leader {
	border-color: rgba(241, 196, 15, 0.5);
	box-shadow: var(--surface-edge), 0 0 0 1px rgba(241, 196, 15, 0.18);
}
body.play-app .dp-frame.is-self {
	background-image: linear-gradient(168deg, rgba(88, 101, 242, 0.2), rgba(88, 101, 242, 0.05));
}

/* Circular portrait medallion with an ornate gold ring + leader crown. */
body.play-app .dp-frame-portrait {
	position: relative;
	flex: none;
	width: 2.55rem;
	height: 2.55rem;
	display: grid;
	place-items: center;
	border-radius: 999px;
	background: radial-gradient(circle at 50% 32%, rgba(255, 255, 255, 0.16), rgba(0, 0, 0, 0.6));
	box-shadow:
		inset 0 0 0 2px rgba(0, 0, 0, 0.6),
		0 0 0 2px rgba(212, 175, 55, 0.85),
		0 0 0 3px rgba(0, 0, 0, 0.5),
		0 2px 9px -3px rgba(0, 0, 0, 0.7);
}
body.play-app .dp-frame.magic .dp-frame-portrait { background: radial-gradient(circle at 50% 32%, rgba(155, 89, 182, 0.6), rgba(22, 11, 30, 0.82)); }
body.play-app .dp-frame.thrill .dp-frame-portrait { background: radial-gradient(circle at 50% 32%, rgba(231, 76, 60, 0.6), rgba(30, 12, 10, 0.82)); }
body.play-app .dp-frame.wayfinder .dp-frame-portrait { background: radial-gradient(circle at 50% 32%, rgba(46, 204, 113, 0.55), rgba(10, 28, 18, 0.82)); }
body.play-app .dp-frame.is-self .dp-frame-portrait {
	box-shadow:
		inset 0 0 0 2px rgba(0, 0, 0, 0.6),
		0 0 0 2px rgba(212, 175, 55, 0.9),
		0 0 0 4px rgba(88, 101, 242, 0.7),
		0 2px 9px -3px rgba(0, 0, 0, 0.7);
}
body.play-app .dp-frame-emoji {
	font-size: 1.25rem;
	line-height: 1;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
}
body.play-app .dp-frame-crown {
	position: absolute;
	top: -0.55rem;
	left: 50%;
	transform: translateX(-50%);
	font-size: 0.85rem;
	filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.75));
}

/* Body: name row, class, XP bar, title. */
body.play-app .dp-frame-body {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.12rem;
}
body.play-app .dp-frame-name-row {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	min-width: 0;
}
body.play-app .dp-frame-name {
	font-weight: 700;
	color: var(--text);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .dp-frame.magic .dp-frame-name { color: #c98fe0; }
body.play-app .dp-frame.thrill .dp-frame-name { color: #ef7d72; }
body.play-app .dp-frame.wayfinder .dp-frame-name { color: #5fd99a; }
body.play-app .dp-frame-you {
	flex: none;
	font-size: 0.58rem;
	font-weight: 800;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: #1c1304;
	background-image: var(--gold-grad);
	padding: 0.05rem 0.35rem;
	border-radius: 999px;
}
body.play-app .dp-frame-lvl {
	flex: none;
	margin-left: auto;
	font-family: var(--font-display);
	font-size: 0.74rem;
	font-weight: 700;
	color: var(--gold-bright);
	font-variant-numeric: tabular-nums;
}
body.play-app .dp-frame-class {
	font-size: 0.72rem;
	color: rgba(154, 163, 181, 0.85);
}

/* XP-to-next-level bar — beveled, class-colored fill (WoW unit-frame feel). */
body.play-app .dp-frame-bar {
	position: relative;
	height: 0.7rem;
	margin-top: 0.1rem;
	border-radius: 5px;
	overflow: hidden;
	background: rgba(0, 0, 0, 0.5);
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.65), inset 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.play-app .dp-frame-bar-fill {
	height: 100%;
	background-image:
		linear-gradient(180deg, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 48%),
		linear-gradient(90deg, #43d17a, #2ecc71);
	transition: width 0.45s ease;
}
body.play-app .dp-frame.magic .dp-frame-bar-fill {
	background-image:
		linear-gradient(180deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0) 48%),
		linear-gradient(90deg, #8a52ad, #b06bd6);
}
body.play-app .dp-frame.thrill .dp-frame-bar-fill {
	background-image:
		linear-gradient(180deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0) 48%),
		linear-gradient(90deg, #d8503e, #ef7d72);
}
body.play-app .dp-frame.wayfinder .dp-frame-bar-fill {
	background-image:
		linear-gradient(180deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0) 48%),
		linear-gradient(90deg, #2fbf6b, #5fd99a);
}
body.play-app .dp-frame-bar-label {
	position: absolute;
	right: 0.4rem;
	top: 50%;
	transform: translateY(-50%);
	font-size: 0.62rem;
	font-weight: 700;
	color: #fff;
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
	font-variant-numeric: tabular-nums;
}
body.play-app .dp-frame-title-line {
	font-size: 0.7rem;
	font-style: italic;
	color: rgba(154, 163, 181, 0.78);
}

@media (prefers-reduced-motion: reduce) {
	body.play-app .vv-stage-pov-hint::before,
	body.play-app .play-gold--bump,
	body.play-app .vv-loot-xp-levelup,
	body.play-app .vv-loot-xp-progress-head:has(.vv-loot-xp-levelup) .vv-loot-xp-level,
	body.play-app .friend-dot--in_raid,
	.play-reward-medal,
	.play-reward-particle {
		animation: none;
	}
	.play-reward-particle { display: none; }
	.play-reward-medal { transform: none; }
}

/* ---- 13. FRIEND CODE ON PROFILE ---------------------------------------- */
body.play-app .profile-friendcode {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: wrap;
	margin: 0.7rem 0 0.2rem;
	padding: 0.5rem 0.7rem;
	border-radius: 12px;
	background: var(--gold-grad-soft);
	border: 1px solid rgba(241, 196, 15, 0.3);
	box-shadow: var(--surface-edge);
}
body.play-app .profile-friendcode-label {
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.9);
}
body.play-app .profile-friendcode-value {
	font-family: var(--font-display);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.13em;
	font-weight: 700;
	font-size: 1.02rem;
	color: var(--gold-bright);
	margin-right: auto;
	text-shadow: 0 0 12px rgba(241, 196, 15, 0.35);
}
body.play-app .profile-friendcode-copy {
	flex: none;
	padding: 0.28rem 0.7rem;
	border-radius: 999px;
	font-size: 0.78rem;
	font-weight: 700;
	color: var(--gold-bright);
	background: rgba(0, 0, 0, 0.3);
	border: 1px solid rgba(241, 196, 15, 0.4);
	cursor: pointer;
	transition: background 0.12s ease, transform 0.1s ease;
}
body.play-app .profile-friendcode-copy:hover { background: rgba(241, 196, 15, 0.14); }
body.play-app .profile-friendcode-copy:active { transform: scale(0.96); }
body.play-app .profile-friendcode-copy.is-copied {
	background: var(--gold-grad);
	color: #2a1d03;
	border-color: rgba(255, 224, 122, 0.8);
}

/* ---- 14. FRIENDS HUB-TILE BADGE ---------------------------------------- */
body.play-app .play-hub-tile { position: relative; }
body.play-app .hub-tile-badge {
	position: absolute;
	top: 8px;
	right: 8px;
	min-width: 1.25rem;
	height: 1.25rem;
	padding: 0 0.35rem;
	display: grid;
	place-items: center;
	border-radius: 999px;
	font-size: 0.72rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
	color: #fff;
	background: linear-gradient(180deg, #ff5a4d, #d8362a);
	border: 2px solid #0c0e14;
	box-shadow: 0 2px 8px -2px rgba(231, 76, 60, 0.8);
	animation: tpq-tile-badge-pop 0.4s cubic-bezier(0.2, 1.5, 0.4, 1);
}
@keyframes tpq-tile-badge-pop {
	0% { transform: scale(0); }
	60% { transform: scale(1.2); }
	100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
	body.play-app .hub-tile-badge { animation: none; }
}

/* ---- 15. ONLINE-FRIENDS COUNT ------------------------------------------ */
/* Friends hub-tile sub-label: "N online" with a live green dot. */
body.play-app .hub-tile-online {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	color: #5fd99a;
	font-weight: 700;
}
body.play-app .hub-tile-online-dot,
body.play-app .friends-presence-dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 999px;
	background: #2ecc71;
	box-shadow: 0 0 6px rgba(46, 204, 113, 0.9);
	flex: none;
}
/* Friends panel summary line. */
body.play-app .friends-presence-summary {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin: 0;
	font-size: 0.9rem;
	color: rgba(180, 188, 204, 0.95);
}
body.play-app .friends-presence-summary strong {
	color: #5fd99a;
	font-variant-numeric: tabular-nums;
}
/* Living presence pulse on the "N of M online" / "N active" dot (friends panel only). */
@keyframes tpq-presence-pulse {
	0%, 100% { box-shadow: 0 0 5px rgba(46, 204, 113, 0.6); }
	50% { box-shadow: 0 0 9px 2px rgba(46, 204, 113, 0.95); }
}
body.play-app .friends-presence-dot { animation: tpq-presence-pulse 2.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { body.play-app .friends-presence-dot { animation: none; } }

/* ============================================================================
   Friends P3 — hero-card vignettes: portrait level pip, class-role badge, drawer
   identity banner, presence-state accent stripe (friends-social-room-plan.md §P3)
   ============================================================================ */
body.play-app .friend-avatar { overflow: visible; }
body.play-app .friend-avatar-lvl {
	position: absolute;
	left: -3px;
	top: -3px;
	min-width: 1.05rem;
	height: 1.05rem;
	padding: 0 0.2rem;
	display: grid;
	place-items: center;
	border-radius: 999px;
	background: linear-gradient(180deg, #2a2030, #15101e);
	border: 1px solid rgba(241, 196, 15, 0.65);
	color: var(--gold-bright);
	font-size: 0.6rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
	line-height: 1;
}
/* Class-role badge: a glyph chip on the name line, a labelled pill in the drawer banner. */
body.play-app .friend-role-badge { flex: none; }
body.play-app .friend-name-line .friend-role-badge {
	display: inline-grid;
	place-items: center;
	width: 1.35rem;
	height: 1.35rem;
	border-radius: 999px;
	border: 1px solid var(--role-color, rgba(255, 255, 255, 0.2));
	background: rgba(0, 0, 0, 0.3);
	font-size: 0.74rem;
	line-height: 1;
}
body.play-app .friend-role-badge--tank { --role-color: rgba(91, 160, 255, 0.7); }
body.play-app .friend-role-badge--healer { --role-color: rgba(122, 230, 160, 0.7); }
body.play-app .friend-role-badge--dps { --role-color: rgba(255, 130, 110, 0.7); }

/* Presence-state accent stripe down the row's left edge — a glanceable "where". */
body.play-app .friend-row { position: relative; }
body.play-app .friend-row::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	width: 3px;
	border-radius: 12px 0 0 12px;
	background: transparent;
	pointer-events: none;
}
body.play-app .friend-row--in_raid::before { background: linear-gradient(180deg, #c56bd6, #8e3fb0); }
body.play-app .friend-row--queuing::before { background: linear-gradient(180deg, #f1c40f, #b8920a); }
body.play-app .friend-row--in_park::before { background: linear-gradient(180deg, #43d17a, #2a9b56); }
body.play-app .friend-row--online::before { background: linear-gradient(180deg, #5fd99a, #3aa56e); }

/* Drawer identity banner (replaces the k/v spec table). */
body.play-app .friend-card-banner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.35rem 0.55rem;
	padding: 0.55rem 0;
	font-size: 0.8rem;
}
body.play-app .friend-card-lv { font-weight: 800; color: var(--gold-bright); font-variant-numeric: tabular-nums; }
body.play-app .friend-card-class { color: var(--text); font-weight: 700; }
body.play-app .friend-card-role {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	padding: 0.06rem 0.45rem;
	border-radius: 999px;
	border: 1px solid var(--role-color, rgba(255, 255, 255, 0.2));
	background: rgba(0, 0, 0, 0.3);
	font-size: 0.72rem;
	font-weight: 700;
}
body.play-app .friend-card-title { color: rgba(200, 208, 224, 0.95); font-style: italic; }

/* ============================================================================
   Friends PB3/PB4/PB5 — power chip, real character portrait, live raid HP bar
   (friends-social-room-plan.md §PB)
   ============================================================================ */
/* PB4: real character portrait (class × gender) layered over the emoji; emoji shows on 404. */
body.play-app .friend-portrait-art {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 999px;
	image-rendering: pixelated;
}
body.play-app .friend-avatar-emoji { line-height: 1; }
/* PB3: power (gear score) chip in the drawer banner. */
body.play-app .friend-card-power {
	display: inline-flex;
	align-items: center;
	gap: 0.2rem;
	padding: 0.06rem 0.45rem;
	border-radius: 999px;
	border: 1px solid rgba(241, 196, 15, 0.55);
	background: linear-gradient(180deg, rgba(60, 48, 18, 0.7), rgba(26, 21, 10, 0.8));
	font-size: 0.72rem;
	font-weight: 800;
	color: var(--gold-bright);
}
/* PB5: a thin boss-HP bar under the location chip for friends mid-raid. */
body.play-app .friend-raid-hp {
	display: block;
	width: 100%;
	max-width: 10rem;
	height: 0.34rem;
	margin-top: 0.22rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.5);
	overflow: hidden;
	box-shadow: inset 0 0 0 1px rgba(197, 107, 214, 0.35);
}
body.play-app .friend-raid-hp-fill {
	display: block;
	height: 100%;
	border-radius: inherit;
	background: linear-gradient(90deg, #ff6a8a, #c56bd6);
	box-shadow: 0 0 6px rgba(197, 107, 214, 0.6);
	transition: width 0.4s ease;
}

/* ============================================================================
   16. PERSISTENT GAME HUD — MMO action bar (play-hud.js)
   The action bar is app-level chrome, present on every /play route. The hub's own
   tile grid is hidden in favor of it.
   ============================================================================ */
body.play-app { --tpq-bar-h: 4.9rem; }

/* Hide the hub's in-flow tile grid — the global bar replaces it. */
body.play-app.play-hud-active .vv-hub-tiles { display: none !important; }

/* Same for the Virtual-Visit stage's secondary action row (Bounties / Day party / Shop /
   Profile). It existed only as entry points when the old tile grid was hidden; the persistent
   action bar now carries all of them, so the row is pure web-UI duplication. */
body.play-app.play-hud-active .vv-stage-actions-secondary { display: none !important; }

/* Leave room at the bottom of the stage for the fixed bar. */
body.play-app.play-hud-active .play-main {
	padding-bottom: calc(var(--tpq-bar-h) + var(--play-safe-bottom));
}

.tpq-actionbar {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 160;
	padding: 0.4rem max(0.5rem, var(--play-safe-left)) calc(0.3rem + var(--play-safe-bottom)) max(0.5rem, var(--play-safe-right));
	background:
		linear-gradient(180deg, rgba(26, 22, 42, 0.82), rgba(10, 11, 17, 0.96));
	border-top: 1px solid rgba(241, 196, 15, 0.22);
	box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.05), 0 -12px 30px -18px rgba(0, 0, 0, 0.9);
	backdrop-filter: blur(10px);
}
.tpq-actionbar-inner {
	counter-reset: tpqslot;
	display: flex;
	justify-content: center;
	align-items: flex-start;
	gap: 0.35rem;
	width: 100%;
	max-width: 40rem;
	margin: 0 auto;
	/* No overflow clipping — the spotlight glow on edge slots must not be cut off. The 7
	   slots fit without scrolling on modern widths; ultra-narrow shrinks them (media query). */
	flex-wrap: nowrap;
}

/* Slot = a beveled square with a colored rim + a keybind corner number + label. */
.tpq-slot {
	counter-increment: tpqslot;
	position: relative;
	flex: 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.15rem;
	padding: 0;
	background: none;
	border: 0;
	cursor: pointer;
	color: var(--text, #e8ecf4);
	font: inherit;
	-webkit-tap-highlight-color: transparent;
}
.tpq-slot-frame {
	position: relative;
	display: grid;
	place-items: center;
	width: 3.05rem;
	height: 3.05rem;
	border-radius: 12px;
	background:
		linear-gradient(160deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0) 55%),
		linear-gradient(180deg, #232838, #161a26);
	border: 1px solid rgba(255, 255, 255, 0.12);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.14),
		inset 0 -2px 6px rgba(0, 0, 0, 0.5),
		0 2px 6px -2px rgba(0, 0, 0, 0.7);
	transition: transform 0.12s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.tpq-slot-icon {
	font-size: 1.5rem;
	line-height: 1;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
}
/* Keybind-style corner number — MMO authenticity. */
.tpq-slot-frame::after {
	content: counter(tpqslot);
	position: absolute;
	top: 2px;
	left: 4px;
	font-family: var(--font-numeric, "Fredoka", sans-serif);
	font-size: 0.6rem;
	font-weight: 800;
	color: rgba(255, 255, 255, 0.5);
	text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
}
.tpq-slot-label {
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	color: rgba(180, 188, 204, 0.85);
	white-space: nowrap;
}

/* Per-action rim colors. */
.tpq-slot[data-hud-action="quest"] .tpq-slot-frame { border-color: rgba(46, 204, 113, 0.5); }
.tpq-slot[data-hud-action="raid"] .tpq-slot-frame { border-color: rgba(176, 107, 214, 0.55); }
.tpq-slot[data-hud-action="dungeon"] .tpq-slot-frame { border-color: rgba(231, 76, 60, 0.5); }
.tpq-slot[data-hud-action="friends"] .tpq-slot-frame { border-color: rgba(95, 217, 154, 0.5); }
.tpq-slot[data-hud-action="shop"] .tpq-slot-frame { border-color: rgba(241, 196, 15, 0.55); }
.tpq-slot[data-hud-action="bounty"] .tpq-slot-frame { border-color: rgba(255, 106, 77, 0.5); }
.tpq-slot[data-hud-action="profile"] .tpq-slot-frame { border-color: rgba(116, 185, 255, 0.5); }

.tpq-slot:hover .tpq-slot-frame { transform: translateY(-2px); border-color: rgba(255, 224, 122, 0.7); }
.tpq-slot:active .tpq-slot-frame { transform: translateY(0) scale(0.95); }

/* Active slot — lit gold, raised, glowing (you're "on" this action). */
.tpq-slot.is-active .tpq-slot-frame {
	background: linear-gradient(180deg, #ffe07a, #f5c518 55%, #d99e06);
	border-color: #ffe89a;
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.6),
		0 0 0 1px rgba(255, 224, 122, 0.5),
		0 6px 18px -4px rgba(241, 196, 15, 0.8);
	transform: translateY(-3px);
}
.tpq-slot.is-active .tpq-slot-icon { filter: none; }
.tpq-slot.is-active .tpq-slot-label { color: var(--gold-bright, #ffd75e); }
.tpq-slot.is-active .tpq-slot-frame::after { color: rgba(42, 29, 3, 0.7); }

/* Friends badge / online dot on the slot. */
.tpq-slot-badge {
	position: absolute;
	top: -4px;
	right: -4px;
	min-width: 1.1rem;
	height: 1.1rem;
	padding: 0 0.3rem;
	display: grid;
	place-items: center;
	border-radius: 999px;
	font-size: 0.66rem;
	font-weight: 800;
	color: #fff;
	background: linear-gradient(180deg, #ff5a4d, #d8362a);
	border: 2px solid #12131b;
	box-shadow: 0 2px 6px -1px rgba(231, 76, 60, 0.8);
}
.tpq-slot-online {
	position: absolute;
	top: 1px;
	right: 1px;
	width: 0.55rem;
	height: 0.55rem;
	border-radius: 999px;
	background: #2ecc71;
	border: 2px solid #12131b;
	box-shadow: 0 0 6px rgba(46, 204, 113, 0.9);
}

@media (max-width: 380px) {
	.tpq-actionbar-inner { gap: 0.25rem; }
	.tpq-slot-frame { width: 2.6rem; height: 2.6rem; }
	.tpq-slot-icon { font-size: 1.25rem; }
	.tpq-slot-label { display: none; }
	body.play-app { --tpq-bar-h: 3.8rem; }
}
@media (max-width: 330px) {
	.tpq-actionbar-inner { gap: 0.2rem; }
	.tpq-slot-frame { width: 2.35rem; height: 2.35rem; }
	.tpq-slot-icon { font-size: 1.1rem; }
}
@media (prefers-reduced-motion: reduce) {
	.tpq-slot .tpq-slot-frame { transition: none; }
}

/* ---- 17. GAME WINDOWS — panels open as framed windows over the stage ---- */
body.play-app .vv-hub-panel {
	border: 1px solid rgba(176, 107, 214, 0.28);
	box-shadow:
		var(--surface-edge),
		0 0 0 1px rgba(0, 0, 0, 0.5),
		0 26px 60px -26px rgba(0, 0, 0, 0.9),
		0 0 40px -16px rgba(176, 107, 214, 0.4);
	background:
		radial-gradient(120% 80% at 50% 0%, rgba(176, 107, 214, 0.1), transparent 60%),
		var(--surface-card);
}
/* The panel already sits above the fixed action bar — .play-main reserves the bar's height (see
   above), so the panel body only needs a small bottom margin. Reserving the full bar height again
   here just left a big empty gap at the bottom of every panel (friends, dungeon finder, …). */
body.play-app.play-hud-active .vv-hub-panel-body {
	padding-bottom: 0.5rem;
}

/* Lift bottom-floating elements above the action bar when it's present. */
body.play-app.play-hud-active .play-daily-toast {
	bottom: calc(var(--tpq-bar-h) + 1rem + var(--play-safe-bottom));
}

/* ---- 18. PLAYER UNIT-FRAME (header) ------------------------------------- */
body.play-app .play-unit {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.2rem 0.45rem 0.2rem 0.2rem;
	border-radius: 999px;
	background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0));
	border: 1px solid rgba(255, 255, 255, 0.08);
	box-shadow: var(--surface-edge);
	--unit-color: #9aa3b5;
}
body.play-app .play-unit--magic { --unit-color: #b06bd6; }
body.play-app .play-unit--thrill { --unit-color: #e74c3c; }
body.play-app .play-unit--wayfinder { --unit-color: #2ecc71; }

body.play-app .play-unit-portrait {
	position: relative;
	flex: none;
	width: 2.3rem;
	height: 2.3rem;
	display: grid;
	place-items: center;
	border-radius: 999px;
	text-decoration: none;
	background: radial-gradient(circle at 50% 35%, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.3));
	box-shadow:
		inset 0 0 0 2px var(--unit-color),
		0 0 12px -3px var(--unit-color);
}
body.play-app .play-unit-emoji { font-size: 1.2rem; line-height: 1; }
body.play-app .play-unit-level {
	position: absolute;
	right: -3px;
	bottom: -4px;
	min-width: 1.05rem;
	height: 1.05rem;
	padding: 0 0.2rem;
	display: grid;
	place-items: center;
	border-radius: 999px;
	font-family: var(--font-display);
	font-size: 0.66rem;
	font-weight: 800;
	color: #2a1d03;
	background: var(--gold-grad);
	border: 1.5px solid #12131b;
	box-shadow: 0 1px 4px -1px rgba(241, 196, 15, 0.8);
}
body.play-app .play-unit-body {
	display: flex;
	flex-direction: column;
	gap: 0.18rem;
	min-width: 4.5rem;
}
body.play-app .play-unit-name {
	font-weight: 700;
	font-size: 0.82rem;
	line-height: 1;
	color: var(--text);
	white-space: nowrap;
	max-width: 8rem;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .play-unit-xp {
	height: 6px;
	width: 100%;
	min-width: 4.5rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.45);
	box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.6);
	overflow: hidden;
}
body.play-app .play-unit-xp-fill {
	height: 100%;
	border-radius: 999px;
	background: linear-gradient(90deg, var(--unit-color), color-mix(in srgb, var(--unit-color) 55%, #fff));
	box-shadow: 0 0 8px -1px var(--unit-color);
	transition: width 0.5s ease;
}
body.play-app .play-unit-logout {
	margin-left: 0.1rem;
	color: rgba(154, 163, 181, 0.7);
	text-decoration: none;
	font-size: 1rem;
}
body.play-app .play-unit-logout:hover { color: #e74c3c; }

@media (max-width: 380px) {
	body.play-app .play-unit-body { min-width: 3.4rem; }
	body.play-app .play-unit-name { max-width: 5.5rem; font-size: 0.78rem; }
}

/* ---- 19. TARGET FRAME — "now playing" (play-hud.js) --------------------- */
.tpq-target-frame {
	position: fixed;
	left: 50%;
	transform: translateX(-50%);
	bottom: calc(var(--tpq-bar-h, 4.9rem) + var(--play-safe-bottom) + 0.4rem);
	z-index: 158;
	max-width: calc(100% - 1.25rem);
	pointer-events: none;
}
/* Idle "next up" suggestion (e.g. daily bounty): a quiet compact corner chip,
   NOT the center-stage gold target frame — that treatment is reserved for an
   actual live queue. Docked right so it stops sitting over mid-screen copy. */
.tpq-target-frame:has(.tpq-target--nextup) {
	left: auto;
	right: 0.6rem;
	transform: none;
}
.tpq-target--nextup {
	padding: 0.22rem 0.6rem 0.22rem 0.24rem;
	gap: 0.4rem;
	border-color: rgba(255, 255, 255, 0.16);
	background: linear-gradient(180deg, rgba(24, 25, 33, 0.94), rgba(14, 15, 21, 0.95));
	box-shadow: 0 4px 12px -6px rgba(0, 0, 0, 0.8);
	opacity: 0.94;
}
.tpq-target--nextup .tpq-target-portrait {
	width: 1.65rem;
	height: 1.65rem;
	font-size: 0.95rem;
	background: radial-gradient(circle at 50% 35%, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.35));
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
}
.tpq-target--nextup .tpq-target-name {
	font-size: 0.72rem;
	max-width: 10rem;
}
.tpq-target--nextup .tpq-target-sub {
	font-size: 0.62rem;
}
.tpq-target {
	pointer-events: auto;
	display: flex;
	align-items: center;
	gap: 0.55rem;
	max-width: 100%;
	padding: 0.32rem 0.8rem 0.32rem 0.32rem;
	border: 0;
	border-radius: 999px;
	cursor: pointer;
	color: var(--text, #e8ecf4);
	font: inherit;
	background:
		linear-gradient(180deg, rgba(36, 28, 18, 0.96), rgba(18, 15, 11, 0.97));
	border: 1px solid rgba(241, 196, 15, 0.45);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.1),
		0 10px 28px -10px rgba(0, 0, 0, 0.8),
		0 0 22px -8px rgba(241, 196, 15, 0.5);
	backdrop-filter: blur(8px);
}
.tpq-target-portrait {
	flex: none;
	width: 2.2rem;
	height: 2.2rem;
	display: grid;
	place-items: center;
	font-size: 1.25rem;
	border-radius: 999px;
	background: radial-gradient(circle at 50% 35%, rgba(241, 196, 15, 0.3), rgba(0, 0, 0, 0.35));
	box-shadow: inset 0 0 0 2px rgba(241, 196, 15, 0.6);
}
.tpq-target-body {
	display: flex;
	flex-direction: column;
	gap: 0.12rem;
	min-width: 0;
}
.tpq-target-name {
	font-family: var(--font-display, "Fredoka", sans-serif);
	font-weight: 700;
	font-size: 0.82rem;
	line-height: 1;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 12rem;
}
.tpq-target-cast {
	height: 4px;
	width: 100%;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.5);
	overflow: hidden;
	position: relative;
}
.tpq-target-cast-fill {
	position: absolute;
	inset: 0;
	border-radius: 999px;
	background: linear-gradient(90deg, transparent, var(--gold-bright, #ffd75e), transparent);
	background-size: 50% 100%;
	background-repeat: no-repeat;
	animation: tpq-cast-sweep 1.6s linear infinite;
}
@keyframes tpq-cast-sweep {
	0% { background-position: -50% 0; }
	100% { background-position: 150% 0; }
}
.tpq-target-sub {
	font-size: 0.7rem;
	font-variant-numeric: tabular-nums;
	color: rgba(200, 170, 255, 0.9);
	white-space: nowrap;
}
.tpq-target.is-ready {
	border-color: #2ecc71;
	box-shadow: 0 0 0 1px rgba(46, 204, 113, 0.5), 0 0 26px -6px rgba(46, 204, 113, 0.8);
	animation: tpq-target-ready 1.3s ease-in-out infinite;
}
.tpq-target.is-ready .tpq-target-cast-fill {
	background: #2ecc71;
	animation: none;
}
.tpq-target.is-ready .tpq-target-sub { color: #5fd99a; }
@keyframes tpq-target-ready {
	0%, 100% { box-shadow: 0 0 0 1px rgba(46, 204, 113, 0.5), 0 0 22px -8px rgba(46, 204, 113, 0.7); }
	50% { box-shadow: 0 0 0 1px rgba(46, 204, 113, 0.8), 0 0 30px -4px rgba(46, 204, 113, 1); }
}
@media (prefers-reduced-motion: reduce) {
	.tpq-target-cast-fill, .tpq-target.is-ready { animation: none; }
}

/* ---- 20. LOCKED SLOTS (tutorial/onboarding — HUD present but not yet usable) ---- */
.tpq-slot.is-locked { cursor: default; }
.tpq-slot.is-locked .tpq-slot-frame {
	border-color: rgba(255, 255, 255, 0.08) !important;
	box-shadow: inset 0 -2px 6px rgba(0, 0, 0, 0.5);
	filter: grayscale(0.8);
}
.tpq-slot.is-locked .tpq-slot-icon { opacity: 0.28; }
.tpq-slot.is-locked .tpq-slot-label { opacity: 0.45; }
.tpq-slot.is-locked:hover .tpq-slot-frame { transform: none; border-color: rgba(255, 255, 255, 0.08) !important; }
.tpq-slot-lock {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	font-size: 0.95rem;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.9));
}
/* Hint that the bar is the game UI you'll unlock. */
body.play-app.play-hud-locked .tpq-actionbar {
	border-top-color: rgba(255, 255, 255, 0.1);
}

/* ============================================================================
   21. TUTORIAL COACHMARK TOUR (play-tour.js) — teach the real HUD
   ============================================================================ */
.tpq-tour-backdrop {
	position: fixed;
	inset: 0;
	z-index: 150;
	background: rgba(6, 7, 11, 0.62);
	backdrop-filter: blur(1px);
}
/* The spotlighted slot pops bright above everything (it's unlocked for this step). */
body.play-tour-active .tpq-slot.is-tour-target .tpq-slot-frame {
	border-color: #ffe89a !important;
	filter: none !important;
	box-shadow:
		0 0 0 3px rgba(255, 224, 122, 0.55),
		0 0 30px -2px rgba(241, 196, 15, 0.95) !important;
	transform: translateY(-5px);
	animation: tpq-tour-pulse 1.2s ease-in-out infinite;
}
body.play-tour-active .tpq-slot.is-tour-target .tpq-slot-icon { opacity: 1 !important; }
body.play-tour-active .tpq-slot.is-tour-target .tpq-slot-label { opacity: 1 !important; color: var(--gold-bright); }
@keyframes tpq-tour-pulse {
	0%, 100% { box-shadow: 0 0 0 3px rgba(255, 224, 122, 0.4), 0 0 22px -2px rgba(241, 196, 15, 0.7); }
	50% { box-shadow: 0 0 0 5px rgba(255, 224, 122, 0.6), 0 0 34px 2px rgba(241, 196, 15, 1); }
}

.tpq-tour-arrow {
	position: fixed;
	z-index: 165;
	transform: translateX(-50%);
	font-size: 2.1rem;
	line-height: 1;
	color: var(--gold-bright, #ffd75e);
	text-shadow: 0 0 14px rgba(241, 196, 15, 0.95);
	pointer-events: none;
	animation: tpq-tour-bounce 0.9s ease-in-out infinite;
}
@keyframes tpq-tour-bounce {
	0%, 100% { margin-top: 0; }
	50% { margin-top: 9px; }
}

.tpq-tour-bubble {
	position: fixed;
	z-index: 166;
	box-sizing: border-box;
	padding: 0.7rem 0.85rem 0.75rem;
	border-radius: 14px;
	color: #f4f7ff;
	background:
		radial-gradient(120% 90% at 50% 0%, rgba(176, 107, 214, 0.18), transparent 60%),
		linear-gradient(180deg, rgba(28, 24, 40, 0.98), rgba(16, 14, 22, 0.98));
	border: 1px solid rgba(241, 196, 15, 0.5);
	box-shadow:
		0 18px 44px -16px rgba(0, 0, 0, 0.9),
		0 0 30px -8px rgba(241, 196, 15, 0.55),
		inset 0 1px 0 rgba(255, 255, 255, 0.1);
	animation: tpq-tour-pop 0.32s cubic-bezier(0.2, 1.4, 0.4, 1);
}
.tpq-tour-bubble.is-center { width: min(21rem, calc(100% - 2rem)); text-align: center; }
@keyframes tpq-tour-pop { from { opacity: 0; transform: scale(0.92) translateY(6px); } }
.tpq-tour-bubble.is-center { animation: tpq-tour-pop-center 0.32s cubic-bezier(0.2,1.4,0.4,1); }
@keyframes tpq-tour-pop-center { from { opacity: 0; transform: translate(-50%, -46%) scale(0.92); } }

.tpq-tour-bubble-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	min-height: 1rem;
	margin-bottom: 0.2rem;
}
.tpq-tour-step {
	font-family: var(--font-numeric, sans-serif);
	font-size: 0.68rem;
	font-weight: 800;
	letter-spacing: 0.06em;
	color: var(--gold-bright, #ffd75e);
	background: rgba(241, 196, 15, 0.12);
	border: 1px solid rgba(241, 196, 15, 0.35);
	border-radius: 999px;
	padding: 0.1rem 0.45rem;
}
.tpq-tour-skip {
	margin-left: auto;
	background: none;
	border: 0;
	color: rgba(154, 163, 181, 0.7);
	font-size: 0.72rem;
	cursor: pointer;
	text-decoration: underline;
}
.tpq-tour-skip:hover { color: #e8ecf4; }
.tpq-tour-title {
	font-family: var(--font-display, "Fredoka", sans-serif);
	font-weight: 700;
	font-size: 1.05rem;
	color: var(--gold-bright, #ffd75e);
	margin-bottom: 0.15rem;
}
.tpq-tour-body { font-size: 0.85rem; line-height: 1.4; color: rgba(232, 236, 244, 0.92); }
.tpq-tour-foot { margin-top: 0.6rem; display: flex; justify-content: center; }
.tpq-tour-taphint {
	font-size: 0.78rem;
	font-weight: 700;
	color: var(--gold-bright, #ffd75e);
	animation: tpq-tour-blink 1.1s ease-in-out infinite;
}
@keyframes tpq-tour-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.tpq-tour-cta {
	padding: 0.5rem 1.2rem;
	border-radius: 999px;
	border: 1px solid rgba(255, 224, 122, 0.75);
	background: var(--gold-grad, linear-gradient(180deg,#ffe07a,#f5c518 55%,#d99e06));
	color: #2a1d03;
	font-weight: 800;
	font-size: 0.9rem;
	cursor: pointer;
	box-shadow: 0 4px 14px -4px rgba(241, 196, 15, 0.8);
}
.tpq-tour-cta:hover { filter: saturate(1.08) brightness(1.03); }
.tpq-tour-cta:active { transform: translateY(1px) scale(0.98); }

@media (prefers-reduced-motion: reduce) {
	.tpq-tour-arrow, .tpq-slot.is-tour-target .tpq-slot-frame, .tpq-tour-taphint, .tpq-tour-bubble { animation: none; }
}

/* ============================================================================
   22. PARK SELECTOR — destination cards, not a web list
   ============================================================================ */
body.play-app .vv-hub-resort,
body.play-app .vv-hub-parks-body .rpg-resort-title {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	margin: 1.1rem 0 0.6rem;
	font-family: var(--font-display);
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--gold-bright, #ffd75e);
}
body.play-app .vv-hub-resort::after {
	content: "";
	flex: 1;
	height: 1px;
	background: linear-gradient(90deg, rgba(241, 196, 15, 0.45), transparent);
}

body.play-app .vv-hub-park-row,
body.play-app .vv-hub-parks-body .rpg-portal-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(8.6rem, 1fr));
	gap: 0.6rem;
}

/* Each park = a beveled "travel here" portal card. */
body.play-app .vv-hub-park-link,
body.play-app .vv-hub-parks-body .rpg-portal {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.35rem;
	min-height: 5.4rem;
	padding: 0.8rem 0.6rem;
	border-radius: 14px;
	border: 1px solid rgba(255, 255, 255, 0.1);
	background:
		radial-gradient(120% 80% at 50% 0%, rgba(176, 107, 214, 0.14), transparent 60%),
		var(--surface-card);
	box-shadow: var(--surface-edge), 0 6px 16px -10px rgba(0, 0, 0, 0.8);
	color: var(--text);
	text-decoration: none;
	font-weight: 700;
	font-size: 0.82rem;
	text-align: center;
	line-height: 1.15;
	transition: transform 0.12s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
body.play-app .vv-hub-park-link::before {
	content: "🎡";
	font-size: 1.85rem;
	line-height: 1;
	filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
}
body.play-app .vv-hub-park-link[data-hub-park="mk"]::before { content: "🏰"; }
body.play-app .vv-hub-park-link[data-hub-park="epcot"]::before { content: "🌐"; }
body.play-app .vv-hub-park-link[data-hub-park="hs"]::before { content: "🎬"; }
body.play-app .vv-hub-park-link[data-hub-park="ak"]::before { content: "🌳"; }
body.play-app .vv-hub-park-link[data-hub-park="usf"]::before { content: "🎥"; }
body.play-app .vv-hub-park-link[data-hub-park="ioa"]::before { content: "🦖"; }
body.play-app .vv-hub-park-link[data-hub-park="epu"]::before { content: "🌌"; }

body.play-app .vv-hub-park-link:hover {
	transform: translateY(-3px);
	border-color: rgba(255, 224, 122, 0.6);
	box-shadow: var(--surface-edge), 0 12px 26px -12px rgba(241, 196, 15, 0.5);
}
body.play-app .vv-hub-park-link:active { transform: translateY(-1px) scale(0.98); }

/* Selected = your active destination: lit gold ring + glow + a corner marker. */
body.play-app .vv-hub-park-link.vv-hub-park--selected {
	position: relative;
	border-color: #ffe89a;
	background:
		radial-gradient(120% 80% at 50% 0%, rgba(241, 196, 15, 0.2), transparent 60%),
		var(--surface-card);
	box-shadow:
		var(--surface-edge),
		0 0 0 1px rgba(255, 224, 122, 0.6),
		0 0 26px -6px rgba(241, 196, 15, 0.7);
	color: var(--gold-bright, #ffd75e);
}
body.play-app .vv-hub-park-link.vv-hub-park--selected::after {
	content: "✦";
	position: absolute;
	top: 5px;
	right: 7px;
	font-size: 0.7rem;
	color: var(--gold-bright, #ffd75e);
}

/* Park selector actually renders as .rpg-portal (ui/index.js rpgParkPortals) — give it the
   destination-card look with a per-park icon, centered name, and a SELECT cta. */
body.play-app .vv-hub-parks-body .rpg-portal::before {
	content: "🎡";
	font-size: 1.85rem;
	line-height: 1;
	filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
}
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="mk"]::before { content: "🏰"; }
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="epcot"]::before { content: "🌐"; }
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="hs"]::before { content: "🎬"; }
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="ak"]::before { content: "🌳"; }
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="usf"]::before { content: "🎥"; }
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="ioa"]::before { content: "🦖"; }
body.play-app .vv-hub-parks-body .rpg-portal[data-hub-park="epu"]::before { content: "🌌"; }
body.play-app .vv-hub-parks-body .rpg-portal-glow { display: none; }
body.play-app .vv-hub-parks-body .rpg-portal-copy {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.12rem;
	width: auto;
	text-align: center;
}
body.play-app .vv-hub-parks-body .rpg-portal-label {
	font-weight: 700;
	font-size: 0.82rem;
	line-height: 1.15;
	color: inherit;
}
body.play-app .vv-hub-parks-body .rpg-portal-cta {
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.8);
}
body.play-app .vv-hub-parks-body .rpg-portal.vv-hub-park--selected {
	position: relative;
	border-color: #ffe89a;
	background:
		radial-gradient(120% 80% at 50% 0%, rgba(241, 196, 15, 0.2), transparent 60%),
		var(--surface-card);
	box-shadow:
		var(--surface-edge),
		0 0 0 1px rgba(255, 224, 122, 0.6),
		0 0 26px -6px rgba(241, 196, 15, 0.7);
	color: var(--gold-bright, #ffd75e);
}
body.play-app .vv-hub-parks-body .rpg-portal.vv-hub-park--selected .rpg-portal-cta { color: var(--gold-bright, #ffd75e); }
body.play-app .vv-hub-parks-body .rpg-portal.vv-hub-park--selected::after {
	content: "✦";
	position: absolute;
	top: 5px;
	right: 7px;
	font-size: 0.7rem;
	color: var(--gold-bright, #ffd75e);
}

/* Drop the redundant "Pick a park, then quest a ride" prompt on the in-park hub — the
   destination cards below are self-explanatory. (Virtual-mode POV stage is untouched.) */
body.play-app.play-inpark-hub-active .vv-hub-idle { display: none; }

/* ============================================================================
   23. QUEST LOG — campaigns as a real video-game quest journal, not a web list
   ============================================================================ */
body.play-app .quest-log {
	display: flex;
	flex-direction: column;
	gap: 0.85rem;
}

/* Quest-log header — banner with crossed-swords title over a torn-parchment rule. */
body.play-app .quest-log-head {
	position: relative;
	padding: 0.2rem 0 0.7rem;
	border-bottom: 1px solid rgba(241, 196, 15, 0.18);
}
body.play-app .quest-log-back {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	font-size: 0.78rem;
	font-weight: 600;
	color: rgba(154, 163, 181, 0.95);
	text-decoration: none;
	margin-bottom: 0.45rem;
}
body.play-app .quest-log-back:hover { color: var(--gold-bright, #ffd75e); }
body.play-app .quest-log-title {
	margin: 0;
	font-family: var(--font-display);
	font-size: 1.4rem;
	letter-spacing: 0.02em;
	color: var(--gold-bright, #ffd75e);
	text-shadow: 0 2px 10px rgba(241, 196, 15, 0.25);
}
body.play-app .quest-log-sub {
	margin: 0.15rem 0 0;
	font-size: 0.74rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.75);
}

/* Card list */
body.play-app .quest-card-list {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
}

/* A quest card = sigil seal on the left, quest detail on the right. */
body.play-app .quest-card {
	position: relative;
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 0.85rem;
	align-items: start;
	padding: 0.85rem 0.95rem;
	border-radius: 14px;
	border: 1px solid rgba(255, 255, 255, 0.08);
	border-left: 3px solid rgba(154, 163, 181, 0.5);
	background:
		radial-gradient(120% 90% at 0% 0%, rgba(120, 130, 160, 0.08), transparent 55%),
		var(--surface-card);
	box-shadow: var(--surface-edge), 0 8px 20px -14px rgba(0, 0, 0, 0.8);
	transition: transform 0.12s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
body.play-app .quest-card:hover {
	transform: translateY(-2px);
	box-shadow: var(--surface-edge), 0 14px 28px -16px rgba(0, 0, 0, 0.85);
}
body.play-app .quest-card--loading {
	display: block;
	border-left-color: rgba(154, 163, 181, 0.3);
}

/* Sigil seal — a wax-stamp medallion that carries the quest's state. */
body.play-app .quest-card-sigil {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.7rem;
	height: 2.7rem;
	border-radius: 50%;
	font-size: 1.35rem;
	background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.25));
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1), inset 0 0 12px rgba(0, 0, 0, 0.45);
	filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.5));
}

body.play-app .quest-card-body { min-width: 0; }
body.play-app .quest-card-titlerow {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: wrap;
}
body.play-app .quest-card-title {
	margin: 0;
	font-family: var(--font-display);
	font-size: 1.02rem;
	letter-spacing: 0.01em;
	color: var(--text, #e8ecf4);
}
body.play-app .quest-card-meta {
	margin: 0.2rem 0 0;
	font-size: 0.72rem;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.8);
}

/* Quest badge (finale star) */
body.play-app .quest-badge {
	display: inline-flex;
	align-items: center;
	padding: 0.1rem 0.45rem;
	border-radius: 999px;
	font-family: var(--font-display);
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}
body.play-app .quest-badge--finale {
	color: #2a1d00;
	background: var(--gold-grad, linear-gradient(180deg, #ffe89a, #f1c40f));
	box-shadow: 0 0 14px -3px rgba(241, 196, 15, 0.7);
}

/* Progress bar — a quest tracker. */
body.play-app .quest-progress {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: 0.5rem;
}
body.play-app .quest-progress-bar {
	flex: 1;
	height: 7px;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.4);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
	overflow: hidden;
}
body.play-app .quest-progress-fill {
	height: 100%;
	border-radius: 999px;
	background: linear-gradient(90deg, #2ecc71, #7be8a4);
	box-shadow: 0 0 10px -1px rgba(46, 204, 113, 0.6);
	transition: width 0.4s ease;
}
body.play-app .quest-progress-label {
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
	font-size: 0.7rem;
	font-weight: 700;
	color: rgba(154, 163, 181, 0.95);
	white-space: nowrap;
}

/* Lock line */
body.play-app .quest-card-lock {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	margin: 0.5rem 0 0;
	font-size: 0.76rem;
	color: #f0a868;
}

body.play-app .quest-card-actions {
	display: flex;
	gap: 0.5rem;
	margin-top: 0.7rem;
	flex-wrap: wrap;
}
body.play-app .quest-embark { flex: 1; min-width: 7rem; }

/* State variants ---------------------------------------------------------- */
body.play-app .quest-card.is-active {
	border-left-color: #2ecc71;
	background:
		radial-gradient(120% 90% at 0% 0%, rgba(46, 204, 113, 0.1), transparent 55%),
		var(--surface-card);
}
body.play-app .quest-card.is-finale {
	border-left-color: var(--gold-bright, #ffd75e);
	background:
		radial-gradient(120% 90% at 0% 0%, rgba(241, 196, 15, 0.12), transparent 55%),
		var(--surface-card);
}
body.play-app .quest-card.is-finale .quest-card-sigil {
	box-shadow: inset 0 0 0 1px rgba(255, 224, 122, 0.5), inset 0 0 12px rgba(0, 0, 0, 0.4),
		0 0 18px -4px rgba(241, 196, 15, 0.6);
}
body.play-app .quest-card.is-locked {
	opacity: 0.72;
	border-left-color: rgba(154, 163, 181, 0.35);
}
body.play-app .quest-card.is-locked .quest-card-sigil { filter: grayscale(0.7) brightness(0.8); }

/* Quest journal — the active quest opened as a parchment page over the log. */
body.play-app .quest-journal {
	position: relative;
	padding: 1rem 1.05rem 1.1rem;
	border-radius: 16px;
	border: 1px solid rgba(241, 196, 15, 0.28);
	background:
		radial-gradient(140% 120% at 100% 0%, rgba(241, 196, 15, 0.08), transparent 55%),
		linear-gradient(168deg, #20283c 0%, #161c2c 100%);
	box-shadow: var(--surface-edge), 0 16px 36px -20px rgba(0, 0, 0, 0.85),
		inset 0 0 0 1px rgba(241, 196, 15, 0.06);
}
body.play-app .quest-journal-head {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	margin-bottom: 0.6rem;
	padding-bottom: 0.6rem;
	border-bottom: 1px solid rgba(241, 196, 15, 0.15);
}
body.play-app .quest-journal-icon { font-size: 1.3rem; }
body.play-app .quest-journal-title {
	margin: 0;
	flex: 1;
	font-family: var(--font-display);
	font-size: 1.12rem;
	color: var(--gold-bright, #ffd75e);
}
body.play-app .quest-journal-tag {
	font-size: 0.6rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	padding: 0.18rem 0.5rem;
	border-radius: 999px;
	color: #7be8a4;
	background: rgba(46, 204, 113, 0.14);
	box-shadow: inset 0 0 0 1px rgba(46, 204, 113, 0.3);
}
body.play-app .quest-journal-story {
	margin: 0 0 0.7rem;
	font-size: 0.9rem;
	line-height: 1.5;
	color: rgba(226, 232, 244, 0.92);
}

/* Objectives — checklist rows. */
body.play-app .quest-objectives {
	list-style: none;
	margin: 0 0 0.6rem;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
}
body.play-app .quest-objective {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.4rem 0.6rem;
	border-radius: 9px;
	background: rgba(0, 0, 0, 0.22);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.04);
	font-size: 0.82rem;
}
body.play-app .quest-objective::before {
	content: "◈";
	color: var(--gold-bright, #ffd75e);
	font-size: 0.75rem;
}
body.play-app .quest-objective-name { color: rgba(154, 163, 181, 0.95); }
body.play-app .quest-objective-val {
	margin-left: auto;
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
	font-weight: 700;
	color: var(--text, #e8ecf4);
}

/* Investigate / boss step rows */
body.play-app .quest-steps { margin-top: 0.7rem; }
body.play-app .quest-steps-label {
	display: block;
	margin-bottom: 0.4rem;
	font-family: var(--font-display);
	font-size: 0.74rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.85);
}
body.play-app .quest-steps-row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.45rem;
}
body.play-app .quest-step-btn { flex: 0 1 auto; }
body.play-app .quest-step-btn--boss {
	border-color: rgba(176, 107, 214, 0.5) !important;
}

/* Empty state already styled via .play-empty; keep journal toast inline. */
body.play-app #campActToast:not(:empty) { margin-top: 0.7rem; }

@media (max-width: 380px) {
	body.play-app .quest-card { padding: 0.75rem 0.7rem; gap: 0.65rem; }
	body.play-app .quest-card-sigil { width: 2.3rem; height: 2.3rem; font-size: 1.15rem; }
	body.play-app .quest-log-title { font-size: 1.25rem; }
}

/* ============================================================================
   24. QUEST GIVER — NPC reveal modal over the victory screen
   ============================================================================ */
.tpq-qg-overlay {
	position: fixed;
	inset: 0;
	z-index: 1200;
	display: none;
	align-items: center;
	justify-content: center;
	padding: 1.1rem;
	background: radial-gradient(120% 90% at 50% 30%, rgba(10, 14, 24, 0.6), rgba(4, 6, 12, 0.85));
	backdrop-filter: blur(3px);
	opacity: 0;
	transition: opacity 0.22s ease;
}
.tpq-qg-overlay.is-in { opacity: 1; }

.tpq-qg-card {
	position: relative;
	width: min(360px, 100%);
	padding: 1.5rem 1.25rem 1.25rem;
	border-radius: 20px;
	text-align: center;
	color: #e8ecf4;
	border: 1px solid rgba(241, 196, 15, 0.35);
	background:
		radial-gradient(130% 90% at 50% 0%, rgba(241, 196, 15, 0.14), transparent 55%),
		linear-gradient(168deg, #222a40 0%, #161c2c 70%, #11151f 100%);
	box-shadow:
		0 30px 70px -28px rgba(0, 0, 0, 0.9),
		inset 0 0 0 1px rgba(255, 255, 255, 0.04),
		inset 0 0 0 1px rgba(241, 196, 15, 0.08);
	transform: translateY(10px) scale(0.98);
	transition: transform 0.26s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.tpq-qg-overlay.is-in .tpq-qg-card { transform: translateY(0) scale(1); }

.tpq-qg-close {
	position: absolute;
	top: 0.5rem;
	right: 0.6rem;
	width: 1.9rem;
	height: 1.9rem;
	border-radius: 50%;
	border: none;
	background: rgba(255, 255, 255, 0.06);
	color: rgba(232, 236, 244, 0.75);
	font-size: 1.2rem;
	line-height: 1;
	cursor: pointer;
	transition: background 0.15s ease, color 0.15s ease;
}
.tpq-qg-close:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }

.tpq-qg-ribbon {
	display: inline-block;
	margin-bottom: 0.85rem;
	padding: 0.22rem 0.85rem;
	border-radius: 999px;
	font-family: var(--font-display, "Baloo 2", system-ui);
	font-size: 0.68rem;
	font-weight: 800;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: #2a1d00;
	background: var(--gold-grad, linear-gradient(180deg, #ffe89a, #f1c40f));
	box-shadow: 0 0 18px -3px rgba(241, 196, 15, 0.7);
	animation: tpq-qg-ribbon-pop 0.5s ease both;
}
@keyframes tpq-qg-ribbon-pop {
	0% { transform: scale(0.6); opacity: 0; }
	70% { transform: scale(1.08); }
	100% { transform: scale(1); opacity: 1; }
}

.tpq-qg-portrait {
	width: 5.2rem;
	height: 5.2rem;
	margin: 0 auto 0.7rem;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 2.7rem;
	border-radius: 50%;
	background: radial-gradient(circle at 35% 28%, rgba(255, 255, 255, 0.16), rgba(0, 0, 0, 0.3));
	box-shadow:
		inset 0 0 0 2px rgba(241, 196, 15, 0.45),
		inset 0 0 18px rgba(0, 0, 0, 0.5),
		0 0 28px -6px rgba(241, 196, 15, 0.55);
	animation: tpq-qg-bob 2.6s ease-in-out infinite;
}
@keyframes tpq-qg-bob {
	0%, 100% { transform: translateY(0); }
	50% { transform: translateY(-5px); }
}
.tpq-qg-portrait.is-accepted { animation: tpq-qg-pop 0.4s ease both; }
@keyframes tpq-qg-pop {
	0% { transform: scale(0.5); opacity: 0; }
	100% { transform: scale(1); opacity: 1; }
}
/* Real NPC bust when art exists; the emoji glyph is the graceful fallback (art_ready pattern):
   the <img> shows by default, and on a missing/404 image the JS adds .is-emoji to swap to the
   emoji span — so portrait coverage can roll out park-by-park without ever showing a broken image. */
.tpq-qg-portrait { overflow: hidden; }
.tpq-qg-portrait-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center top;
	border-radius: 50%;
}
.tpq-qg-portrait-emoji { display: none; line-height: 1; }
.tpq-qg-portrait.is-emoji { overflow: visible; }
.tpq-qg-portrait.is-emoji .tpq-qg-portrait-img { display: none; }
.tpq-qg-portrait.is-emoji .tpq-qg-portrait-emoji { display: block; }

.tpq-qg-name {
	font-family: var(--font-display, "Baloo 2", system-ui);
	font-size: 1.25rem;
	font-weight: 800;
	color: var(--gold-bright, #ffd75e);
	margin-bottom: 0.55rem;
}
.tpq-qg-accepted-title {
	font-family: var(--font-display, "Baloo 2", system-ui);
	font-size: 1.4rem;
	font-weight: 800;
	color: var(--gold-bright, #ffd75e);
	margin-bottom: 0.55rem;
}

.tpq-qg-bubble {
	position: relative;
	margin: 0 auto 0.95rem;
	padding: 0.7rem 0.9rem;
	border-radius: 12px;
	font-size: 0.9rem;
	line-height: 1.45;
	color: rgba(226, 232, 244, 0.95);
	background: rgba(0, 0, 0, 0.28);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.tpq-qg-bubble::before {
	content: "";
	position: absolute;
	top: -7px;
	left: 50%;
	transform: translateX(-50%);
	border-left: 8px solid transparent;
	border-right: 8px solid transparent;
	border-bottom: 8px solid rgba(0, 0, 0, 0.28);
}

.tpq-qg-quest {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	margin-bottom: 1.05rem;
	padding: 0.6rem 0.7rem;
	border-radius: 12px;
	border: 1px dashed rgba(241, 196, 15, 0.4);
	background: rgba(241, 196, 15, 0.06);
}
.tpq-qg-quest-label {
	font-size: 0.6rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.85);
}
.tpq-qg-quest-title {
	font-family: var(--font-display, "Baloo 2", system-ui);
	font-size: 1rem;
	font-weight: 700;
	color: #e8ecf4;
}

.tpq-qg-actions {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
.tpq-qg-actions .play-action-btn { width: 100%; }

/* ============================================================================
   25. QUEST CONSOLE — the ride/boss picker as a game "select" screen: land (or
   difficulty) tabs + a focal selected-card built on the app's rpgPanel chrome +
   a roster of chips to feature another option. Replaces the old <ul> list.
   Shared by in-park and Virtual Visit (same renderer). Per-land accent via
   inline `--accent`.
   ============================================================================ */
body.play-app .quest-console {
	display: flex;
	flex-direction: column;
	flex: 1;
	min-height: 0;
	gap: 0.7rem;
}
/* Keep scrolling inside the console body, not the outer panel. */
body.play-app .vv-hub-panel-body:has(.quest-console) { overflow: hidden; }

/* Tabs (lands / Heroic-Mythic) — a horizontal pill rail. */
body.play-app .quest-tabs {
	display: flex;
	gap: 0.4rem;
	overflow-x: auto;
	padding-bottom: 0.15rem;
	scrollbar-width: none;
	flex: 0 0 auto;
}
body.play-app .quest-tabs::-webkit-scrollbar { display: none; }
body.play-app .quest-tab {
	--accent: #c9a24d;
	position: relative;
	flex: 0 0 auto;
	padding: 0.42rem 0.85rem;
	border-radius: 999px;
	border: 1px solid rgba(255, 255, 255, 0.1);
	background: rgba(255, 255, 255, 0.03);
	color: rgba(200, 206, 220, 0.85);
	font-family: var(--font-display);
	font-size: 0.82rem;
	font-weight: 700;
	white-space: nowrap;
	cursor: pointer;
	transition: color 0.14s ease, border-color 0.14s ease, background 0.14s ease, box-shadow 0.14s ease;
}
body.play-app .quest-tab:hover { border-color: var(--accent); color: #fff; }
body.play-app .quest-tab.is-active {
	color: #fff;
	border-color: var(--accent);
	background: color-mix(in srgb, var(--accent) 22%, transparent);
	box-shadow: 0 0 14px -4px var(--accent);
}
body.play-app .quest-tab .play-land-chip-ambience-dot {
	position: static;
	display: inline-block;
	margin-left: 0.3rem;
}

/* Console body — focal card then roster, scrolls internally. */
body.play-app .quest-console-body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}

/* Focal card — rpgPanel game window tinted by the land accent. */
body.play-app .quest-focal { --accent: #c9a24d; flex: 0 0 auto; }
body.play-app .quest-focal .rpg-panel.raid-demo {
	border-color: color-mix(in srgb, var(--accent) 55%, rgba(0, 0, 0, 0.5));
}
body.play-app .quest-focal .raid-demo-glow {
	background: radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--accent) 38%, transparent), transparent 72%);
	opacity: 0.65;
}
body.play-app .quest-focal .raid-channel { color: color-mix(in srgb, var(--accent) 65%, #fff); }
body.play-app .quest-focal .raid-live-dot { background: var(--accent); }

body.play-app .quest-focal-main { display: flex; align-items: center; gap: clamp(0.6rem, 2.5vw, 1.1rem); }
/* Fluidly scale the glyph + name with viewport so the focal reads well on a 320px phone and a
   wide desktop alike (no abrupt jumps). */
body.play-app .quest-focal-glyph {
	flex: 0 0 auto;
	width: clamp(3.2rem, 13vw, 5rem);
	height: clamp(3.2rem, 13vw, 5rem);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: clamp(1.85rem, 7.5vw, 2.9rem);
	border-radius: clamp(12px, 3.5vw, 18px);
	background: radial-gradient(circle at 35% 28%, color-mix(in srgb, var(--accent) 42%, transparent), rgba(0, 0, 0, 0.4));
	box-shadow:
		inset 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent),
		inset 0 2px 10px rgba(0, 0, 0, 0.5),
		0 0 22px -6px var(--accent);
}
body.play-app .quest-focal-info { min-width: 0; }
body.play-app .quest-focal-name {
	font-family: var(--font-display);
	font-size: clamp(1.05rem, 4.6vw, 1.5rem);
	line-height: 1.12;
	font-weight: 800;
	color: #f4ecd6;
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
body.play-app .quest-focal-stats { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.45rem; }
body.play-app .quest-stat--land { color: color-mix(in srgb, var(--accent) 72%, #fff); }
body.play-app .quest-stat {
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
	font-size: 0.78rem;
	font-weight: 700;
	padding: 0.18rem 0.5rem;
	border-radius: 7px;
	background: rgba(0, 0, 0, 0.3);
	color: rgba(210, 216, 228, 0.95);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}
body.play-app .quest-focal .rpg-bar-block { margin-top: 0.85rem; }
body.play-app .quest-embark {
	width: 100%;
	margin-top: 0.95rem;
	font-size: 1.02rem;
	padding: 0.72rem;
	letter-spacing: 0.01em;
}
body.play-app .quest-focal-empty { padding: 1.4rem 0.5rem; text-align: center; }

/* Roster — compact chips to feature another ride/boss. The `min(8rem, 100%)` floor stops the
   minmax from forcing horizontal overflow on very narrow phones (always ≥1 column that fits). */
body.play-app .quest-roster {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(8rem, 100%), 1fr));
	gap: 0.45rem;
	flex: 0 0 auto;
}
body.play-app .quest-chip {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.08rem;
	padding: 0.5rem 0.6rem;
	border-radius: 10px;
	border: 1px solid rgba(255, 255, 255, 0.07);
	border-left: 3px solid rgba(255, 255, 255, 0.12);
	background: var(--surface-card);
	color: var(--text);
	text-align: left;
	cursor: pointer;
	min-width: 0;
	transition: transform 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}
body.play-app .quest-chip:hover { transform: translateY(-1px); border-left-color: rgba(201, 162, 77, 0.6); }
body.play-app .quest-chip.is-active {
	border-color: rgba(201, 162, 77, 0.5);
	border-left-color: var(--gold-bright, #ffd75e);
	background:
		radial-gradient(120% 100% at 0% 0%, rgba(241, 196, 15, 0.1), transparent 60%),
		var(--surface-card);
	box-shadow: 0 0 16px -6px rgba(241, 196, 15, 0.5);
}
body.play-app .quest-chip-glyph { font-size: 1.05rem; }
body.play-app .quest-chip-name {
	font-family: var(--font-display);
	font-weight: 700;
	font-size: 0.82rem;
	line-height: 1.12;
	width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
body.play-app .quest-chip-wait {
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
	font-size: 0.68rem;
	color: rgba(154, 163, 181, 0.85);
}
body.play-app .quest-chip.is-closed { opacity: 0.55; }
/* Dungeon roster: active chip glows red instead of gold. */
body.play-app .dungeon-console .quest-chip.is-active {
	border-color: rgba(231, 76, 60, 0.5);
	border-left-color: #ff6a4d;
	background:
		radial-gradient(120% 100% at 0% 0%, rgba(231, 76, 60, 0.12), transparent 60%),
		var(--surface-card);
	box-shadow: 0 0 16px -6px rgba(231, 76, 60, 0.55);
}

/* Quest console responsive polish ------------------------------------------ */
/* Roomy phones up: the focal embark sizes to content (not a stretched full-width slab) and the
   roster packs a touch denser. */
@media (min-width: 560px) {
	body.play-app .quest-embark {
		width: auto;
		min-width: 15rem;
		padding-inline: 1.7rem;
	}
	body.play-app .quest-roster { grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }
}
/* Desktop: cap the focal card so it doesn't stretch thin across a wide panel; keep it left-anchored
   with the roster filling the row below. */
@media (min-width: 900px) {
	body.play-app .quest-focal .rpg-panel.raid-demo { max-width: 42rem; }
	body.play-app .quest-roster { grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr)); }
}
/* Very narrow phones: guarantee a clean 2-up roster and tighten the focal padding. */
@media (max-width: 360px) {
	body.play-app .quest-roster { grid-template-columns: repeat(2, 1fr); gap: 0.38rem; }
	body.play-app .quest-tab { padding: 0.36rem 0.68rem; font-size: 0.78rem; }
	body.play-app .quest-chip { padding: 0.45rem 0.5rem; }
	body.play-app .quest-embark { font-size: 0.96rem; padding: 0.66rem; }
}

/* Quest console: "pick a ride" prompt (shown before a ride is featured) + wide-screen centering. */
body.play-app .quest-pick-prompt {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.7rem 0.85rem;
	border-radius: 12px;
	border: 1px solid rgba(255, 255, 255, 0.07);
	border-left: 3px solid var(--accent, #c9a24d);
	background: linear-gradient(180deg, rgba(42, 38, 50, 0.75), rgba(24, 22, 30, 0.85));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
	flex: 0 0 auto;
}
body.play-app .quest-pick-glyph {
	font-size: 1.85rem;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
body.play-app .quest-pick-copy { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
body.play-app .quest-pick-title {
	font-family: var(--font-display);
	font-weight: 800;
	font-size: 1.05rem;
	color: #f4ecd6;
}
body.play-app .quest-pick-sub {
	font-size: 0.78rem;
	color: color-mix(in srgb, var(--accent) 55%, #aab2c2);
}

/* Wide screens: center the whole console (tabs + focal + roster) instead of stretching it
   left-anchored across the panel. */
@media (min-width: 720px) {
	body.play-app .quest-console {
		max-width: 46rem;
		margin-inline: auto;
		width: 100%;
	}
	body.play-app .quest-focal .rpg-panel.raid-demo { max-width: none; }
	/* Desktop has no easy horizontal scroll (hidden scrollbar) — wrap the land/difficulty tabs so
	   every land is reachable instead of being clipped past the right edge. */
	body.play-app .quest-tabs {
		flex-wrap: wrap;
		overflow-x: visible;
		justify-content: center;
	}
}

/* The "Replay tutorial" hub footer was hidden in Virtual-Visit stage/stream modes. Now that idle
   regular virtual uses the normal hub layout, it reappeared and overlapped the (tall) park grid on
   mobile. Keep it hidden across Virtual Visit — it stays available on the in-park hub. */
body.play-app.play-virtual-hub-active .play-hub-footer { display: none; }

/* ============================================================================
   27. CHARACTER SHEET & BAG — make Profile read like a WoW character sheet and
   Inventory like a bag (rarity-bordered slots). Mostly restyles existing
   classes; portrait wrapper added in profile.js, data-rarity added in ui/shop.js.
   ============================================================================ */

/* Rarity palette — shared by gear slots + bag/shop item slots via [data-rarity]. */
body.play-app [data-rarity="common"] { --rarity: #9aa3b5; }
body.play-app [data-rarity="uncommon"] { --rarity: #5fbf72; }
body.play-app [data-rarity="rare"] { --rarity: #4aa3df; }
body.play-app [data-rarity="epic"] { --rarity: #b06bd6; }
body.play-app [data-rarity="legendary"] { --rarity: #e8a23d; }
body.play-app [data-rarity="mythic"] { --rarity: #e0556e; }
body.play-app [data-rarity="quest"] { --rarity: var(--gold-bright, #ffd75e); }

/* ---- Character header: class-ringed portrait + identity ---- */
body.play-app .play-profile-hero {
	--unit-color: #9aa3b5;
	display: flex;
	align-items: center;
	gap: 0.9rem;
	padding: 0.85rem 0.9rem;
	border-radius: 14px;
	border: 1px solid rgba(255, 255, 255, 0.08);
	background:
		radial-gradient(130% 100% at 0% 0%, color-mix(in srgb, var(--unit-color) 18%, transparent), transparent 60%),
		var(--surface-card);
	box-shadow: var(--surface-edge), 0 8px 22px -14px rgba(0, 0, 0, 0.85);
	margin-bottom: 0.7rem;
}
body.play-app .play-profile-hero[data-archetype="thrill_chaser"] { --unit-color: #e74c3c; }
body.play-app .play-profile-hero[data-archetype="magic_maker"] { --unit-color: #b06bd6; }
body.play-app .play-profile-hero[data-archetype="wayfinder"] { --unit-color: #2ecc71; }

body.play-app .play-profile-portrait {
	position: relative;
	flex: 0 0 auto;
	width: 3.6rem;
	height: 3.6rem;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.35));
	box-shadow:
		inset 0 0 0 2px var(--unit-color),
		inset 0 0 10px rgba(0, 0, 0, 0.5),
		0 0 18px -5px var(--unit-color);
}
body.play-app .play-profile-portrait-emoji { font-size: 1.85rem; line-height: 1; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6)); }
body.play-app .play-profile-portrait-level {
	position: absolute;
	right: -3px;
	bottom: -3px;
	min-width: 1.25rem;
	height: 1.25rem;
	padding: 0 0.25rem;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 999px;
	font-family: var(--font-numeric);
	font-size: 0.72rem;
	font-weight: 800;
	color: #2a1d00;
	background: var(--gold-grad, linear-gradient(180deg, #ffe89a, #f1c40f));
	box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55), 0 1px 3px rgba(0, 0, 0, 0.6);
}
body.play-app .play-profile-hero-body { min-width: 0; flex: 1; }

/* Portrait doubles as the avatar-picker trigger (a button). */
body.play-app button.play-profile-portrait {
	appearance: none;
	-webkit-appearance: none;
	padding: 0;
	font: inherit;
	color: inherit;
	cursor: pointer;
	transition: transform 0.12s ease;
}
body.play-app button.play-profile-portrait:hover { transform: translateY(-1px); }
body.play-app .play-profile-portrait-edit {
	position: absolute;
	top: -3px;
	right: -3px;
	width: 1.25rem;
	height: 1.25rem;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 999px;
	font-size: 0.6rem;
	color: #2a1d00;
	background: var(--gold-grad, linear-gradient(180deg, #ffe89a, #f1c40f));
	box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55);
	opacity: 0;
	transition: opacity 0.14s ease;
}
body.play-app button.play-profile-portrait:hover .play-profile-portrait-edit,
body.play-app button.play-profile-portrait.is-editing .play-profile-portrait-edit { opacity: 1; }

/* Avatar emoji palette. */
body.play-app .play-avatar-picker {
	margin-top: 0.7rem;
	padding: 0.7rem;
	border-radius: 12px;
	border: 1px solid rgba(241, 196, 15, 0.22);
	background: rgba(0, 0, 0, 0.28);
	box-shadow: var(--surface-edge);
}
body.play-app .play-avatar-picker[hidden] { display: none; }
body.play-app .play-avatar-picker-hint {
	margin: 0 0 0.55rem;
	font-size: 0.74rem;
	color: rgba(180, 188, 204, 0.85);
}
body.play-app .play-avatar-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(2.2rem, 1fr));
	gap: 0.35rem;
}
body.play-app .play-avatar-opt {
	aspect-ratio: 1 / 1;
	display: grid;
	place-items: center;
	font-size: 1.25rem;
	line-height: 1;
	border-radius: 9px;
	border: 1px solid var(--border);
	background: rgba(255, 255, 255, 0.03);
	cursor: pointer;
	transition: transform 0.1s ease, border-color 0.12s ease, background 0.12s ease;
}
body.play-app .play-avatar-opt:hover {
	border-color: rgba(241, 196, 15, 0.5);
	background: rgba(255, 255, 255, 0.06);
	transform: translateY(-1px);
}
body.play-app .play-avatar-opt:disabled { opacity: 0.5; cursor: default; transform: none; }
body.play-app .play-avatar-opt.is-selected {
	border-color: rgba(241, 196, 15, 0.85);
	background: var(--gold-grad-soft, rgba(241, 196, 15, 0.16));
	box-shadow: 0 0 0 1px rgba(241, 196, 15, 0.5), 0 0 12px -4px rgba(241, 196, 15, 0.6);
}
body.play-app .play-avatar-opt--reset {
	font-size: 1.05rem;
	color: rgba(180, 188, 204, 0.9);
}
body.play-app .play-profile-hero .play-profile-compact-id {
	font-family: var(--font-display);
	font-size: 1.02rem;
	font-weight: 700;
	color: #f3ead2;
	margin: 0 0 0.35rem;
}
body.play-app .play-profile-hero .profile-xp-bar--compact { margin: 0.1rem 0 0.25rem; }
body.play-app .play-profile-role {
	color: color-mix(in srgb, var(--unit-color) 70%, #fff);
	font-weight: 700;
}

/* ---- Attributes panel (STM/EFF/CHA/AP) — WoW attribute tiles ---- */
body.play-app .profile-stats--compact {
	grid-template-columns: repeat(2, 1fr);
	gap: 0.4rem;
}
body.play-app .profile-stats .profile-stat {
	border-radius: 10px;
	background: linear-gradient(180deg, rgba(44, 40, 52, 0.7), rgba(26, 24, 32, 0.85));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* ---- Equipment slots — framed character-sheet slots ---- */
body.play-app .play-gear-totals {
	border-radius: 10px;
	border: 1px solid rgba(201, 162, 77, 0.25);
	background: rgba(0, 0, 0, 0.25);
	padding: 0.45rem 0.7rem;
}
body.play-app .play-gear-slots {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr));
	gap: 0.5rem;
}
body.play-app .play-gear-slot {
	--rarity: #9aa3b5;
	border-radius: 11px;
	border: 1px solid rgba(0, 0, 0, 0.5);
	border-left: 3px solid var(--rarity);
	background: linear-gradient(180deg, rgba(46, 42, 54, 0.85), rgba(26, 24, 32, 0.92));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 4px 12px -9px rgba(0, 0, 0, 0.8);
}
body.play-app .play-gear-slot.is-auto { opacity: 0.92; }
body.play-app .play-gear-slot-label {
	font-family: var(--font-display);
	font-weight: 700;
	color: #e8dec6;
}
body.play-app .play-gear-equipped-name { color: #f3ead2; font-weight: 700; }
body.play-app .play-gear-statchip {
	background: color-mix(in srgb, var(--rarity) 18%, rgba(0, 0, 0, 0.3));
	border: 1px solid color-mix(in srgb, var(--rarity) 35%, transparent);
	color: #e8eef6;
}

/* ---- Profile sections → game panels ---- */
body.play-app .profile-section {
	border-radius: 12px;
	border: 1px solid rgba(255, 255, 255, 0.07);
	background: linear-gradient(180deg, rgba(40, 36, 48, 0.45), rgba(22, 20, 28, 0.55));
}
body.play-app .profile-section-summary {
	font-family: var(--font-display);
	color: #e8dec6;
}

/* ---- Inventory bag + shop: rarity-bordered item slots ---- */
body.play-app .play-shop-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(11rem, 100%), 1fr));
	gap: 0.5rem;
}
body.play-app .play-shop-item {
	--rarity: #9aa3b5;
	position: relative;
	border-radius: 11px;
	border: 1px solid rgba(0, 0, 0, 0.5);
	border-top: 2px solid var(--rarity);
	background:
		radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, var(--rarity) 16%, transparent), transparent 65%),
		linear-gradient(180deg, rgba(44, 40, 52, 0.9), rgba(24, 22, 30, 0.95));
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rarity) 18%, transparent), 0 5px 14px -10px rgba(0, 0, 0, 0.85);
}
body.play-app .play-shop-item:hover {
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rarity) 45%, transparent), 0 0 18px -6px var(--rarity);
}
body.play-app .play-shop-item-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.6rem;
	height: 2.6rem;
	margin-bottom: 0.4rem;
	border-radius: 9px;
	font-size: 1.45rem;
	background: linear-gradient(160deg, rgba(40, 36, 24, 0.9), rgba(16, 14, 10, 0.95));
	box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--rarity) 55%, transparent), inset 0 2px 7px rgba(0, 0, 0, 0.6);
}
body.play-app .play-shop-item-name { color: #f3ead2; font-weight: 700; }
body.play-app .play-inv-qty {
	font-family: var(--font-numeric);
	color: var(--gold-bright, #ffd75e);
	font-weight: 800;
}

/* ---- Wallet (was unstyled) — a gold coin pouch ---- */
body.play-app .rpg-wallet {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.4rem 0.85rem;
	border-radius: 999px;
	border: 1px solid rgba(201, 162, 77, 0.45);
	background: radial-gradient(120% 100% at 0% 0%, rgba(241, 196, 15, 0.14), transparent 60%), rgba(0, 0, 0, 0.3);
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4), 0 0 16px -8px rgba(241, 196, 15, 0.6);
	margin: 0.1rem 0 0.6rem;
}
body.play-app .rpg-wallet-icon { font-size: 1.1rem; }
body.play-app .rpg-wallet-amt {
	font-family: var(--font-numeric);
	font-variant-numeric: tabular-nums;
	font-size: 1.15rem;
	font-weight: 800;
	color: var(--gold-bright, #ffd75e);
}
body.play-app .rpg-wallet-label {
	font-size: 0.68rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(154, 163, 181, 0.85);
}

/* ---- Active boosts chips ---- */
body.play-app .play-shop-bag-chip {
	border-radius: 999px;
	border: 1px solid rgba(46, 204, 113, 0.35);
	background: rgba(46, 204, 113, 0.12);
}

/* ============================================================================
   28. GROUP FINDER (LFG) — WoW dungeon-finder console for the Dungeon + Raid
   tabs: role/readiness banner, activity roster, Find/Post/Solo entry points,
   live party composition (filled + open role slots), and the open-group board.
   Markup from play-park-hub.js mountGroupFinder + ui/raid.js finder renderers.
   ============================================================================ */
body.play-app .play-finder {
	display: flex;
	flex-direction: column;
	gap: 0.85rem;
}

/* Per-role accent (class = role): thrill→Tank, magic→Healer, wayfinder→DPS. */
body.play-app .play-finder .thrill { --role-color: #e74c3c; }
body.play-app .play-finder .magic { --role-color: #b06bd6; }
body.play-app .play-finder .wayfinder { --role-color: #2ecc71; }
body.play-app .play-finder .neutral { --role-color: #9aa3b5; }

/* ---- Role + readiness banner ---- */
body.play-app .play-finder-banner {
	--role-color: #9aa3b5;
	display: flex;
	align-items: center;
	gap: 0.85rem;
	padding: 0.7rem 0.85rem;
	border-radius: 14px;
	border: 1px solid rgba(255, 255, 255, 0.08);
	background:
		radial-gradient(130% 120% at 0% 0%, color-mix(in srgb, var(--role-color) 22%, transparent), transparent 62%),
		var(--surface-card);
	box-shadow: var(--surface-edge), 0 8px 22px -14px rgba(0, 0, 0, 0.85);
}
body.play-app .play-finder-portrait {
	position: relative;
	flex: 0 0 auto;
	width: 52px;
	height: 52px;
	display: grid;
	place-items: center;
	font-size: 1.7rem;
	border-radius: 50%;
	background: radial-gradient(circle at 50% 35%, color-mix(in srgb, var(--role-color) 30%, #1b1f2a), #11131b);
	box-shadow:
		inset 0 0 0 2px var(--role-color),
		0 0 13px -3px var(--role-color);
}
body.play-app .play-finder-level {
	position: absolute;
	right: -3px;
	bottom: -3px;
	min-width: 20px;
	height: 20px;
	padding: 0 4px;
	display: grid;
	place-items: center;
	font-size: 0.7rem;
	font-weight: 800;
	color: #1a1205;
	border-radius: 999px;
	background: linear-gradient(180deg, #ffe08a, #e8a23d);
	box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55);
}
body.play-app .play-finder-id {
	flex: 1 1 auto;
	min-width: 0;
}
body.play-app .play-finder-role-line {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: wrap;
}
body.play-app .play-finder-role-label {
	font-size: 0.64rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.5);
}
body.play-app .play-finder-role {
	font-family: var(--font-display, inherit);
	font-weight: 700;
	font-size: 1.02rem;
	color: color-mix(in srgb, var(--role-color) 70%, #fff);
}
body.play-app .play-finder-band {
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	padding: 0.1rem 0.45rem;
	border-radius: 999px;
	border: 1px solid rgba(255, 255, 255, 0.16);
	color: rgba(255, 255, 255, 0.78);
}
body.play-app .play-finder-band[data-band="seasoned"] {
	color: #7bc4e8;
	border-color: rgba(74, 163, 223, 0.5);
	background: rgba(74, 163, 223, 0.12);
}
body.play-app .play-finder-band[data-band="veteran"] {
	color: #ffd75e;
	border-color: rgba(232, 162, 61, 0.55);
	background: rgba(232, 162, 61, 0.14);
}
body.play-app .play-finder-readiness {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: 0.4rem;
}
body.play-app .play-finder-readiness-track {
	flex: 1 1 auto;
	height: 7px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.09);
	overflow: hidden;
}
body.play-app .play-finder-readiness-fill {
	height: 100%;
	border-radius: 999px;
	background: linear-gradient(90deg, var(--role-color), color-mix(in srgb, var(--role-color) 55%, #fff));
	box-shadow: 0 0 8px -1px var(--role-color);
}
body.play-app .play-finder-readiness-val {
	flex: 0 0 auto;
	font-size: 0.68rem;
	color: rgba(255, 255, 255, 0.62);
}

/* ---- Activity picker ---- */
body.play-app .play-finder-activity { display: flex; flex-direction: column; gap: 0.5rem; }
body.play-app .play-finder-act-label {
	font-size: 0.66rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.5);
}
body.play-app .play-finder-act-roster { max-height: 188px; overflow-y: auto; }
/* Locked attraction while queued — committed selection, non-interactive until you cancel search. */
body.play-app .play-finder-act.is-locked {
	cursor: default;
	opacity: 1;
	border-color: var(--wow-gold, #c9a24d);
	box-shadow: inset 0 0 0 1px rgba(201, 162, 77, 0.45), 0 0 12px -6px var(--wow-gold, #c9a24d);
}
body.play-app .play-finder-act.is-locked:hover { transform: none; }
body.play-app .play-finder-act.is-locked .quest-chip-glyph { filter: none; opacity: 0.85; }

/* ---- State body ---- */
body.play-app .play-finder-state {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	padding: 0.8rem;
	border-radius: 14px;
	border: 1px solid rgba(255, 255, 255, 0.08);
	background: var(--surface-card);
	box-shadow: var(--surface-edge);
}
body.play-app .play-finder-hint { margin: 0; color: rgba(255, 255, 255, 0.66); font-size: 0.84rem; }
body.play-app .play-finder-cta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}
body.play-app .play-finder-cta .play-action-btn { flex: 1 1 auto; }
body.play-app .play-finder-solo[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Searching */
body.play-app .play-finder-searching {
	display: flex;
	align-items: center;
	gap: 0.7rem;
}
body.play-app .play-finder-spinner {
	font-size: 1.5rem;
	animation: tpq-finder-search 1.6s ease-in-out infinite;
}
@keyframes tpq-finder-search {
	0%, 100% { transform: rotate(-12deg) scale(1); }
	50% { transform: rotate(12deg) scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
	body.play-app .play-finder-spinner { animation: none; }
}
body.play-app .play-finder-searching-title {
	margin: 0 0 0.15rem;
	font-weight: 700;
	font-family: var(--font-display, inherit);
}
body.play-app .play-finder-searching-body p { margin: 0; }

/* ---- Party composition ---- */
body.play-app .play-finder-comp { display: flex; flex-direction: column; gap: 0.5rem; }
body.play-app .play-finder-comp-head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	font-size: 0.66rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.5);
}
body.play-app .play-finder-comp-count { color: var(--gold-bright, #ffd75e); font-weight: 700; }
body.play-app .play-finder-slots {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
	gap: 0.45rem;
}
body.play-app .play-finder-slot {
	--role-color: #9aa3b5;
	display: flex;
	flex-direction: column;
	gap: 0.12rem;
	padding: 0.5rem 0.6rem;
	border-radius: 11px;
	border: 1px solid color-mix(in srgb, var(--role-color) 45%, rgba(255, 255, 255, 0.1));
	background:
		linear-gradient(180deg, color-mix(in srgb, var(--role-color) 14%, transparent), transparent),
		rgba(255, 255, 255, 0.03);
	border-left: 3px solid var(--role-color);
}
body.play-app .play-finder-slot.is-open {
	border-style: dashed;
	background: rgba(255, 255, 255, 0.02);
	opacity: 0.78;
}
body.play-app .play-finder-slot-icon { font-size: 1.1rem; }
body.play-app .play-finder-slot-name {
	font-weight: 600;
	font-size: 0.84rem;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .play-finder-slot-name em {
	font-style: normal;
	font-size: 0.6rem;
	font-weight: 700;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--gold-bright, #ffd75e);
	margin-left: 0.25rem;
}
body.play-app .play-finder-slot-role {
	font-size: 0.66rem;
	color: color-mix(in srgb, var(--role-color) 60%, #cfd4e0);
}
body.play-app .play-finder-slot.is-open .play-finder-slot-name { color: rgba(255, 255, 255, 0.55); }

body.play-app .play-finder-gate {
	margin: 0;
	padding: 0.4rem 0.55rem;
	border-radius: 9px;
	border-left: 3px solid #e8a23d;
	background: rgba(232, 162, 61, 0.1);
	color: #f0c87a;
	font-size: 0.78rem;
}
body.play-app .play-finder-launch {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	flex-wrap: wrap;
}
body.play-app .play-finder-launch-hint { font-size: 0.72rem; }
body.play-app .play-finder-launch .play-action-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
body.play-app .play-finder-leave { align-self: flex-start; }

/* ---- Open-group board ---- */
body.play-app .play-finder-board-wrap { display: flex; flex-direction: column; gap: 0.5rem; }
body.play-app .play-finder-board-label {
	margin: 0;
	font-size: 0.66rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.5);
}
body.play-app .play-finder-board-empty { margin: 0; font-size: 0.8rem; }
body.play-app .play-finder-board {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	gap: 0.5rem;
}
body.play-app .play-finder-card {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding: 0.6rem;
	border-radius: 12px;
	border: 1px solid rgba(255, 255, 255, 0.1);
	background: var(--surface-card);
	box-shadow: var(--surface-edge);
}
body.play-app .play-finder-card-top {
	display: flex;
	justify-content: space-between;
	align-items: center;
}
body.play-app .play-finder-card-kind {
	font-size: 0.66rem;
	letter-spacing: 0.04em;
	color: rgba(255, 255, 255, 0.72);
}
body.play-app .play-finder-card-size { font-weight: 700; color: var(--gold-bright, #ffd75e); font-size: 0.8rem; }
body.play-app .play-finder-card-needs {
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem;
	min-height: 1.4rem;
}
body.play-app .play-finder-need {
	--role-color: #9aa3b5;
	display: grid;
	place-items: center;
	width: 1.55rem;
	height: 1.55rem;
	font-size: 0.92rem;
	border-radius: 8px;
	border: 1px dashed color-mix(in srgb, var(--role-color) 55%, rgba(255, 255, 255, 0.15));
	background: color-mix(in srgb, var(--role-color) 12%, transparent);
}
body.play-app .play-finder-card .play-action-btn { width: 100%; }

/* Phone: single-column comp + board, stacked CTA. */
@media (max-width: 520px) {
	body.play-app .play-finder-slots,
	body.play-app .play-finder-board { grid-template-columns: 1fr; }
	body.play-app .play-finder-cta .play-action-btn { flex-basis: 100%; }
}

/* ============================================================================
   29. WoW FRAME — an ornate "World of Warcraft" window treatment applied (via the
   .vv-hub-panel--wow modifier, toggled in play-hub.js openPanel) to the Dungeons &
   Raids finder and the Profile character sheet. Gold double-border, dark stone +
   parchment ground, CSS-only corner flourishes, Cinzel serif headers, red action
   button. CSS-only — no art assets. Scoped to --wow so other panels are untouched.
   ============================================================================ */
body.play-app {
	--font-wow: "Cinzel", var(--font-display);
	--wow-gold: #c9a24d;
	--wow-gold-bright: #e7c97a;
	--wow-stone-a: #20222b;
	--wow-stone-b: #14151c;
}

body.play-app .vv-hub-panel--wow {
	position: relative;
	border: 2px solid var(--wow-gold);
	border-radius: 12px;
	background:
		radial-gradient(150% 90% at 50% -10%, rgba(201, 162, 77, 0.1), transparent 55%),
		linear-gradient(180deg, var(--wow-stone-a), var(--wow-stone-b));
	box-shadow:
		inset 0 0 0 1px rgba(0, 0, 0, 0.7),
		inset 0 0 0 4px rgba(201, 162, 77, 0.18),
		inset 0 2px 26px rgba(0, 0, 0, 0.55),
		0 0 0 1px rgba(0, 0, 0, 0.6),
		0 26px 60px -26px rgba(0, 0, 0, 0.92),
		0 0 36px -14px rgba(201, 162, 77, 0.35);
}

/* CSS-only corner flourishes — a gold gem clipped to a diamond on the top-left and
   bottom-right corners (a tasteful diagonal pair sitting on the gold rim). */
body.play-app .vv-hub-panel--wow::before,
body.play-app .vv-hub-panel--wow::after {
	content: "";
	position: absolute;
	width: 0.9rem;
	height: 0.9rem;
	background: linear-gradient(135deg, var(--wow-gold-bright), var(--wow-gold) 55%, #7c5e22);
	clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
	box-shadow: 0 0 6px -1px rgba(231, 201, 122, 0.6);
	pointer-events: none;
	z-index: 3;
}
body.play-app .vv-hub-panel--wow::before { top: -0.5rem; left: -0.5rem; }
body.play-app .vv-hub-panel--wow::after { bottom: -0.5rem; right: -0.5rem; }

/* ── WoW windows float OVER the game (like WoW), not as a full-bleed page. The wrap
   becomes a fixed, centered overlay with the park stage dimmed behind it. Driven by
   :has() so no extra JS — only wraps that contain a --wow panel are affected. ── */
/* :not([hidden]) so closePanel()'s `hidden` attribute still hides the window — otherwise this
   rule's display:grid would override [hidden]{display:none} and the window could never close. */
body.play-app .vv-hub-panel-wrap:not([hidden]):has(.vv-hub-panel--wow) {
	position: fixed;
	/* Float between the sticky header and the action bar, so both stay usable and the window
	   sits over the game stage (like a WoW window over the world). */
	top: calc(3.4rem + var(--play-safe-top, 0px));
	left: 0;
	right: 0;
	bottom: calc(var(--tpq-bar-h, 0px) + var(--play-safe-bottom, 0px));
	z-index: 90; /* above the stage; header (200) + action bar stay above as app chrome */
	margin: 0;
	display: grid;
	place-items: center;
	padding: clamp(0.5rem, 3vw, 1.6rem);
	background: radial-gradient(120% 90% at 50% 30%, rgba(8, 9, 14, 0.5), rgba(4, 5, 9, 0.74));
	-webkit-backdrop-filter: blur(2px);
	backdrop-filter: blur(2px);
	overflow: auto;
	overscroll-behavior: contain;
}
body.play-app .vv-hub-panel-wrap:has(.vv-hub-panel--wow) .vv-hub-panel--wow {
	flex: 0 1 auto;
	width: min(780px, 100%);
	max-height: min(88vh, 100%);
	margin: auto;
}
/* Keep the park stage visible (dimmed) behind the floating window. */
body.play-app .play-hub--panel-open:has(.vv-hub-panel--wow) .vv-hub-hero { display: revert; }

/* On phones the wrapping app header is tall and would overlap the window's top; hide it while a
   WoW window is open (no JS — keys off the open, non-hidden wrap) and drop the window to the top. */
@media (max-width: 640px) {
	body.play-app:has(.vv-hub-panel-wrap:not([hidden]) .vv-hub-panel--wow) .play-header {
		display: none;
	}
	body.play-app .vv-hub-panel-wrap:has(.vv-hub-panel--wow) {
		top: var(--play-safe-top, 0px);
	}
}

/* On phones the Quest Log should FILL the window height (not size to its content and float in a
   small centered box) — so the rail and quest detail get a roomy scroll area instead of forcing
   you to scroll inside a cramped panel. Scoped to the quest log via :has(.qlog). */
@media (max-width: 720px) {
	/* Flex (not grid place-items: stretch) — with auto grid rows the row sizes to content, so the
	   panel grew past the viewport instead of filling it. A flex column with a flex:1 panel makes
	   the panel exactly fill the (fixed-height) wrap, so the inner body scrolls within. */
	body.play-app .vv-hub-panel-wrap:has(.vv-hub-panel--wow):has(.qlog) {
		display: flex;
		flex-direction: column;
	}
	body.play-app .vv-hub-panel-wrap:has(.vv-hub-panel--wow) .vv-hub-panel--wow:has(.qlog) {
		flex: 1;
		min-height: 0;
		width: 100%;
		max-height: none;
		margin: 0;
	}
}

/* Ornate header: gold underline rule + Cinzel serif title. */
body.play-app .vv-hub-panel--wow .vv-hub-panel-head {
	border-bottom: 1px solid rgba(201, 162, 77, 0.4);
	box-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
	padding-bottom: 0.55rem;
	margin-bottom: 0.35rem;
}
body.play-app .vv-hub-panel--wow .vv-hub-panel-title,
body.play-app .vv-hub-panel--wow h3,
body.play-app .vv-hub-panel--wow .profile-subhead {
	font-family: var(--font-wow);
	font-weight: 700;
	letter-spacing: 0.02em;
	color: var(--wow-gold-bright);
	text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7), 0 0 12px rgba(201, 162, 77, 0.35);
}
body.play-app .vv-hub-panel--wow .vv-hub-panel-close {
	border-color: rgba(201, 162, 77, 0.5);
	color: var(--wow-gold-bright);
}
body.play-app .vv-hub-panel--wow .vv-hub-panel-close:hover {
	background: rgba(163, 32, 29, 0.4);
	border-color: #c9433d;
}

/* Red primary action — the WoW "Find Group" button. Scoped to the frame so it only
   recolors inside these windows; a standalone .play-action-btn--wow mirrors it. */
body.play-app .vv-hub-panel--wow .play-action-btn.primary,
body.play-app .play-action-btn--wow {
	background: linear-gradient(180deg, #b3322c, #8a1f1b 52%, #6e1512);
	border: 1px solid var(--wow-gold);
	color: #ffeede;
	font-family: var(--font-wow);
	font-weight: 700;
	letter-spacing: 0.02em;
	text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.18),
		inset 0 -2px 6px rgba(0, 0, 0, 0.4),
		0 3px 10px -5px rgba(0, 0, 0, 0.8);
}
body.play-app .vv-hub-panel--wow .play-action-btn.primary:hover:not([disabled]),
body.play-app .play-action-btn--wow:hover:not([disabled]) {
	background: linear-gradient(180deg, #c83b34, #9a2420 52%, #7c1714);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.22),
		0 0 16px -5px rgba(200, 59, 52, 0.7);
}
body.play-app .vv-hub-panel--wow .play-action-btn.primary:active:not([disabled]),
body.play-app .play-action-btn--wow:active:not([disabled]) {
	transform: translateY(1px);
	box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.55);
}

/* Secondary (non-primary) buttons inside the frame read as carved stone. */
body.play-app .vv-hub-panel--wow .play-action-btn:not(.primary):not(.play-action-btn--wow) {
	background: linear-gradient(180deg, rgba(60, 56, 50, 0.9), rgba(32, 30, 27, 0.95));
	border: 1px solid rgba(201, 162, 77, 0.38);
	color: #e7dcc2;
}
body.play-app .vv-hub-panel--wow .play-action-btn:not(.primary):hover:not([disabled]) {
	border-color: var(--wow-gold);
	color: #fff;
}

/* ============================================================================
   30. DUNGEONS & RAIDS — the finder as one window with a left category rail
   (Dungeon Finder / Raid Finder / Premade Groups), role medallions, a "Type"
   picker, and a parchment info panel. Markup: play-park-hub.js mountGroupFinder.
   ============================================================================ */
body.play-app .play-finder-shell {
	display: grid;
	grid-template-columns: minmax(140px, 188px) minmax(0, 1fr);
	gap: 0.85rem;
	align-items: start;
}

/* Left category rail — stone tabs with a gold active edge. */
body.play-app .play-finder-rail {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
body.play-app .play-finder-rail-btn {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	padding: 0.6rem 0.65rem;
	border-radius: 10px;
	border: 1px solid rgba(201, 162, 77, 0.28);
	background: linear-gradient(180deg, rgba(48, 45, 40, 0.7), rgba(26, 24, 21, 0.85));
	color: #d8cfb8;
	font-family: var(--font-wow);
	font-size: 0.82rem;
	font-weight: 600;
	text-align: left;
	cursor: pointer;
	transition: border-color 0.15s, background 0.15s, transform 0.1s;
}
body.play-app .play-finder-rail-btn:hover { border-color: var(--wow-gold); color: #fff; }
body.play-app .play-finder-rail-btn.is-active {
	border-color: var(--wow-gold-bright);
	background:
		radial-gradient(120% 120% at 0% 0%, rgba(201, 162, 77, 0.28), transparent 60%),
		linear-gradient(180deg, rgba(70, 60, 40, 0.9), rgba(38, 32, 24, 0.95));
	color: #fff5e0;
	box-shadow: inset 3px 0 0 var(--wow-gold-bright), 0 0 14px -7px var(--wow-gold);
}
body.play-app .play-finder-rail-glyph {
	font-size: 1.35rem;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
}
body.play-app .play-finder-rail-label { line-height: 1.15; }

/* Right pane */
body.play-app .play-finder-pane {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	min-width: 0;
}

/* Role medallions — Tank/Healer/DPS as gold-ringed badges, the player's role lit. */
body.play-app .play-finder-medallions {
	display: flex;
	gap: 0.7rem;
	justify-content: center;
	padding: 0.2rem 0;
}
body.play-app .play-finder-medallion {
	--role-color: #9aa3b5;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.2rem;
	width: 4.1rem;
	opacity: 0.4;
	filter: grayscale(0.5);
	transition: opacity 0.15s, filter 0.15s;
}
body.play-app .play-finder-medallion.is-self { opacity: 1; filter: none; }
body.play-app .play-finder-medallion-icon {
	width: 2.5rem;
	height: 2.5rem;
	display: grid;
	place-items: center;
	font-size: 1.3rem;
	border-radius: 50%;
	background: radial-gradient(circle at 50% 35%, color-mix(in srgb, var(--role-color) 28%, #1b1f2a), #11131b);
	box-shadow: inset 0 0 0 2px var(--wow-gold), inset 0 0 0 3px rgba(0, 0, 0, 0.6);
}
body.play-app .play-finder-medallion.is-self .play-finder-medallion-icon {
	box-shadow:
		inset 0 0 0 2px var(--wow-gold-bright),
		0 0 14px -3px var(--role-color);
}
body.play-app .play-finder-medallion-label {
	font-size: 0.64rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: #cfd4e0;
}

/* "Type" picker row (dungeon difficulty). */
body.play-app .play-finder-type {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	flex-wrap: wrap;
}
body.play-app .play-finder-type-label {
	font-family: var(--font-wow);
	font-size: 0.78rem;
	color: var(--wow-gold-bright);
}
body.play-app .play-finder-type .play-finder-diff { margin: 0; }

/* Parchment info panel — warm aged ground inside the stone window. */
body.play-app .play-finder-parchment {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	padding: 0.85rem;
	border-radius: 10px;
	border: 1px solid rgba(201, 162, 77, 0.35);
	background:
		radial-gradient(140% 120% at 50% 0%, rgba(74, 62, 40, 0.4), transparent 65%),
		linear-gradient(180deg, rgba(38, 34, 28, 0.92), rgba(24, 21, 17, 0.96));
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5), inset 0 2px 14px rgba(0, 0, 0, 0.4);
}

/* Phone: rail becomes a 3-up grid of compact, stacked tabs so every category fits the
   screen (no horizontal overflow — the Raid/Premade tabs were falling off the edge). */
@media (max-width: 640px) {
	body.play-app .play-finder-shell { grid-template-columns: 1fr; }
	body.play-app .play-finder-rail {
		display: grid;
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 0.4rem;
	}
	body.play-app .play-finder-rail-btn {
		flex-direction: column;
		align-items: center;
		text-align: center;
		gap: 0.2rem;
		padding: 0.45rem 0.2rem;
		min-width: 0;
	}
	body.play-app .play-finder-rail-glyph { font-size: 1.2rem; }
	body.play-app .play-finder-rail-label { font-size: 0.68rem; line-height: 1.05; }
	body.play-app .play-finder-rail-btn.is-active {
		box-shadow: inset 0 3px 0 var(--wow-gold-bright), 0 0 14px -7px var(--wow-gold);
	}
}

/* ============================================================================
   Quest Log — WoW-style two-pane journal. Mounts in the gilded --wow panel
   frame (floats centered over the dimmed game). Left = grouped quest list,
   right = quest detail (story / objectives / rewards, the ride picker, or the
   bounty board). Narrow screens flip master → detail with a ← back button.
   ============================================================================ */
body.play-app .qlog {
	flex: 1;
	min-height: 0;
	/* Cap + center as a "console" so the two-pane log doesn't stretch edge-to-edge in the
	   full-screen Quest room (it was designed for the old narrow centered panel). On wide screens
	   the painted room fills the sides; the log reads intentional. (campaign-visual-modernization.md) */
	width: 100%;
	max-width: 60rem;
	margin-inline: auto;
	display: flex;
	gap: 0.85rem;
	align-items: stretch;
}
body.play-app .qlog--loading {
	align-items: center;
	justify-content: center;
}

/* ── Left rail: the quest list ── */
body.play-app .qlog-rail {
	flex: 0 0 15rem;
	min-height: 0;
	display: flex;
	flex-direction: column;
	border: 1px solid rgba(201, 162, 77, 0.32);
	border-radius: 12px;
	/* Translucent "carved glass" so the painted Quest room (rooms/quest.png) reads THROUGH the panel
	   instead of being hidden behind an opaque slab — the room is the base layer now. Blur keeps the
	   list legible over the busy backdrop. (campaign-visual-modernization.md P0) */
	background: linear-gradient(180deg, rgba(16, 12, 9, 0.58), rgba(9, 7, 6, 0.66));
	-webkit-backdrop-filter: blur(5px) saturate(1.05);
	backdrop-filter: blur(5px) saturate(1.05);
	box-shadow:
		inset 0 1px 0 rgba(231, 201, 122, 0.12),
		inset 0 0 0 1px rgba(0, 0, 0, 0.45),
		0 10px 30px -14px rgba(0, 0, 0, 0.7);
	overflow: hidden;
}
body.play-app .qlog-rail-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	padding: 0.6rem 0.75rem;
	font-family: var(--font-wow);
	color: var(--wow-gold-bright);
	font-weight: 700;
	letter-spacing: 0.03em;
	border-bottom: 1px solid rgba(201, 162, 77, 0.3);
	flex-shrink: 0;
}
body.play-app .qlog-rail-count {
	font-family: var(--font-display);
	font-size: 0.8rem;
	background: rgba(201, 162, 77, 0.18);
	color: var(--wow-gold-bright);
	border-radius: 999px;
	padding: 0.05rem 0.5rem;
}
body.play-app .qlog-rail-list {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	padding: 0.4rem;
}
body.play-app .qlog-group {
	margin: 0.5rem 0.3rem 0.25rem;
	font-size: 0.66rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wow-gold);
	opacity: 0.85;
}
body.play-app .qlog-group:first-child {
	margin-top: 0.1rem;
}
body.play-app .qlog-empty-note {
	margin: 0.1rem 0.4rem 0.5rem;
	padding: 0.6rem 0.7rem;
	border: 1px dashed rgba(201, 162, 77, 0.28);
	border-radius: 10px;
	background: rgba(10, 8, 6, 0.4);
	color: var(--text-dim, #a9a397);
	font-size: 0.78rem;
	line-height: 1.4;
}
/* Mission cards: each quest is a framed card with a quest-giver portrait medallion.
   (campaign-visual-modernization.md P1) */
body.play-app .qlog-entry {
	width: 100%;
	display: flex;
	align-items: center;
	gap: 0.6rem;
	min-height: 3rem;
	padding: 0.5rem 0.55rem;
	margin-bottom: 0.35rem;
	border: 1px solid rgba(201, 162, 77, 0.18);
	border-radius: 12px;
	background: linear-gradient(180deg, rgba(20, 16, 11, 0.5), rgba(10, 8, 6, 0.58));
	color: var(--text, #e9e6df);
	text-align: left;
	cursor: pointer;
	font: inherit;
	transition: transform 0.12s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
body.play-app .qlog-entry:hover {
	border-color: rgba(231, 201, 122, 0.45);
	box-shadow: 0 4px 14px -9px rgba(0, 0, 0, 0.75);
}
body.play-app .qlog-entry:active {
	transform: translateY(1px);
}
/* Active = the quest you're ON: a warm left-lit fill + a gold spine so it's instantly findable. */
body.play-app .qlog-entry.is-active {
	border-color: rgba(231, 201, 122, 0.5);
	background: linear-gradient(100deg, rgba(60, 46, 18, 0.5), rgba(16, 12, 8, 0.58) 62%);
	box-shadow: inset 3px 0 0 rgba(231, 201, 122, 0.6), 0 4px 14px -10px rgba(201, 162, 77, 0.5);
}
body.play-app .qlog-entry.is-selected {
	border-color: rgba(231, 201, 122, 0.7);
	background: linear-gradient(180deg, rgba(48, 37, 18, 0.66), rgba(24, 18, 10, 0.66));
	box-shadow: inset 4px 0 0 var(--wow-gold-bright, #e7c97a), inset 0 0 0 1px rgba(231, 201, 122, 0.3), 0 6px 18px -9px rgba(201, 162, 77, 0.55);
}
/* Sealed/locked = a positive identity (a dashed wax-seal edge), not a greyed-out broken button. */
body.play-app .qlog-entry.is-locked {
	opacity: 0.78;
	filter: saturate(0.65);
	border-style: dashed;
	border-color: rgba(201, 162, 77, 0.24);
}
/* Keyboard/controller focus — the Quest Log mounts in .vv-hub-panel--wow, outside .tpq-room's
   focus rings, so it had none. Mirror the room's gold ring on every interactive control here. */
body.play-app .qlog-entry:focus-visible,
body.play-app .qlog-back:focus-visible,
body.play-app .qlog-q-btn:focus-visible,
body.play-app .qlog-accept:focus-visible,
body.play-app [data-lore-continue]:focus-visible {
	outline: 2px solid rgba(255, 224, 122, 0.85);
	outline-offset: 2px;
}
/* Portrait/glyph medallion */
body.play-app .qlog-entry-medal {
	position: relative;
	flex-shrink: 0;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 10px;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	background: radial-gradient(circle at 38% 30%, rgba(231, 201, 122, 0.16), rgba(0, 0, 0, 0.4));
	box-shadow: inset 0 0 0 1.5px rgba(201, 162, 77, 0.4), inset 0 0 10px rgba(0, 0, 0, 0.5);
}
body.play-app .qlog-entry-portrait {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center top;
}
body.play-app .qlog-entry-medal .qlog-entry-glyph {
	display: none;
}
body.play-app .qlog-entry-medal.is-emoji {
	overflow: visible;
}
body.play-app .qlog-entry-medal.is-emoji .qlog-entry-portrait {
	display: none;
}
body.play-app .qlog-entry-medal.is-emoji .qlog-entry-glyph {
	display: flex;
	font-size: 1.3rem;
	line-height: 1;
}
body.play-app .qlog-entry.is-active .qlog-entry-medal {
	box-shadow: inset 0 0 0 1.5px rgba(231, 201, 122, 0.7), 0 0 10px -2px rgba(231, 201, 122, 0.45);
}
/* Inline step-progress bar inside an active campaign card */
body.play-app .qlog-entry-bar {
	display: block;
	height: 4px;
	margin-top: 0.32rem;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.4);
	box-shadow: inset 0 0 0 1px rgba(201, 162, 77, 0.2);
	overflow: hidden;
}
body.play-app .qlog-entry-bar-fill {
	display: block;
	height: 100%;
	border-radius: 999px;
	background: linear-gradient(90deg, var(--wow-gold), var(--wow-gold-bright));
	box-shadow: 0 0 8px rgba(231, 201, 122, 0.55);
}
body.play-app .qlog-entry-text {
	min-width: 0;
	flex: 1;
	display: flex;
	flex-direction: column;
}
body.play-app .qlog-entry-title {
	font-weight: 700;
	font-size: 0.86rem;
	line-height: 1.2;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* Modern gold pill badge instead of the dated WoW-addon "[Active]" bracket text. */
body.play-app .qlog-entry-tag {
	display: inline-block;
	margin-right: 0.4rem;
	padding: 0.04rem 0.42rem;
	font-size: 0.58rem;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	vertical-align: 0.1em;
	color: #1d1509;
	background: linear-gradient(180deg, var(--wow-gold-bright), var(--wow-gold));
	border-radius: 999px;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
body.play-app .qlog-entry-sub {
	font-size: 0.72rem;
	color: var(--text-dim, #a9a397);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
body.play-app .qlog-entry-lock {
	flex-shrink: 0;
	font-size: 0.8rem;
}

/* ── Right pane: quest detail ── */
body.play-app .qlog-detail {
	flex: 1;
	min-width: 0;
	min-height: 0;
	display: flex;
	flex-direction: column;
	/* .qlog-detail is a <section>, and the site-wide `section { padding-bottom: 2.5rem }` rule leaks
	   ~40px of dead space under every detail screen. Cancel it — the detail manages its own padding. */
	padding: 0;
	border: 1px solid rgba(201, 162, 77, 0.26);
	border-radius: 12px;
	/* Translucent so the painted room shows through (see .qlog-rail). The warm top radial stays as a
	   gilded "lantern glow" over the glass; blur holds story/objective text legible. */
	background:
		radial-gradient(150% 90% at 50% 0%, rgba(120, 92, 44, 0.22), transparent 62%),
		linear-gradient(180deg, rgba(14, 11, 9, 0.6), rgba(8, 7, 6, 0.68));
	-webkit-backdrop-filter: blur(5px) saturate(1.05);
	backdrop-filter: blur(5px) saturate(1.05);
	box-shadow:
		inset 0 1px 0 rgba(231, 201, 122, 0.12),
		0 10px 30px -14px rgba(0, 0, 0, 0.7);
	overflow: hidden;
}
body.play-app .qlog-back {
	display: none; /* narrow screens only */
	align-self: flex-start;
	margin: 0.3rem 0 0 0.5rem;
	background: transparent;
	border: 1px solid rgba(201, 162, 77, 0.3);
	color: var(--wow-gold-bright);
	border-radius: 999px;
	padding: 0.25rem 0.7rem;
	font: inherit;
	font-size: 0.8rem;
	cursor: pointer;
	transition: border-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
}
body.play-app .qlog-back:hover {
	border-color: var(--wow-gold-bright);
	color: #fff;
}
body.play-app .qlog-back:active {
	transform: translateY(1px);
}
body.play-app .qlog-detail-head {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	padding: 0.5rem 0.85rem 0.45rem;
	border-bottom: 1px solid rgba(201, 162, 77, 0.25);
	flex-shrink: 0;
}
body.play-app .qlog-detail-sigil {
	font-size: 1.6rem;
	line-height: 1;
}
body.play-app .qlog-detail-title {
	margin: 0;
	font-family: var(--font-wow);
	color: var(--wow-gold-bright);
	font-size: 1rem;
	line-height: 1.15;
	text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7);
}
body.play-app .qlog-detail-tag {
	margin: 0.1rem 0 0;
	font-size: 0.76rem;
	color: var(--wow-gold);
	opacity: 0.9;
}
body.play-app .qlog-detail-body {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}
body.play-app .qlog-detail-scroll {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	padding: 0.55rem 0.85rem;
}
/* "More below" cue — a bouncing chevron pinned to the bottom of the scroll area, shown only
   while the list overflows and isn't scrolled to the end (toggled via .has-more in campaign.js).
   Makes it obvious on mobile that the requirement list continues past the fold. */
/* Scroll affordance: fade the bottom edge of the content while it overflows and isn't at the
   bottom (toggled via .has-more in campaign.js). A non-covering signal — nothing opaque sits over
   the text; the last row simply fades, hinting "more below". */
body.play-app .qlog-scroll-cue {
	display: none;
}
body.play-app .qlog-detail-scroll.has-more {
	-webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 1.7rem), transparent);
	mask-image: linear-gradient(to bottom, #000 calc(100% - 1.7rem), transparent);
}

/* ── Themed "quest note": short in-world flavor text on a quest screen — a dark gilded "letter"
   card with a gold spine, not a parchment block. ── */
body.play-app .qlog-quest-note {
	display: flex;
	align-items: flex-start;
	gap: 0.55rem;
	margin: 0 0 0.85rem;
	padding: 0.6rem 0.75rem;
	border-radius: 8px;
	border: 1px solid rgba(201, 162, 77, 0.3);
	border-left: 3px solid var(--wow-gold);
	background: linear-gradient(180deg, rgba(44, 37, 23, 0.55), rgba(26, 22, 15, 0.6));
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.3);
}
body.play-app .qlog-quest-note-icon {
	font-size: 1.05rem;
	line-height: 1.35;
	flex-shrink: 0;
	filter: drop-shadow(0 0 6px rgba(201, 162, 77, 0.35));
}
body.play-app .qlog-quest-note-text {
	margin: 0;
	font-style: italic;
	line-height: 1.55;
	font-size: 0.9rem;
	color: var(--text-soft, #d6d1c6);
}
body.play-app .qlog-quest-note-text strong {
	color: var(--wow-gold-bright);
	font-style: normal;
}

/* ── WoW quest-detail sections (dark, gilded) for the active campaign journal. ── */
body.play-app .qlog-q-sec {
	/* These are <section> elements, so the site-wide `section { padding: 3.5rem 0 }` (2.5rem on
	   mobile) leaks ~56px of dead space above AND below every block (progress, description,
	   objectives, rewards) — the big empty bands. Cancel it; spacing is managed via margin here. */
	padding: 0;
	margin: 0 0 0.75rem;
}
body.play-app .qlog-q-sec:last-child {
	margin-bottom: 0.2rem;
}
/* The journal's action toast sits empty until something happens — don't reserve its top margin
   (a stray gap under the rewards) until it actually holds a message. */
body.play-app .qlog-detail-body > .vv-hub-panel-toast:empty {
	margin: 0;
}
body.play-app .qlog-q-progress {
	margin-bottom: 0.8rem;
}
body.play-app .qlog-q-progress .bar-block {
	margin: 0;
}
body.play-app .qlog-q-head {
	margin: 0 0 0.5rem;
	font-family: var(--font-wow);
	font-size: 0.92rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wow-gold-bright);
	border-bottom: 1px solid rgba(201, 162, 77, 0.28);
	padding-bottom: 0.22rem;
	text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}
body.play-app .qlog-quest-story {
	margin: 0 0 0.5rem;
	color: var(--text-soft, #d6d1c6);
	line-height: 1.6;
	font-size: 0.92rem;
}
body.play-app .qlog-quest-story:last-child {
	margin-bottom: 0;
}
body.play-app .qlog-quest-story strong {
	color: var(--wow-gold-bright);
}
body.play-app .qlog-obj-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
/* Objectives as clean cards (not a dashed to-do list) with a satisfying check.
   (campaign-visual-modernization.md P2) */
body.play-app .qlog-obj {
	display: flex;
	align-items: flex-start;
	gap: 0.6rem;
	padding: 0.5rem 0.55rem;
	margin-bottom: 0.32rem;
	border-radius: 9px;
	border: 1px solid rgba(201, 162, 77, 0.14);
	background: rgba(0, 0, 0, 0.22);
}
body.play-app .qlog-obj:last-child {
	margin-bottom: 0;
}
body.play-app .qlog-obj-box {
	flex-shrink: 0;
	width: 1.25rem;
	height: 1.25rem;
	margin-top: 0.04rem;
	border: 1.5px solid rgba(201, 162, 77, 0.55);
	border-radius: 6px;
	background: rgba(0, 0, 0, 0.35);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 0.85rem;
	font-weight: 800;
	line-height: 1;
}
/* Completed objective: keep it in the list, ticked and dimmed (don't make it vanish). */
body.play-app .qlog-obj.is-done {
	border-color: rgba(95, 217, 154, 0.3);
	background: rgba(67, 196, 131, 0.08);
}
body.play-app .qlog-obj.is-done .qlog-obj-box {
	color: #0e1a12;
	border-color: #5fd99a;
	background: linear-gradient(180deg, #6fe0a6, #43c483);
	box-shadow: 0 0 8px rgba(95, 217, 154, 0.5);
}
body.play-app .qlog-obj-text {
	color: var(--text, #e9e6df);
	line-height: 1.45;
	font-size: 0.9rem;
}
body.play-app .qlog-obj.is-done .qlog-obj-text {
	color: var(--text-dim, #a9a397);
	text-decoration: line-through;
	text-decoration-color: rgba(95, 217, 154, 0.6);
}
body.play-app .qlog-obj.is-done .qlog-obj-text strong {
	color: var(--text-dim, #a9a397);
}
body.play-app .qlog-obj-text strong {
	color: var(--wow-gold-bright);
}
body.play-app .qlog-obj-text em {
	color: var(--text-dim, #a9a397);
	font-style: normal;
}
/* "Find it in the park, then tap Investigate" guidance above the step's action buttons. */
body.play-app .qlog-q-hint {
	margin: 0 0 0.5rem;
	padding: 0.4rem 0.6rem;
	border-radius: 7px;
	border-left: 3px solid var(--wow-gold);
	background: rgba(201, 162, 77, 0.1);
	color: var(--text-soft, #d6d1c6);
	font-size: 0.84rem;
	line-height: 1.4;
}
body.play-app .qlog-q-hint strong {
	color: var(--wow-gold-bright);
}
body.play-app .qlog-q-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: -0.3rem 0 1.05rem;
}
body.play-app .qlog-q-btn {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	min-height: 2.75rem;
	font: inherit;
	font-size: 0.85rem;
	font-weight: 700;
	cursor: pointer;
	padding: 0.55rem 0.85rem;
	border-radius: 6px;
	color: var(--wow-gold-bright);
	background: linear-gradient(180deg, rgba(50, 42, 25, 0.92), rgba(34, 28, 18, 0.96));
	border: 1px solid rgba(201, 162, 77, 0.45);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 1px 3px rgba(0, 0, 0, 0.4);
}
body.play-app .qlog-q-btn:hover:not([disabled]) {
	border-color: var(--wow-gold);
	background: linear-gradient(180deg, rgba(64, 53, 30, 0.95), rgba(42, 34, 21, 0.98));
}
body.play-app .qlog-q-btn--boss {
	color: #f0b3a6;
	border-color: rgba(180, 70, 56, 0.6);
	background: linear-gradient(180deg, rgba(64, 28, 24, 0.9), rgba(40, 18, 16, 0.95));
}
body.play-app .qlog-q-btn--boss:hover:not([disabled]) {
	border-color: #c9433d;
	background: linear-gradient(180deg, rgba(82, 34, 28, 0.95), rgba(52, 22, 18, 0.98));
}
body.play-app .qlog-q-reward-lead {
	margin: 0 0 0.45rem;
	color: var(--text-dim, #a9a397);
	font-size: 0.86rem;
}
body.play-app .qlog-q-rewards {
	display: flex;
	flex-wrap: wrap;
	gap: 0.45rem;
}
/* Rewards as little loot cards with a rarity glow (not flat text tags). (P2) */
body.play-app .qlog-q-reward {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	font-size: 0.84rem;
	font-weight: 700;
	color: var(--text, #e9e6df);
	background: linear-gradient(180deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.45));
	border: 1px solid rgba(201, 162, 77, 0.3);
	border-radius: 9px;
	padding: 0.34rem 0.6rem;
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
body.play-app .qlog-q-reward--ap {
	color: var(--wow-gold-bright);
	border-color: rgba(201, 162, 77, 0.55);
	background: linear-gradient(180deg, rgba(201, 162, 77, 0.18), rgba(201, 162, 77, 0.08));
	box-shadow: 0 0 10px -3px rgba(231, 201, 122, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
/* Item reward glows by rarity (matches the shop/inventory + socket rarity language). */
body.play-app .qlog-q-reward--item[data-rarity="uncommon"] { color: #4ade80; border-color: rgba(74, 222, 128, 0.5); box-shadow: 0 0 10px -3px rgba(74, 222, 128, 0.45); }
body.play-app .qlog-q-reward--item[data-rarity="rare"] { color: #60a5fa; border-color: rgba(96, 165, 250, 0.5); box-shadow: 0 0 10px -3px rgba(96, 165, 250, 0.5); }
body.play-app .qlog-q-reward--item[data-rarity="epic"] { color: #c084fc; border-color: rgba(192, 132, 252, 0.55); box-shadow: 0 0 11px -3px rgba(192, 132, 252, 0.55); }
body.play-app .qlog-q-reward--item[data-rarity="legendary"] { color: #f59e0b; border-color: rgba(245, 158, 11, 0.6); box-shadow: 0 0 13px -2px rgba(245, 158, 11, 0.6); }
body.play-app .qlog-q-reward--item[data-rarity="mythic"] { color: #ff7a4d; border-color: rgba(255, 122, 77, 0.6); box-shadow: 0 0 14px -2px rgba(255, 122, 77, 0.65); }
body.play-app .qlog-q-reward--title {
	color: #d8b8ff;
	border-color: rgba(190, 140, 255, 0.45);
	box-shadow: 0 0 10px -3px rgba(190, 140, 255, 0.45);
}

/* ── Call-to-adventure offer hero: quest-giver bust + ribbon (P3) ── */
body.play-app .qlog-offer-hero {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	margin: 0.2rem 0 0.9rem;
}
body.play-app .qlog-offer-ribbon {
	font-family: var(--font-wow);
	font-size: 0.7rem;
	font-weight: 800;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: #1d1509;
	background: linear-gradient(180deg, var(--wow-gold-bright), var(--wow-gold));
	border-radius: 999px;
	padding: 0.18rem 0.85rem;
	box-shadow: 0 2px 8px -2px rgba(231, 201, 122, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
body.play-app .qlog-offer-portrait {
	position: relative;
	width: 5.4rem;
	height: 5.4rem;
	border-radius: 14px;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	background: radial-gradient(circle at 38% 28%, rgba(231, 201, 122, 0.22), rgba(0, 0, 0, 0.45));
	box-shadow: inset 0 0 0 2px rgba(201, 162, 77, 0.5), inset 0 0 16px rgba(0, 0, 0, 0.55), 0 0 24px -8px rgba(231, 201, 122, 0.6);
}
body.play-app .qlog-offer-portrait img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center top;
}
body.play-app .qlog-offer-glyph {
	display: none;
	font-size: 2.6rem;
	line-height: 1;
}
body.play-app .qlog-offer-portrait.is-emoji { overflow: visible; }
body.play-app .qlog-offer-portrait.is-emoji img { display: none; }
body.play-app .qlog-offer-portrait.is-emoji .qlog-offer-glyph { display: flex; }
body.play-app .qlog-offer-hero.is-locked .qlog-offer-portrait { filter: saturate(0.55) brightness(0.8); }
body.play-app .qlog-offer-hero.is-locked .qlog-offer-portrait { box-shadow: inset 0 0 0 2px rgba(150, 140, 120, 0.5); }
/* A sealed offer reads as stone, not gold — the ribbon promises "Sealed Quest", so look it. */
body.play-app .qlog-offer-hero.is-locked .qlog-offer-ribbon {
	color: #e8e3d6;
	background: linear-gradient(180deg, rgba(120, 112, 96, 0.95), rgba(78, 72, 60, 0.95));
}
body.play-app .qlog-offer-hero.is-finale .qlog-offer-portrait {
	box-shadow: inset 0 0 0 2px rgba(231, 201, 122, 0.85), 0 0 28px -6px rgba(231, 201, 122, 0.8);
}

/* ── Finale rail card = crowned (P3) ── */
body.play-app .qlog-entry.is-finale {
	border-color: rgba(231, 201, 122, 0.45);
	background: linear-gradient(180deg, rgba(48, 36, 14, 0.55), rgba(20, 15, 8, 0.6));
}
body.play-app .qlog-entry.is-finale .qlog-entry-medal {
	background: radial-gradient(circle at 40% 30%, rgba(255, 224, 130, 0.3), rgba(40, 28, 8, 0.6));
	box-shadow: inset 0 0 0 1.5px rgba(255, 224, 130, 0.75), 0 0 12px -2px rgba(255, 224, 130, 0.6);
}

/* ── Investigate "Discovery" lore reveal (replaces the old green success toast). ── */
body.play-app .qlog-lore .qlog-lore-head {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-bottom: 0.7rem;
}
body.play-app .qlog-lore-sigil {
	font-size: 1.3rem;
	filter: drop-shadow(0 0 8px rgba(96, 165, 250, 0.45));
}
body.play-app .qlog-lore-h {
	margin: 0;
	font-family: var(--font-wow);
	font-size: 1.05rem;
	color: var(--wow-gold-bright);
	letter-spacing: 0.03em;
	text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}
/* Discovery lore = an arcane "codex unlock" card (glows; pops in via TPQJuice). (P2) */
body.play-app .qlog-lore-card {
	margin-bottom: 0.75rem;
	padding: 0.8rem 0.9rem;
	border-radius: 12px;
	border: 1px solid rgba(155, 89, 182, 0.4);
	border-left: 3px solid #b06fd6;
	background: linear-gradient(180deg, rgba(46, 30, 60, 0.55), rgba(26, 18, 34, 0.6));
	box-shadow: 0 0 18px -6px rgba(155, 89, 182, 0.5), inset 0 1px 0 rgba(216, 184, 255, 0.12);
}
body.play-app .qlog-lore-title {
	margin: 0 0 0.4rem;
	font-family: var(--font-wow);
	font-size: 0.95rem;
	color: #d8b8ff;
}
body.play-app .qlog-lore-text {
	margin: 0 0 0.4rem;
	color: var(--text-soft, #d6d1c6);
	font-style: italic;
	line-height: 1.6;
	font-size: 0.92rem;
}
body.play-app .qlog-lore-text:last-child {
	margin-bottom: 0;
}
body.play-app .qlog-lore-text strong {
	color: var(--wow-gold-bright);
	font-style: normal;
}
body.play-app .qlog-lore-field {
	margin: 0.3rem 0 0;
	font-size: 0.85rem;
	color: var(--text, #e9e6df);
}
body.play-app .qlog-lore-field strong {
	color: var(--wow-gold-bright);
}
body.play-app .qlog-story {
	margin: 0 0 0.75rem;
	font-style: italic;
	color: var(--text-soft, #d6d1c6);
	line-height: 1.5;
	font-size: 0.9rem;
}
body.play-app .qlog-section {
	margin: 0.5rem 0 0.75rem;
}
body.play-app .qlog-section-label,
body.play-app .qlog-steps-label,
body.play-app .qlog-rewards-label {
	display: block;
	font-size: 0.72rem;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--wow-gold);
	margin-bottom: 0.3rem;
}
body.play-app .qlog-objectives {
	list-style: none;
	margin: 0;
	padding: 0;
}
body.play-app .qlog-objective {
	display: flex;
	justify-content: space-between;
	gap: 0.5rem;
	padding: 0.3rem 0.5rem;
	border-radius: 6px;
	background: rgba(0, 0, 0, 0.25);
	margin-bottom: 0.3rem;
	font-size: 0.85rem;
}
body.play-app .qlog-objective-val {
	color: var(--wow-gold-bright);
	font-weight: 700;
}
body.play-app .qlog-steps {
	margin: 0.75rem 0;
}
body.play-app .qlog-steps-row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}
body.play-app .qlog-step-btn {
	flex: 0 0 auto;
}
body.play-app .qlog-lock-line {
	margin: 0.5rem 0 0;
	color: #e0a3a3;
	font-size: 0.85rem;
}

/* "To unlock" checklist — finale prerequisites as a WoW todo list. */
body.play-app .qlog-reqs-wrap {
	margin-top: 0.75rem;
}
body.play-app .qlog-reqs {
	list-style: none;
	margin: 0;
	padding: 0;
}
body.play-app .qlog-req {
	display: flex;
	align-items: flex-start;
	gap: 0.55rem;
	padding: 0.4rem 0.5rem;
	margin-bottom: 0.35rem;
	border: 1px solid rgba(201, 162, 77, 0.18);
	border-radius: 7px;
	background: rgba(0, 0, 0, 0.25);
	font-size: 0.86rem;
}
body.play-app .qlog-req-box {
	flex-shrink: 0;
	width: 1.15rem;
	height: 1.15rem;
	margin-top: 0.08rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 1.5px solid rgba(201, 162, 77, 0.5);
	border-radius: 4px;
	background: transparent;
	color: #14130c;
	font-weight: 800;
	font-size: 0.78rem;
	line-height: 1;
}
body.play-app .qlog-req.is-met .qlog-req-box {
	background: var(--wow-gold-bright);
	border-color: var(--wow-gold-bright);
}
body.play-app .qlog-req-text {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	min-width: 0;
}
body.play-app .qlog-req-loc {
	font-size: 0.74rem;
	color: var(--wow-gold);
	opacity: 0.9;
}
body.play-app .qlog-req-label {
	line-height: 1.3;
}
body.play-app .qlog-req.is-met .qlog-req-label {
	color: var(--text-dim, #a9a397);
	text-decoration: line-through;
	text-decoration-color: rgba(201, 162, 77, 0.5);
}
body.play-app .qlog-rewards {
	margin-top: 0.75rem;
	padding-top: 0.6rem;
	border-top: 1px solid rgba(201, 162, 77, 0.2);
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.5rem;
}
body.play-app .qlog-rewards-label {
	margin-bottom: 0;
}
body.play-app .qlog-reward {
	font-size: 0.82rem;
	background: rgba(201, 162, 77, 0.12);
	border: 1px solid rgba(201, 162, 77, 0.25);
	border-radius: 6px;
	padding: 0.15rem 0.45rem;
}
body.play-app .qlog-detail-foot {
	flex-shrink: 0;
	padding: 0.6rem 0.85rem;
	border-top: 1px solid rgba(201, 162, 77, 0.2);
}
body.play-app .qlog-detail-foot .play-action-btn {
	width: 100%;
}

/* Ride-quest screen: give it the same inset as the rest of the detail pane (otherwise the quest
   note, land tabs and ride cards sit flush to the edge). The flex chain is declared on the wrapper
   we own (direct-child selectors) so the ride console always fills + scrolls — instead of relying
   on the `.qlog-detail-body [data-ride-mount]` descendant rule, which silently breaks scrolling if
   the detail nesting ever changes. No bottom padding so the roster reaches the panel edge. */
body.play-app .qlog-ride-inset {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	padding: 0.5rem 0.85rem 0;
}
/* Ride picker reclaims its top space: the big "Start a ride quest" header is redundant with the
   panel title + the in-console "N attractions" header, so slim it right down to a thin strip and
   let the attraction roster take the room. */
body.play-app .qlog-detail--ride .qlog-detail-head {
	padding: 0.4rem 0.85rem 0.4rem;
	align-items: center;
	gap: 0.45rem;
}
body.play-app .qlog-detail--ride .qlog-detail-sigil {
	font-size: 1.15rem;
}
body.play-app .qlog-detail--ride .qlog-detail-title {
	font-size: 0.92rem;
}
body.play-app .qlog-detail--ride .qlog-detail-tag {
	display: none; /* the panel title already names the park */
}
body.play-app .qlog-ride-inset > [data-ride-mount],
body.play-app .qlog-detail-body [data-ride-mount] {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
}
body.play-app .qlog-ride-inset > [data-ride-mount] > .quest-console,
body.play-app .qlog-detail-body [data-ride-mount] .quest-console {
	flex: 1;
	min-height: 0;
}
/* Keep the ride note compact so the attraction roster gets the most scroll room on small phones. */
body.play-app .qlog-ride-inset .qlog-quest-note {
	margin-bottom: 0.55rem;
	padding: 0.45rem 0.6rem;
}
body.play-app .qlog-ride-inset .qlog-quest-note-text {
	font-size: 0.82rem;
	line-height: 1.4;
}

/* ── Narrow: master → detail flip ── */
@media (max-width: 720px) {
	body.play-app .qlog {
		position: relative;
	}
	body.play-app .qlog-rail {
		flex: 1;
	}
	body.play-app .qlog-detail {
		display: none;
	}
	body.play-app .qlog--detail-open .qlog-rail {
		display: none;
	}
	body.play-app .qlog--detail-open .qlog-detail {
		display: flex;
	}
	body.play-app .qlog-back {
		display: inline-block;
	}
}

/* ============================================================================
   32. ACTIVE-STATUS POP-UP — clicking the bottom HUD "now playing" target opens
   this small WoW-framed window over the game to check/manage the active ride,
   dungeon, or raid (Complete / Abandon / Raid HUD). Markup: play-status.js.
   ============================================================================ */
body.play-app .tpq-status-backdrop {
	position: fixed;
	inset: 0;
	z-index: 1100;
	background: radial-gradient(120% 90% at 50% 30%, rgba(8, 9, 14, 0.5), rgba(4, 5, 9, 0.78));
	-webkit-backdrop-filter: blur(2px);
	backdrop-filter: blur(2px);
}
body.play-app .tpq-status-window {
	position: fixed;
	z-index: 1101;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	width: min(440px, calc(100vw - 1.5rem));
	max-height: 80vh;
	overflow: auto;
	padding: 0.9rem 1rem 1.05rem;
	border: 2px solid var(--wow-gold);
	border-radius: 12px;
	background:
		radial-gradient(150% 90% at 50% -10%, rgba(201, 162, 77, 0.1), transparent 55%),
		linear-gradient(180deg, var(--wow-stone-a), var(--wow-stone-b));
	box-shadow:
		inset 0 0 0 1px rgba(0, 0, 0, 0.7),
		inset 0 0 0 4px rgba(201, 162, 77, 0.18),
		0 0 0 1px rgba(0, 0, 0, 0.6),
		0 26px 60px -26px rgba(0, 0, 0, 0.92),
		0 0 36px -14px rgba(201, 162, 77, 0.35);
}
body.play-app .tpq-status-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
	border-bottom: 1px solid rgba(201, 162, 77, 0.4);
	padding-bottom: 0.5rem;
	margin-bottom: 0.7rem;
}
body.play-app .tpq-status-title {
	margin: 0;
	font-family: var(--font-wow);
	font-weight: 700;
	font-size: 1.05rem;
	letter-spacing: 0.02em;
	color: var(--wow-gold-bright);
	text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7), 0 0 12px rgba(201, 162, 77, 0.35);
}
body.play-app .tpq-status-close {
	flex: 0 0 auto;
	width: 2rem;
	height: 2rem;
	border-radius: 50%;
	border: 1px solid rgba(201, 162, 77, 0.5);
	background: rgba(0, 0, 0, 0.3);
	color: var(--wow-gold-bright);
	font-size: 1.2rem;
	line-height: 1;
	cursor: pointer;
}
body.play-app .tpq-status-close:hover {
	background: rgba(163, 32, 29, 0.4);
	border-color: #c9433d;
	color: #fff;
}
/* The hosted active-queue card sheds its own card chrome inside the framed window. */
body.play-app .tpq-status-body .play-queue-card,
body.play-app .tpq-status-body .play-card {
	background: transparent;
	border: none;
	box-shadow: none;
	padding: 0;
	margin: 0;
}
@media (max-width: 480px) {
	body.play-app .tpq-status-window {
		top: auto;
		bottom: calc(var(--tpq-bar-h, 0px) + 0.5rem);
		transform: translate(-50%, 0);
		max-height: 72vh;
	}
}

/* ──────────────────────────────────────────────────────────────────────────
   NAME COSMETICS (Novelty shop items)
   - .friend-flair / .char-flair: emoji worn beside the name. Every flair you OWN
     shows at once, side by side (no equip step) — collect them all.
   - .name-glow--aurora: the legendary goldsink — an animated rainbow aurora glow
     applied to the name itself, everywhere it renders.
   ────────────────────────────────────────────────────────────────────────── */
.friend-flair,
.char-flair {
	display: inline-block;
	font-size: 0.95em;
	line-height: 1;
	filter: drop-shadow(0 0 4px rgba(255, 215, 120, 0.55));
}
.friend-flair + .friend-flair,
.char-flair + .char-flair {
	margin-left: 0.1em;
}
.char-flair {
	font-size: 1.05em;
}

/* Living aurora glow — the ultimate flex. Animated gradient text + soft halo. */
@keyframes tpq-aurora-glow {
	0% { background-position: 0% 50%; filter: drop-shadow(0 0 6px rgba(120, 200, 255, 0.7)); }
	50% { background-position: 100% 50%; filter: drop-shadow(0 0 12px rgba(220, 140, 255, 0.85)); }
	100% { background-position: 0% 50%; filter: drop-shadow(0 0 6px rgba(120, 255, 200, 0.7)); }
}
/* Apply ONLY to the name text (a dedicated inline-block span) — never the parent
   that also holds flair emojis, or background-clip:text would clip them away. */
.name-glow--aurora {
	display: inline-block;
	background-image: linear-gradient(90deg, #7be0ff, #c08bff, #ffd76a, #7bffb0, #7be0ff);
	background-size: 300% 100%;
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: transparent;
	font-weight: 800;
	animation: tpq-aurora-glow 4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
	.name-glow--aurora { animation: none; }
}

/* Sink-ladder glow tiers (economy-loot-rewards.md §1.3 rung 8) — ember < tidal < gilded
   < aurora (1M) < solstice (2M). Same name-text-only application rule as aurora. */
.name-glow--ember {
	display: inline-block;
	background-image: linear-gradient(90deg, #ff9d5c, #ff5e3a, #ffc16b, #ff9d5c);
	background-size: 300% 100%;
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: transparent;
	font-weight: 800;
	animation: tpq-aurora-glow 5s ease-in-out infinite;
}
.name-glow--tidal {
	display: inline-block;
	background-image: linear-gradient(90deg, #5cd6ff, #3a7bff, #6bf0e0, #5cd6ff);
	background-size: 300% 100%;
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: transparent;
	font-weight: 800;
	animation: tpq-aurora-glow 6s ease-in-out infinite;
}
.name-glow--gilded {
	display: inline-block;
	background-image: linear-gradient(90deg, #ffe07a, #d99e06, #fff3c4, #ffe07a);
	background-size: 300% 100%;
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: transparent;
	font-weight: 800;
	animation: tpq-aurora-glow 4.5s ease-in-out infinite;
}
.name-glow--solstice {
	display: inline-block;
	background-image: linear-gradient(90deg, #fff3c4, #ffb347, #ff6b6b, #ffd76a, #fff3c4);
	background-size: 300% 100%;
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: transparent;
	font-weight: 900;
	animation: tpq-aurora-glow 3s ease-in-out infinite;
	filter: drop-shadow(0 0 10px rgba(255, 180, 80, 0.6));
}
@media (prefers-reduced-motion: reduce) {
	.name-glow--ember,
	.name-glow--tidal,
	.name-glow--gilded,
	.name-glow--solstice {
		animation: none;
	}
}


/* ============================================================================
   Campaign UI — step timeline, offer rewards, complete banner, ride-pane cap
   (campaign-visual-modernization.md — remaining)
   ============================================================================ */
body.play-app .qlog-step-chain { display: flex; align-items: center; margin: 0 0 0.6rem; padding: 0.15rem 0.2rem; }
body.play-app .qlog-step-node { position: relative; flex: 1 1 0; display: flex; align-items: center; justify-content: center; min-width: 0; }
body.play-app .qlog-step-node::before { content: ""; position: absolute; left: -50%; right: 50%; top: 50%; height: 3px; transform: translateY(-50%); background: rgba(201, 162, 77, 0.25); z-index: 0; }
body.play-app .qlog-step-node:first-child::before { display: none; }
body.play-app .qlog-step-node.is-done::before, body.play-app .qlog-step-node.is-current::before { background: linear-gradient(90deg, var(--wow-gold), var(--wow-gold-bright)); }
body.play-app .qlog-step-dot { position: relative; z-index: 1; width: 1.6rem; height: 1.6rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.78rem; font-weight: 800; font-family: var(--font-numeric, inherit); border: 1.5px solid rgba(201, 162, 77, 0.4); background: rgba(10, 8, 6, 0.85); color: var(--text-dim, #a9a397); }
body.play-app .qlog-step-node.is-done .qlog-step-dot { border-color: #5fd99a; background: linear-gradient(180deg, #6fe0a6, #43c483); color: #0e1a12; box-shadow: 0 0 8px rgba(95, 217, 154, 0.4); }
body.play-app .qlog-step-node.is-current .qlog-step-dot { border-color: #ffe07a; background: radial-gradient(circle at 40% 30%, rgba(255, 224, 130, 0.4), rgba(40, 28, 8, 0.9)); color: #ffe9b0; box-shadow: 0 0 0 3px rgba(255, 224, 130, 0.18), 0 0 12px -1px rgba(255, 224, 130, 0.7); }

body.play-app .qlog-offer-rewards { margin: 0 0 0.7rem; }
body.play-app .qlog-offer-rewards .qlog-q-rewards { margin-top: 0.35rem; }

body.play-app .qlog-complete-banner { display: flex; align-items: center; gap: 0.5rem; justify-content: center; margin: 0 0 0.7rem; padding: 0.5rem 0.8rem; border-radius: 12px; border: 1px solid rgba(255, 224, 130, 0.5); background: linear-gradient(180deg, rgba(70, 52, 16, 0.6), rgba(34, 25, 8, 0.65)); box-shadow: 0 0 22px -6px rgba(255, 224, 130, 0.6); }
body.play-app .qlog-complete-crown { font-size: 1.5rem; filter: drop-shadow(0 0 8px rgba(255, 224, 130, 0.7)); }
body.play-app .qlog-complete-title { font-family: var(--font-wow); font-size: 1.1rem; font-weight: 800; letter-spacing: 0.04em; color: #ffe9b0; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6); }

/* Keep the ride-picker roster from sprawling in the wide console. */
body.play-app .qlog-detail--ride .qlog-ride-inset { max-width: 40rem; margin-inline: auto; }
