/* Wall screen: a single dark look on purpose — it runs 24/7 in an office. Sized in vw/vh
   so it fills a TV at 1080p or 4K without zoom; readable from about 3 m. */

:root {
  color-scheme: dark;
  --bg: #070c10;
  --panel: #0e171d;
  --line: #1c2a33;
  --row: #121e25;
  --ink: #dce6ec;
  --dim: #7e919e;
  --ok: #34c27e;
  --warn: #f0b429;
  --crit: #ff5a5a;
  --na: #3a4a55;
  --ap: #5db7d3;
  --cs: #b79cf0;
  --ged: #e98fb4;
  --ca: #d2a679;
  --cron: #8fd3a8;
  --bak: #7fa7ff;
  --mono: "Cascadia Mono", "JetBrains Mono", "IBM Plex Mono", Consolas, "DejaVu Sans Mono", monospace;
  --sans: "Segoe UI", "IBM Plex Sans", Roboto, "Helvetica Neue", Arial, sans-serif;
  --fs: clamp(12px, 0.9vw, 34px);
}

* { box-sizing: border-box; }
/* `display: grid` on .overlay would otherwise beat the attribute. */
[hidden] { display: none !important; }
html, body { height: 100%; margin: 0; background: var(--bg); color: var(--ink); }
body { font-family: var(--sans); font-size: var(--fs); line-height: 1.35; overflow: hidden; cursor: default; }

.wall {
  height: 100%;
  padding: 1.1em 1.3em;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 0.9em;
  transition: transform 1s ease;
}

/* ── top bar ── */
/* No flex `gap` anywhere: the wall iMac runs a Safari older than 14.1, which ignores it
   (the footer items and the host/clock came out glued together). Margins space the flex
   children instead; grid `gap` is fine there. */
.top { display: flex; align-items: center; }
.brand { font-weight: 700; font-size: 1.5em; letter-spacing: 0.08em; }
.brand, .envs { margin-right: 1.2em; }
.envs { display: flex; }
.env + .env { margin-left: 0.5em; }
.env {
  font: 500 0.95em var(--mono);
  padding: 0.35em 1em;
  border-radius: 0.4em;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--dim);
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}
.env .dot { margin-right: 0.55em; }
.env:hover { border-color: var(--dim); color: var(--ink); }
.env:focus-visible { outline: 2px solid var(--ap); outline-offset: 2px; }
.env.on { background: #12242d; border-color: var(--ap); color: var(--ink); }
.env.crit:not(.on) { border-color: var(--crit); color: var(--crit); }
.clock { margin-left: auto; display: flex; align-items: baseline; font-family: var(--mono); color: var(--dim); }
.clock .host { margin-right: 1.3em; }
.clock b { color: var(--ink); font-weight: 500; font-size: 1.4em; font-variant-numeric: tabular-nums; }

.dot { width: 0.65em; height: 0.65em; border-radius: 50%; display: inline-block; flex: none; background: var(--na); }
.dot.ok { background: var(--ok); }
.dot.warn { background: var(--warn); }
.dot.crit { background: var(--crit); animation: pulse 1.6s ease-in-out infinite; }

/* ── zones: 2 × 2 — ArturPro | Client Space on top, GED | Credit Assessment below —
   plus a right-hand column: cron jobs on top (6/10 of the height, the longer list), backups
   below (4/10). Three tracks so the column splits apart from the two halves on the left
   (5 + 5): track 1 = 5fr, track 2 = 1fr, track 3 = 4fr. ── */
.zones { display: grid; grid-template-columns: 1fr 1fr minmax(18em, 0.6fr); grid-template-rows: minmax(0, 5fr) minmax(0, 1fr) minmax(0, 4fr); gap: 0.8em; min-height: 0; }
.zone.ap { grid-column: 1; grid-row: 1; }
.zone.cs { grid-column: 2; grid-row: 1; }
.zone.ged { grid-column: 1; grid-row: 2 / span 2; }
.zone.ca { grid-column: 2; grid-row: 2 / span 2; }
.zone.cron { grid-column: 3; grid-row: 1 / span 2; grid-template-rows: auto auto minmax(0, 1fr) auto; }
.zone.bak { grid-column: 3; grid-row: 3; grid-template-rows: auto auto minmax(0, 1fr) auto; }
.zone {
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 3px solid var(--ap);
  border-radius: 0.6em;
  padding: 0.7em 0.9em;
  display: grid;
  /* The feed takes what is left; a hidden feed (no journal) leaves its row empty. */
  grid-template-rows: auto auto auto auto minmax(0, 1fr) auto;
  gap: 0.55em;
  min-height: 0;
  overflow: hidden;
}
.zone.cs { border-top-color: var(--cs); }
.zone.ged { border-top-color: var(--ged); }
.zone.ca { border-top-color: var(--ca); }
.zone.cron { border-top-color: var(--cron); }
.zone.bak { border-top-color: var(--bak); }
.zone.is-crit { border-color: var(--crit); box-shadow: 0 0 0 1px var(--crit) inset; }
.h { display: flex; align-items: baseline; }
.h h2 { margin: 0 0.8em 0 0; font-size: 1.25em; font-weight: 700; }
/* "always PROD": this zone does not follow the tabs. */
.pin { font: 500 0.75em var(--mono); text-transform: uppercase; letter-spacing: 0.06em; color: var(--ca); border: 1px solid var(--ca); border-radius: 0.3em; padding: 0.05em 0.5em; }
/* Clicking a zone's header (or its button) expands it over the whole wall. */
.h { cursor: zoom-in; }
.zoomed .h { cursor: zoom-out; }
.zoom {
  margin-left: 0.6em;
  font: 500 0.8em var(--mono);
  padding: 0.2em 0.7em;
  border-radius: 0.4em;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--dim);
  cursor: pointer;
}
.zoom:hover { border-color: var(--dim); color: var(--ink); }
.zoom:focus-visible { outline: 2px solid var(--ap); outline-offset: 2px; }
.state { margin-left: auto; font: 500 0.9em var(--mono); padding: 0.2em 0.8em; border-radius: 99px; background: rgba(126, 145, 158, 0.15); color: var(--dim); }
.state.ok { background: rgba(52, 194, 126, 0.14); color: var(--ok); }
.state.warn { background: rgba(240, 180, 41, 0.14); color: var(--warn); }
.state.crit { background: rgba(255, 90, 90, 0.18); color: var(--crit); }

.svc { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.45em; }
.tile {
  border: 1px solid var(--line);
  border-radius: 0.4em;
  padding: 0.35em 0.55em;
  display: flex;
  align-items: center;
  font: 0.85em var(--mono);
  white-space: nowrap;
  overflow: hidden;
}
.tile .lbl { overflow: hidden; text-overflow: ellipsis; }
.tile .dot { margin-right: 0.45em; }
.tile .val { margin-left: auto; padding-left: 0.45em; color: var(--dim); }
.tile.crit { border-color: rgba(255, 90, 90, 0.6); }
.tile.crit .val { color: var(--crit); }
.tile.warn .val { color: var(--warn); }
.tile.unknown { opacity: 0.6; }

.kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.5em; }
.kpi { border: 1px solid var(--line); border-radius: 0.4em; padding: 0.45em 0.6em; display: flex; flex-direction: column; }
.kpi > * + * { margin-top: 0.15em; }
.kpi .l { color: var(--dim); font-size: 0.75em; text-transform: uppercase; letter-spacing: 0.08em; }
.kpi .v { font: 500 1.6em var(--mono); font-variant-numeric: tabular-nums; }
.kpi .v.crit { color: var(--crit); }
.kpi .v.warn { color: var(--warn); }
.kpi svg { width: 100%; height: 1.3em; display: block; }
.kpi svg polyline { fill: none; stroke-width: 1.6; vector-effect: non-scaling-stroke; }
.kpi svg polygon { stroke: none; opacity: 0.18; }
.ap .kpi svg polyline { stroke: var(--ap); }
.ap .kpi svg polygon { fill: var(--ap); }
.cs .kpi svg polyline { stroke: var(--cs); }
.cs .kpi svg polygon { fill: var(--cs); }
.ged .kpi svg polyline { stroke: var(--ged); }
.ged .kpi svg polygon { fill: var(--ged); }
.ca .kpi svg polyline { stroke: var(--ca); }
.ca .kpi svg polygon { fill: var(--ca); }
.kpi.crit svg polyline { stroke: var(--crit); }
.kpi.crit svg polygon { fill: var(--crit); }
.kpi.warn svg polyline { stroke: var(--warn); }
.kpi.warn svg polygon { fill: var(--warn); }

.reasons { font-size: 0.85em; color: var(--warn); display: flex; flex-wrap: wrap; min-height: 0; }
.reasons > * { margin: 0 1.2em 0.3em 0; }
.reasons:empty { display: none; }
.reasons .crit { color: var(--crit); }

.feed { border: 1px solid var(--line); border-radius: 0.4em; overflow: hidden; display: flex; flex-direction: column; min-height: 0; }
.fh { font-size: 0.75em; text-transform: uppercase; letter-spacing: 0.08em; color: var(--dim); padding: 0.4em 0.7em; border-bottom: 1px solid var(--line); display: flex; }
.fh span:last-child { margin-left: auto; }
/* The collector sends up to 40 lines; what does not fit scrolls. A thin, dim bar so the
   wall stays calm from across the room. */
.rows { flex: 1 1 auto; overflow-x: hidden; overflow-y: auto; min-height: 0; scrollbar-width: thin; scrollbar-color: var(--na) transparent; }
.rows::-webkit-scrollbar { width: 0.5em; }
.rows::-webkit-scrollbar-track { background: transparent; }
.rows::-webkit-scrollbar-thumb { background: var(--na); border-radius: 0.25em; }
.rows::-webkit-scrollbar-thumb:hover { background: var(--dim); }
.row {
  display: grid;
  grid-template-columns: 5.2em 4.6em 6.5em minmax(0, 1fr);
  gap: 0.6em;
  padding: 0.3em 0.7em;
  font: 0.85em var(--mono);
  border-bottom: 1px solid var(--row);
  align-items: center;
}
.row.fresh { animation: flash 2.5s ease-out; }
.row .t { color: var(--dim); font-variant-numeric: tabular-nums; }
.row .mod { color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row .m { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row .x { color: var(--dim); }
.lv { font-size: 0.85em; text-transform: uppercase; padding: 0 0.4em; border-radius: 0.25em; text-align: center; }
.lv.error { background: rgba(255, 90, 90, 0.16); color: var(--crit); }
.lv.warning { background: rgba(240, 180, 41, 0.14); color: var(--warn); }
.lv.info { background: rgba(183, 156, 240, 0.14); color: var(--cs); }
.empty { padding: 0.8em; color: var(--dim); font-size: 0.85em; }

/* ── cron jobs column: the column is tall and narrow, so a job takes two lines —
   name and state, then duration and age — rather than truncating its name ── */
.cron-sum { font: 500 1.6em var(--mono); font-variant-numeric: tabular-nums; }
.cron-sum.crit { color: var(--crit); }
.cron-sum.warn { color: var(--warn); }
.crow {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: 0.5em;
  row-gap: 0.1em;
  padding: 0.35em 0.7em;
  font: 0.85em var(--mono);
  border-bottom: 1px solid var(--row);
  align-items: center;
}
.crow .n { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crow .meta { grid-column: 2 / -1; display: flex; color: var(--dim); font-size: 0.9em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.crow .meta .a { margin-left: auto; padding-left: 0.8em; }
.crow .st { min-width: 3.4em; font-size: 0.85em; text-align: center; padding: 0 0.3em; border-radius: 0.25em; background: rgba(52, 194, 126, 0.14); color: var(--ok); }
.crow.warn .st { background: rgba(240, 180, 41, 0.14); color: var(--warn); }
.crow.crit .st { background: rgba(255, 90, 90, 0.16); color: var(--crit); }
.crow.crit .n { color: var(--crit); }
/* Nobody hovers a wall screen: why a job is red or amber is written under it. */
.crow .why { grid-column: 2 / -1; font-size: 0.85em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--warn); }
.crow.crit .why { color: var(--crit); }

/* ── backups: the schedule sits next to the "3/3 OK" — it is what LATE is measured against ── */
.bak-sum { display: flex; align-items: baseline; flex-wrap: wrap; }
.bak-sum .cron-sum { margin-right: 0.8em; }
.bak-sum .sched { font: 0.8em var(--mono); color: var(--dim); }
.bak-sum .sched .nx { margin-left: 0.8em; color: var(--ink); }
.bak .crow .meta .d { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ── one zone expanded: the others step aside, messages are shown whole ── */
.zones.has-zoom > .zone:not(.zoomed) { display: none; }
.zones.has-zoom > .zone.zoomed { grid-column: 1 / -1; grid-row: 1 / -1; }
.zone.zoomed .svc { grid-template-columns: repeat(auto-fill, minmax(14em, 1fr)); }
.zone.zoomed .row { grid-template-columns: 5.2em 4.6em 12em minmax(0, 1fr); align-items: start; }
.zone.zoomed .row .m { white-space: normal; overflow-wrap: anywhere; }
.zone.zoomed .crow .n, .zone.zoomed .crow .why { white-space: normal; overflow-wrap: anywhere; }
.zone.cron.zoomed .rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(26em, 1fr)); align-content: start; }

.notice { align-self: start; border: 1px dashed var(--na); border-radius: 0.4em; padding: 0.55em 0.7em; color: var(--dim); font-size: 0.85em; }

/* ── footer ── */
/* Read from across the room: full ink and full size, not the dim grey of secondary labels. */
.bottom { display: flex; align-items: center; font: 1em var(--mono); color: var(--ink); border-top: 1px solid var(--line); padding-top: 0.6em; }
.items { display: flex; flex-wrap: wrap; min-width: 0; margin-bottom: -0.3em; }
.item { display: inline-flex; align-items: center; white-space: nowrap; margin: 0 1.6em 0.3em 0; }
.item .dot { margin-right: 0.45em; }
.item.crit { color: var(--crit); }
.item.warn { color: var(--warn); }
.fresh { margin-left: auto; padding-left: 1.2em; color: var(--ok); white-space: nowrap; }

/* ── stale data: the whole screen says so ── */
.wall.stale .zones { opacity: 0.45; filter: grayscale(0.6); }
.wall.stale .fresh { color: var(--warn); font-weight: 700; }
.wall.stale { box-shadow: inset 0 0 0 6px var(--warn); }

.overlay { position: fixed; top: 0; right: 0; bottom: 0; left: 0; display: grid; place-items: center; background: rgba(7, 12, 16, 0.88); }
.overlay-box { max-width: 42em; border: 1px solid var(--warn); border-radius: 0.6em; padding: 1.5em 2em; background: var(--panel); }
.overlay-box h2 { margin: 0 0 0.4em; color: var(--warn); }
.overlay-box p { margin: 0; color: var(--ink); }

@keyframes pulse { 50% { opacity: 0.35; } }
@keyframes flash { from { background: rgba(93, 183, 211, 0.22); } to { background: transparent; } }

@media (prefers-reduced-motion: reduce) {
  .dot.crit, .row.fresh { animation: none; }
  .wall { transition: none; }
}

/* A laptop or a small window: stack the zones rather than shrink them. */
@media (max-width: 900px) {
  body { overflow: auto; }
  .wall { height: auto; min-height: 100%; }
  .zones { grid-template-columns: 1fr; grid-template-rows: none; }
  .zones > .zone { grid-column: auto; grid-row: auto; }
  .zone .feed { min-height: 12em; }
  .svc, .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .top { flex-wrap: wrap; }
}
