@charset "UTF-8";
/* ==========================================================================
   Sovereign Terminal — instrument widgets
   --------------------------------------------------------------------------
   SYSTEM STATUS, GLOBAL NODE, SIGNAL FEED and SYS.TIME. Everything here
   inherits the tokens declared in main.css — there are no local colours and
   no local type stack, so recolouring the theme recolours the instruments.

   The shared shell is .instr: a hard-bordered box with a micro-caps head and
   a hairline that runs out to the right edge. .instr--bare drops the frame for
   dropping a readout inside a section that already has one.
   ========================================================================== */

/* ── The shared shell ────────────────────────────────────────────────────── */
.instr {
	border: var(--hair) solid var(--ink);
	background: var(--surface);
	padding: clamp(0.9rem, 1.6vw, 1.25rem);
	display: grid;
	gap: 0.9rem;
	align-content: start;
}

/* Bare: no box, no padding. The parent section supplies both. */
.instr--bare {
	border: 0;
	background: none;
	padding: 0;
}

.instr__head {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	min-width: 0;
}

.instr__title {
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-weight: 600;
	letter-spacing: var(--track-eyebrow);
	text-transform: uppercase;
	color: var(--ink);
	white-space: nowrap;
}

/* The hairline that fills the rest of the head row. */
.instr__rule {
	flex: 1;
	height: var(--hair);
	min-width: 1rem;
	background: var(--line);
}

.instr__live {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-weight: 600;
	letter-spacing: var(--track-eyebrow);
	text-transform: uppercase;
	color: var(--accent);
	white-space: nowrap;
}

.instr__pip {
	width: 6px;
	height: 6px;
	background: var(--accent);
	border-radius: 50%;
	animation: st-pip 2s var(--ease) infinite;
}

@keyframes st-pip {
	0%, 100% { opacity: 1; }
	50%      { opacity: 0.25; }
}

/* ── SYSTEM STATUS: the metered rows ─────────────────────────────────────── */
.meters {
	display: grid;
	gap: 0.55rem;
}

/* Label | track | figure. The track takes the slack, so labels stay flush
   left and figures flush right however long either string is. */
.meter {
	display: grid;
	grid-template-columns: minmax(5.25rem, auto) 1fr minmax(4.75rem, auto);
	align-items: center;
	gap: 0.7rem;
}

.meter__label,
.meter__value {
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	white-space: nowrap;
}

.meter__label { color: var(--ink-400); }

.meter__value {
	color: var(--ink);
	font-weight: 600;
	text-align: right;
	font-variant-numeric: tabular-nums;
}

.meter__track {
	position: relative;
	height: 6px;
	min-width: 2rem;
	background: var(--ink-050);
	overflow: hidden;
}

/* Width lives on the element as --meter (printed by PHP). The bar starts
   collapsed and is released when JS adds .is-filled, so it sweeps out on
   first sight rather than appearing already drawn. */
.meter__fill {
	position: absolute;
	inset: 0 auto 0 0;
	width: 0;
	background: var(--accent);
	transition: width 1.1s var(--ease-out);
}

.meter.is-filled .meter__fill {
	width: var(--meter, 0%);
	/* A genuinely zero reading (an archive with nothing filed this week) would
	   otherwise paint an empty track that reads as a broken widget rather than
	   as a zero. The floor keeps a sliver of the bar visible so the row still
	   looks like a meter at rest; the figure beside it states the real value. */
	min-width: 3px;
}

/* Scripting off: no .is-filled ever lands, so the bars would stay empty next
   to their figures. Without JS they are drawn full-width immediately. */
.no-js .meter__fill {
	width: var(--meter, 0%);
	transition: none;
}

@media (prefers-reduced-motion: reduce) {
	.meter__fill { transition: none; }
}

/* ── The lime operational strip ──────────────────────────────────────────── */
.opstrip {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
	margin: 0;
	padding: 0.6rem 0.8rem;
	background: var(--lime);
	border: var(--hair) solid var(--ink);
}

.opstrip__text {
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-weight: 700;
	letter-spacing: var(--track-eyebrow);
	text-transform: uppercase;
	color: var(--ink);
}

.opstrip__pip {
	flex: none;
	width: 9px;
	height: 9px;
	background: var(--ink);
	border-radius: 50%;
}

/* ── GLOBAL NODE: the world plate ────────────────────────────────────────── */
.nodemap {
	position: relative;
	aspect-ratio: 2 / 1;
	border: var(--hair) solid var(--line);
	background: var(--ink-025);
	overflow: hidden;
}

/* The continents are suggested rather than drawn: a dot grid reads as a
   world plate at this size, and it costs no asset and no request. */
.nodemap__grid {
	position: absolute;
	inset: 0;
	background-image: radial-gradient(var(--ink-200) 0.9px, transparent 0.9px);
	background-size: 9px 9px;
	opacity: 0.28;
}

.nodemap__pin {
	position: absolute;
	transform: translate(-50%, -50%);
	display: grid;
	justify-items: center;
	gap: 3px;
	/* The plate is small and the labels are absolutely positioned, so two
	   nearby nodes can still overlap at narrow widths however far apart their
	   coordinates are. The label gets the plate's own ground behind it and a
	   stacking order, so the one in front stays readable rather than the pair
	   dissolving into each other. */
	z-index: 1;
	white-space: nowrap;
}

.nodemap__dot {
	width: 8px;
	height: 8px;
	background: var(--accent);
	border-radius: 50%;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

.nodemap__code {
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	color: var(--ink-400);
	background: var(--ink-025);
	padding: 0 2px;
}

/* Below the width at which the plate is only a couple of hundred pixels wide,
   four labels cannot all be placed without collisions. The pins stay — they
   are the graphic — and the codes give way; every city is named in full in the
   clock rows directly beneath. */
@media (max-width: 420px) {
	.nodemap__code { display: none; }
}

/* ── The clock rows ──────────────────────────────────────────────────────── */
.nodelist {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0;
}

.nodelist__item {
	display: grid;
	grid-template-columns: 3rem auto 1fr;
	align-items: baseline;
	gap: 0.7rem;
	padding: 0.45rem 0;
	border-top: var(--hair) solid var(--line-soft);
}

.nodelist__item:first-child { border-top: 0; }

.nodelist__code {
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-weight: 700;
	letter-spacing: 0.08em;
	color: var(--ink);
}

.nodelist__time {
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--accent);
	/* The clock reflows every minute. A fixed column keeps the city names
	   from shuffling left and right as 09:59 becomes 10:00. */
	min-width: 3.9rem;
}

.nodelist__city {
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--ink-400);
	text-align: right;
}

/* ── SIGNAL FEED: the tape ───────────────────────────────────────────────── */
.tape {
	list-style: none;
	margin: 0;
	padding: 0;
	counter-reset: none;
}

.tape__row {
	display: grid;
	grid-template-columns: 1.9rem 5.5rem 1fr;
	align-items: baseline;
	gap: 0.65rem;
	padding: 0.5rem 0;
	border-top: var(--hair) solid var(--line-soft);
}

.tape__row:first-child { border-top: 0; }

.tape__num,
.tape__stamp {
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.tape__num {
	font-weight: 600;
	color: var(--accent);
}

.tape__stamp { color: var(--ink-500); }

.tape__link {
	font-family: var(--font-body);
	font-size: var(--fs-sm);
	font-weight: 500;
	line-height: 1.35;
	color: var(--ink);
	text-decoration: none;
	/* Two lines maximum: the tape is a scan list, and a five-line headline in
	   it stops it reading as rows. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.tape__link:hover,
.tape__link:focus-visible {
	color: var(--accent);
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* ── SYS.TIME: the masthead clock ────────────────────────────────────────── */
.systime {
	display: grid;
	grid-template-columns: auto;
	gap: 1px;
	padding: 0 clamp(0.6rem, 1vw, 0.9rem);
	border-left: var(--hair) solid var(--line);
	border-right: var(--hair) solid var(--line);
	align-content: center;
	line-height: 1.15;
}

.systime__label,
.systime__zone {
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ink-500);
	white-space: nowrap;
}

.systime__clock {
	font-family: var(--font-mono);
	font-size: var(--fs-xs);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--ink);
	/* Tabular figures still change width between 1 and 2 in some fallbacks;
	   a floor keeps the masthead from twitching once a second. */
	min-width: 5.2rem;
}

/* ── Inverted context ────────────────────────────────────────────────────
   Any instrument dropped inside a dark band. `.band--dark` is the class the
   bands actually carry; `.instr--dark` is the opt-in for an instrument that
   is inverted on its own, without a dark band around it.

   Only the values that MUST change are restated — everything else is already
   a token, so recolouring the theme recolours these too. */
.band--dark .instr,
.panel--subscribe .instr,
.instr--dark {
	border-color: var(--line-dark);
	background: transparent;
}

.band--dark .instr__title,
.panel--subscribe .instr__title,
.instr--dark .instr__title,
.band--dark .meter__value,
.panel--subscribe .meter__value,
.instr--dark .meter__value,
.band--dark .nodelist__code,
.panel--subscribe .nodelist__code,
.instr--dark .nodelist__code,
.band--dark .tape__link,
.panel--subscribe .tape__link,
.instr--dark .tape__link {
	color: var(--on-dark);
}

.band--dark .instr__rule,
.panel--subscribe .instr__rule,
.instr--dark .instr__rule {
	background: var(--line-dark);
}

.band--dark .nodelist__item,
.panel--subscribe .nodelist__item,
.instr--dark .nodelist__item,
.band--dark .tape__row,
.panel--subscribe .tape__row,
.instr--dark .tape__row {
	border-top-color: var(--line-dark-soft);
}

/* These three were the contrast failures: mid-greys chosen against the pale
   ground, left sitting on near-black. */
.band--dark .meter__label,
.panel--subscribe .meter__label,
.instr--dark .meter__label,
.band--dark .nodelist__city,
.panel--subscribe .nodelist__city,
.instr--dark .nodelist__city,
.band--dark .tape__stamp,
.panel--subscribe .tape__stamp,
.instr--dark .tape__stamp {
	color: var(--on-dark-dim);
}

/* Violet is the system accent on the pale ground, but it is too dark to read
   on near-black — on an inverted ground lime takes the live/active role. */
.band--dark .instr__live,
.panel--subscribe .instr__live,
.instr--dark .instr__live,
.band--dark .tape__num,
.panel--subscribe .tape__num,
.instr--dark .tape__num,
.band--dark .nodelist__time,
.panel--subscribe .nodelist__time,
.instr--dark .nodelist__time {
	color: var(--lime);
}

.band--dark .instr__pip,
.panel--subscribe .instr__pip,
.instr--dark .instr__pip,
.band--dark .meter__fill,
.panel--subscribe .meter__fill,
.instr--dark .meter__fill,
.band--dark .nodemap__dot,
.panel--subscribe .nodemap__dot,
.instr--dark .nodemap__dot {
	background: var(--lime);
}

.band--dark .tape__link:hover,
.band--dark .tape__link:focus-visible,
.panel--subscribe .tape__link:hover,
.panel--subscribe .tape__link:focus-visible,
.instr--dark .tape__link:hover,
.instr--dark .tape__link:focus-visible {
	color: var(--lime);
}

.band--dark .meter__track,
.panel--subscribe .meter__track,
.instr--dark .meter__track {
	background: var(--line-dark);
}

.band--dark .nodemap,
.panel--subscribe .nodemap,
.instr--dark .nodemap {
	border-color: var(--line-dark);
	background: rgba(255, 255, 255, 0.03);
}

.band--dark .nodemap__grid,
.panel--subscribe .nodemap__grid,
.instr--dark .nodemap__grid {
	background-image: radial-gradient(var(--on-dark-dim) 0.9px, transparent 0.9px);
	opacity: 0.35;
}

.band--dark .nodemap__code,
.panel--subscribe .nodemap__code,
.instr--dark .nodemap__code {
	color: var(--on-dark-dim);
	/* The label carries its ground with it so overlapping pins stay legible;
	   on an inverted plate that ground has to invert too, or each code sits in
	   a pale box on near-black. */
	background: var(--dark-2);
}

/* The operational strip keeps its lime ground in every context — it is the
   design's one affirmative, and inverting it would make it just another box. */

/* ── Narrow ──────────────────────────────────────────────────────────────── */
@media (max-width: 540px) {
	/* The three-column tape row collapses: the stamp moves under the
	   headline rather than squeezing it into a two-word column. */
	.tape__row {
		grid-template-columns: 1.6rem 1fr;
		row-gap: 0.2rem;
	}

	.tape__stamp { grid-column: 2; order: 2; }
	.tape__link  { grid-column: 2; order: 1; }

	.meter {
		grid-template-columns: 1fr auto;
		row-gap: 0.3rem;
	}

	/* The bar spans the full row under its label and figure. */
	.meter__track {
		grid-column: 1 / -1;
		order: 3;
	}

	.nodelist__city { display: none; }
}
