:root {
	--bg: #f4f6f8;
	--surface: #ffffff;
	--text: #17222b;
	--muted: #64748b;
	--accent: #0e7490;
	--accent-dark: #155e75;
	--border: #e2e8f0;
	--ok: #15803d;
	--warn: #b45309;
	--bad: #b91c1c;
	--tint: #e3eff4;        /* light accent wash for containers */
	--tint-border: #c6dde7;
	--tint-strong: #abd2e3; /* deeper wash: cards that must pop off a tinted container */
	--tint-strong-border: #94bfd1;
}

* { box-sizing: border-box; }
body {
	margin: 0;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
	background: var(--bg);
	color: var(--text);
	line-height: 1.5;
}
a { color: var(--accent); text-decoration: none; }
h1 { font-size: 1.5rem; margin: 0.5rem 0 1rem; }
h2 { font-size: 1.1rem; margin: 1.5rem 0 0.5rem; }
code { background: var(--bg); padding: 0.1em 0.35em; border-radius: 4px; font-size: 0.9em; }
.muted { color: var(--muted); font-weight: normal; font-size: 0.9em; }

/* top bar */
.topbar {
	display: flex; justify-content: space-between; align-items: center;
	background: var(--surface); border-bottom: 1px solid var(--border);
	padding: 0.6rem 1.25rem;
}
.topbar nav { display: flex; gap: 1rem; }
.topbar nav a { color: var(--text); font-weight: 500; }
.topbar nav a:hover { color: var(--accent); }
.topbar-right { display: flex; align-items: center; gap: 0.75rem; }
.brand {
	font-weight: 700; font-size: 1.15rem; color: var(--accent-dark); letter-spacing: 0.02em;
	display: inline-flex; align-items: center; gap: 0.45rem;
}
.brand-mark { height: 1.5em; }
.tag {
	font-size: 0.7rem; font-weight: 600; text-transform: uppercase;
	background: var(--accent); color: #fff; border-radius: 4px;
	padding: 0.1rem 0.4rem; vertical-align: middle;
}

.container { max-width: 1100px; margin: 1.5rem auto; padding: 0 1.25rem; }

/* login */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.login-card {
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
	padding: 2.5rem; width: min(420px, 92vw);
	box-shadow: 0 10px 30px rgba(2, 32, 45, 0.08);
}
.login-card form { display: flex; flex-direction: column; gap: 0.75rem; margin-top: 1rem; }
.login-card .logo { width: 150px; display: block; margin: 0 auto 0.75rem; }
.error {
	background: #fef2f2; border: 1px solid #fecaca; color: var(--bad);
	border-radius: 8px; padding: 0.5rem 0.75rem; margin-top: 0.75rem; font-size: 0.9rem;
}

/* cards */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1rem; }
.card {
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
	padding: 1rem 1.25rem; color: var(--text); display: block;
	transition: box-shadow 0.15s, transform 0.15s;
}
.card:hover { box-shadow: 0 6px 18px rgba(2, 32, 45, 0.1); transform: translateY(-1px); }
.card-title { font-weight: 600; }
.card-value { font-size: 1.7rem; font-weight: 700; color: var(--accent-dark); margin: 0.25rem 0; }
.card-value .unit { font-size: 0.9rem; font-weight: 500; color: var(--muted); }
.card-sub { color: var(--muted); font-size: 0.8rem; }
.card-sub.assigned-point { color: var(--text); font-weight: 600; font-size: 0.9rem; }
.cards.wide { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.card-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.card-pills { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.card-actions { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; margin-top: 0.6rem; }
.card-actions form { margin: 0; display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
/* buttons that belong together (Assign/Unassign + Activate) wrap as a unit;
   with a point select present the pair takes the full card width: select on
   its own line, Assign + Activate together on the next (display: contents
   lifts the assign form's children into the pair's flex flow) */
.btn-pair { display: flex; gap: 0.4rem; align-items: center; min-width: 0; max-width: 100%; }
.btn-pair form { flex-wrap: nowrap; }
.btn-pair:has(select) { flex: 1 1 100%; flex-wrap: wrap; }
.btn-pair form:has(select) { display: contents; }
.btn-pair select { flex: 1 1 100%; min-width: 0; }
.btn-pair .btn { flex-shrink: 0; }

/* point page */
.point-head { display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 0.75rem; }
.point-actions { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
/* chart period navigation (‹ August 2026 ›) + the day/week/month/year group */
.chart-nav { display: flex; gap: 0.35rem; align-items: center; }
#period-label { font-weight: 600; min-width: 11ch; text-align: center; white-space: nowrap; }
.view-btns { display: flex; }
.view-btns .btn { border-radius: 0; margin-left: -1px; }
.view-btns .btn:first-child { border-radius: 8px 0 0 8px; margin-left: 0; }
.view-btns .btn:last-child { border-radius: 0 8px 8px 0; }
.view-btns .btn.active {
	background: var(--accent); border-color: var(--accent); color: #fff;
	position: relative; /* keep the shared border on top of the neighbours */
}
#chart {
	height: 460px; margin-top: 1.25rem;
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
}
/* installation capture panel (device online but not activated) */
.capture-panel {
	margin-top: 1rem; padding: 1.1rem 1.25rem;
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
}
.capture-actions { display: flex; gap: 0.75rem; align-items: center; margin-top: 0.5rem; }
.capture-panel img { display: block; max-width: 100%; border-radius: 8px; margin-top: 0.75rem; }

/* latest-photo modal (button beside the chart controls) */
.photo-modal {
	padding: 1.1rem 1.25rem; max-width: min(920px, 92vw);
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
}
.photo-modal::backdrop { background: rgba(2, 32, 45, 0.45); }
.photo-modal img { display: block; max-width: 100%; max-height: 70vh; border-radius: 8px; margin-top: 0.75rem; }

/* stats (mgmt) */
.stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 1rem; }
.stat {
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
	padding: 1.1rem 1.25rem; color: var(--text);
}
.stat-num { font-size: 1.9rem; font-weight: 700; color: var(--accent-dark); }
.stat-label { color: var(--muted); font-size: 0.85rem; }

/* tables */
table {
	width: 100%; border-collapse: collapse; background: var(--surface);
	border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
}
th, td { text-align: left; padding: 0.55rem 0.8rem; border-bottom: 1px solid var(--border); }
th { background: #f8fafc; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); }
tr:last-child td { border-bottom: none; }

/* pills */
.pill {
	display: inline-block; padding: 0.1rem 0.55rem; border-radius: 999px;
	font-size: 0.75rem; font-weight: 600; background: var(--bg); color: var(--muted);
}
.pill.ok { background: #dcfce7; color: var(--ok); }
.pill.warn { background: #fef3c7; color: var(--warn); }
.pill.bad { background: #fee2e2; color: var(--bad); }

/* Assign select: points already watched by another device (label also
   carries an em-dash suffix — Safari ignores option colors) */
option.taken { color: var(--warn); }

/* points browse page: latest registered capture per card */
.point-card .point-img { display: block; margin: 0.5rem 0 0.35rem; }
.point-card .point-img img { width: 100%; border-radius: 6px; display: block; }
/* htmx infinite scroll: invisible next-batch trigger */
.scroll-sentinel { height: 1px; }

/* device card: unacknowledged movement/tilt */
.card.moved { background: #fef3c7; border-color: #fcd34d; }
.moved-note {
	display: flex; justify-content: space-between; align-items: center; gap: 0.5rem;
	color: var(--warn); font-size: 0.85rem; font-weight: 600; margin: 0.35rem 0;
}
.moved-note form { margin: 0; }

/* forms & buttons */
input, select {
	padding: 0.5rem 0.65rem; border: 1px solid var(--border); border-radius: 8px;
	font-size: 0.95rem; background: var(--surface); color: var(--text);
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.cell-input { padding: 0.25rem 0.5rem; font-size: 0.85rem; width: 100%; min-width: 7rem; }
.inline-form { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin: 0.5rem 0; }
.btn {
	padding: 0.5rem 0.9rem; border: 1px solid var(--border); border-radius: 8px;
	background: var(--surface); color: var(--text); font-size: 0.9rem; font-weight: 500;
	cursor: pointer;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); color: #fff; }
.btn-danger:hover { border-color: var(--bad); color: var(--bad); }
.btn-ghost { border: none; background: none; color: var(--muted); }
.btn-small { padding: 0.25rem 0.6rem; font-size: 0.8rem; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn:disabled:hover { border-color: var(--border); color: var(--text); }

/* icon-only delete button, top-right of premise/point boxes */
.trash-form { margin: 0; display: inline-flex; align-self: center; }
.btn-trash {
	border: none; background: none; padding: 0.3rem; border-radius: 6px;
	color: var(--muted); cursor: pointer; display: inline-flex; align-items: center;
}
.btn-trash:hover { color: var(--bad); background: #fee2e2; }
.btn-trash svg { width: 16px; height: 16px; }
.btn-edit, .btn-cancel {
	border: none; background: none; padding: 0.3rem; border-radius: 6px;
	color: var(--muted); cursor: pointer; display: inline-flex; align-items: center;
}
.btn-edit:hover, .btn-cancel:hover { color: var(--accent); background: #cffafe; }
.btn-edit svg, .btn-cancel svg { width: 16px; height: 16px; }

/* premises/groups rename rows: plain text until the pencil (editmode.js)
   adds .editing to the head — then the edit form swaps in, the pencil gives
   way to the X, and the section's add forms appear */
.row-view { display: flex; align-items: baseline; gap: 0.6rem; min-width: 0; }
.row-name { font-weight: 600; font-size: 1rem; }
.premise-head .row-name { font-size: 1.1rem; }
.row-sub { color: var(--muted); font-size: 0.9rem; }
.premise-head .inline-form, .card-head .inline-form, .user-row .inline-form { display: none; }
.premise-head.editing .inline-form, .card-head.editing .inline-form, .user-row.editing .inline-form { display: flex; }
.premise-head.editing .row-view, .card-head.editing .row-view, .user-row.editing .row-view { display: none; }
.premise-head.editing .btn-edit, .card-head.editing .btn-edit, .user-row.editing .btn-edit { display: none; }
.premise-head .btn-cancel, .card-head .btn-cancel, .user-row .btn-cancel { display: none; }
.premise-head.editing .btn-cancel, .card-head.editing .btn-cancel, .user-row.editing .btn-cancel { display: inline-flex; }
.premise .add-form { display: none; }
.premise.editing .add-form { display: flex; }
.premise-head { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.5rem; }
.premise-head .inline-form, .card-head .inline-form { margin: 0; }
/* push the icon buttons right as a cluster, whichever of them are visible */
.premise-head .inline-form, .premise-head .row-view { margin-right: auto; }
/* point-card rename: keep name + Save on one line, the input flexes instead
   of wrapping. min-width: 0 on both the form and the input is load-bearing:
   without it the input's intrinsic ~20ch width propagates up as the form's
   automatic minimum (notably in Safari) and the row overflows the card. */
.card-head .inline-form { flex: 1; flex-wrap: nowrap; min-width: 0; }
.card-head .inline-form .cell-input { flex: 1; width: auto; min-width: 0; }
.card-head .inline-form .btn { flex-shrink: 0; }
.card-head .row-view { flex: 1; min-width: 0; }
.card-head .row-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* device-card rename: the status pills yield the line to the edit form */
.card-head.editing .card-pills { display: none; }

/* users page: one tinted section, one line per user, name left,
   everything else clustered right */
.user-row {
	display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;
	padding: 0.45rem 0; border-bottom: 1px solid var(--tint-border);
}
.user-row:last-child { border-bottom: none; }
.user-row .row-view, .user-row .inline-form { margin-right: auto; }
.user-row form { margin: 0; }
.user-row code { font-size: 0.85rem; }
.user-row .check-label { font-size: 0.85rem; white-space: nowrap; }
/* Rotate/Revoke are edit-mode actions: hidden on the plain row, shown while
   editing. Edit mode stays on one line: the UUID and pills hide, the form
   flexes and its inputs shrink instead of wrapping the row */
.user-row .row-action { display: none; }
.user-row.editing .row-action { display: inline-flex; }
.user-row.editing { flex-wrap: nowrap; }
.user-row.editing code, .user-row.editing .pill { display: none; }
.user-row .inline-form { flex: 1 1 auto; flex-wrap: nowrap; min-width: 0; }
.user-row .inline-form .cell-input { flex: 0 1 13rem; width: auto; min-width: 0; }
.user-row .inline-form .btn { flex-shrink: 0; }
.user-row.revoked .row-name, .user-row.revoked code { opacity: 0.45; }
/* closed rows in the alarm-history table */
tr.revoked td { opacity: 0.55; }

/* groups page: point/user member cards */
.member-card { display: flex; flex-direction: column; }
.member-card .inline-form { margin-top: auto; margin-bottom: 0; }
.member-card select { flex: 1; min-width: 0; }
.member-card h3 {
	margin: 0 0 0.35rem; font-size: 0.8rem; text-transform: uppercase;
	letter-spacing: 0.03em; color: var(--muted);
}
.member-list { list-style: none; padding: 0; margin: 0 0 0.75rem; }
.member-list li {
	display: flex; justify-content: space-between; align-items: center; gap: 0.5rem;
	padding: 0.15rem 0; font-weight: 600;
}

/* user api docs */
.api-docs { max-width: 760px; }
.api-docs pre {
	background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
	padding: 0.75rem 1rem; overflow-x: auto; font-size: 0.85rem; line-height: 1.45;
}
.api-docs pre code { background: none; padding: 0; font-size: inherit; }
.api-docs h2 { margin-top: 2rem; }

/* user export page */
.export-toolbar { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 1rem; }
.export-premise label { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; }
.export-premise input[type="checkbox"] { width: auto; margin: 0; accent-color: var(--accent); }
.export-points {
	display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: 0.35rem 1rem;
}

/* a premise/group rectangle that visually contains the cards belonging to it */
.premise {
	background: var(--tint); border: 1px solid var(--tint-border); border-radius: 12px;
	padding: 1rem 1.25rem; margin-bottom: 1.5rem;
}
.premise h2 { margin-top: 0; }
.premise .card { background: var(--surface); }
.card.tint { background: var(--tint); border-color: var(--tint-border); }
/* mgmt premises: point cards deeper than the premise wash so they stand out
   and the white rename input pops */
.premise .card.tint-strong { background: var(--tint-strong); border-color: var(--tint-strong-border); }

/* meter editor: each numbered stage is a card; controls that belong together
   sit in a captioned field group. .editor-toolbar remains for the JS-rendered
   per-dial / per-mask rows (meter_editor.js). */
.editor-section {
	background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
	padding: 1.1rem 1.25rem; margin-bottom: 1.5rem;
}
.editor-section > h2 { margin-top: 0; }
.editor-row { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; margin: 0.75rem 0; }
.field-group {
	display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap;
	border: 1px solid var(--border); border-radius: 10px;
	padding: 0.45rem 0.8rem 0.6rem; margin: 0; min-width: 0;
}
.field-group legend {
	font-size: 0.72rem; font-weight: 600; text-transform: uppercase;
	letter-spacing: 0.04em; color: var(--muted); padding: 0 0.35rem;
}
.editor-toolbar {
	display: flex; gap: 1rem; align-items: center; flex-wrap: wrap;
	margin: 0.6rem 0;
}
.field-group label,
.editor-toolbar label { display: flex; gap: 0.4rem; align-items: center; font-size: 0.9rem; }
.editor-canvas {
	max-width: 100%; border: 1px solid var(--border); border-radius: 12px;
	background: #111; cursor: crosshair; display: block; margin: 0 auto;
}
.tool-active { background: var(--accent); border-color: var(--accent); color: #fff; }
/* one option row per dial, all visible at once; the selected row matches
   the red outline on the canvas */
.dial-row {
	margin: 0.35rem 0; padding: 0.25rem 0.6rem;
	border: 1px solid var(--border); border-radius: 8px;
}
.dial-row.selected { border-color: #ef4444; background: var(--tint); }
#config-json { width: 100%; font-family: ui-monospace, monospace; font-size: 0.85rem; }
.debug-grid {
	display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: 1rem; margin-top: 1rem;
}
.debug-grid figure {
	margin: 0; background: var(--bg); border: 1px solid var(--border);
	border-radius: 8px; padding: 0.5rem;
}
.debug-grid img { max-width: 100%; display: block; margin: 0 auto; }
.debug-grid figcaption { font-size: 0.8rem; color: var(--muted); margin-top: 0.3rem; }
.bad-cell { color: var(--bad); font-weight: 700; }
.review-card {
	display: flex; gap: 1rem; align-items: flex-start;
	background: var(--surface); border: 1px solid var(--border);
	border-radius: 10px; padding: 0.9rem; margin-top: 1rem;
}
.review-img img { max-width: 340px; max-height: 240px; border-radius: 6px; display: block; }
.review-body { flex: 1; min-width: 240px; display: flex; flex-direction: column; gap: 0.35rem; }
.review-body .card-actions { margin-top: 0.3rem; }
.review-picks { display: flex; gap: 0.3rem; flex-wrap: wrap; margin: 0.2rem 0; border: 0; padding: 0; min-inline-size: 0; }
@media (max-width: 720px) {
	.review-card { flex-direction: column; }
	.review-img img { max-width: 100%; }
}
#test-json { max-height: 400px; overflow: auto; background: var(--bg); padding: 0.75rem; border-radius: 8px; }
