/* Retrofit Twin base: tokens, reset, element defaults, typography, layout primitives. No framework. */

/* --- TOKENS --------------------------------------------------------------- */

:root {
	/* Eco-tech: warm neutrals, deep teal-green accent, golden solar. */

	/* Neutrals — warm greys with a soft undertone. The app's only greys. */
	--n-0:   #1C1917;
	--n-20:  #292524;
	--n-40:  #44403C;
	--n-55:  #6B6560;
	--n-70:  #A8A29E;
	--n-82:  #D6D3D1;
	--n-88:  #E7E5E4;
	--n-92:  #F5F5F4;
	--n-96:  #FAFAF9;
	--n-100: #FFFFFF;

	/* Text — warm near-black down to muted. */
	--ink:    #1C1917;   /* primary — ~17:1 on white */
	--ink-2:  #44403C;   /* secondary — ~10:1 */
	--ink-3:  #6B6560;   /* captions, units, empty states — ~5:1 */
	--ink-on: #FFFFFF;   /* text on an accent fill */

	/* Surfaces — flat white, separated by rules not shadow. */
	--paper:     #FFFFFF;   /* every panel, field, dialog, the nav bar */
	--bg:        #F5F5F4;   /* page canvas only */
	--inset:     var(--n-92);   /* table heads, hover fills */
	--rule:      var(--n-88);   /* the hairline that divides everything */
	--rule-soft: var(--n-92);   /* interior dividers, one step lighter */

	/* Accent — a single deep teal-green. Buttons, links, active nav, focus. */
	--accent:       #0F766E;
	--accent-hover: #115E59;
	--accent-tint:  rgb(15 118 110 / 0.10);   /* hover wash */
	--accent-ink:   #FFFFFF;                   /* text on the accent fill */

	/* Solar — golden yellow. Charts read --brand for the solar series and the est-solar dot. */
	--brand:    #EAB308;
	--brand-on: #1C1917;   /* glyph on a yellow fill */

	/* Data — grid import / export. */
	--d-import: #EA580C;   /* drawn from the grid */
	--d-export: #3B82F6;   /* sent back to the grid */

	/* Status. */
	--bad:    #DC2626;
	--bad-bg: #FEF2F2;
	--ok:     #059669;
	--ok-bg:  #ECFDF5;

	/* Semantic pill fills — one white glyph on each. */
	--pill-red:   #EA580C;   /* temperature, alerts */
	--pill-blue:  #3B82F6;   /* water, humidity */
	--pill-green: #059669;   /* online, healthy */
	--pill-amber: #F59E0B;   /* sun, power */
	--pill-slate: #64748B;   /* cloud, overcast */
	--pill-on:    #FFFFFF;

	--focus: var(--accent);

	/* Type — one system family. No web font: the app runs offline on a LAN. */
	--sans: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
	--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

	/* Eight steps. Each carries size, line height and tracking — never set one alone. */
	--t-2xs: 0.6875rem;  --lh-2xs: 0.875rem;  --ls-2xs: 0.06em;    /* eyebrows, units */
	--t-xs:  0.75rem;    --lh-xs:  1rem;       --ls-xs:  0.01em;    /* captions, hints */
	--t-sm:  0.8125rem;  --lh-sm:  1.125rem;   --ls-sm:  0.005em;   /* dense UI, data rows */
	--t-md:  0.875rem;   --lh-md:  1.375rem;   --ls-md:  0;         /* body */
	--t-lg:  1rem;       --lh-lg:  1.5rem;     --ls-lg:  0;         /* section titles */
	--t-xl:  1.5rem;     --lh-xl:  1.875rem;   --ls-xl:  -0.01em;   /* page titles */
	--t-2xl: 2rem;       --lh-2xl: 2.25rem;    --ls-2xl: -0.02em;   /* hero */
	--t-3xl: 2.75rem;    --lh-3xl: 1;          --ls-3xl: -0.03em;   /* the big meter reading */

	/* Space. */
	--s-1: 0.25rem;  --s-2: 0.5rem;   --s-3: 0.75rem;  --s-4: 1rem;
	--s-5: 1.25rem;  --s-6: 1.5rem;   --s-8: 2rem;     --s-10: 2.5rem;
	--s-12: 3rem;    --s-16: 4rem;

	/* Widths. */
	--page-max: 1200px;
	--nav-height: 4.5rem;

	/* Radius — only inputs, buttons, pills and the dialog get one. No card radius. */
	--r-field: 0.4rem;
	--r-pill:  999px;

	/* The one shadow: dialogs and the account dropdown, which must lift off the page. */
	--shadow-pop: 0 4px 12px rgb(26 26 26 / 0.08), 0 16px 40px rgb(26 26 26 / 0.14);

	/* Motion. */
	--dur-fast: 120ms;
	--dur:      200ms;
	--ease:     cubic-bezier(0.2, 0, 0, 1);

	--tap: 2.25rem;   /* minimum interactive height */
}

/* --- RESET -------------------------------------------------------------------- */

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

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

body {
	font-family: var(--sans);
	font-size: var(--t-md);
	line-height: var(--lh-md);
	color: var(--ink);
	background: var(--bg);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

img, svg, canvas { display: block; max-width: 100%; }
img { height: auto; }

/* Views toggle visibility with the `hidden` attribute (JS: el.hidden = true); component classes that set `display` would otherwise beat the UA [hidden] rule. */
[hidden] { display: none !important; }

input, button, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
button:disabled { cursor: not-allowed; }

a { color: inherit; text-decoration: none; }

/* --- ELEMENT DEFAULTS ------------------------------------------------------- */

h1, h2, h3 { font-weight: 650; letter-spacing: var(--ls-lg); }
h1 { font-size: var(--t-xl); line-height: var(--lh-xl); letter-spacing: var(--ls-xl); }
h2 { font-size: var(--t-lg); line-height: var(--lh-lg); }
h3 { font-size: var(--t-md); line-height: var(--lh-md); }

code {
	padding: 0.1em 0.35em;
	border-radius: 0.25rem;
	background: var(--inset);
	font-family: var(--mono);
	font-size: 0.9em;
}

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

/* Form controls — styled at element level: <input> needs no class to look right. */

input[type='text'], input[type='password'], input[type='email'],
input[type='number'], input[type='date'], input[type='search'],
input:not([type]), select, textarea {
	width: 100%;
	min-height: var(--tap);
	padding: var(--s-2) var(--s-3);
	background: var(--paper);
	border: 1px solid var(--rule);
	border-radius: var(--r-field);
	color: var(--ink);
	transition: border-color var(--dur-fast) var(--ease),
	            box-shadow var(--dur-fast) var(--ease);
}
textarea { min-height: 4.5rem; resize: vertical; line-height: var(--lh-md); }
input[type='number'], input[type='date'] { font-variant-numeric: tabular-nums; }

:is(input, select, textarea):focus-visible {
	outline: none;
	border-color: var(--accent);
	box-shadow: 0 0 0 3px var(--accent-tint);
}
:is(input, select, textarea):disabled {
	background: var(--inset);
	color: var(--ink-3);
	cursor: not-allowed;
}
::placeholder { color: var(--ink-3); opacity: 1; }

select {
	appearance: none;
	padding-right: var(--s-8);
	/* Hardcoded: a data URI can't read a custom property. */
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238A8A8A' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right var(--s-3) center;
}

input[type='checkbox'] {
	width: 1rem; height: 1rem;
	min-height: 0;
	padding: 0;
	accent-color: var(--accent);
	cursor: pointer;
}

/* Table — bare <table> is styled; devices.js builds rows with no classes. */

table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--t-sm);
	line-height: var(--lh-sm);
}
thead th {
	position: sticky;
	top: 0;
	z-index: 1;
	padding: var(--s-2) var(--s-4);
	background: var(--inset);
	border-bottom: 1px solid var(--rule);
	font-size: var(--t-2xs);
	line-height: var(--lh-2xs);
	font-weight: 650;
	letter-spacing: var(--ls-2xs);
	text-transform: uppercase;
	color: var(--ink-3);
	text-align: left;
	white-space: nowrap;
}
tbody td { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--rule-soft); }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--inset); }
.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Dialog — the shell; contents live in components.css. */

dialog {
	margin: auto;
	width: calc(100vw - 2rem);
	max-width: 32rem;
	max-height: calc(100dvh - 3rem);
	padding: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	border: 1px solid var(--rule);
	border-radius: var(--r-field);
	background: var(--paper);
	color: var(--ink);
	box-shadow: var(--shadow-pop);
}
dialog[data-size='lg'] { max-width: 44rem; }
dialog::backdrop { background: rgb(26 26 26 / 0.45); }

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* --- TYPOGRAPHY HELPERS --------------------------------------------------------- */

/* The uppercase micro-label above a value. */
.eyebrow {
	font-size: var(--t-2xs);
	line-height: var(--lh-2xs);
	font-weight: 650;
	letter-spacing: var(--ls-2xs);
	text-transform: uppercase;
	color: var(--ink-3);
}

.caption {
	font-size: var(--t-xs);
	line-height: var(--lh-xs);
	letter-spacing: var(--ls-xs);
	color: var(--ink-3);
}

.subtitle {
	margin-top: var(--s-1);
	font-size: var(--t-sm);
	line-height: var(--lh-sm);
	color: var(--ink-2);
}

.tnum { font-variant-numeric: tabular-nums; }

/* Last so they win over any type helper they pair with. */
.muted { color: var(--ink-2); }
.faint { color: var(--ink-3); }
.capitalize { text-transform: capitalize; }

/* A meter reading. Leading is 1: a number has no descenders to clear. */
.metric {
	font-size: var(--t-3xl);
	font-weight: 700;
	line-height: 1;
	letter-spacing: var(--ls-3xl);
	font-variant-numeric: tabular-nums;
}
.metric--sm { font-size: var(--t-xl); font-weight: 650; letter-spacing: var(--ls-xl); }
/* Sized against its container, not the viewport, so it gives ground in a narrow column. */
.metric--huge { font-size: clamp(2.25rem, 12cqi, 3.75rem); }
.metric__unit {
	margin-left: 0.15em;
	font-size: var(--t-md);
	font-weight: 500;
	letter-spacing: 0;
	color: var(--ink-3);
}
.metric--huge .metric__unit { font-size: var(--t-lg); }

/* min-width:0 so it truncates as a flex item too. */
.truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- LAYOUT PRIMITIVES -------------------------------------------------------- */
/* Deliberately few. Callers tune them with --gap / --cols / --size. */

.row {
	display: flex;
	align-items: center;
	gap: var(--gap, var(--s-3));
}
.row--between { justify-content: space-between; }
.row--top     { align-items: flex-start; }
.row--wrap    { flex-wrap: wrap; }

.stack {
	display: flex;
	flex-direction: column;
	gap: var(--gap, var(--s-3));
}

.grid {
	display: grid;
	gap: var(--gap, var(--s-4));
	grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
}
@media (min-width: 640px) {
	.grid { grid-template-columns: repeat(var(--cols-sm, var(--cols, 1)), minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
	.grid { grid-template-columns: repeat(var(--cols-lg, var(--cols-sm, var(--cols, 1))), minmax(0, 1fr)); }
}

/* The centered content column. Everything below the nav sits inside one of these. */
/* A white sheet on the canvas — the content strip reads a step brighter than --bg. */
.page {
	width: 100%;
	max-width: var(--page-max);
	margin: 0 auto;
	padding: var(--s-6) var(--s-4);
	background: var(--paper);
	border: 1px solid var(--rule);
	border-radius: var(--r-field);
}
@media (min-width: 640px) {
	.page { padding: var(--s-8) var(--s-8); }
}
