/* Vyking review apps — ingress list.
   The palette is a deep cool "ink" rather than neutral black; the accent cyan
   is inherited from the previous design. Status colours are tuned to sit next
   to that cyan without fighting it. */

:root {
	--ink: #0d1519;
	--surface: #142027;
	--surface-2: #1b2a33;
	--line: #24363f;
	--text: #dce7eb;
	--text-dim: #8aa0aa;
	--accent: #4fc0d2;
	--ok: #3fbf8f;
	--warn: #e0a33e;
	--err: #e36b6b;
	--idle: #6b8593;

	/* Keep in sync with <meta http-equiv="refresh"> in index.html. */
	--refresh-window: 300s;

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

	--gutter: 24px;
}

*,
*::before,
*::after {
	box-sizing: border-box;
}

/* Rows are switched to display:block in the narrow layout below, which would
   otherwise win over the user-agent rule for [hidden]. */
[hidden] {
	display: none !important;
}

html {
	background: var(--ink);
}

body {
	margin: 0;
	padding: 0 var(--gutter) 64px;
	background: var(--ink);
	color: var(--text);
	font-family: var(--font-ui);
	font-size: 15px;
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: 2px;
}

.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* --------------------------------------------------------------- freshness
   The one moving thing on the page: a hairline that drains across the top over
   the auto-refresh window, so you can see at a glance how stale the data is.
   Pure CSS, so it still works with scripting disabled. */

.freshness {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--line);
	z-index: 20;
}

.freshness__bar {
	display: block;
	height: 100%;
	width: 100%;
	background: var(--accent);
	transform-origin: left center;
	animation: drain var(--refresh-window) linear forwards;
}

@keyframes drain {
	from { transform: scaleX(1); }
	to   { transform: scaleX(0); }
}

/* ---------------------------------------------------------------- masthead */

.masthead {
	max-width: 1400px;
	margin: 0 auto;
	padding: 28px 0 20px;
}

.masthead__row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}

.brand {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	color: var(--text-dim);
	font-size: 13px;
}

/* The inverted wordmark already says "Vyking", so the text beside it does not
   repeat it. Served as an <img> so the logo's own class names stay inside its
   document and cannot collide with this stylesheet. */
.logo {
	height: 22px;
	width: auto;
	flex: none;
}

.countdown {
	color: var(--text-dim);
	font-family: var(--font-mono);
	font-size: 12px;
	font-variant-numeric: tabular-nums;
}

.ns {
	margin: 6px 0 0;
	font-family: var(--font-mono);
	font-size: 32px;
	font-weight: 600;
	letter-spacing: -0.02em;
	line-height: 1.15;
	overflow-wrap: anywhere;
}

main {
	max-width: 1400px;
	margin: 0 auto;
}

/* ------------------------------------------------------------------ banner */

.banner {
	margin: 0 0 20px;
	padding: 12px 16px;
	border: 1px solid var(--err);
	border-left-width: 3px;
	border-radius: 4px;
	background: rgba(227, 107, 107, 0.09);
	font-size: 14px;
}

.banner strong {
	display: block;
	margin-bottom: 2px;
	font-weight: 500;
}

.banner code {
	color: var(--text-dim);
	font-family: var(--font-mono);
	font-size: 12.5px;
	overflow-wrap: anywhere;
}

/* ----------------------------------------------------------------- toolbar */

/* Two facets, two rows: partners on top because that is the cut people reach
   for first, state and free text underneath. */
.toolbar {
	display: flex;
	flex-direction: column;
	gap: 10px;
	margin-bottom: 14px;
}

.toolbar__row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px 20px;
}

.pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.pills--partner {
	padding-bottom: 10px;
	border-bottom: 1px solid var(--line);
}

.pills--partner .pill {
	font-family: var(--font-mono);
	font-size: 12.5px;
}

.pill--all {
	font-family: var(--font-ui);
}

.pill__n {
	margin-left: 7px;
	padding-left: 7px;
	border-left: 1px solid var(--line);
	color: var(--idle);
	font-family: var(--font-ui);
	font-size: 12px;
}

.pill[aria-pressed="true"] .pill__n {
	border-left-color: var(--accent);
	color: var(--text-dim);
}

.pill {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	margin: 0;
	padding: 5px 12px 5px 10px;
	border: 1px solid var(--line);
	border-radius: 999px;
	background: var(--surface);
	color: var(--text-dim);
	font: inherit;
	font-size: 13px;
	font-variant-numeric: tabular-nums;
	cursor: default;
}

.js .pill {
	cursor: pointer;
}

.js .pill:hover {
	border-color: var(--idle);
	color: var(--text);
}

.pill[aria-pressed="true"] {
	border-color: var(--accent);
	background: var(--surface-2);
	color: var(--text);
}

.search {
	display: none;
	align-items: center;
	gap: 12px;
	margin-left: auto;
}

.js .search {
	display: flex;
}

.search input {
	width: 260px;
	max-width: 100%;
	padding: 6px 12px;
	border: 1px solid var(--line);
	border-radius: 4px;
	background: var(--surface);
	color: var(--text);
	font: inherit;
	font-size: 14px;
}

.search input::placeholder {
	color: var(--idle);
}

.search input:focus {
	border-color: var(--accent);
	outline: none;
}

.count {
	color: var(--text-dim);
	font-size: 12.5px;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/* ------------------------------------------------------------------- table */

.panel {
	border: 1px solid var(--line);
	border-radius: 6px;
	background: var(--surface);
	overflow-x: auto;
}

table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
}

thead th {
	position: sticky;
	top: 0;
	z-index: 10;
	padding: 10px 16px;
	border-bottom: 1px solid var(--line);
	background: var(--surface-2);
	color: var(--text-dim);
	font-size: 12.5px;
	font-weight: 500;
	text-align: left;
	white-space: nowrap;
}

.js th[data-sort] {
	cursor: pointer;
	user-select: none;
}

.js th[data-sort]:hover {
	color: var(--text);
}

th[data-sort]::after {
	content: "";
	display: inline-block;
	width: 0.7em;
	margin-left: 0.35em;
	color: var(--accent);
}

th[aria-sort="ascending"]::after  { content: "\2191"; }
th[aria-sort="descending"]::after { content: "\2193"; }

tbody td {
	padding: 12px 16px;
	border-bottom: 1px solid var(--line);
	vertical-align: top;
}

tbody tr:last-child td {
	border-bottom: 0;
}

tbody tr:hover td {
	background: var(--surface-2);
}

/* Branch-derived names and review-app hosts are both long; these widths stop
   either one from wrapping until the window really is too narrow. */
.col-partner { width: 120px; }
.col-name { width: 24%; }
.col-cert { width: 20%; }

/* Rows arrive sorted by partner, so the repeated value reads as a group label.
   Keeping it quiet stops that repetition from competing with the names. */
.partner {
	color: var(--text-dim);
	font-family: var(--font-mono);
	font-size: 13px;
	overflow-wrap: anywhere;
}

.partner--none {
	color: var(--idle);
	font-style: italic;
}

.col-deployed {
	width: 96px;
	white-space: nowrap;
}

/* The lamp sits at the head of the name cell rather than in a column of its
   own, so the dots still form one scannable line down the left edge. The flex
   goes on a wrapper, not the <td> itself, which would drop the cell out of the
   table's column sizing. */
.name-cell {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}

.name-cell .dot {
	margin-top: 6px;
}

thead th.col-name {
	padding-left: 35px;
}

/* Status lamp in the leading column: scanning down the left edge shows what is
   broken without reading anything. */
.dot {
	display: inline-block;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: var(--idle);
	flex: none;
}

.dot--up   { background: var(--ok); }
.dot--down { background: var(--err); }
.dot--cert { background: var(--warn); }

/* Nothing to report is not the same as something being wrong: a hollow lamp
   reads as "no signal" instead of as a fault. */
.dot--unknown {
	background: none;
	box-shadow: inset 0 0 0 1.5px var(--idle);
}

.name {
	font-weight: 500;
	overflow-wrap: anywhere;
}

.digest {
	margin-top: 3px;
	font-size: 12.5px;
}

.hosts {
	margin: 0;
	padding: 0;
	list-style: none;
}

.hosts li + li {
	margin-top: 4px;
}

.hosts a {
	color: var(--accent);
	font-family: var(--font-mono);
	font-size: 13px;
	text-decoration: none;
	overflow-wrap: anywhere;
}

.hosts a:hover,
.hosts a:focus-visible {
	text-decoration: underline;
}

.hosts--none {
	color: var(--idle);
	font-size: 13px;
}

.deployed {
	font-size: 13.5px;
	font-variant-numeric: tabular-nums;
}

.deployed--never {
	color: var(--idle);
}

.cert__state {
	font-weight: 500;
}

.cert__state--ready   { color: var(--ok); }
.cert__state--pending { color: var(--warn); }
.cert__state--failed  { color: var(--err); }
.cert__state--unknown { color: var(--idle); }

.cert__msg {
	margin: 2px 0 0;
	max-width: 60ch;
	color: var(--text-dim);
	font-size: 13px;
}

/* ---------------------------------------------------------------- tooltips
   The old markup positioned these absolutely with no positioned ancestor, so
   they anchored to the viewport. The owner is now the containing block, and
   :focus-within makes them reachable from the keyboard. */

.tt {
	position: relative;
	display: inline-block;
	border-bottom: 1px dotted var(--idle);
	color: var(--text-dim);
	font-family: var(--font-mono);
	cursor: help;
}

.tt__body {
	position: absolute;
	top: calc(100% + 6px);
	left: 0;
	z-index: 30;
	display: none;
	padding: 6px 9px;
	border: 1px solid var(--line);
	border-radius: 4px;
	background: var(--surface-2);
	color: var(--text);
	font-family: var(--font-mono);
	font-size: 12px;
	white-space: nowrap;
	box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
}

.tt:hover .tt__body,
.tt:focus-within .tt__body {
	display: block;
}

/* ------------------------------------------------------ empty / no results */

.empty {
	padding: 56px 24px;
	border: 1px dashed var(--line);
	border-radius: 6px;
	text-align: center;
}

.empty h2 {
	margin: 0 0 6px;
	font-size: 17px;
	font-weight: 500;
}

.empty p {
	margin: 0;
	color: var(--text-dim);
	font-size: 14px;
}

.empty code {
	color: var(--text);
	font-family: var(--font-mono);
	font-size: 13px;
}

.noresults {
	padding: 40px 16px;
	color: var(--text-dim);
	text-align: center;
}

/* ------------------------------------------------------------- narrow view */

@media (max-width: 760px) {
	:root { --gutter: 16px; }

	.ns { font-size: 26px; }

	.panel {
		border: 0;
		border-radius: 0;
		background: none;
	}

	thead { display: none; }

	tbody tr {
		display: block;
		margin-bottom: 12px;
		border: 1px solid var(--line);
		border-radius: 6px;
		background: var(--surface);
	}

	tbody tr:hover td { background: none; }

	tbody td {
		display: block;
		padding: 10px 14px;
		border-bottom: 1px solid var(--line);
	}

	tbody tr td:last-child { border-bottom: 0; }

	/* Column widths are meaningless once the cells stack, and would otherwise
	   squeeze every name into a hyphen-by-hyphen column. */
	.col-partner,
	.col-name,
	.col-cert,
	.col-deployed {
		width: auto;
	}

	.pills--partner {
		padding-bottom: 12px;
	}

	td.col-name { padding-top: 12px; }

	/* The partner is the group key, so on a card it reads as a line above the
	   name rather than as its own labelled block. */
	td.col-partner {
		padding: 10px 14px 0 33px;
		border-bottom: 0;
	}

	/* Needs to outrank td[data-label]::before further down this block. */
	td.col-partner[data-label]::before { content: none; }

	td.col-partner + td.col-name { padding-top: 2px; }

	/* An empty certificate cell has nothing to label. */
	td.col-empty { display: none; }

	td[data-label]::before {
		content: attr(data-label);
		display: block;
		margin-bottom: 3px;
		color: var(--text-dim);
		font-size: 12px;
	}

	.search {
		width: 100%;
		margin-left: 0;
	}

	.search input { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
	.freshness__bar {
		animation: none;
		opacity: 0.35;
	}
}
