/* The app (index.html): every rule of its layout.
 *
 * The look is the display's - its wallpaper, its materials, its colours, its
 * typographies and symbols (styles/tokens.css, overrides.css, typography.css,
 * components/icon.css, components/gauge.css are loaded before this file) -
 * and none of its geometry: nothing here is placed by the pixel. The shell is
 * a grid that follows the window, a page is a column of blocks that scrolls
 * natively, tiles stand in a grid that takes as many columns as there is
 * room for, and text is the browser's.
 *
 *   upright   header / page / navigation along the foot
 *   across    navigation as a column on the left / header and page beside it
 *
 * The measures that are the app's own stand here at the top. */

:root {
  --gutter: 16px;               /* between the window's edge and a page's content */
  --block-gap: 12px;            /* between two cards, two rows of tiles' blocks */
  --tile-min: 104px;            /* a tile is never narrower; the grid takes as many as fit */
  --tile-gap: 10px;
  --tile-pad: 12px;
  --page-max: 980px;            /* a page's content on a very wide window */
  --nav-button-w: 54px;
  --nav-button-h: 46px;
  --control-h: 44px;            /* what a finger needs */
  --row-h: 56px;

  /* what the phone reports, and over it the distance chosen in Darstellung /
   * Abstand zum Rand (--edge, set by main.js): at the top and at the foot */
  --safe-t: calc(env(safe-area-inset-top, 0px) + var(--edge, 0px));
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: calc(env(safe-area-inset-bottom, 0px) + var(--edge, 0px));
  --safe-l: env(safe-area-inset-left, 0px);
}

/* ------------------------------------------------------------------ reset */

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

[hidden] { display: none !important; }

html {
  height: 100%;
  background: var(--color-page);
}

body {
  position: fixed;
  inset: 0;
  margin: 0;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--wallpaper);
  color: var(--color-ink);
  font: 400 16px/20px var(--font-family);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  /* an app has no text selection, no callouts, no tap flash */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, p { margin: 0; font: inherit; }

button {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.icon {
  display: inline-block;
  flex: none;
  width: 24px;
  height: 24px;
}

/* the display's battery, standing in a row instead of at a place */
.battery {
  position: relative;
  flex: none;
  width: var(--w);
  height: var(--h);
}

/* ------------------------------------------------------------- the shell */

.app {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-areas: "top" "page" "nav";
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-columns: minmax(0, 1fr);
}

.top  { grid-area: top; }
.page { grid-area: page; }
.nav  { grid-area: nav; }

/* The distance kept from the foot (Darstellung / Abstand zum Rand) is black,
 * as the glass's own edge is: on a wallpaper it would read as a strip of the
 * page that nothing is in. Over the navigation and a sheet, under the way in,
 * and it takes no finger. */
.app::after {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 15;
  height: var(--edge, 0px);
  background: #000000;
  pointer-events: none;
}

@media (orientation: landscape) {
  .app {
    grid-template-areas: "nav top" "nav page";
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-columns: auto minmax(0, 1fr);
  }
}

/* --- the navigation: along the foot ... */
.nav {
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: 4px;
  padding: 6px calc(8px + var(--safe-r)) calc(6px + var(--safe-b)) calc(8px + var(--safe-l));
  background: var(--material-bar);
  -webkit-backdrop-filter: var(--blur-material);
  backdrop-filter: var(--blur-material);
  border-top: 1px solid var(--color-divider);
}

/* ... or as a column on the left */
@media (orientation: landscape) {
  .nav {
    flex-direction: column;
    justify-content: flex-start;
    gap: 6px;
    padding: calc(10px + var(--safe-t)) 8px calc(10px + var(--safe-b)) calc(8px + var(--safe-l));
    border-top: 0;
    border-right: 1px solid var(--color-divider);
    overflow-y: auto;
    scrollbar-width: none;
  }
}

.nav-button {
  display: grid;
  place-items: center;
  flex: none;
  width: var(--nav-button-w);
  height: var(--nav-button-h);
  border-radius: 14px;
  color: var(--color-ink);
  transition: background-color 0.2s, color 0.2s;
}

.nav-button > .icon { width: 28px; height: 28px; }

.nav-button.active {
  background: var(--color-accent);
  color: var(--color-on-accent);
}

.nav-button:active { filter: var(--press); }

/* --- the header: the page's name, and what the vehicle says of itself */
.top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 2px 12px;
  min-height: 60px;
  padding: calc(8px + var(--safe-t)) calc(var(--gutter) + var(--safe-r)) 8px var(--gutter);
  transition: background-color 0.2s;
}

@media (orientation: portrait) {
  .top { padding-left: calc(var(--gutter) + var(--safe-l)); }
}

.top-name {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  min-height: 40px;
}

.top-title {
  overflow: hidden;
  font: 600 24px/30px var(--font-family);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.top-back {
  display: grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  margin-left: -10px;
  border-radius: 50%;
}

.top-back:active { background: var(--color-recess); }



.top-status {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  min-width: 0;
}

.top-icons {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.top-icons > .icon { width: 22px; height: 22px; }

.status-flame       { color: var(--color-heater-flame); }
.status-lamp        { color: var(--color-lamp-lit); }
.status-plug        { color: var(--color-on-grid); }
.status-bluetooth   { color: var(--color-bluetooth); }
.status-thermometer { width: 20px; height: 20px; color: var(--color-thermometer); }

.top-banner {
  overflow: hidden;
  color: var(--color-muted);
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.top-reading {
  display: flex;
  align-items: baseline;
  flex: none;
  gap: 4px;
  white-space: nowrap;
}

.top-reading > .icon,
.top-reading > .battery { align-self: center; }

.temp-inside, .voltage { font: 600 20px/24px var(--font-family); }
.temp-slash, .temp-outside { color: var(--color-muted); }
.voltage { margin-right: 2px; }

/* A narrow window: the readings are a strip of their own over the name. */
@media (max-width: 599px) {
  .top { grid-template-columns: minmax(0, 1fr); }
  .top-status { order: -1; }
  .top-icons { margin-right: auto; }
  .temp-inside, .voltage { font-size: 17px; }
  .temp-slash, .temp-outside { font-size: 14px; }
}

/* an alarm standing: the header wears its ground */
.top[data-status="alarm"] {
  --color-ink: var(--on-alarm-active);
  --color-muted: color-mix(in srgb, var(--on-alarm-active) 82%, transparent);
  --color-thermometer: var(--on-alarm-active);
  background: var(--alarm-active);
  color: var(--color-ink);
}

/* an alarm that has ended and is not acknowledged yet: the same, in yellow */
.top[data-status="alarm-ended"] {
  --color-ink: var(--on-alarm-resolved);
  --color-muted: color-mix(in srgb, var(--on-alarm-resolved) 72%, transparent);
  --color-thermometer: var(--on-alarm-resolved);
  background: var(--alarm-resolved);
  color: var(--color-ink);
}

/* --- the page: the one area that scrolls */
.page {
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 6px calc(var(--gutter) + var(--safe-r)) 28px var(--gutter);
}

@media (orientation: portrait) {
  .page { padding-left: calc(var(--gutter) + var(--safe-l)); }
}

/* across, the page reaches the foot of the glass itself */
@media (orientation: landscape) {
  .page { padding-bottom: calc(28px + var(--safe-b)); }
}

.page-body {
  display: flex;
  flex-direction: column;
  gap: var(--block-gap);
  max-width: var(--page-max);
  margin: 0 auto;
}

.heading {
  margin-top: 8px;
  font: 600 16px/22px var(--font-family);
}

.heading:first-child { margin-top: 0; }

.note {
  padding: 2px;
  color: var(--color-muted);
  font-size: 15px;
}

.note.said { color: var(--color-ink); }

.foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--block-gap);
}

/* ------------------------------------------------------------------ tiles */

.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--tile-min), 1fr));
  gap: var(--tile-gap);
}

/* One build for all of them: badge top left, two lines bottom left, a level
 * or a graph behind. Frosted while off, solid while on. */
.tile {
  --kind: var(--color-accent);
  --ink: var(--tile-ink-off);
  --quiet: var(--tile-muted-off);
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  aspect-ratio: 1;
  min-width: 0;
  overflow: hidden;
  padding: var(--tile-pad);
  border-radius: var(--tile-radius);
  background-color: var(--material-off);
  color: var(--ink);
  /* upright is the page's, sideways the tile's (dom.js, press) */
  touch-action: pan-y;
  transition: background-color 0.2s, box-shadow 0.2s, filter 0.1s;
}

.tile.on {
  --ink: var(--tile-ink-on);
  --quiet: var(--tile-muted-on);
  background-color: var(--material-on);
  box-shadow: var(--shadow-on);
}

.tile.reading {
  --ink: var(--color-ink);
  --quiet: var(--color-muted);
  background-color: var(--material-info);
}

.tile.pressed { filter: var(--press); }
.tile.opens { cursor: pointer; }

.tile.mixed { box-shadow: inset 0 0 0 2px var(--color-accent); }

/* what is on a tile lies over what is behind it */
.tile > :is(.badge, .tile-text) { position: relative; }

.badge {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background-color: var(--badge-off);
  color: var(--color-muted);
  transition: background-color 0.2s, color 0.2s;
}

.badge > .icon { width: 20px; height: 20px; }

.tile > .badge { color: var(--quiet); }

/* lit: a control that is on, and every reading */
.tile.on > .badge,
.tile.reading > .badge,
.card .reading-head > .badge {
  background-color: var(--kind);
  color: #ffffff;
}

.tile-text { min-width: 0; }

/* A name may take two lines: whole words where they fit, a long one hyphenated. */
.tile-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font: 600 14px/18px var(--font-family);
  overflow-wrap: break-word;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.tile-status,
.tile-title {
  overflow: hidden;
  color: var(--quiet);
  font: 400 14px/18px var(--font-family);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.tile-value {
  overflow: hidden;
  font: 600 22px/28px var(--font-family);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* the level behind a light or a motor: across, as far as it is set */
.tile-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--level, 0) * 100%);
  background-color: color-mix(in srgb, var(--kind) 36%, transparent);
  opacity: 0;
  transition: opacity 0.2s;
}

:is(.dimmer-tile, .motor-tile).on > .tile-fill { opacity: 1; }

/* never plain white while on: the colour lies faintly over the whole tile */
:is(.dimmer-tile, .motor-tile).on {
  background-image: linear-gradient(color-mix(in srgb, var(--kind) 22%, transparent), color-mix(in srgb, var(--kind) 22%, transparent));
}

/* a switch that is on is lit all over */
.toggle-tile.on {
  background-image: linear-gradient(color-mix(in srgb, var(--kind) 36%, transparent), color-mix(in srgb, var(--kind) 36%, transparent));
}

/* a light is lit in its own colour when it has one (tiles.js, --tile-tint) */
.dimmer-tile { --kind: var(--tile-tint, var(--color-light-border)); }

/* the level behind a reading: from the foot */
.level-tile > .tile-fill {
  inset: auto 0 0 0;
  width: auto;
  height: calc(var(--level, 0) * 100%);
  background-color: color-mix(in srgb, var(--kind) 34%, transparent);
  opacity: 1;
  transition: height 0.3s;
}

[data-kind="power"]       { --kind: var(--color-power-border); }
[data-kind="temperature"] { --kind: var(--color-temp-border); }
[data-kind="water"]       { --kind: var(--color-water-border); }
[data-kind="waste"]       { --kind: var(--color-waste-border); }
[data-kind="light"]       { --kind: var(--color-light-border); }
.tilt-tile                { --kind: var(--color-tilt-border); }

.graph > path {
  fill: var(--kind, var(--color-accent));
  fill-opacity: 0.22;
}

.tile-graph,
.card-graph {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* the three dots in a tile's corner */
.tile-more {
  position: absolute;
  top: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 44px;
  height: 40px;
  color: var(--quiet);
}

.tile-more > span {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
}

.tile-more:active { color: var(--ink); }

/* shown, not operated: everything fades but the line that says why */
.tile.unusable > :is(.badge, .tile-fill, .tile-more),
.tile.unusable .tile-name {
  opacity: var(--disabled-opacity);
}

/* the round level */
.vial {
  --vial-colour: var(--color-tilt-border);
  position: relative;
  aspect-ratio: 1;
  border: 2px solid var(--vial-colour);
  border-radius: 50%;
  background: color-mix(in srgb, var(--vial-colour) 10%, transparent);
}

.vial[data-state="level"]   { --vial-colour: var(--color-confirm); }
.vial[data-state="unknown"] { --vial-colour: var(--color-inactive); }

.vial-ring,
.vial-bubble {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.vial-ring {
  width: 34%;
  height: 34%;
  border: 1.5px solid var(--vial-colour);
}

.vial-bubble {
  left: calc(50% + var(--dx, 0) * 50%);
  top: calc(50% + var(--dy, 0) * 50%);
  width: 22%;
  height: 22%;
  background: var(--vial-colour);
  transition: left 0.2s, top 0.2s;
}

.vial-tick {
  position: absolute;
  background: var(--vial-colour);
}

.vial-tick-n, .vial-tick-s { left: calc(50% - 1.5px); width: 3px; height: 11%; }
.vial-tick-e, .vial-tick-w { top: calc(50% - 1.5px); height: 3px; width: 11%; }
.vial-tick-n { top: 3%; }
.vial-tick-s { bottom: 3%; }
.vial-tick-e { right: 3%; }
.vial-tick-w { left: 3%; }

.tile-vial {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 38%;
  border-width: 1.5px;
}

/* ------------------------------------------------------- cards and rows */

.card {
  position: relative;
  min-width: 0;
  padding: 2px var(--gutter);
  border-radius: var(--card-radius);
  background-color: var(--material-info);
}

.card-title {
  padding: 14px 0 6px;
  font: 600 16px/22px var(--font-family);
}

.card-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--block-gap);
}

.card-pair.top { align-items: start; }

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;              /* a value too long for its row (a serial number) goes under its name */
  gap: 4px 12px;
  width: 100%;
  min-height: var(--row-h);
  padding: 6px 0;
  text-align: left;
}

.row + .row { border-top: 1px solid var(--color-divider); }

.row-label {
  flex: 1 1 0;                  /* a long name takes a second line before the row does */
  min-width: 0;
}

.row-value {
  min-width: 0;
  font-weight: 600;
  text-align: right;
  overflow-wrap: anywhere;
}

.row-stacked {
  flex-direction: column;
  align-items: flex-start;
  padding: 14px 0;
}

/* ---------------------------------------------------------------- controls */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  height: var(--control-h);
  padding: 0 18px;
  border-radius: var(--control-radius);
  font: 600 16px/20px var(--font-family);
  white-space: nowrap;
  transition: background-color 0.2s, filter 0.1s;
}

.button.neutral { background: var(--color-neutral); color: var(--color-on-neutral); }
.button.recess  { background: var(--color-recess); color: var(--color-ink); }
.button.accent  { background: var(--color-accent); color: var(--color-on-accent); }
.button.wide    { flex: 1 1 auto; max-width: 360px; }
.button.running { background: var(--color-alarm); color: #ffffff; }
.button:active  { filter: var(--press); }
.button:disabled { opacity: var(--disabled-opacity); }

/* a choice of few: a recessed track, the part in force a lifted patch */
.segmented {
  display: inline-flex;
  flex: none;
  padding: var(--segment-inset);
  border-radius: var(--control-radius);
  background: var(--color-recess);
}

.segment {
  min-width: 60px;
  height: calc(var(--control-h) - 2 * var(--segment-inset));
  padding: 0 14px;
  border-radius: calc(var(--control-radius) - var(--segment-inset));
  font: 600 15px/20px var(--font-family);
  white-space: nowrap;
  transition: background-color 0.2s;
}

.segment.on {
  background: var(--segment-on);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.14);
}

.stepper {
  display: flex;
  align-items: center;
  flex: none;
  gap: 8px;
}

.stepper-value {
  min-width: 70px;
  font-weight: 600;
  text-align: right;
  white-space: nowrap;
}

.stepper-button {
  width: var(--control-h);
  padding: 0;
  font-size: 20px;
}

.switch {
  position: relative;
  flex: none;
  width: 52px;
  height: 32px;
  border-radius: 16px;
  background: var(--color-recess);
  transition: background-color 0.2s;
}

.switch.on { background: var(--color-confirm); }

.switch-knob {
  position: absolute;
  left: 3px;
  top: 3px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);
  transition: transform 0.2s var(--ease);
}

.switch.on > .switch-knob { transform: translateX(20px); }

/* a choice of many: the platform's own picker behind a field of ours */
.picker {
  position: relative;
  display: inline-flex;
  flex: 0 1 auto;
  min-width: 150px;
}

.picker-field {
  width: 100%;
  height: var(--control-h);
  margin: 0;
  padding: 0 40px 0 14px;
  border: 0;
  border-radius: var(--control-radius);
  background: var(--color-recess);
  color: var(--color-ink);
  font: 600 16px/20px var(--font-family);
  -webkit-appearance: none;
  appearance: none;
}

.picker-arrow {
  position: absolute;
  right: 10px;
  top: calc(50% - 10px);
  width: 20px;
  height: 20px;
  color: var(--color-muted);
  pointer-events: none;
}

/* a band with a grip: the value is where the finger is */
.slider {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  height: var(--control-h);
  overflow: hidden;
  border-radius: var(--control-radius);
  background: var(--color-recess);
  touch-action: none;
  transition: opacity 0.2s;
}

.slider-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(min(var(--from, 0), var(--at, 0)) * 100%);
  width: calc((max(var(--from, 0), var(--at, 0)) - min(var(--from, 0), var(--at, 0))) * 100%);
  background: var(--color-accent);
}

.slider-grip {
  position: absolute;
  top: 5px;
  bottom: 5px;
  left: clamp(3px, calc(var(--at, 0) * 100% - 3px), calc(100% - 9px));
  width: 6px;
  border-radius: 3px;
  background: #ffffff;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.22), 0 1px 3px rgb(0 0 0 / 0.3);
}

.slider-hue { background: linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000); }
.slider-cct { background: linear-gradient(to right, rgb(255 170 90), rgb(205 225 255)); }   /* LightPreview::rgbForCct, 0 and 100 */
:is(.slider-hue, .slider-cct) > .slider-fill { display: none; }
.slider.faded { opacity: 0.35; }

/* ------------------------------------------------------------------ sheets */

.overlay {
  position: absolute;
  inset: 0;
  z-index: 10;
  pointer-events: none;
}

.sheet {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: auto;
}

.sheet-shade {
  position: absolute;
  inset: 0;
  background: var(--shade);
  -webkit-backdrop-filter: var(--blur-shade);
  backdrop-filter: var(--blur-shade);
  animation: shade-in 0.2s;
}

.sheet-panel {
  position: relative;
  width: 100%;
  max-width: 560px;
  max-height: calc(100% - var(--safe-t) - 12px);
  overflow-y: auto;
  padding: 18px calc(18px + var(--safe-r)) calc(22px + var(--safe-b)) calc(18px + var(--safe-l));
  border-radius: var(--sheet-radius) var(--sheet-radius) 0 0;
  background: var(--material-sheet);
  -webkit-backdrop-filter: var(--blur-material);
  backdrop-filter: var(--blur-material);
  box-shadow: var(--shadow-sheet);
  animation: sheet-up 0.28s var(--ease);
}

/* a wider window, or a phone held across: the sheet stands in the middle */
@media (orientation: landscape), (min-width: 600px) {
  .sheet { align-items: center; }
  .sheet-panel {
    max-height: calc(100% - 16px - var(--safe-t) - var(--safe-b));
    padding: 18px;
    border-radius: var(--sheet-radius);
    animation-name: sheet-in;
  }
}

@keyframes shade-in { from { opacity: 0; } }
@keyframes sheet-up { from { transform: translateY(100%); } }
@keyframes sheet-in { from { opacity: 0; transform: scale(0.96); } }

/* the grip a sheet is drawn down by (sheets.js), and the head it belongs to */
.sheet-grip {
  width: 40px;
  height: 5px;
  margin: -8px auto 10px;
  border-radius: 3px;
  background: var(--color-inactive);
}

.sheet-panel { transition: transform 0.25s var(--ease); }
.sheet-panel.dragging { transition: none; }

.sheet-head {
  touch-action: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--control-h);
}

.sheet-title {
  min-width: 0;
  overflow: hidden;
  font: 600 20px/24px var(--font-family);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 6px;
  margin-top: 14px;
}

.sheet-label {
  color: var(--color-muted);
  font-size: 14px;
}

.sheet-control {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.sheet-control > .picker { flex: 1 1 auto; }

.sheet-value {
  flex: none;
  min-width: 58px;
  font-weight: 600;
  text-align: right;
}

.sheet-note {
  min-height: 20px;
  margin-top: 12px;
  color: var(--color-muted);
}

@media (orientation: landscape), (min-width: 600px) {
  .sheet-row {
    grid-template-columns: 140px minmax(0, 1fr);
    align-items: center;
    gap: 12px;
  }
  .sheet-label { font-size: 16px; }
}


/* ----------------------------------------------------------------- pages */

/* --- a reading in full: power's total, a temperature probe */
.reading-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 28px;
  min-height: 150px;
  overflow: hidden;
  padding: 14px var(--gutter);
}

.reading-head,
.reading-foot { position: relative; display: flex; }

.reading-head { align-items: center; gap: 10px; min-width: 0; }
.reading-foot { align-items: flex-end; justify-content: space-between; gap: 12px; }

.reading-title {
  overflow: hidden;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.reading-value { font: 600 34px/40px var(--font-family); white-space: nowrap; }

.reading-side { display: flex; gap: 20px; }

.stat { display: flex; flex-direction: column; align-items: flex-end; }
.stat-label { color: var(--color-muted); font-size: 14px; }
.stat-value { font: 600 20px/24px var(--font-family); white-space: nowrap; }

/* --- power: every device on a line of its own */
.power-list { --kind: var(--color-power-border); }

.power-row {
  display: grid;
  grid-template-columns: minmax(110px, 1.4fr) minmax(40px, 1fr) 78px;
  align-items: center;
  gap: 12px;
  min-height: var(--row-h);
  padding: 6px 0;
}

.power-row + .power-row { border-top: 1px solid var(--color-divider); }

.power-name { overflow: hidden; font-weight: 600; white-space: nowrap; text-overflow: ellipsis; }
.power-detail { color: var(--color-muted); font-size: 14px; white-space: nowrap; }
.power-spark { width: 100%; height: 26px; }
.power-spark > path { fill-opacity: 0.45; }
.power-watts { font: 600 20px/24px var(--font-family); text-align: right; white-space: nowrap; }

/* --- water: a tank as a vessel with a scale to read the level off */
.tank-card {
  display: flex;
  gap: 8px;
  padding: 14px var(--gutter);
}

.tank-words {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
}

.tank-caption { min-height: 20px; color: var(--color-muted); }

.tank-vessel,
.tank-scale {
  position: relative;
  flex: none;
  height: clamp(110px, 44vh, 190px);
}

.tank-vessel {
  width: 64px;
  overflow: hidden;
  border-radius: 20px;
  background: var(--color-recess);
}

.tank-level {
  position: absolute;
  inset: auto 0 0 0;
  height: calc(var(--level, 0) * 100%);
  background: var(--kind);
  transition: height 0.3s;
}

.tank-card.unknown .tank-level { height: 0; }

.tank-scale { width: 34px; }

.tank-mark {
  position: absolute;
  left: 0;
  bottom: calc(var(--at) * 100%);
  display: flex;
  align-items: center;
  gap: 4px;
  height: 0;
  color: var(--color-muted);
  font-size: 12px;
}

.tank-mark::before {
  content: "";
  width: 6px;
  height: 1.5px;
  background: var(--color-inactive);
}

/* --- level: the vehicles in their dials, or the vial */
.choice-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--block-gap);
}

.level-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px var(--gutter);
}

.dial,
.level-vial {
  width: min(100%, 230px, 42vh);
}

.dial {
  position: relative;
  aspect-ratio: 1;
}

.dial-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  color: var(--color-inactive);
}

/* the vehicle's canvas (140 x 125) as wide as the dial and in the middle of it */
.dial-vehicle {
  position: absolute;
  left: 0;
  top: calc((100% - 100% * 125 / 140) / 2);
  width: 100%;
  height: calc(100% * 125 / 140);
  transform: rotate(var(--lean, 0deg));
  transition: transform 0.2s;
}

.level-card.unknown .dial-vehicle { color: var(--color-inactive); }

/* The drawings, named here as images and not through --icon-image: a url() in
 * a custom property is resolved against this file by one browser and against
 * the file that uses it (components/icon.css) by another. */
.icon-scale-ring {
  -webkit-mask: url("../core/icons/scale_ring.svg") center / contain no-repeat;
  mask: url("../core/icons/scale_ring.svg") center / contain no-repeat;
}
.icon-van-rear {
  -webkit-mask: url("../core/icons/van_rear.svg") center / contain no-repeat;
  mask: url("../core/icons/van_rear.svg") center / contain no-repeat;
}
.icon-van-side {
  -webkit-mask: url("../core/icons/van_side.svg") center / contain no-repeat;
  mask: url("../core/icons/van_side.svg") center / contain no-repeat;
}

.level-values { display: flex; gap: 28px; }

.level-value {
  font: 600 28px/36px var(--font-family);
  white-space: nowrap;
  transition: color 0.2s;
}

.level-value.is-level { color: var(--color-confirm); }

/* --- heating */
.heater-head { gap: 12px; }
.heater-words { flex: 1 1 auto; min-width: 0; }
.heater-state { font-weight: 600; }
.heater-detail { color: var(--color-muted); font-size: 14px; }
.heater-badge.on { background-color: var(--color-heater-flame); color: #ffffff; }

/* --- settings: the list */
.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--block-gap);
}

.settings-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 104px;
  padding: 14px 10px;
  border-radius: var(--tile-radius);
  background: var(--material-off);
  font-size: 15px;
  text-align: center;
  transition: filter 0.1s;
}

.settings-tile > .icon { width: 36px; height: 36px; color: var(--color-accent); }
.settings-tile:active { filter: var(--press); }

/* --- settings: the accent */
.swatches { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; }

.swatch {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--swatch);
  transition: box-shadow 0.2s;
}

.swatch.picked { box-shadow: 0 0 0 3px var(--material-on), 0 0 0 5.5px var(--swatch); }

/* --- settings: the menu's entries */
.menu-row { justify-content: flex-start; }
.menu-row-icon { margin-right: 4px; }

.check {
  display: grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border: 2px solid var(--color-inactive);
  border-radius: 9px;
  transition: background-color 0.2s, border-color 0.2s;
}

.check > .icon { width: 18px; height: 18px; color: var(--color-on-accent); opacity: 0; }
.checked > .check { border-color: var(--color-accent); background: var(--color-accent); }
.checked > .check > .icon { opacity: 1; }

/* --- settings: the clock's fields */
.columns {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 6px;
  padding: 6px 0 14px;
}

.stepper-column {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.column-button { width: 60px; padding: 0; }

.column-value,
.column-mark { font: 600 28px/36px var(--font-family); }

.column-mark { margin-top: calc(var(--control-h) + 6px); }
.column-caption { color: var(--color-muted); font-size: 13px; }

/* ------------------------------------------------- title lines, switch rows */

/* A title and, in its line, what is wrong with the thing it is about
 * (components/title-line.js, the rule): the status keeps its words, quiet;
 * the title gives way and ends in an ellipsis. */
.title-line {
  display: flex;
  align-items: baseline;
  gap: 12px;                    /* --title-status-gap */
  min-width: 0;
}

.title-line > :first-child {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.title-status {
  flex: none;
  color: var(--color-muted);
  font: 400 16px/20px var(--font-family);
  white-space: nowrap;
}

.sheet-head > .title-line { flex: 1 1 auto; }

/* A row with a switch at its right end is one touch target (switchRow): the
 * switch darkens wherever on the row the finger is. */
.switch-row {
  cursor: pointer;
}

.switch-row:active > .switch { filter: var(--press); }
.switch-row:disabled { opacity: var(--disabled-opacity); }
.switch-row > .row-label { text-align: left; }
.sheet-body > .switch-row { margin-top: 10px; }

/* --- the controls page: the bar over it, and choosing the favourites */
.choice-bar.end { justify-content: flex-end; }
.choice-bar.choosing { align-items: center; }

.choice-count {
  font-weight: 600;
  color: var(--color-muted);
}

.choice-count.said { color: var(--color-ink); }

.page-blocks {
  display: flex;
  flex-direction: column;
  gap: var(--block-gap);
}

/* while choosing, a tile is not operated: what lies over it takes the finger */
.pick {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 8px;
  border-radius: inherit;
  touch-action: pan-y;
}

.pick::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 2px transparent;
  transition: box-shadow 0.2s;
}

.pick.picked::after { box-shadow: inset 0 0 0 3px var(--color-accent); }

.pick-number {
  display: grid;
  place-items: center;
  min-width: 30px;
  height: 30px;
  padding: 0 6px;
  border: 2px solid var(--color-inactive);
  border-radius: 15px;
  background: var(--material-info);
  font: 600 16px/20px var(--font-family);
}

.pick.picked > .pick-number {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-on-accent);
}

/* --- the battery voltages: the whole of it on one scale */
.battery-scale {
  --scale-band-y: 41px;
  --scale-band-h: 14px;
  position: relative;
  height: 92px;
  margin: 4px 0;
}

.battery-scale > * { position: absolute; }

.scale-symbol {
  top: 14px;
  transition: left 0.25s var(--ease);
}

.scale-band {
  left: 0;
  top: var(--scale-band-y);
  width: 100%;
  height: var(--scale-band-h);
  overflow: hidden;
  border-radius: calc(var(--scale-band-h) / 2);
}

.scale-zone,
.scale-tick {
  position: absolute;
  top: 0;
  height: 100%;
  transition: left 0.25s var(--ease), width 0.25s var(--ease);
}

.zone-0 { background-color: var(--color-alarm); }
.zone-1 { background-color: var(--color-battery-low); }
.zone-2 { background-color: color-mix(in srgb, var(--color-battery-full) 55%, #ffe14d); }
.zone-3 { background-color: var(--color-battery-full); }

.scale-tick {
  width: 1px;
  background-color: rgb(255 255 255 / 0.7);
}

.scale-label {
  top: 62px;
  width: 44px;
  color: var(--color-muted);
  font-size: 12px;
  line-height: 16px;
  text-align: center;
  transition: left 0.25s var(--ease);
}

.scale-now {
  top: calc(var(--scale-band-y) - 4px);
  width: 4px;
  height: calc(var(--scale-band-h) + 8px);
  margin-left: -2px;
  border-radius: 2px;
  background-color: #ffffff;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.18), 0 1px 4px rgb(0 0 0 / 0.3);
  transition: left 0.25s var(--ease);
}

.scale-now-label {
  color: var(--color-ink);
  font-weight: 600;
}

/* --- the alarm's sheet: red while it stands, yellow once it has ended */
.alarm-sheet { --state: var(--alarm-active); --on-state: var(--on-alarm-active); --state-ink: var(--alarm-active-ink); }
.alarm-sheet[data-standing="no"] { --state: var(--alarm-resolved); --on-state: var(--on-alarm-resolved); --state-ink: var(--alarm-resolved-ink); }
.alarm-sheet .sheet-head { display: none; }

.alarm-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.alarm-plate {
  display: grid;
  place-items: center;
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: 14px;
  background: var(--state);
  color: var(--on-state);
}

.alarm-plate > .icon { width: 28px; height: 28px; }

.alarm-words { flex: 1 1 auto; min-width: 0; }
.alarm-title { font: 600 20px/26px var(--font-family); }
.alarm-state { color: var(--state-ink); font-weight: 600; }
.alarm-where { margin-top: 2px; color: var(--color-muted); }
.alarm-more { flex: none; color: var(--color-muted); white-space: nowrap; }

.alarm-card {
  margin-top: 16px;
  padding: 4px 16px;
  border-radius: var(--card-radius);
  background: var(--material-info);
}

.alarm-figures {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px 28px;
  padding: 12px 0;
  border-bottom: 1px solid var(--color-divider);
}

.alarm-figure { display: flex; flex-direction: column; }
.alarm-caption { color: var(--color-muted); font-size: 14px; }
.alarm-figure-value { font: 600 24px/30px var(--font-family); white-space: nowrap; }
.alarm-reading > .alarm-figure-value { font-size: 34px; line-height: 40px; }

.alarm-foot {
  display: flex;
  gap: 12px;
  margin-top: 16px;
}

.alarm-foot > .button { flex: 1 1 0; min-width: 0; padding: 0 12px; }

/* while choosing, the three dots are not a way anywhere */
.choosing .tile-more { visibility: hidden; }

/* --- bluetooth: the field a new PIN is typed in, on the phone's keyboard */
.pin-entry {
  display: flex;
  gap: 12px;
  width: 100%;
  margin-top: 10px;
}

.pin-field {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--control-h);
  margin: 0;
  padding: 0 12px;
  border: 0;
  border-radius: var(--control-radius);
  background: var(--color-recess);
  color: var(--color-ink);
  font: 600 20px/24px var(--font-family);
  letter-spacing: 0.12em;
  text-align: center;
  -webkit-appearance: none;
  appearance: none;
  /* text selection is off for the app; a field needs it */
  -webkit-user-select: text;
  user-select: text;
}

.pin-field::placeholder { color: var(--color-inactive); }
.pin-field:focus { outline: 2px solid var(--color-accent); outline-offset: 0; }
.pin-field:disabled { opacity: var(--disabled-opacity); }

/* ------------------------------------------------------------ the way in */

/* What lies over the app while there is no master (connect.js). */
.gate {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: calc(24px + var(--safe-t)) calc(24px + var(--safe-r)) calc(24px + var(--safe-b)) calc(24px + var(--safe-l));
  background: var(--wallpaper);
}

.gate-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  max-width: 380px;
  text-align: center;
}

.gate-symbol {
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  border-radius: 26px;
  background: var(--color-accent);
  color: var(--color-on-accent);
  box-shadow: var(--shadow-on);
}

.gate-symbol > .icon { width: 44px; height: 44px; }
.gate-title { font: 600 24px/30px var(--font-family); }
.gate-text { color: var(--color-muted); }
.gate-connect { width: 100%; height: 52px; font-size: 18px; }
.gate-error { color: var(--color-alarm); }

.gate-help {
  width: 100%;
  color: var(--color-muted);
  font-size: 14px;
  text-align: left;
}

.gate-help > summary {
  color: var(--color-ink);
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}

.gate-help > ol { margin: 10px 0 0; padding-left: 20px; }
.gate-help li + li { margin-top: 6px; }

.gate-demo {
  padding: 8px 12px;
  color: var(--color-accent);
  font-weight: 600;
}

/* the demonstration says that it is one, and a tap on it leaves it */
.demo-chip {
  flex: none;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-on-accent);
  font: 600 13px/20px var(--font-family);
}

.pin-note { width: 100%; margin-top: 8px; font-size: 14px; }

/* ------------------------------------------------------------ a new version */

/* Over the foot, above the navigation and a sheet, until it is taken (shell.js). */
.update-bar {
  position: fixed;
  left: calc(12px + var(--safe-l));
  right: calc(12px + var(--safe-r));
  bottom: calc(76px + var(--safe-b));
  z-index: 16;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 520px;
  margin: 0 auto;
  padding: 8px 8px 8px 16px;
  border-radius: 18px;
  background: var(--material-sheet);
  -webkit-backdrop-filter: var(--blur-material);
  backdrop-filter: var(--blur-material);
  box-shadow: var(--shadow-sheet);
  animation: sheet-up 0.3s var(--ease);
}

.update-text { font-weight: 600; }
.update-take { flex: none; }

/* across, the navigation is a column: the bar stands at the foot of the page */
@media (orientation: landscape) {
  .update-bar { bottom: calc(12px + var(--safe-b)); left: calc(96px + var(--safe-l)); }
}

/* ------------------------------------------------------------- page slides */

/* A page opened from another slides in from the right, and back out to it
 * on Back (main.js, render: the view transition). The header and the
 * navigation stand still; only the page moves. A tab just stands there. */
.page { view-transition-name: page; }

@keyframes slide-out-left  { to   { transform: translateX(-28%); opacity: 0.4; } }
@keyframes slide-in-right  { from { transform: translateX(100%); } }
@keyframes slide-out-right { to   { transform: translateX(100%); } }
@keyframes slide-in-left   { from { transform: translateX(-28%); opacity: 0.4; } }

::view-transition-group(page) { animation-duration: 0.32s; animation-timing-function: var(--ease); }
:root[data-slide="forward"]::view-transition-old(page) { animation: slide-out-left 0.32s var(--ease) both; }
:root[data-slide="forward"]::view-transition-new(page) { animation: slide-in-right 0.32s var(--ease) both; }
:root[data-slide="back"]::view-transition-old(page)    { animation: slide-out-right 0.32s var(--ease) both; z-index: 1; }
:root[data-slide="back"]::view-transition-new(page)    { animation: slide-in-left 0.32s var(--ease) both; }

@media (prefers-reduced-motion: reduce) {
  .sheet-panel, .sheet-shade, .update-bar { animation: none; transition: none; }
}
