/* ============================================================================
   theme.css — design tokens, reset and page backdrop.
   The single source of truth for colour, type and spacing across the site.
   Every other stylesheet references these variables and never hard-codes a hex.
   ========================================================================= */

/* ── Non-colour tokens ───────────────────────────────────────────────────── */
:root {
	--font-head: 'Orbitron', sans-serif;
	--font-body: 'Exo 2', sans-serif;
	--font-mono: 'Share Tech Mono', monospace;

	--transition: 0.3s ease;
	--radius:     16px;   /* cards, panels */
	--radius-sm:  8px;    /* rows, buttons, inputs */
	--maxw:       1300px; /* page content width */
}

/* ── Dark (default) ──────────────────────────────────────────────────────── */
:root,
[data-theme="dark"] {
	--bg:          #0a0e14;
	--bg2:         #111720;
	--surface:     #1a2332;
	--surface2:    #1f2d42;

	--border:      rgba(0, 212, 255, 0.18);
	--border2:     rgba(0, 212, 255, 0.08);
	--border-hi:   rgba(0, 212, 255, 0.45);

	--text:        #e8f4ff;
	--text2:       #8ba8c8;
	--text3:       #526880;

	--glow:        rgba(0, 212, 255, 0.12);
	--glow2:       rgba(0, 212, 255, 0.05);

	--accent:      #00d4ff;
	--accent-dim:  #0e86b8;
	--accent2:     #00ff88;
	--warn:        #ffaa00;
	--danger:      #ff4444;

	--online:      #00ff88;
	--unavailable: #e8a020;
	--offline:     #ff4444;

	/* Status colours used as TEXT rather than as a dot, border or fill. The
	   vivid values above were chosen against dark backgrounds and several drop
	   below 4.5:1 when used for small labels, so these are tuned per theme.
	   Worst-case surface here is --surface2; in light mode it is --bg2. */
	--online-text:      #00ff88;
	--warn-text:        #ffaa00;
	--unavailable-text: #e8a020;
	--danger-text:      #ff5f5f;

	--uv-low:       #3dd68c;
	--uv-moderate:  #f5d423;
	--uv-high:      #f5a623;
	--uv-very-high: #ff4f4f;
	--uv-extreme:   #c07af0;

	/* Each status colour gets its own faint fill and its own halo, so a "poor"
	   pill is tinted red rather than sharing one generic cyan wash. */
	--tint-good: rgba(0, 255, 136, 0.08);
	--tint-fair: rgba(255, 170, 0, 0.08);
	--tint-poor: rgba(255, 68, 68, 0.08);

	/* Stronger than --tint-*: meant to read as "this half is the live one" at a
	   glance. Tuned so the label on top still clears 4.5:1. */
	--fill-good: rgba(0, 255, 136, 0.16);
	--fill-poor: rgba(255, 68, 68, 0.16);
	--on-fill-good: #00ff88;
	--on-fill-poor: #ff5f5f;
	--halo-good: rgba(0, 255, 136, 0.35);
	--halo-fair: rgba(255, 170, 0, 0.35);
	--halo-poor: rgba(255, 68, 68, 0.35);

	/* The at-a-glance figures — temperatures and band names. Theme blue rather
	   than body text, and picked for contrast: this has to clear 4.5:1 because
	   the band names and the home-page temperatures are normal-size text. */
	--readout: #00d4ff;   /* 8.92:1 on --surface */

	--orb1: rgba(0, 212, 255, 0.25);
	--orb2: rgba(0, 255, 136, 0.20);

	--row-hover: rgba(0, 212, 255, 0.05);
}

/* ── Light ───────────────────────────────────────────────────────────────── */
[data-theme="light"] {
	--bg:          #eef3f8;
	--bg2:         #dde8f0;
	--surface:     #ffffff;
	--surface2:    #f0f6fc;

	--border:      rgba(0, 100, 180, 0.20);
	--border2:     rgba(0, 100, 180, 0.08);
	--border-hi:   rgba(0, 100, 180, 0.50);

	--text:        #0d1f33;
	--text2:       #3a5a7a;
	--text3:       #7a9ab8;

	--glow:        rgba(47, 191, 113, 0.08);
	--glow2:       rgba(47, 191, 113, 0.03);

	--accent:      #2f7dbf;
	--accent-dim:  #1e6fa8;
	--accent2:     #2fbf71;
	--warn:        #b87a00;
	--danger:      #cc2222;

	--online:      #2fbf71;
	--unavailable: #c49200;
	--offline:     #cc2222;

	--online-text:      #1c7444;
	--warn-text:        #8b5c00;
	--unavailable-text: #816000;
	--danger-text:      #c72121;

	--uv-low:       #1a8a54;
	--uv-moderate:  #b58500;
	--uv-high:      #d1701a;
	--uv-very-high: #cc2a2a;
	--uv-extreme:   #8b3fbf;

	--tint-good: rgba(47, 191, 113, 0.10);
	--tint-fair: rgba(184, 122, 0, 0.10);
	--tint-poor: rgba(204, 34, 34, 0.08);

	/* Light mode needs a stronger fill to register as coloured, which in turn
	   needs a darker label than --online-text / --danger-text. */
	--fill-good: rgba(47, 191, 113, 0.20);
	--fill-poor: rgba(204, 34, 34, 0.20);
	--on-fill-good: #1a6a3e;
	--on-fill-poor: #9f1a1a;
	--halo-good: rgba(47, 191, 113, 0.25);
	--halo-fair: rgba(184, 122, 0, 0.25);
	--halo-poor: rgba(204, 34, 34, 0.25);

	--readout: #1e6fa8;   /* 5.39:1 on --surface; --accent's 4.37 would fail */

	--orb1: rgba(47, 125, 191, 0.18);
	--orb2: rgba(47, 191, 113, 0.14);

	--row-hover: rgba(0, 100, 180, 0.05);
}

/* Warm orb palette — used by the solar page. */
body.orbs-warm {
	--orb1: rgba(255, 170, 0, 0.20);
	--orb2: rgba(0, 212, 255, 0.20);
}

/* ── Reset ───────────────────────────────────────────────────────────────── */
*,
*::before,
*::after {
	box-sizing: border-box;
	margin: 0;
	padding: 0;
}

html {
	scroll-behavior: smooth;
}

body {
	font-family: var(--font-body);
	background: var(--bg);
	color: var(--text);
	min-height: 100vh;
	overflow-x: hidden;
	transition: background var(--transition), color var(--transition);
}

/* ── Backdrop: faint grid + drifting glow orbs ───────────────────────────── */
body::before {
	content: '';
	position: fixed;
	inset: 0;
	background-image:
		linear-gradient(var(--border2) 1px, transparent 1px),
		linear-gradient(90deg, var(--border2) 1px, transparent 1px);
	background-size: 40px 40px;
	pointer-events: none;
	z-index: 0;
	transition: background-image var(--transition);
}

.orb {
	position: fixed;
	border-radius: 50%;
	filter: blur(80px);
	pointer-events: none;
	z-index: 0;
	opacity: 0.35;
}

.orb1 {
	width: 500px;
	height: 500px;
	background: radial-gradient(circle, var(--orb1), transparent 70%);
	top: -120px;
	left: -120px;
	animation: drift1 18s ease-in-out infinite;
}

.orb2 {
	width: 400px;
	height: 400px;
	background: radial-gradient(circle, var(--orb2), transparent 70%);
	bottom: 10%;
	right: -80px;
	animation: drift2 22s ease-in-out infinite;
}

@keyframes drift1 {
	0%, 100% { transform: translate(0, 0); }
	50%      { transform: translate(40px, 30px); }
}

@keyframes drift2 {
	0%, 100% { transform: translate(0, 0); }
	50%      { transform: translate(-30px, -40px); }
}

/* ── Shared animations ───────────────────────────────────────────────────── */
@keyframes pulse {
	0%, 100% { opacity: 1;   transform: scale(1); }
	50%      { opacity: 0.4; transform: scale(0.7); }
}

@keyframes fadeUp {
	to { opacity: 1; transform: translateY(0); }
}

.fade-in {
	opacity: 0;
	transform: translateY(18px);
	animation: fadeUp 0.5s ease forwards;
}

.fade-in:nth-child(1) { animation-delay: 0.05s; }
.fade-in:nth-child(2) { animation-delay: 0.12s; }
.fade-in:nth-child(3) { animation-delay: 0.19s; }
.fade-in:nth-child(4) { animation-delay: 0.26s; }
.fade-in:nth-child(5) { animation-delay: 0.33s; }

@media (prefers-reduced-motion: reduce) {
	.orb,
	.fade-in,
	.status-dot {
		animation: none !important;
	}

	.fade-in {
		opacity: 1;
		transform: none;
	}

	html { scroll-behavior: auto; }
}
