/* ---------------------------------------------------------------------------
   carldixon — shared stylesheet
   Dark, technical, no build step. Every page on the site pulls this in.

   Brace style: the opening brace goes on its own line, except for rules short
   enough to sit on one line entirely.

   Sections:
     tokens · base · site header · hero · section headings · cards · buttons
     page chrome · footer · source viewer · high score table · syntax colours
   --------------------------------------------------------------------------- */

/* --- tokens --------------------------------------------------------------- */

:root
{
	--bg:          #0b0e14;
	--bg-grid:     #131822;
	--panel:       #11161f;
	--panel-hi:    #161d29;
	--line:        #232b39;
	--line-hi:     #33405a;
	--text:        #c8d2e0;
	--text-dim:    #7d8aa0;
	--text-faint:  #5a6577;
	--accent:      #5ccfe6;
	--accent-warm: #ffb454;
	--accent-good: #7ee787;

	--mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
	--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

	--radius: 10px;
	--maxw: 980px;

	/* The site header is sticky, so anything else that sticks has to clear it. */
	--head-height: 57px;
}

/* --- base ----------------------------------------------------------------- */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body
{
	margin: 0;
	background-color: var(--bg);
	/* Faint engineering grid. Cheap, static, sets the tone. */
	background-image:
		linear-gradient(var(--bg-grid) 1px, transparent 1px),
		linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
	background-size: 48px 48px, 48px 48px;
	background-position: -1px -1px;
	color: var(--text);
	font-family: var(--sans);
	font-size: 16px;
	line-height: 1.6;
	min-height: 100vh;
}

.wrap
{
	max-width: var(--maxw);
	margin: 0 auto;
	padding: 0 20px;
}

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

code, kbd, pre { font-family: var(--mono); }

code
{
	background: var(--panel-hi);
	border: 1px solid var(--line);
	border-radius: 4px;
	padding: 0.1em 0.35em;
	font-size: 0.88em;
}

hr
{
	border: 0;
	border-top: 1px solid var(--line);
	margin: 2.5rem 0;
}

/* --- site header ---------------------------------------------------------- */

.site-head
{
	border-bottom: 1px solid var(--line);
	background: rgba(11, 14, 20, 0.85);
	backdrop-filter: blur(6px);
	position: sticky;
	top: 0;
	z-index: 10;
}

.site-head .wrap
{
	display: flex;
	align-items: center;
	gap: 16px;
	min-height: 56px;
	flex-wrap: wrap;
}

.brand
{
	font-family: var(--mono);
	font-weight: 700;
	letter-spacing: 0.06em;
	color: var(--text);
	text-transform: uppercase;
	font-size: 0.92rem;
}
.brand:hover { text-decoration: none; color: var(--accent); }
.brand .caret { color: var(--accent); }

.site-nav
{
	margin-left: auto;
	display: flex;
	gap: 18px;
	font-family: var(--mono);
	font-size: 0.82rem;
}
.site-nav a { color: var(--text-dim); }
.site-nav a:hover { color: var(--accent); text-decoration: none; }

/* --- hero ----------------------------------------------------------------- */

.hero { padding: 72px 0 48px; }

.hero h1
{
	font-family: var(--mono);
	font-size: clamp(2rem, 6vw, 3.2rem);
	line-height: 1.05;
	margin: 0 0 12px;
	letter-spacing: -0.02em;
	color: #eef3fa;
}

.hero p.blurb
{
	max-width: 62ch;
	color: var(--text-dim);
	font-size: 1.05rem;
	margin: 0 0 10px;
}

/* --- section headings ----------------------------------------------------- */

.section-title
{
	font-family: var(--mono);
	font-size: 0.78rem;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--text-faint);
	display: flex;
	align-items: center;
	gap: 14px;
	margin: 0 0 22px;
}
.section-title::after
{
	content: "";
	flex: 1;
	height: 1px;
	background: var(--line);
}

/* --- project cards -------------------------------------------------------- */

.projects
{
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
	gap: 18px;
	padding-bottom: 48px;
}

.card
{
	background: var(--panel);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	padding: 22px;
	display: flex;
	flex-direction: column;
	transition: border-color 0.15s ease, transform 0.15s ease, background 0.15s ease;
}
.card:hover
{
	border-color: var(--line-hi);
	background: var(--panel-hi);
	transform: translateY(-2px);
}

/* Its own clipping box, deliberately not the card's: an element that both
   clips (overflow + radius) and moves (the card's hover transform) is a
   known Safari bug — the clip can stop applying while/after the transform
   runs, and the image leaks past the card's rounded corners. Keeping the
   thumbnail's clip separate from the transformed element avoids that. */
.card-thumb
{
	margin: 14px 0 16px;
	border-radius: 8px;
	overflow: hidden;
	aspect-ratio: 3 / 2;
	background: var(--panel-hi);
}
.card-thumb img
{
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Modifier for thumbnails that aren't a 3:2 screenshot (e.g. a wide banner
   strip) — show the whole image at its own ratio instead of cropping it
   into the 3:2 box. */
.card-thumb.is-native
{
	aspect-ratio: auto;
	display: flex;
	justify-content: center;
}
.card-thumb.is-native img
{
	width: auto;
	max-width: 100%;
	height: auto;
	object-fit: contain;
}

.card .card-top
{
	display: flex;
	align-items: baseline;
	gap: 10px;
	margin-bottom: 8px;
}

.card h3
{
	margin: 0;
	font-size: 1.15rem;
	font-family: var(--mono);
	letter-spacing: -0.01em;
	color: #eef3fa;
}
.card h3 a { color: inherit; }
.card h3 a:hover { color: var(--accent); text-decoration: none; }

.card p
{
	margin: 0 0 16px;
	color: var(--text-dim);
	font-size: 0.94rem;
}

.tags
{
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin: 0 0 18px;
	padding: 0;
	list-style: none;
}
.tags li
{
	font-family: var(--mono);
	font-size: 0.7rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-faint);
	border: 1px solid var(--line);
	border-radius: 999px;
	padding: 2px 9px;
}

.card-actions
{
	margin-top: auto;
	display: flex;
	gap: 10px;
	flex-wrap: wrap;
}

/* --- buttons -------------------------------------------------------------- */

.btn
{
	font-family: var(--mono);
	font-size: 0.8rem;
	padding: 7px 14px;
	border-radius: 6px;
	border: 1px solid var(--line-hi);
	color: var(--text);
	background: transparent;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 7px;
	line-height: 1.4;
}
.btn:hover { text-decoration: none; border-color: var(--accent); color: var(--accent); }

.btn-primary
{
	border-color: transparent;
	background: var(--accent);
	color: #06222a;
	font-weight: 600;
}
.btn-primary:hover { background: #7bdcef; color: #06222a; border-color: transparent; }

/* --- generic project page chrome ------------------------------------------ */

.page { padding: 44px 0 64px; }

.page h1
{
	font-family: var(--mono);
	font-size: clamp(1.6rem, 4vw, 2.2rem);
	margin: 0 0 6px;
	color: #eef3fa;
	letter-spacing: -0.02em;
}

.page .subtitle
{
	color: var(--text-dim);
	margin: 0 0 26px;
	max-width: 66ch;
}

.notice
{
	border: 1px solid var(--line);
	border-left: 3px solid var(--accent-warm);
	background: var(--panel);
	border-radius: 0 var(--radius) var(--radius) 0;
	padding: 14px 18px;
	color: var(--text-dim);
	font-size: 0.92rem;
}

/* --- footer --------------------------------------------------------------- */

.site-foot
{
	border-top: 1px solid var(--line);
	margin-top: 40px;
	padding: 26px 0 40px;
	font-family: var(--mono);
	font-size: 0.78rem;
	color: var(--text-faint);
}
.site-foot .wrap { display: flex; gap: 16px; flex-wrap: wrap; }
.site-foot .right { margin-left: auto; }

/* --- source viewer -------------------------------------------------------- */

.viewer
{
	display: grid;
	grid-template-columns: 220px minmax(0, 1fr);
	gap: 0;
	border: 1px solid var(--line);
	border-radius: var(--radius);
	overflow: hidden;
	background: var(--panel);
}

.viewer .filelist
{
	border-right: 1px solid var(--line);
	padding: 12px 0;
	margin: 0;
	list-style: none;
	background: #0d1219;
	max-height: 78vh;
	overflow-y: auto;
}
.viewer .filelist li { margin: 0; }

.viewer .filelist button
{
	display: block;
	width: 100%;
	text-align: left;
	background: none;
	border: 0;
	border-left: 2px solid transparent;
	color: var(--text-dim);
	font-family: var(--mono);
	font-size: 0.82rem;
	padding: 7px 16px;
	cursor: pointer;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.viewer .filelist button:hover { color: var(--text); background: var(--panel-hi); }

.viewer .filelist button[aria-current="true"]
{
	color: var(--accent);
	border-left-color: var(--accent);
	background: var(--panel-hi);
}

.viewer .filelist .group
{
	font-family: var(--mono);
	font-size: 0.68rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--text-faint);
	padding: 10px 16px 4px;
}

.viewer .filepane { min-width: 0; display: flex; flex-direction: column; }

.viewer .filebar
{
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 9px 14px;
	border-bottom: 1px solid var(--line);
	font-family: var(--mono);
	font-size: 0.78rem;
	color: var(--text-dim);
	background: var(--panel-hi);
}
.viewer .filebar .path { color: var(--text); white-space: nowrap; }

.viewer .filebar .stat
{
	color: var(--text-faint);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	min-width: 0;
}
.viewer .filebar .spacer { flex: 1 1 0; min-width: 8px; }
.viewer .filebar .btn { padding: 4px 10px; font-size: 0.74rem; }

/* The code area is one scroll box containing a sticky line-number gutter and
   the code itself, so the numbers track vertical scroll for free and stay put
   during horizontal scroll. */
.viewer .codewrap
{
	display: flex;
	align-items: flex-start;
	overflow: auto;
	max-height: 74vh;
	font-size: 0.82rem;
	line-height: 1.55;
	tab-size: 4;
}
.viewer .codewrap pre { margin: 0; }
.viewer .codewrap pre.code { flex: 1 1 auto; min-width: 0; }

.viewer .gutter
{
	position: sticky;
	left: 0;
	z-index: 1;
	flex: 0 0 auto;
	padding: 16px 12px 16px 16px;
	text-align: right;
	color: var(--text-faint);
	background: #0d1219;
	border-right: 1px solid var(--line);
	user-select: none;
	font-variant-numeric: tabular-nums;
}

/* Undo the inline-<code> styling from further up the sheet — in particular the
   0.88em size, which would otherwise make code lines shorter than the gutter's
   and drift the two out of alignment a fraction of a pixel per line. */
.viewer pre.code code
{
	background: transparent;
	border: 0;
	border-radius: 0;
	font-size: 1em;
	padding: 16px 18px;
	display: block;
	white-space: pre;
}

.viewer .empty
{
	padding: 40px 20px;
	text-align: center;
	color: var(--text-dim);
	font-family: var(--mono);
	font-size: 0.85rem;
}

@media (max-width: 720px)
{
	.viewer { grid-template-columns: 1fr; }

	.viewer .filelist
	{
		border-right: 0;
		border-bottom: 1px solid var(--line);
		max-height: 190px;
	}

	.hero { padding: 48px 0 32px; }
}

/* --- high score table ------------------------------------------------------
   Used by Metascore Per Hour. Everything is scoped to .table-shell so a plain
   <table> dropped into some future page is not dragged into this styling. */

.controls
{
	display: flex;
	gap: 10px;
	margin: 0 0 12px;
	flex-wrap: wrap;
}

#filter-input, #score-filter
{
	font-family: var(--mono);
	font-size: 0.86rem;
	padding: 8px 11px;
	background: var(--panel);
	color: var(--text);
	border: 1px solid var(--line);
	border-radius: 6px;
}
#filter-input { flex: 1 1 260px; min-width: 0; }
#filter-input:focus, #score-filter:focus { outline: none; border-color: var(--accent); }

#row-count
{
	font-family: var(--mono);
	font-size: 0.78rem;
	color: var(--text-faint);
	margin: 0 0 16px;
}

/* The table runs to its full height and the page scrolls, so the shell must
   NOT be a scroll container — an overflow value here would trap the sticky
   header inside it and it would scroll away with the rest of the page. Narrow
   screens are the exception, at the end of this section. */
.table-shell
{
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--panel);
}

.table-shell table { border-collapse: collapse; width: 100%; font-size: 0.9rem; }

.table-shell th,
.table-shell td
{
	padding: 8px 14px;
	text-align: left;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}
.table-shell td:nth-child(2) { white-space: normal; }

.table-shell thead th
{
	position: sticky;
	top: var(--head-height);
	z-index: 1;
	background: var(--panel-hi);
	border-bottom: 1px solid var(--line-hi);
	font-family: var(--mono);
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--text-faint);
	font-weight: 600;
}

.table-shell tbody tr { border-top: 1px solid #0f141c; }
.table-shell tbody tr:nth-child(even) { background: #0e131b; }
.table-shell tbody tr:hover { background: var(--panel-hi); }
.table-shell tbody a { color: var(--text); }
.table-shell tbody a:hover { color: var(--accent); }

.table-shell tbody td:first-child { color: var(--text-faint); font-family: var(--mono); font-size: 0.8rem; }
.table-shell td.num { font-family: var(--mono); }
.table-shell td.mph { color: var(--accent-warm); font-family: var(--mono); font-weight: 600; }
.table-shell .unnamed { color: var(--text-faint); font-size: 0.85em; }

/* Top 150 get a nod. Rows are rendered in rank order and filtering only hides
   them, so nth-child tracks rank rather than what is on screen. */
.table-shell tbody tr:nth-child(-n+150) td.mph { color: var(--accent-good); }

/* Narrow screens: let the table scroll sideways rather than squeezing the
   columns. That makes the shell a scroll container, which measures a sticky
   offset from itself rather than the viewport — the header would hover a
   header's height down the table and sit on the first two rows. So it scrolls
   away instead. This block has to come last: it overrides rules of equal
   specificity. */
@media (max-width: 640px)
{
	.table-shell { overflow-x: auto; }
	.table-shell thead th { position: static; }

	/* Tighten the cells so MPH — the entire point of the table — still fits on
	   a phone instead of hiding off the right edge. */
	.table-shell table { font-size: 0.8rem; }
	.table-shell th, .table-shell td { padding: 7px 6px; }
	.table-shell th:first-child, .table-shell td:first-child { padding-left: 10px; }
	.table-shell thead th { font-size: 0.64rem; letter-spacing: 0.04em; }
}

/* --- syntax colours --------------------------------------------------------
   Class names match highlight.js, so swapping in the real library (or one of
   its themes) needs no changes here. */

.hljs { color: var(--text); }
.hljs-comment, .hljs-quote            { color: #5c6b7f; font-style: italic; }
.hljs-keyword, .hljs-selector-tag     { color: #ffa759; }
.hljs-literal                         { color: #f28779; }
.hljs-string                          { color: #bae67e; }
.hljs-attr                            { color: #ffd580; }
.hljs-number                          { color: #ffcc66; }
.hljs-built_in                        { color: #73d0ff; }
.hljs-title, .hljs-name,
.hljs-function .hljs-title            { color: #5ccfe6; }
.hljs-tag                             { color: #6f7c91; }
.hljs-meta                            { color: #77a8d9; }
