@font-face { font-family: "Inter"; src: url("/fonts/Inter-Regular.ttf") format("truetype"); font-weight: 400; }
@font-face { font-family: "Inter"; src: url("/fonts/Inter-Medium.ttf") format("truetype"); font-weight: 500; }
@font-face { font-family: "Inter"; src: url("/fonts/Inter-SemiBold.ttf") format("truetype"); font-weight: 600; }
@font-face { font-family: "Material Symbols Rounded"; src: url("/fonts/MaterialSymbolsRounded.ttf") format("truetype"); }

:root {
	--bg: #090b14;
	--bg-elevated: #0d1020;
	--card: #10132350;
	--card-solid: #11142380;
	--border: #202540;
	--border-soft: #1a1e33;
	--accent: #6d6cf0;
	--accent-hover: #7f7ef5;
	--accent-soft: #6d6cf026;
	--text: #e7e8f0;
	--text-dim: #9296ab;
	--text-faint: #6b6f85;
	--green: #4ade80;
	--radius: 14px;
	--radius-sm: 10px;
}

* { box-sizing: border-box; }

html, body {
	margin: 0;
	padding: 0;
	background: var(--bg);
	color: var(--text);
	font-family: "Inter", -apple-system, "Segoe UI", sans-serif;
	font-size: 14px;
	/* .full-bleed sections (landing page hero) span exactly 100vw via negative
	   margins -- on a page that's otherwise tall enough to have its own
	   vertical scrollbar, 100vw measures WIDER than the visible viewport by
	   the scrollbar's own width, which overflows a few pixels horizontally
	   and shows a second, horizontal scrollbar. Harmless to hide site-wide. */
	overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent-hover); }

.icon {
	font-family: "Material Symbols Rounded";
	font-weight: normal;
	font-style: normal;
	line-height: 1;
	letter-spacing: normal;
	text-transform: none;
	display: inline-block;
	white-space: nowrap;
	word-wrap: normal;
	direction: ltr;
	font-feature-settings: "liga";
	-webkit-font-feature-settings: "liga";
	-webkit-font-smoothing: antialiased;
	font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 24;
	vertical-align: middle;
}
.icon.filled { font-variation-settings: "FILL" 1, "wght" 400, "GRAD" 0, "opsz" 24; }

.page { max-width: 1240px; margin: 0 auto; padding: 0 24px 60px; animation: page-fade-in 0.3s ease; }
@keyframes page-fade-in {
	from { opacity: 0; transform: translateY(8px); }
	to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
	.page { animation: none; }
}

/* ---- top nav ---------------------------------------------------------- */
.nav {
	background: var(--bg-elevated);
	border-bottom: 1px solid var(--border-soft);
	position: sticky;
	top: 0;
	z-index: 20;
}
.nav-inner {
	max-width: 1240px;
	margin: 0 auto;
	padding: 0 24px;
	height: 72px;
	display: flex;
	align-items: center;
	gap: 28px;
}
.logo { display: flex; align-items: center; gap: 12px; color: var(--text); }
.logo .logo-icon { color: var(--accent); flex-shrink: 0; }
.logo-text { display: flex; flex-direction: column; justify-content: center; }
.logo-title { font-weight: 800; font-size: 21px; letter-spacing: 0.4px; line-height: 1; }
.logo-tagline { font-size: 10.5px; font-weight: 500; letter-spacing: 0.2px; color: var(--text-faint); margin-top: 3px; white-space: nowrap; }
.nav-links { display: flex; align-items: center; gap: 24px; flex: 1; }
.nav-link { display: flex; align-items: center; gap: 6px; color: var(--text-dim); font-size: 14px; font-weight: 500; padding: 8px 2px; border-bottom: 2px solid transparent; transition: color 0.15s ease, border-color 0.15s ease; }
.nav-link .icon { font-size: 19px; }
.nav-link:hover { color: var(--text); }
.nav-link.active { color: var(--text); border-bottom-color: var(--accent); }
.nav-search {
	display: flex; align-items: center; gap: 8px; background: var(--bg);
	border: 1px solid var(--border); border-radius: 10px; padding: 7px 12px; width: 220px;
}
.nav-search input { background: none; border: none; outline: none; color: var(--text); font-size: 13px; width: 100%; font-family: inherit; }
.nav-search .icon { color: var(--text-faint); font-size: 18px; }
.nav-right { display: flex; align-items: center; gap: 16px; }
.nav-bell { color: var(--text-dim); font-size: 22px; position: relative; cursor: pointer; }
.nav-bell .dot { position: absolute; top: -2px; right: -2px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.nav-user {
	display: flex; align-items: center; gap: 8px; background: none; border: none; cursor: pointer;
	font-family: inherit; padding: 4px 6px; border-radius: 8px; color: inherit;
}
.nav-user:hover { background: var(--bg); }
.nav-user .name { font-size: 13px; font-weight: 500; }

.profile-menu-wrap { position: relative; }
.profile-menu {
	display: none; position: absolute; top: calc(100% + 10px); right: 0; width: 260px;
	background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius);
	box-shadow: 0 12px 32px rgba(0,0,0,0.45); z-index: 30; overflow: hidden;
}
.profile-menu.open { display: block; }
.profile-menu-header { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--border-soft); }
.profile-menu-badges { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.profile-menu-item {
	display: flex; align-items: center; gap: 10px; padding: 11px 16px; font-size: 13px; color: var(--text);
}
.profile-menu-item:hover { background: var(--bg); }
.profile-menu-item .icon { font-size: 18px; color: var(--text-dim); }
/* ---- status colors (view_helpers.ts's userBadges/userNameClass) -----------
   Member=gray, Premium=pink, HourBoost=green, Support=dark red,
   Admin=light red, Media=white, Reseller=white -- exact colors requested. */
:root {
	--status-member: #9296ab;
	--status-premium: #ec4899;
	--status-hourboost: #22c55e;
	--status-support: #7f1d2d;
	--status-designer: #8b5cf6;
	--status-admin: #f0556c;
	--status-media: #ffffff;
	--status-reseller: #ffffff;
}

/* Diagonal gradient + glossy top highlight + clipped corners -- a step up
   from a flat color pill (too plain) without going as far as the fully
   illustrated emblem badges in the reference (no per-status artwork to
   maintain) -- the "something in between" the user asked for. The clipped
   top-left/bottom-right corners are the nod to the angular "wing" reference;
   the inset highlight is what gives it the slight glossy/metallic feel. */
.status-pill {
	position: relative; display: inline-flex; align-items: center; gap: 5px;
	font-size: 12px; font-weight: 700; padding: 6px 14px; white-space: nowrap;
	clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
	box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -8px 10px -6px rgba(0,0,0,0.35);
	text-shadow: 0 1px 2px rgba(0,0,0,0.35);
}
.status-pill-icon { font-size: 1.15em; }

.status-pill.member {
	background: transparent; color: var(--status-member); border: 1px solid var(--border);
	box-shadow: none; text-shadow: none; font-weight: 600;
}
.status-pill.premium   { background: linear-gradient(135deg, #ff9ed4, var(--status-premium) 55%, #c2277e); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -8px 10px -6px rgba(0,0,0,0.35), 0 3px 10px -2px #ec489966; }
.status-pill.hourboost { background: linear-gradient(135deg, #86f0ae, var(--status-hourboost) 55%, #16893f); color: #06240f; box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -8px 10px -6px rgba(0,0,0,0.35), 0 3px 10px -2px #22c55e66; }
.status-pill.support   { background: linear-gradient(135deg, #b84a5e, var(--status-support) 55%, #4e1420); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -8px 10px -6px rgba(0,0,0,0.35), 0 3px 10px -2px #7f1d2d66; }
.status-pill.designer  { background: linear-gradient(135deg, #c4b5fd, var(--status-designer) 55%, #5b21b6); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -8px 10px -6px rgba(0,0,0,0.35), 0 3px 10px -2px #8b5cf666; }
.status-pill.admin     { background: linear-gradient(135deg, #ff9b7a, var(--status-admin) 55%, #c22f45); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 -8px 10px -6px rgba(0,0,0,0.35), 0 3px 10px -2px #f0556c66; }
.status-pill.media     { background: linear-gradient(135deg, #ffffff, #d7dbe8 55%, #9ca3bf); color: #1a1e33; box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -8px 10px -6px rgba(0,0,0,0.2), 0 3px 10px -2px #ffffff40; }
.status-pill.reseller  { background: linear-gradient(135deg, #ffffff, #bcd7f2 55%, #5ec8ff); color: #0d2436; box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -8px 10px -6px rgba(0,0,0,0.2), 0 3px 10px -2px #5ec8ff55; }

/* A nickname colored by its single highest-priority status, no pill --
   used in the nav, post authors, shoutbox, sidebar lists. Flat color, no
   animation -- an animated gradient sheen + sparkles were tried and
   explicitly removed again (looked "off"/crooked at small inline sizes,
   e.g. wall posts) in favor of this simpler, calmer look. */
.name-member    { color: var(--status-member); }
.name-premium   { color: var(--status-premium); }
.name-hourboost { color: var(--status-hourboost); }
.name-support   { color: var(--status-support); }
.name-designer  { color: var(--status-designer); }
.name-admin     { color: var(--status-admin); }
.name-media     { color: var(--status-media); }
.name-reseller  { color: var(--status-reseller); }
.btn-ghost {
	background: transparent; color: var(--text); border: 1px solid var(--border);
	padding: 6px 14px; border-radius: 8px; font-size: 13px; font-weight: 500; cursor: pointer; font-family: inherit;
	white-space: nowrap;
}

/* ---- avatars ----------------------------------------------------------- */
.avatar {
	/* inline-flex, not flex -- flex makes this a block-level box, which
	   text-align:center on an ancestor has NO effect on (that only centers
	   inline-level content). Caused the avatar to sit flush left wherever
	   it was meant to be centered via text-align (e.g. .post-author) while
	   still letting the fallback initial letter center itself internally. */
	border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
	color: #fff; font-weight: 600; flex-shrink: 0;
}
.avatar-28 { width: 28px; height: 28px; font-size: 12px; }
.avatar-32 { width: 32px; height: 32px; font-size: 13px; }
.avatar-40 { width: 40px; height: 40px; font-size: 15px; }
.avatar-72 { width: 72px; height: 72px; font-size: 24px; }
.avatar-110 { width: 110px; height: 110px; font-size: 34px; }

/* ---- generic card -------------------------------------------------------*/
.card {
	background: var(--card-solid);
	border: 1px solid var(--border-soft);
	border-radius: var(--radius);
}
.card-header {
	display: flex; align-items: center; justify-content: space-between;
	padding: 16px 20px; border-bottom: 1px solid var(--border-soft);
}
.card-header .title { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 15px; }
.card-header .title .icon { color: var(--accent); font-size: 20px; }
.view-all { font-size: 12.5px; color: var(--text-dim); display: flex; align-items: center; gap: 4px; }

/* ---- page header --------------------------------------------------------*/
.page-header { display: flex; align-items: flex-end; justify-content: space-between; margin: 28px 0 20px; }
.page-header h1 { margin: 0 0 4px; font-size: 26px; }
.page-header p { margin: 0; color: var(--text-dim); font-size: 14px; }
.btn {
	display: inline-flex; align-items: center; gap: 6px; font-family: inherit;
	font-size: 13.5px; font-weight: 600; padding: 9px 16px; border-radius: 9px;
	border: 1px solid var(--border); background: var(--bg-elevated); color: var(--text); cursor: pointer;
}
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover { background: var(--accent-hover); color: #fff; }
.btn:hover { border-color: var(--accent); }
.btn:disabled, .btn.primary:disabled {
	background: var(--bg-elevated); border-color: var(--border); color: var(--text-faint);
	cursor: not-allowed;
}
.btn:disabled:hover, .btn.primary:disabled:hover { background: var(--bg-elevated); border-color: var(--border); }

/* ---- layout grid ---------------------------------------------------------*/
/* Only used on the home page. Each column is ONE grid cell (a flex-column
   stack of its cards), so the FIRST card in each column lines up at the
   same Y for free -- that's the pairing that's actually visible at a
   glance (Shoutbox next to Latest posts). An earlier version gave every
   card below that its own explicit grid-row so row 2 also lined up
   (Forum Categories / Latest profile posts) -- technically exact, but
   whichever side was shorter then had empty space forced into it to reach
   the row's height, which read as an even worse "unevenness" than the
   thing it fixed. Letting everything after the first card flow freely is
   the better trade-off: one guaranteed alignment, zero dead gaps. */
.layout { display: grid; grid-template-columns: 1fr 340px; gap: 20px; align-items: start; }
.cell-left  { grid-column: 1; grid-row: 1; }
.cell-right { grid-column: 2; grid-row: 1; }
.cell-stack { display: flex; flex-direction: column; gap: 20px; }

/* ---- shoutbox ------------------------------------------------------------*/
.shout-online { display: flex; align-items: center; gap: 6px; color: var(--text-dim); font-size: 12.5px; }
.shout-online .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); }
.shout-body {
	max-height: 260px; overflow-y: auto; padding: 14px 20px; display: flex; flex-direction: column; gap: 14px;
	scrollbar-width: thin; scrollbar-color: var(--border) transparent; /* Firefox */
}
.shout-body::-webkit-scrollbar { width: 8px; }
.shout-body::-webkit-scrollbar-track { background: transparent; }
.shout-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
.shout-body::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
.shout-msg { display: flex; gap: 10px; align-items: flex-start; }
.shout-msg .shout-msg-body { flex: 1; min-width: 0; }
.shout-msg .meta { display: flex; align-items: baseline; gap: 8px; margin-bottom: 2px; }
.shout-msg .author { font-weight: 600; font-size: 13px; }
.shout-msg .time { font-size: 11.5px; color: var(--text-faint); }
.shout-msg .text { font-size: 13.5px; color: var(--text); line-height: 1.4; }
.shout-mod-actions { display: flex; gap: 4px; flex-shrink: 0; opacity: 0; transition: opacity 0.12s; }
.shout-msg:hover .shout-mod-actions { opacity: 1; }
.shout-delete, .shout-mute { background: none; border: none; color: var(--text-faint); cursor: pointer; padding: 2px; }
.shout-delete:hover { color: #f0556c; }
.shout-mute:hover { color: var(--accent); }
.shout-form input:disabled { opacity: 0.6; cursor: not-allowed; }

#mute-dialog {
	background: var(--card-solid); border: 1px solid var(--border); border-radius: var(--radius);
	padding: 20px; color: var(--text); width: 320px; max-width: 90vw;
}
#mute-dialog::backdrop { background: rgba(0,0,0,0.5); }
#mute-dialog h3 { margin: 0 0 14px; font-size: 15px; }
#mute-form { display: flex; flex-direction: column; gap: 10px; }
#mute-form label { font-size: 12px; color: var(--text-dim); margin-bottom: -4px; }
#mute-form select, #mute-form input {
	background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
	padding: 8px 10px; color: var(--text); font-family: inherit; font-size: 13px; outline: none;
}
.mute-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
/* Matches the shoutbox card's total height (.shout-body's 260px + the
   .shout-form row below it, ~66px) so "Latest posts" and "Community
   Shoutbox" bottom out at the same y -- keeps Forum Categories and Latest
   profile posts, the next row down in each column, starting flush too. */
.latest-posts-body {
	max-height: 326px; overflow-y: auto;
	scrollbar-width: thin; scrollbar-color: var(--border) transparent;
}
.latest-posts-body::-webkit-scrollbar { width: 8px; }
.latest-posts-body::-webkit-scrollbar-track { background: transparent; }
.latest-posts-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
.latest-posts-body::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

.shout-form { display: flex; gap: 10px; padding: 14px 20px; border-top: 1px solid var(--border-soft); }
.shout-form input {
	flex: 1; background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
	padding: 10px 14px; color: var(--text); font-family: inherit; font-size: 13.5px; outline: none;
}
.shout-form input:focus { border-color: var(--accent); }

/* ---- sticker/emoji picker (shoutbox) ---------------------------------*/
.sticker-picker-wrap { position: relative; }
.sticker-picker {
	display: none; position: absolute; bottom: calc(100% + 8px); right: 0; width: 260px;
	background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius);
	box-shadow: 0 12px 32px rgba(0,0,0,0.45); padding: 10px; z-index: 30;
	grid-template-columns: repeat(5, 1fr); gap: 4px;
}
.sticker-picker.open { display: grid; }
.sticker-option {
	display: flex; align-items: center; justify-content: center; width: 44px; height: 44px;
	border-radius: 8px; border: none; background: transparent; cursor: pointer;
}
.sticker-option:hover { background: var(--bg); }
.sticker-option img { width: 28px; height: 28px; }
.icon-btn {
	width: 38px; height: 38px; border-radius: 10px; border: 1px solid var(--border); background: var(--bg);
	color: var(--text-dim); display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.icon-btn.send { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ---- category table -------------------------------------------------------*/
.cat-row {
	/* Each row is its OWN grid (not one shared grid across the whole card),
	   so a flexible last column (used to be minmax(140px, auto)) resolves
	   to a DIFFERENT width per row depending on that row's own content --
	   the row with a real last post (avatar + text) needs much more space
	   there than a bare "No posts yet" row, which visibly shifted every
	   other column (Threads/Messages/name) out of alignment between rows.
	   A fixed width keeps every row's grid identical regardless of content. */
	display: grid; grid-template-columns: auto 1fr 90px 90px 220px; gap: 16px; align-items: center;
	padding: 18px 20px; border-bottom: 1px solid var(--border-soft);
	/* Without this, a row with a real last post (avatar + two text lines)
	   is visibly taller than a "No posts yet" row (one line) right above
	   or below it -- every row now reserves that same height whether or
	   not it actually needs it, so the list reads as one even table
	   instead of a jagged one where only some rows are "full size". */
	min-height: 82px;
}
.cat-row:last-child { border-bottom: none; }
.cat-row .icon-wrap {
	width: 42px; height: 42px; background: none; color: var(--text-dim);
	display: flex; align-items: center; justify-content: center;
}
.cat-row .icon-wrap .icon { font-size: 24px; }
.cat-row .cat-name { font-weight: 600; font-size: 15px; }
/* .stat is shared with .topic-row (category.ejs's reply-count column) --
   was .cat-row-scoped only, so topic-row's own "0 Replies" rendered
   completely unstyled (left-aligned, no label styling) until this moved
   out to a base rule both rows can use. */
.stat { text-align: center; }
.stat .n { font-weight: 600; font-size: 15px; }
.stat .label { color: var(--text-faint); font-size: 12px; margin-bottom: 2px; }
.cat-row .last-post { display: flex; align-items: center; justify-content: flex-start; gap: 10px; text-align: left; }
.cat-row .last-post .lp-title { font-size: 13.5px; color: var(--text); font-weight: 600; max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cat-row .last-post .lp-title a { display: block; overflow: hidden; text-overflow: ellipsis; }
.cat-row .last-post .lp-meta { font-size: 12px; color: var(--text-faint); }

/* ---- sidebar lists ---------------------------------------------------------*/
.list-item { display: flex; align-items: center; gap: 10px; padding: 12px 20px; border-bottom: 1px solid var(--border-soft); }
.list-item:last-child { border-bottom: none; }
.list-item .lt { font-size: 13px; font-weight: 500; color: var(--text); margin-bottom: 2px; display: block; }
.list-item .lm { font-size: 11.5px; color: var(--text-faint); }
.list-item .lm a { color: var(--text-dim); }

/* Profile wall / "Latest profile posts" -- unlike .lt/.lm above (title +
   dim meta line, correct for category/topic previews), here the SECOND
   line is the actual message body, not meta -- so it's the one that should
   read as normal (white, larger) text, with the date/time dim instead. */
.wall-post-meta { font-size: 13px; font-weight: 500; color: var(--text); margin-bottom: 4px; display: block; }
.wall-post-meta a { font-size: 15px; font-weight: 700; }
.wall-post-time { font-size: 12px; color: var(--text-faint); font-weight: 400; }
.wall-post-body { font-size: 14.5px; color: var(--text); line-height: 1.5; }

/* ---- stats ---------------------------------------------------------*/
.stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; padding: 18px 20px; }
.stats-grid .stat-n { font-size: 20px; font-weight: 700; }
.stats-grid .stat-l { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; }

/* ---- members online --------------------------------------------------*/
/* Reuses .list-item (same row style as "Latest posts"/"Latest profile
   posts" above it) instead of the old flex-wrap chip list -- consistent
   with the rest of the sidebar instead of a bespoke, unfinished-looking
   layout, and each row is now a real link straight to that member's profile. */
.online-row:hover { background: var(--bg); }
.online-total { padding: 10px 20px; font-size: 11.5px; color: var(--text-faint); border-top: 1px solid var(--border-soft); }

/* ---- community member directory (homepage, under Forum Categories) -----*/
.member-directory { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; padding: 10px; }
.member-card {
	display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 10px;
	color: inherit; text-decoration: none;
}
.member-card:hover { background: var(--bg); }
.member-card-text { min-width: 0; }
.member-card-name { font-size: 13.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.member-card-role { display: flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--text-faint); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.member-card-role .icon { color: var(--text-faint); }
@media (max-width: 900px) {
	.member-directory { grid-template-columns: repeat(2, 1fr); }
}

/* ---- topics / posts ------------------------------------------------------*/
.topic-row { display: grid; grid-template-columns: 1fr 90px 160px auto; gap: 16px; align-items: center; padding: 16px 20px; border-bottom: 1px solid var(--border-soft); }
.topic-row:last-child { border-bottom: none; }
.topic-row .t-title { font-weight: 600; font-size: 14px; }
.topic-row .t-meta { font-size: 12px; color: var(--text-faint); margin-top: 3px; }
.topic-row .t-last-reply { font-size: 12px; color: var(--text-faint); line-height: 1.5; text-align: right; }
.mod-actions { display: flex; gap: 6px; }
.mod-actions form { margin: 0; }
.mod-actions .icon-btn { width: 32px; height: 32px; }
.pin { color: var(--accent); font-size: 16px; margin-right: 4px; }

.post {
	display: grid; grid-template-columns: 140px 1fr; gap: 20px; padding: 20px; border-bottom: 1px solid var(--border-soft);
}
.post:last-child { border-bottom: none; }
.post-author { display: flex; flex-direction: column; align-items: center; text-align: center; }
.post-author .name { font-weight: 600; font-size: 13.5px; margin-top: 8px; }
.post-author-badges { display: flex; flex-direction: column; align-items: center; gap: 4px; margin-top: 6px; }
.post-body { font-size: 14px; line-height: 1.6; }
.post-body p { margin: 0 0 10px; }
.post-body p:last-child { margin-bottom: 0; }
.post-body code { background: var(--bg); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; font-size: 0.9em; font-family: "Consolas", "Monaco", monospace; }
.post-body pre { background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; overflow-x: auto; margin: 10px 0; white-space: pre-wrap; }
.post-body pre code { background: none; border: none; padding: 0; white-space: pre-wrap; }
.post-body strong { font-weight: 700; }
.post-body em { font-style: italic; }
.post-body u { text-decoration: underline; }
.post-body s { text-decoration: line-through; }
.post-body h1, .post-body h2, .post-body h3 { margin: 14px 0 8px; line-height: 1.3; }
.post-body h1 { font-size: 1.5em; }
.post-body h2 { font-size: 1.3em; }
.post-body h3 { font-size: 1.1em; }
.post-body ul, .post-body ol { margin: 8px 0; padding-left: 24px; }
.post-body li { margin: 2px 0; }
.post-body blockquote {
	margin: 10px 0; padding: 4px 14px; border-left: 3px solid var(--accent);
	color: var(--text-dim); font-style: italic;
}
.post-body a { color: var(--accent); word-break: break-word; }
.post-body a:hover { text-decoration: underline; }
.post-body img { max-width: 100%; border-radius: 8px; margin: 6px 0; }
/* Quill's alignment format is class-based (ql-align-*), not inline style --
   kept as-is through sanitize-html (src/sanitize.ts allows "class" on <p>). */
.post-body .ql-align-center { text-align: center; }
.post-body .ql-align-right { text-align: right; }
.post-body .ql-align-justify { text-align: justify; }
.post-time { font-size: 11.5px; color: var(--text-faint); }
.post-time-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }

.post-attachments { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.post-attachment {
	display: inline-flex; align-items: center; gap: 6px; width: fit-content;
	background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
	padding: 6px 12px; font-size: 12.5px; color: var(--text); text-decoration: none;
}
.post-attachment:hover { border-color: var(--accent); }
.post-attachment .icon { font-size: 15px; }
.post-attachment-size { color: var(--text-faint); }
.post-attachment-image { display: block; width: fit-content; margin-top: 8px; }
.post-attachment-image img { max-width: 320px; max-height: 320px; border-radius: 10px; border: 1px solid var(--border); display: block; }
.ticket-attach-btn { cursor: pointer; font-size: 12.5px; padding: 6px 12px; }
.ticket-attach-filename { font-size: 12px; color: var(--text-faint); }
.reply-form-footer { display: flex; align-items: center; gap: 10px; }

/* ---- skin editor (visual skin picker, /skins/editor) --------------------*/
.skin-editor-toolbar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 18px 20px; border-bottom: 1px solid var(--border); }
.skin-editor-spacer { flex: 1; }
.skin-side-toggle { display: flex; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.skin-side-btn { background: var(--bg); border: none; color: var(--text-dim); padding: 8px 20px; font-size: 13px; font-weight: 600; cursor: pointer; font-family: inherit; }
.skin-side-btn.active { background: var(--accent); color: #fff; }
.skin-sync-toggle { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-dim); cursor: pointer; }
#skin-config-name {
	box-sizing: border-box; appearance: none; margin: 0; width: 220px; height: 40px; line-height: 38px;
	background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 0 14px;
	color: var(--text); font-family: inherit; font-size: 13.5px; outline: none;
}
#skin-editor-error, #skin-editor-success { margin: 16px 20px 0; }
#skin-breadcrumb { display: flex; align-items: center; gap: 12px; padding: 16px 20px 0; }
#skin-breadcrumb-title { font-weight: 600; font-size: 14.5px; }
.skin-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; padding: 20px; }
.skin-card {
	position: relative; cursor: pointer; border-radius: 10px; background: var(--bg);
	border: 1px solid var(--border); overflow: hidden; transition: border-color 0.12s;
}
.skin-card:hover { border-color: var(--accent); }
.skin-card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.skin-card-bar { position: absolute; top: 0; left: 0; bottom: 38px; width: 3px; }
.skin-card-img { width: 100%; aspect-ratio: 2 / 1; object-fit: contain; background: #0000; display: block; padding: 6px 6px 0; box-sizing: border-box; }
.skin-card-label { padding: 6px 10px 9px; }
.skin-card-title { font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.skin-card-sub { font-size: 11px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.skin-card-clear {
	position: absolute; top: 6px; right: 6px; background: rgba(0,0,0,0.55); border: none; border-radius: 50%;
	width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #fff;
	opacity: 0; transition: opacity 0.12s;
}
.skin-card-clear .icon { font-size: 14px; }
.skin-card:hover .skin-card-clear { opacity: 1; }
.reply-closed { display: flex; align-items: center; gap: 8px; color: var(--text-faint); font-size: 13.5px; justify-content: center; }
.reply-closed .icon { font-size: 16px; }

.post-content { display: flex; flex-direction: column; }
.post-reactions { display: flex; justify-content: flex-end; gap: 6px; margin-top: auto; padding-top: 10px; }
.reaction-btn {
	display: inline-flex; align-items: center; gap: 4px; background: var(--bg);
	border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px;
	font-size: 13px; cursor: pointer; color: var(--text); line-height: 1.4;
}
.reaction-btn:hover { border-color: var(--accent); }
.reaction-btn.active { border-color: var(--accent); background: rgba(var(--accent-rgb, 124, 58, 237), 0.15); }
.reaction-btn:disabled { opacity: 0.45; cursor: default; }
.reaction-count { font-size: 11.5px; color: var(--text-dim); }

.attachment-input {
	display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-dim); cursor: pointer;
}
.attachment-input .icon { font-size: 16px; }
.attachment-input input[type=file] { font-size: 12px; color: var(--text-dim); }
.attachment-input input[type=file]::file-selector-button {
	background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
	color: var(--text-dim); font-family: inherit; font-size: 12px; padding: 5px 10px;
	margin-right: 8px; cursor: pointer;
}
.attachment-input input[type=file]::file-selector-button:hover { border-color: var(--accent); color: var(--text); }
/* Older WebKit/Chromium alias -- ::file-selector-button is the standard
   name, but some engine versions still only recognize this prefixed one. */
.attachment-input input[type=file]::-webkit-file-upload-button {
	background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
	color: var(--text-dim); font-family: inherit; font-size: 12px; padding: 5px 10px;
	margin-right: 8px; cursor: pointer;
}
.attachment-input input[type=file]::-webkit-file-upload-button:hover { border-color: var(--accent); color: var(--text); }

.reply-form, .form-card { padding: 20px; }
.reply-form textarea, .form-card textarea, .form-card input[type=text] {
	width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
	padding: 12px 14px; color: var(--text); font-family: inherit; font-size: 13.5px; outline: none; resize: vertical;
}
.form-card input[type=text] { margin-bottom: 12px; }
.reply-form textarea:focus, .form-card textarea:focus, .form-card input:focus { border-color: var(--accent); }

/* Quill (public/editor.js) -- the "snow" theme ships light-mode colors by
   default, overridden here to match the rest of the site's dark palette
   instead of carrying a second, forum-specific theme CSS file.
   IMPORTANT: Quill does NOT nest the toolbar inside the element you pass to
   `new Quill(container, ...)` -- that element itself just gets turned into
   `.ql-container.ql-snow` in place, and the toolbar is built as a SEPARATE
   element next to it. Every rule below that scoped itself as
   ".rich-editor .ql-toolbar..." (a descendant combinator) silently matched
   nothing at all -- confirmed live 2026-10-14 via getComputedStyle() showing
   Quill's own default #ccc border completely unaffected by those rules
   despite !important. Fixed by dropping the wrong ".rich-editor " ancestor
   assumption everywhere below and targeting Quill's own classes directly. */
/* .rich-editor (the element passed to `new Quill(...)`) BECOMES
   .ql-container.ql-snow in place once Quill runs -- it never ends up
   wrapping the toolbar (that's a separate sibling, inserted right before
   it, see the big comment above). So "one dark frame around the whole
   editor" is actually two adjacently-bordered pieces with matching side
   borders and only their OUTER corners rounded, not a border on a single
   wrapping element. */
.rich-editor { background: var(--bg); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; margin-bottom: 12px; }
.rich-editor.ql-container {
	border: 1px solid var(--border) !important; border-top: none !important; border-radius: 0 0 10px 10px;
}
.ql-toolbar.ql-snow {
	background: var(--card-solid) !important; border: 1px solid var(--border) !important; border-bottom: 1px solid var(--border-soft) !important;
	border-radius: 10px 10px 0 0; padding: 8px 10px;
}
.ql-container.ql-snow { font-family: inherit; font-size: 13.5px; }
.ql-editor {
	color: var(--text); min-height: 140px; padding: 12px 14px; outline: none;
	scrollbar-width: thin; scrollbar-color: var(--border) transparent;
}
.ql-editor::-webkit-scrollbar { width: 8px; }
.ql-editor::-webkit-scrollbar-track { background: transparent; }
.ql-editor::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
.ql-editor::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
.ql-editor.ql-blank::before { color: var(--text-faint) !important; font-style: normal !important; }
.ql-snow .ql-stroke { stroke: var(--text-dim); }
.ql-snow .ql-fill, .ql-snow .ql-stroke.ql-fill { fill: var(--text-dim); }
.ql-snow .ql-picker { color: var(--text-dim); }
.ql-snow .ql-picker-options { background: var(--card-solid) !important; border: 1px solid var(--border) !important; }
.ql-toolbar.ql-snow button:hover .ql-stroke,
.ql-toolbar.ql-snow button.ql-active .ql-stroke { stroke: var(--accent); }
.ql-toolbar.ql-snow button:hover .ql-fill,
.ql-toolbar.ql-snow button.ql-active .ql-fill { fill: var(--accent); }
/* Faint box around each toolbar control (buttons + pickers) -- user asked
   for some visible separation between them, they had none before. */
.ql-toolbar.ql-snow button,
.ql-toolbar.ql-snow .ql-picker-label {
	border: 1px solid var(--border) !important; border-radius: 6px; margin: 1px;
}
.ql-toolbar.ql-snow button.ql-active,
.ql-toolbar.ql-snow .ql-expanded .ql-picker-label { border-color: var(--accent) !important; }
.ql-editor pre.ql-syntax { background: var(--bg-elevated); border-radius: 8px; }
.ql-editor a { color: var(--accent); }

/* Custom 5-step size picker (public/editor.js) -- Quill's own snow.css base
   rule (".ql-snow .ql-picker.ql-size ...::before { content:'Normal' }")
   loads after this file and would otherwise win -- !important is the
   reliable way to override a third-party stylesheet this project doesn't
   control, confirmed live 2026-10-14 (plain specificity bumps weren't
   enough once the exact competing selector was found). */
.ql-snow .ql-picker.ql-size { width: 96px; }
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before { content: "Size: 3" !important; }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="11px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="11px"]::before { content: "Size: 1" !important; }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12.5px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12.5px"]::before { content: "Size: 2" !important; }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="17px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="17px"]::before { content: "Size: 4" !important; }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="21px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="21px"]::before { content: "Size: 5" !important; }

.reply-form { display: flex; flex-direction: column; gap: 12px; }

.auth-wrap { max-width: 400px; margin: 80px auto; }
.auth-wrap h1 { text-align: center; font-size: 22px; margin-bottom: 6px; }
.auth-wrap .sub { text-align: center; color: var(--text-dim); font-size: 13px; margin-bottom: 24px; }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; color: var(--text-dim); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.5px; }
.field input { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 11px 14px; color: var(--text); font-family: inherit; font-size: 14px; outline: none; }
.field input:focus { border-color: var(--accent); }
.field textarea { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 11px 14px; color: var(--text); font-family: inherit; font-size: 14px; outline: none; resize: vertical; }
.field textarea:focus { border-color: var(--accent); }
.field select { width: 100%; height: 42px; background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 0 14px; color: var(--text); font-family: inherit; font-size: 14px; outline: none; cursor: pointer; }
.field select:focus { border-color: var(--accent); }
.auth-error { background: #f0556c1a; border: 1px solid #f0556c40; color: #f0859a; font-size: 13px; padding: 10px 14px; border-radius: 9px; margin-bottom: 16px; }
.redeem-success { background: #4ade801a; border: 1px solid #4ade8040; color: var(--green); font-size: 13px; padding: 10px 14px; border-radius: 9px; margin-bottom: 16px; }
.auth-switch { text-align: center; margin-top: 18px; font-size: 13px; color: var(--text-dim); }
.auth-switch a { color: var(--accent); font-weight: 500; }

.profile-header { display: flex; gap: 20px; align-items: center; padding: 24px; }
.profile-header .info h2 { margin: 0 0 6px; font-size: 20px; }
.profile-badges { display: flex; flex-wrap: wrap; gap: 6px; }

/* ---- profile banner + overlapping avatar -------------------------------*/
.profile-banner {
	position: relative; height: 220px; background-color: var(--bg-elevated); background-size: cover; background-position: center;
	display: flex; align-items: flex-start; justify-content: flex-end; padding: 16px;
}
/* Both the "Edit profile banner" label and the remove button sit in a flex
   row together (see profile.ejs) -- a <button> carries its own
   browser-default padding/line-height a <label> doesn't, which read as
   "crooked" (not vertically aligned) next to the text pill beside it even
   with align-items set on the row. Giving both an identical EXPLICIT
   height/box-sizing, instead of leaning on .btn-ghost's padding to produce
   the same height indirectly, is what actually makes them line up. */
.profile-banner-edit {
	display: inline-flex; align-items: center; justify-content: center; gap: 6px;
	height: 34px; box-sizing: border-box; margin: 0; padding: 0 14px;
	background: rgba(9,11,20,0.65); backdrop-filter: blur(2px); cursor: pointer; font: inherit; line-height: normal;
}
.profile-banner-remove { width: 34px; padding: 0; }
/* The nickname + badges sit ON the banner image itself (not below it) --
   absolutely positioned so .profile-banner's own flex layout (used for the
   "Edit profile banner" button top-right) doesn't also grab it. Left offset
   clears the avatar, which overlaps up from below via .profile-header-row's
   negative margin. filter:drop-shadow (not text-shadow -- that gets clipped
   away on the gradient-sheen status names, which use background-clip:text)
   keeps the name/badges legible over an arbitrary banner photo. */
.profile-identity-text { position: absolute; left: 153px; bottom: -6px; z-index: 2; }
.profile-name-mobile { display: none; margin: 0 0 8px; font-size: 19px; }
/* Crisp dark outline instead of a blurred drop-shadow -- a soft blur on
   small/thin text read as fuzzy/"not lying flat" against a busy banner
   photo. A tight 1px outline in every direction keeps the glyph edges
   sharp no matter what's behind them. */
.profile-identity-text .profile-name {
	text-shadow:
		0 1px 0 rgba(0,0,0,0.9), 0 -1px 0 rgba(0,0,0,0.9),
		1px 0 0 rgba(0,0,0,0.9), -1px 0 0 rgba(0,0,0,0.9),
		0 2px 4px rgba(0,0,0,0.6);
}
.profile-identity-text .profile-name.name-premium,
.profile-identity-text .profile-name.name-hourboost,
.profile-identity-text .profile-name.name-support,
.profile-identity-text .profile-name.name-designer,
.profile-identity-text .profile-name.name-admin,
.profile-identity-text .profile-name.name-media,
.profile-identity-text .profile-name.name-reseller {
	/* These use background-clip:text (see .name-* rules), which drops
	   text-shadow entirely -- filter:drop-shadow still renders for them. */
	text-shadow: none;
	filter: drop-shadow(0 1px 1px rgba(0,0,0,0.9)) drop-shadow(0 2px 4px rgba(0,0,0,0.6));
}
.profile-header-row { display: flex; align-items: flex-end; gap: 20px; padding: 0 24px 20px; margin-top: -55px; position: relative; z-index: 2; }
.profile-avatar-wrap { position: relative; flex-shrink: 0; }
.profile-avatar-wrap .avatar { border: 4px solid var(--bg-elevated); }
.profile-avatar-edit { position: absolute; right: -2px; bottom: -2px; width: 32px; height: 32px; cursor: pointer; }
/* Clicking the avatar itself removes it (confirm-gated) -- an unstyled
   button wrapping the real avatar, with an "x" overlay that only appears
   on hover so it doesn't look clickable-to-delete at a glance. */
.profile-avatar-click { all: unset; cursor: pointer; position: relative; display: inline-flex; border-radius: 50%; }
.profile-avatar-click::after {
	content: "close";
	font-family: "Material Symbols Rounded"; font-feature-settings: "liga"; -webkit-font-feature-settings: "liga";
	position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
	font-size: 30px; color: #fff; background: rgba(9,11,20,0.6); border-radius: 50%;
	opacity: 0; transition: opacity 0.15s;
}
.profile-avatar-click:hover::after { opacity: 1; }
.profile-header-row .info { padding-bottom: 6px; }
.profile-name { margin: 0 0 10px; font-size: 28px; }
.profile-badges-lg .status-pill-lg { font-size: 13px; padding: 7px 16px; }

.profile-meta {
	display: flex; flex-wrap: wrap; gap: 4px 20px; padding: 14px 24px 20px;
	font-size: 12.5px; color: var(--text-dim); border-top: 1px solid var(--border-soft);
}
.profile-meta span { display: flex; align-items: center; gap: 6px; }
.profile-meta .icon { color: var(--text-faint); }

.invite-code { font-family: monospace; background: var(--bg); border: 1px solid var(--border); padding: 8px 12px; border-radius: 8px; display: inline-block; margin: 4px 6px 4px 0; font-size: 13px; }
.invite-used { opacity: 0.4; text-decoration: line-through; }

.empty-state { padding: 40px 20px; text-align: center; color: var(--text-faint); font-size: 13.5px; }

.site-footer { max-width: 1240px; margin: 20px auto 0; padding: 20px 24px 30px; text-align: center; font-size: 12px; color: var(--text-faint); }
.site-footer a { color: var(--text-dim); }
.site-footer-dot { margin: 0 8px; }

.format-hint { font-size: 11.5px; color: var(--text-faint); margin-top: -4px; }

/* ---- pagination ---------------------------------------------------------*/
.pagination { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 20px; }
.pg-btn {
	min-width: 36px; height: 36px; padding: 0 10px; border-radius: 9px; border: 1px solid var(--border);
	background: var(--bg-elevated); color: var(--text-dim); display: flex; align-items: center; justify-content: center;
	font-size: 13px; font-weight: 500;
}
.pg-btn:hover { border-color: var(--accent); color: var(--text); }
.pg-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.pg-btn.disabled { opacity: 0.35; pointer-events: none; }
.pg-ellipsis { color: var(--text-faint); padding: 0 4px; }

@media (max-width: 920px) {
	.layout { grid-template-columns: 1fr; }
	.cell-left, .cell-right { grid-column: 1; grid-row: auto; }
	.nav-search { display: none; }
	.cat-row { grid-template-columns: auto 1fr; }
	.cat-row .stat, .cat-row .last-post { display: none; }
}

/* ---- phone-width nav -------------------------------------------------
   Below this, the nav's five text links + search + user name no longer
   fit in one row and were overflowing the viewport (real horizontal
   scroll on a phone) -- collapse to icon-only links and drop anything
   that's decoration rather than navigation. */
@media (max-width: 680px) {
	.nav-inner { padding: 0 12px; gap: 8px; }
	.logo-tagline { display: none; }
	.nav-links { gap: 10px; }
	.nav-link-label { display: none; }
	.nav-link { padding: 8px 0; }
	.nav-link .icon { font-size: 21px; }
	.notif-menu { width: calc(100vw - 32px); max-width: 320px; }
	.nav-user .name { display: none; }
	.nav-right { gap: 0; }
	.page { padding: 0 14px 40px; }
	.page-header { flex-wrap: wrap; gap: 12px; }
	.sub-grid { grid-template-columns: 1fr; }
	.sub-grid > * { grid-column: 1 !important; grid-row: auto !important; }
	/* The nickname-on-banner trick (position:absolute at a fixed left
	   offset) collided with the badges wrapping under it once the avatar +
	   badges row got this narrow -- fall back to a plain name heading
	   above the badges instead, same as any other profile field. */
	.profile-identity-text { display: none; }
	.profile-name-mobile { display: block; }
	.profile-banner { height: 160px; }
	.profile-header-row { margin-top: -40px; flex-wrap: wrap; }
	.profile-avatar-wrap .avatar { width: 84px !important; height: 84px !important; }
}

/* ---- subscription page -----------------------------------------------*/
/* Grid, not the site's usual .layout (which forces align-items:start) --
   default grid align-items is stretch, so the Subscription and Buy
   Subscription cards (both grid-row:1) are forced to the SAME height
   automatically, whichever has more content. Combined with
   .sub-card-stretch's flex column + footer margin-top:auto below, that
   keeps both cards' bottom buttons level with each other no matter how
   many rows either one has -- requested explicitly after the two buttons
   ended up visibly uneven with a plain two-column layout. */
.sub-grid { display: grid; grid-template-columns: 750px 1fr; gap: 20px; }
.sub-card-stretch { display: flex; flex-direction: column; }
.sub-card-stretch .sub-card-footer { margin-top: auto; }
.sub-card-header { display: flex; align-items: center; gap: 14px; padding: 20px; }
.sub-card-header .icon-wrap {
	width: 44px; height: 44px; border-radius: 12px; background: var(--accent-soft); color: var(--accent);
	display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.sub-card-header .icon-wrap .icon { font-size: 23px; }
.sub-icon-plain { color: var(--accent); font-size: 26px; }
.sub-card-header .st-title { font-weight: 600; font-size: 15.5px; }
.sub-card-header .st-desc { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.sub-row {
	display: flex; align-items: center; justify-content: space-between;
	padding: 14px 20px; border-top: 1px solid var(--border-soft); font-size: 13.5px;
}
.sub-row .k { color: var(--text-dim); }
.sub-row .v { font-weight: 600; }
.sub-row .v.accent { color: var(--accent); }
.sub-row .v.status-dot { display: flex; align-items: center; gap: 7px; color: var(--green); }
.sub-row .v.status-dot .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); }
.sub-row .v.status-dot.offline { color: #f0556c; }
.sub-row .v.status-dot.offline .dot { background: #f0556c; }
.sub-card-footer { padding: 18px 20px; border-top: 1px solid var(--border-soft); }
.sub-card-footer .btn { flex: 1; width: 100%; justify-content: center; padding: 11px; font-size: 14px; }
.sub-support-row {
	display: flex; align-items: center; gap: 14px; padding: 18px 20px;
}
.sub-support-row .icon-wrap { background: var(--accent-soft); color: var(--accent); }

/* ---- buy subscription panel ------------------------------------------*/
.plan-list { display: flex; flex-direction: column; gap: 10px; padding: 16px 20px; }
.plan-option {
	display: flex; align-items: center; gap: 10px; padding: 12px 14px;
	border: 1px solid var(--border); border-radius: 10px; cursor: pointer; font-size: 13.5px;
}
.plan-option:hover { border-color: var(--accent); }
.plan-option:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.plan-option input { accent-color: var(--accent); margin: 0; }
.plan-option .plan-name { flex: 1; font-weight: 500; }
.plan-option .plan-price { font-weight: 700; color: var(--accent); }

/* ---- notifications + private messages (nav badges, dropdown, inbox/thread) ----
   Nav icons are real <a>/<button> elements now, so they reset browser chrome;
   the red-dot-style badge is a count pill, not the old decorative dot. */
.nav-icon-link {
	position: relative; color: var(--text-dim); font-size: 22px; cursor: pointer;
	background: none; border: none; padding: 4px; border-radius: 8px; display: inline-flex; align-items: center;
	transition: color 0.15s ease;
}
.nav-icon-link:hover { color: var(--text); }
.nav-badge {
	position: absolute; top: -4px; right: -6px; min-width: 17px; height: 17px; padding: 0 5px; border-radius: 9px;
	background: var(--accent); color: #fff; font-size: 10.5px; font-weight: 700; line-height: 17px; text-align: center;
	font-family: inherit;
}
.notif-wrap { position: relative; }
.notif-menu-title { font-weight: 600; font-size: 14px; }
.notif-empty { padding: 18px 16px; color: var(--text-faint); font-size: 13px; }
.notif-item {
	display: block; padding: 11px 16px; border-bottom: 1px solid var(--border-soft); color: var(--text); text-decoration: none;
}
.notif-item:hover { background: var(--bg); color: var(--text); }
.notif-item.unread { background: var(--accent-soft); }
.notif-item-text { display: block; font-size: 13px; line-height: 1.4; }
.notif-item-time { display: block; font-size: 11.5px; color: var(--text-faint); margin-top: 3px; }
.notif-all { border-top: 1px solid var(--border-soft); }

.notif-row { color: var(--text); }
.notif-row:hover { color: var(--text); background: var(--bg); }
.notif-row.unread { background: var(--accent-soft); }
.notif-row-icon { color: var(--accent); font-size: 20px; }
.notif-row-text { font-size: 13.5px; }
.notif-row-time { font-size: 11.5px; color: var(--text-faint); margin-top: 3px; }

/* ---- landing page (/home) ----------------------------------------------
   Styled after a reference screenshot the user gave (neverlose.cc): a big
   full-bleed hero with a dark image behind it and one centered CTA, a thin
   colored "product" banner strip below it, then a plain (no card/no icon)
   bold-title + text feature grid on its own gradient band. .full-bleed
   breaks a section out of .page's max-width:1240px/24px-padding container
   so it can span the whole viewport width, same trick used for all three
   bands here. */
.full-bleed { width: 100vw; position: relative; left: 50%; right: 50%; margin-left: -50vw; margin-right: -50vw; }

.hero { min-height: 560px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
/* 72px nav + ~150px for .page's bottom padding and the footer below the
   hero -- leaves just enough room that the whole page fits one viewport
   without its own scrollbar, instead of overflowing by exactly that much. */
.hero-solo { min-height: calc(100vh - 222px); }
.hero-bg {
	position: absolute; inset: 0;
	/* Placeholder background until a real in-game screenshot is dropped in --
	   swap this for background-image: url(...) once one exists, the dark
	   radial glow + vignette below still work fine layered under a photo. */
	background:
		radial-gradient(ellipse 900px 500px at 30% 20%, #6d6cf03d, transparent 60%),
		radial-gradient(ellipse 700px 500px at 80% 70%, #6d6cf024, transparent 60%),
		linear-gradient(180deg, #0b0e1a, #090b14 70%);
}
.hero-bg::after {
	content: ""; position: absolute; inset: 0;
	background: radial-gradient(ellipse 60% 50% at 50% 100%, #090b14cc, transparent);
}
.hero-inner { position: relative; text-align: center; max-width: 640px; padding: 0 24px; }
.hero-fade-in { animation: hero-fade-in 1.1s ease both; }
@keyframes hero-fade-in {
	from { opacity: 0; transform: translateY(14px); }
	to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .hero-fade-in { animation: none; } }
.hero-wordmark { font-size: 56px; font-weight: 700; letter-spacing: 2px; color: var(--text); }
.hero-wordmark .accent { color: var(--accent); }
.hero-sub { margin: 16px 0 32px; color: var(--text-dim); font-size: 15px; line-height: 1.6; }
.hero-actions { display: flex; align-items: center; justify-content: center; gap: 12px; }
.hero-btn { padding: 13px 28px; font-size: 14px; border-radius: var(--radius-sm); }
.hero-scroll-hint { position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%); }
.hero-scroll-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); animation: hero-scroll-bounce 1.6s ease-in-out infinite; }
@keyframes hero-scroll-bounce {
	0%, 100% { opacity: 0.4; transform: translateY(0); }
	50% { opacity: 1; transform: translateY(6px); }
}
@media (prefers-reduced-motion: reduce) { .hero-scroll-dot { animation: none; } }

.product-banner {
	background: linear-gradient(100deg, #6d6cf024, #6d6cf00a 50%, transparent 85%);
	border-bottom: 1px solid var(--border-soft);
}
.product-banner-inner {
	max-width: 1240px; margin: 0 auto; padding: 28px 24px;
	display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
}
.product-banner-title { font-size: 22px; font-weight: 700; }
.product-banner-sub { color: var(--text-dim); font-size: 13.5px; margin-top: 4px; }

.landing-section { margin: 56px 0; }
.landing-section-header { text-align: center; margin-bottom: 28px; }
.landing-section-header .eyebrow { color: var(--accent); font-size: 12px; font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase; }
.landing-section-header h2 { margin: 6px 0 0; font-size: 24px; }

.screenshot-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.screenshot-tile {
	margin: 0; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--border-soft);
	background: var(--bg-elevated); aspect-ratio: 16 / 10;
}
.screenshot-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.screenshot-tile figcaption { padding: 10px 14px; font-size: 12.5px; color: var(--text-dim); }
.screenshot-placeholder {
	display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
	color: var(--text-faint); font-size: 12.5px; border-style: dashed;
}
.screenshot-placeholder .icon { font-size: 30px; }

.feature-band { background: linear-gradient(180deg, #05060c, #0d1428); padding: 64px 0; }
.feature-band-inner {
	max-width: 1100px; margin: 0 auto; padding: 0 24px;
	display: grid; grid-template-columns: repeat(3, 1fr); gap: 36px 48px;
}
.feature-plain-title { font-weight: 700; font-size: 15px; margin-bottom: 6px; }
.feature-plain-desc { color: var(--text-dim); font-size: 13px; line-height: 1.55; }

.landing-cta { text-align: center; margin: 64px 0 40px; }
.landing-cta h2 { margin: 0 0 8px; font-size: 24px; }
.landing-cta p { margin: 0 0 24px; color: var(--text-dim); font-size: 14px; }

@media (max-width: 900px) {
	.hero-wordmark { font-size: 40px; }
	.screenshot-grid { grid-template-columns: 1fr; }
	.feature-band-inner { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
	.product-banner-inner { flex-direction: column; align-items: flex-start; }
}

.msg-row { color: var(--text); }
.msg-row:hover { color: var(--text); background: var(--bg); }
.msg-row.unread { background: var(--accent-soft); }
.msg-row.unread .msg-row-preview { color: var(--text); font-weight: 600; }
.msg-row-top { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.msg-row-top > span:first-child { font-weight: 600; font-size: 14px; }
.msg-row-time { font-size: 11.5px; color: var(--text-faint); white-space: nowrap; }
.msg-row-preview { font-size: 13px; color: var(--text-dim); margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-row-you { color: var(--text-faint); }

.pm-thread { padding: 16px 20px; display: flex; flex-direction: column; gap: 12px; }
.ticket-thread {
	max-height: 480px; overflow-y: auto;
	scrollbar-width: thin; scrollbar-color: var(--border) transparent; /* Firefox */
}
.ticket-thread::-webkit-scrollbar { width: 8px; }
.ticket-thread::-webkit-scrollbar-track { background: transparent; }
.ticket-thread::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
.ticket-thread::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
.pm-msg { display: flex; align-items: flex-end; gap: 10px; max-width: 80%; }
.pm-msg.mine { align-self: flex-end; flex-direction: row-reverse; }
.pm-bubble { background: var(--bg); border: 1px solid var(--border); border-radius: 14px; padding: 9px 13px; min-width: 0; }
.pm-msg.mine .pm-bubble { background: var(--accent-soft); border-color: var(--accent); }
.pm-body { font-size: 14px; white-space: pre-wrap; word-break: break-word; }
.pm-time { font-size: 11px; color: var(--text-faint); margin-top: 4px; }

.pm-report { background: none; border: none; color: var(--text-faint); cursor: pointer; padding: 0 2px; font-family: inherit; }
.pm-report:hover { color: var(--text-dim); }

/* ---- support tickets (routes/support.ts, views/support_tickets.ejs) ---- */
.ticket-status {
	display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 999px;
	font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px; margin-right: 8px;
}
.ticket-status.open      { background: #f0556c1a; color: #f0859a; border: 1px solid #f0556c40; }
.ticket-status.in_review { background: #f6c3431a; color: #f8d57a; border: 1px solid #f6c34340; }
.ticket-status.resolved  { background: #4ade801a; color: var(--green); border: 1px solid #4ade8040; }
.ticket-category { font-size: 11.5px; color: var(--text-faint); }
.ticket-status-form select {
	background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
	color: var(--text); font-family: inherit; font-size: 12.5px; padding: 6px 10px; outline: none; cursor: pointer;
}

/* ---- modal overlay (support contact form, header.ejs) ---- */
.modal-overlay {
	display: none; position: fixed; inset: 0; background: #05060cb3;
	align-items: center; justify-content: center; z-index: 200; padding: 20px;
}
.modal-overlay.open { display: flex; }
.modal-card { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius); width: 100%; max-width: 440px; max-height: 90vh; overflow-y: auto; }
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px; border-bottom: 1px solid var(--border-soft); }
.modal-header .title { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 15px; }
.modal-header .title .icon { color: var(--accent); font-size: 20px; }
.modal-close { background: none; border: none; color: var(--text-dim); cursor: pointer; display: flex; padding: 4px; }
.modal-close:hover { color: var(--text); }
.modal-body { padding: 20px; display: flex; flex-direction: column; gap: 14px; }
.modal-body .field label { display: block; font-size: 12px; color: var(--text-dim); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.5px; }

/* ---- email-confirmation banner (header.ejs) ---- */
.verify-banner { display:flex; align-items:center; justify-content:center; gap:8px; flex-wrap:wrap; padding:10px 16px; background:var(--accent-soft); border-bottom:1px solid var(--border-soft); font-size:13px; color:var(--text); }
.verify-banner .icon { color:var(--accent); font-size:18px; }
.verify-banner a { color:var(--accent); font-weight:600; }

