:root {
  --bg: #14171c;
  --panel: #1d222a;
  --panel-edge: #2b323c;
  --ink: #eef2f6;
  --ink-dim: #97a2af;
  --amber: #f0a92b;
  --amber-deep: #c9761a;
  --green: #4ec27a;
  --grey: #6b7683;
  --red: #e2564a;
  --house-edge: #262c35;
  --wire-0: #e0803a;
  --wire-1: #4a9ed8;
  --wire-2: #7fb861;
  --wire-3: #b47ad0;
  --wire-4: #d8b23c;
  --wire-5: #52b5a8;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 1.5rem 1.5rem;
  background:
    radial-gradient(circle at 50% -10%, #232a34 0%, var(--bg) 55%) no-repeat;
  background-color: var(--bg);
  min-height: 100vh;
  color: var(--ink);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.masthead {
  position: relative;
  max-width: 72rem;
  margin: 0 auto;
  padding: 1.5rem 0 0;
  text-align: center;
}

.masthead h1 {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.masthead__tagline {
  margin: 0.25rem 0 0;
  color: var(--ink-dim);
  font-size: 0.9rem;
}

/* --- Dashboard nav ------------------------------------------------------ */

/* Ranged right of the title rather than above it, so the title stays centred. */
.nav {
  position: absolute;
  top: 1.5rem;
  right: 0;
}

.nav__row {
  display: flex;
  gap: 0.4rem;
}

/* The hamburger is the phone layout's copy of the same links; see the media
   query at the end of the file. */
.nav__menu { display: none; }

.nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.6rem;
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink-dim);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
  list-style: none;
}

.nav__toggle::-webkit-details-marker { display: none; }

.nav__menu[open] .nav__toggle {
  border-color: var(--amber-deep);
  color: var(--ink);
}

.nav__items {
  position: absolute;
  top: calc(100% + 0.4rem);
  right: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.5rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.75rem;
  background: var(--panel);
  box-shadow: 0 18px 40px -20px #000;
  text-align: left;
}

.nav__items .button { white-space: nowrap; }

/* The board holds the kegs box, the houses, and the wires drawn between them.
   Everything the wires connect has to share this positioned ancestor. */
.board {
  position: relative;
  max-width: 108rem;
  margin: 1.5rem auto 0;
}

/* Wires sit under the boxes. The box fills are nearly transparent so a wire
   shows through them, while the cards themselves are opaque, so each wire
   visually terminates at the edge of the card it points at. */
.wires {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}

/* The modifier only carries the colour; whether that colour is a stroke or a
   fill is decided by the element, so a path never gets filled in. */
.wire {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  opacity: 0.55;
}

.wire-dot {
  fill: currentColor;
  stroke: none;
  opacity: 0.9;
}

.wire--0 { color: var(--wire-0); }
.wire--1 { color: var(--wire-1); }
.wire--2 { color: var(--wire-2); }
.wire--3 { color: var(--wire-3); }
.wire--4 { color: var(--wire-4); }
.wire--5 { color: var(--wire-5); }

.kegs {
  max-width: 56rem;
  margin: 0 auto;
}

.kegs, .house {
  position: relative;
  z-index: 1;
  padding: 1.15rem 1.25rem 1.35rem;
  border: 1px solid var(--house-edge);
  border-radius: 1.25rem;
  background: rgba(255, 255, 255, 0.018);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035);
  text-align: center;
}

.box__name {
  display: inline-block;
  margin: 0 0 1rem;
  padding: 0.35rem 1.1rem;
  border: 1px solid var(--house-edge);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* Houses sit side by side when there is room, and stack when there is not. */
.houses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(38rem, 100%), 1fr));
  gap: 2rem;
  margin-top: 4rem;
  align-items: start;
}

.keg-cards, .taps {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.25rem;
}

/* --- Wi-Fi signal, beside a house's name -------------------------------- */

/* Five bars climbing left to right, sized off the label they sit in so they
   stay in proportion when the phone layout shrinks the pill. */
.wifi {
  display: inline-flex;
  align-items: flex-end;
  gap: 0.1em;
  height: 1em;
  margin-left: 0.5em;
  vertical-align: -0.1em;
}

.wifi__bar {
  width: 0.2em;
  border-radius: 0.06em;
  background: currentColor;
  /* The bars it is not reaching stay visible, so you can see how many are
     missing rather than only how many are there. */
  opacity: 0.25;
}

.wifi__bar:nth-child(1) { height: 30%; }
.wifi__bar:nth-child(2) { height: 47.5%; }
.wifi__bar:nth-child(3) { height: 65%; }
.wifi__bar:nth-child(4) { height: 82.5%; }
.wifi__bar:nth-child(5) { height: 100%; }

.wifi__bar--on { opacity: 1; }

/* Only a signal worth worrying about takes a colour. A dashboard that lights
   up green when everything is fine teaches you to stop looking at it, so four
   and five bars simply inherit the label's own grey. */
.wifi--fair { color: var(--amber); }
.wifi--poor { color: var(--red); }

/* Not a weak signal: a board that has stopped saying anything at all. Every
   bar is empty, which reads as "no reading" rather than as "zero bars". */
.wifi--stale { color: var(--grey); }

/* --- Keg card ---------------------------------------------------------- */

.keg-card {
  flex: 0 1 14rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1rem 1rem 1.15rem;
  border: 1px solid var(--panel-edge);
  border-radius: 1rem;
  background: linear-gradient(180deg, var(--panel) 0%, #171b21 100%);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

.keg-card--pouring {
  border-color: var(--amber-deep);
  box-shadow: 0 0 0 1px rgba(240, 169, 43, 0.25), 0 12px 32px -18px var(--amber);
}

.keg-card__body { width: 100%; }

.keg-card__name {
  margin: 0.75rem 0 0.15rem;
  font-size: 1.05rem;
  font-weight: 650;
}

.keg-card__meta {
  margin: 0 0 0.5rem;
  font-size: 0.85rem;
}

.keg-card__size { color: var(--ink-dim); }

/* --- Tap card ---------------------------------------------------------- */

.tap {
  /* Grow to share the row evenly, but never balloon when a house has one tap. */
  flex: 1 1 12rem;
  max-width: 20rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1rem 1rem 1.15rem;
  text-align: center;
  border: 1px solid var(--panel-edge);
  border-radius: 1rem;
  background: linear-gradient(180deg, var(--panel) 0%, #171b21 100%);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

/* Only the phone layout uses these as rows; everywhere else the card stacks
   as though the wrappers were not in the markup. */
.tap__line { display: contents; }

.tap--pouring {
  border-color: var(--amber-deep);
  box-shadow: 0 0 0 1px rgba(240, 169, 43, 0.25), 0 12px 32px -18px var(--amber);
}

.tap--offline { opacity: 0.55; }

/* Held for three seconds to pause, and held again to resume. Selection is off
   because a press this long would otherwise start selecting the card's text. */
.tap {
  position: relative;
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* Fills left to right as the press goes on: red on the way to pausing a tap,
   green on the way to letting it run again. */
.tap::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: var(--red);
  transform: scaleX(var(--hold, 0));
  transform-origin: left center;
  opacity: 0;
  transition: opacity 120ms ease;
}

.tap--holding::after { opacity: 1; }

.tap--paused.tap--holding::after { background: var(--green); }

/* A paused tap is not reporting anything, and says so in red. */
.tap--paused { border-color: rgba(226, 86, 74, 0.45); }

.tap--paused .status { color: var(--red); background: rgba(226, 86, 74, 0.12); }

.tap--paused .status__dot { background: var(--red); animation: none; }

.tap__name {
  margin: 0 0 0.3rem;
  font-size: 1.15rem;
  font-weight: 650;
}

.tap__keg {
  margin: 0 0 0.85rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--ink-dim);
}

.tap__keg--empty { color: var(--grey); font-style: italic; }

.tap__seen {
  margin: 0.6rem 0 0;
  font-size: 0.72rem;
  color: var(--grey);
}

/* --- Status pill ------------------------------------------------------- */

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.05);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.status__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--grey);
}

.tap--idle .status { color: var(--green); }
.tap--idle .status__dot { background: var(--green); }

.tap--pouring .status { color: var(--amber); background: rgba(240, 169, 43, 0.12); }
.tap--pouring .status__dot { background: var(--amber); animation: pulse 1s ease-in-out infinite; }

@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.7); }
}

/* --- Keg --------------------------------------------------------------- */

.keg-defs { position: absolute; width: 0; height: 0; }

.keg {
  position: relative;
  width: 5.75rem;
  filter: drop-shadow(0 14px 14px rgba(0, 0, 0, 0.45));
}

.keg__svg { display: block; width: 100%; height: auto; }

.keg--empty { filter: drop-shadow(0 14px 14px rgba(0, 0, 0, 0.45)); }

.keg--pouring { filter: drop-shadow(0 0 14px rgba(240, 169, 43, 0.4)); }

.keg-card--pouring .status__dot { background: var(--amber); }

/* Beer only runs while the tap is pouring. */
.keg__stream {
  position: absolute;
  bottom: -0.35rem;
  left: 50%;
  translate: -50% 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
}

.keg--pouring .keg__stream { opacity: 1; }

.keg__drop {
  width: 0.3rem;
  height: 0.55rem;
  border-radius: 0 0 50% 50%;
  background: linear-gradient(180deg, var(--amber) 0%, var(--amber-deep) 100%);
  animation: drip 900ms linear infinite;
}

.keg__drop:nth-child(2) { animation-delay: 300ms; }
.keg__drop:nth-child(3) { animation-delay: 600ms; }

@keyframes drip {
  0%   { opacity: 0; transform: translateY(-0.5rem) scaleY(0.6); }
  30%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(1.4rem) scaleY(1.2); }
}

@media (prefers-reduced-motion: reduce) {
  .keg__drop, .tap--pouring .status__dot { animation: none; }
}

/* --- Buttons, forms and flashes ---------------------------------------- */

.actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
  margin: 0.75rem 0 0;
}

.button-form { display: inline; margin: 0; }

/* Running total, on both tap cards and keg cards. */
.usage {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.4rem;
  margin: 0.7rem 0 0;
}

.usage__label {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey);
}

.usage__total {
  font-size: 1rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

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

.button {
  display: inline-block;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.5rem;
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink-dim);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.button:hover {
  color: var(--ink);
  border-color: var(--amber-deep);
  background: rgba(240, 169, 43, 0.1);
}

/* The one link in the masthead worth a stranger's attention, so it is tinted
   rather than left as another grey outline - but not filled, which would make
   it louder than anything on the board below. */
.button--app {
  border-color: rgba(240, 169, 43, 0.4);
  background: rgba(240, 169, 43, 0.1);
  color: var(--amber);
}

.button--app:hover {
  border-color: var(--amber);
  background: rgba(240, 169, 43, 0.18);
  color: #ffbe45;
}

.button--primary {
  border-color: var(--amber-deep);
  background: var(--amber);
  color: #1a1206;
}

.button--primary:hover { background: #ffbe45; color: #1a1206; }

.masthead__back { margin: 0 0 0.75rem; font-size: 0.8rem; }
.masthead__back a { color: var(--ink-dim); text-decoration: none; }
.masthead__back a:hover { color: var(--amber); }

.flash {
  max-width: 72rem;
  margin: 1rem auto 0;
  padding: 0.7rem 1rem;
  border: 1px solid var(--amber-deep);
  border-radius: 0.6rem;
  background: rgba(240, 169, 43, 0.1);
  color: var(--amber);
  font-size: 0.85rem;
}

.flash--alert {
  border-color: #a13c3c;
  background: rgba(180, 60, 60, 0.12);
  color: #f0a0a0;
}

.form {
  max-width: 26rem;
  padding: 1.5rem;
  border: 1px solid var(--panel-edge);
  border-radius: 1rem;
  background: var(--panel);
}

.form__field { margin-bottom: 1.1rem; }

.form__field label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.form__field input {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.5rem;
  background: #12161b;
  color: var(--ink);
  font: inherit;
}

.form__field input:focus {
  outline: none;
  border-color: var(--amber-deep);
  box-shadow: 0 0 0 3px rgba(240, 169, 43, 0.15);
}

.form__actions { display: flex; gap: 0.6rem; align-items: center; }

.form__errors {
  margin-bottom: 1.1rem;
  padding: 0.75rem 1rem;
  border: 1px solid #a13c3c;
  border-radius: 0.6rem;
  background: rgba(180, 60, 60, 0.12);
  color: #f0a0a0;
  font-size: 0.85rem;
}

.form__errors p { margin: 0.15rem 0; }

.keg-card__cost {
  color: var(--ink);
  font-weight: 600;
}

.keg-card__cost::before {
  content: "·";
  margin: 0 0.35rem;
  color: var(--grey);
  font-weight: 400;
}

.form__hint {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.72rem;
  color: var(--grey);
}

/* --- Settling up a finished keg ---------------------------------------- */

.settle {
  max-width: 40rem;
  margin: 0 auto;
}

.notice {
  margin: 0 0 1.25rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.6rem;
  background: rgba(255, 255, 255, 0.03);
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.notice a { color: var(--amber); }

.settle__table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--panel-edge);
  border-radius: 1rem;
  background: var(--panel);
  overflow: hidden;
}

.settle__table th,
.settle__table td {
  padding: 0.75rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--panel-edge);
}

.settle__table thead th {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.settle__table .numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.settle__table .strong { font-weight: 650; color: var(--ink); }

.settle__table tbody tr:last-child td { border-bottom: 1px solid var(--panel-edge); }

.settle__table tfoot th,
.settle__table tfoot td {
  border-bottom: none;
  background: rgba(255, 255, 255, 0.03);
  font-weight: 600;
}

.settle__note {
  margin: 1rem 0 0;
  font-size: 0.78rem;
  color: var(--grey);
}

.settle__actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

.settle__hint {
  font-size: 0.78rem;
  color: var(--grey);
}

.settle__hint a, .settle__note a { color: var(--amber); }

/* Shown only in the phone layout; see the media query at the end. */
.button--phone-only { display: none; }


.button--danger {
  border-color: #7d3535;
  background: rgba(180, 60, 60, 0.14);
  color: #e79a9a;
}

.button--danger:hover {
  border-color: #a44646;
  background: rgba(180, 60, 60, 0.24);
  color: #ffc4c4;
}

/* --- Keg history -------------------------------------------------------- */

.history {
  max-width: 64rem;
  margin: 0 auto;
}

.history__table td:first-child { white-space: nowrap; }

/* --- The keg password gate ---------------------------------------------- */

/* Asked for before anything that throws figures away - see
   keg_password_controller.js and KegPasswordGuard. */
.gate {
  width: min(22rem, calc(100vw - 2rem));
  padding: 0;
  border: 1px solid var(--panel-edge);
  border-radius: 1rem;
  background: var(--panel);
  color: var(--ink);
}

.gate::backdrop {
  background: rgba(8, 10, 13, 0.72);
}

.gate__form {
  display: flex;
  flex-direction: column;
  padding: 1.1rem 1.15rem 1.15rem;
}

.gate__title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 650;
}

.gate__message {
  margin: 0.4rem 0 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--ink-dim);
}

.gate__label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 1rem 0 0.35rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.gate__input {
  width: 100%;
  min-height: 2.75rem;
  padding: 0 0.75rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.5rem;
  background: #12161b;
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
  letter-spacing: 0.2em;
}

.gate__input:focus {
  outline: none;
  border-color: var(--amber-deep);
  box-shadow: 0 0 0 3px rgba(240, 169, 43, 0.15);
}

.gate__actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.1rem;
}

.gate__actions .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  padding: 0 1rem;
  font-size: 0.85rem;
}

/* --- Tooltip ------------------------------------------------------------ */

/* Shown on hover for a mouse and on focus for everything else: a phone has no
   hover, and the mark is reachable by tapping it. */
.tooltip {
  position: relative;
  display: inline-flex;
}

.tooltip__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  border: 1px solid var(--panel-edge);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.04);
  color: var(--grey);
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1;
  cursor: help;
}

.tooltip__mark:focus-visible {
  outline: none;
  border-color: var(--amber-deep);
  color: var(--amber);
}

/* Beside the mark rather than above it. The label line it sits on is mostly
   empty, and above would put the bubble over the sentence explaining what is
   about to be thrown away. */
.tooltip__bubble {
  position: absolute;
  top: 50%;
  left: calc(100% + 0.45rem);
  translate: 0 -50%;
  z-index: 10;
  padding: 0.3rem 0.55rem;
  border: 1px solid var(--panel-edge);
  border-radius: 0.4rem;
  background: #0f1317;
  box-shadow: 0 10px 24px -12px #000;
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms ease;
}

/* The little nib pointing back at the mark. */
.tooltip__bubble::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 100%;
  translate: 0 -50%;
  border: 0.3rem solid transparent;
  border-right-color: var(--panel-edge);
}

.tooltip:hover .tooltip__bubble,
.tooltip:focus-within .tooltip__bubble {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .tooltip__bubble { transition: none; }
}

/* --- Getting the Android app -------------------------------------------- */

.getapp {
  max-width: 30rem;
  margin: 0 auto;
  text-align: center;
}

.getapp__mark {
  width: 5.5rem;
  height: 5.5rem;
  margin-top: 1.5rem;
}

.getapp__blurb {
  margin: 1rem 0 0;
  color: var(--ink-dim);
  font-size: 0.95rem;
  line-height: 1.55;
}

.getapp__blurb code {
  color: var(--ink);
  font-size: 0.85em;
}

/* The one thing on the page to press, so it is the full width of the column
   rather than a button floating in the middle of it. */
.getapp__download {
  display: block;
  margin-top: 1.5rem;
  padding: 0.9rem 1rem;
  font-size: 1rem;
  text-align: center;
}

.getapp__figures {
  margin: 0.6rem 0 0;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  color: var(--grey);
}

/* Numbered, because the order matters: the warning only makes sense once you
   have seen it, and allowing the install only makes sense once it has asked. */
.getapp__steps {
  margin: 1.75rem 0 0;
  padding: 1rem 1.25rem 1rem 2.5rem;
  border: 1px solid var(--panel-edge);
  border-radius: 1rem;
  background: var(--panel);
  text-align: left;
  color: var(--ink-dim);
  font-size: 0.9rem;
  line-height: 1.55;
}

.getapp__steps li + li { margin-top: 0.75rem; }

.getapp__steps strong { color: var(--ink); font-weight: 650; }

.getapp__steps::marker { color: var(--grey); }

.getapp__note {
  margin: 1rem 0 0;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--grey);
}

/* --- Inside the Android app --------------------------------------------- */

/* The native toolbar already carries the page title, the back arrow and the
   History link, so the masthead would be a second header saying the same
   things. The tagline stays: it is the only part that says something the
   toolbar cannot, such as which tap a new keg is going on. */
body.native .masthead { padding-top: 0; }

body.native .masthead h1,
body.native .masthead__back,
body.native .nav { display: none; }

body.native .masthead__tagline { margin-top: 0.9rem; }

/* Nothing above the board but the toolbar, so it does not need a masthead's
   worth of air over it.
   
   The air is body's padding rather than the board's margin on purpose. With
   the masthead collapsed to nothing, the board is body's first in-flow child,
   and a top margin there escapes body and offsets the whole box - which body's
   min-height: 100vh then turns into exactly that much scroll, on a page whose
   contents fit. Padding cannot escape, so the page ends where the screen
   does. */
body.native { padding-top: 0.5rem; }

body.native .board { margin-top: 0; }

/* --- Phones ------------------------------------------------------------- */

/* A phone gets the taps and nothing else: the kegs box and the wires drawn
   between the boxes both go, and each tap card collapses to a compact row -
   the labels that were stacked down the middle sit side by side instead.

   The sizes here are set for a phone read at arm's length beside a keezer,
   which is where this layout actually gets used: the type is a step up from
   the wide layout's rather than a step down, and anything you press is at
   least 2.75rem tall, the 44px Android counts as a touch target. */
@media (max-width: 40rem) {
  body {
    /* In a browser the gesture bar sits over the bottom of the page. Inside
       the Android shell the activity insets the WebView instead, so env()
       resolves to zero there and the two do not stack. */
    padding: 0 0.7rem calc(0.6rem + env(safe-area-inset-bottom));
  }

  .masthead { padding-top: 1rem; }
  .masthead h1 { font-size: 1.5rem; }
  .masthead__tagline { font-size: 0.85rem; }

  /* Too little room for a row of buttons beside the title, so the links move
     into the menu behind the hamburger. */
  .nav { top: 0.8rem; }
  .nav__row { display: none; }
  .nav__menu { display: block; }
  .nav__toggle { width: 2.75rem; height: 2.75rem; font-size: 1.3rem; }

  /* Four columns of settling up, on a phone: tighter, and the house names get
     to stay on one line. */
  .settle__table th,
  .settle__table td {
    padding: 0.65rem 0.5rem;
    font-size: 0.9rem;
  }

  .settle__table thead th { font-size: 0.65rem; letter-spacing: 0.08em; }

  /* The button above what it does, rather than beside it. */
  .settle__actions {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
    margin-top: 1.25rem;
  }

  .settle__actions .button { white-space: nowrap; }

  .settle__hint { font-size: 0.82rem; line-height: 1.5; }

  /* Each row of the history becomes a card, with the header row's labels moved
     onto the cells themselves - seven columns will not fit across a phone. */
  .history__table {
    border: none;
    border-radius: 0;
    background: none;
  }

  .history__table thead { display: none; }

  .history__table,
  .history__table tbody,
  .history__table tr,
  .history__table td {
    display: block;
    width: 100%;
  }

  .history__table tr {
    margin-bottom: 0.6rem;
    padding: 0.45rem 0.85rem;
    border: 1px solid var(--panel-edge);
    border-radius: 0.85rem;
    background: linear-gradient(180deg, var(--panel) 0%, #171b21 100%);
  }

  .history__table td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.35rem 0;
    border-bottom: none;
    font-size: 0.95rem;
    text-align: right;
  }

  .history__table td + td { border-top: 1px solid rgba(255, 255, 255, 0.04); }

  .history__table td::before {
    content: attr(data-label);
    flex: none;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--grey);
    text-align: left;
  }

  .board { margin-top: 1rem; }

  .wires { display: none; }

  /* No top margin: the margin was clearing the kegs box, and the kegs box is
     not here. */
  .houses {
    grid-template-columns: 1fr;
    gap: 0.55rem;
    margin-top: 0;
  }

  /* min-width: 0 is what lets the column be narrower than the widest thing in
     it. A grid item's automatic minimum size is its min-content, and the tap
     card's top line does not wrap, so without this the whole page is floored
     at the width of the longest keg name plus everything beside it - and any
     phone narrower than that scrolls sideways. The same applies at each step
     down to the line itself, which is why it is repeated: an item that cannot
     shrink stops every item above it from shrinking either. */
  .house {
    min-width: 0;
    padding: 0.55rem 0.6rem 0.6rem;
    border-radius: 0.9rem;
  }

  .box__name {
    margin-bottom: 0.4rem;
    padding: 0.22rem 0.8rem;
    font-size: 0.68rem;
  }

  /* The kegs box takes too much of a phone screen to earn its place, so it
     goes and each tap card carries its keg's name and Finish button instead. */
  .kegs { display: none; }

  .button--phone-only { display: inline-flex; }

  .taps { gap: 0.4rem; }

  /* Tap cards run full width and hold two rows: the top line reads
     "tap1: Moo Brew Pale Ale" with the status and the poured total ranged
     right beside it, and the time and the buttons go underneath. */
  .tap {
    flex: 1 1 100%;
    min-width: 0;
    max-width: none;
    align-items: stretch;
    gap: 0.4rem;
    padding: 0.55rem 0.65rem 0.6rem;
    border-radius: 0.85rem;
    text-align: left;
  }

  .tap__line {
    display: flex;
    align-items: center;
    min-width: 0;
    gap: 0.6rem;
  }

  /* A long clock and two full-size buttons will not always share one line, so
     the buttons drop onto a line of their own rather than shrinking below the
     size a finger can hit. */
  .tap__line + .tap__line {
    flex-wrap: wrap;
    row-gap: 0.55rem;
  }

  .tap__name { margin: 0; font-size: 1.15rem; }
  .tap__name::after { content: ":"; }

  /* The keg name takes the slack on the top line, and is the part that gets
     clipped when a long name runs the line out of room. */
  .tap__keg {
    flex: 1;
    min-width: 0;
    margin: 0;
    font-size: 1rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Holds the bottom row apart, so the buttons stay hard right. It does not
     shrink: the clock is the one thing on the card that has to stay legible
     from across a room. */
  .tap__seen {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 0.8rem;
    white-space: nowrap;
  }

  /* The pill drops to a bare dot - green idle, grey offline, amber pouring -
     which reads at a glance and leaves the keg name more of the line. The
     word itself stays in the markup for screen readers. */
  .status {
    gap: 0;
    padding: 0;
    background: none;
  }

  .tap--pouring .status { background: none; }

  .status__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .status__dot { width: 0.8rem; height: 0.8rem; }

  .usage {
    justify-content: flex-end;
    gap: 0.35rem;
    margin: 0;
  }

  .usage__label { font-size: 0.65rem; }
  .usage__total { font-size: 1.1rem; }

  .actions {
    flex: 1 1 auto;
    justify-content: flex-end;
    gap: 0.5rem;
    margin: 0;
  }

  /* Buttons are finger targets first. 2.75rem is the smallest Android counts
     as one, and centring the label inside that height is why these become
     flex rather than keeping the vertical padding of the wide layout. */
  .button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.75rem;
    padding: 0 0.95rem;
    font-size: 0.85rem;
  }

  /* Still the full width of its column: the rule above would otherwise shrink
     the one button on the page down to the width of its label. */
  .getapp__download {
    display: flex;
    min-height: 3.25rem;
    font-size: 1rem;
  }

  .getapp__mark { width: 4.75rem; height: 4.75rem; margin-top: 1rem; }

  .getapp__steps { font-size: 0.95rem; }

  /* Big enough to type into without the browser offering to zoom in first. */
  .form__field input {
    min-height: 2.75rem;
    font-size: 1rem;
  }
}

/* --- Narrow phones ------------------------------------------------------ */

/* Below this the tap card's bottom line runs out of room and the buttons wrap
   onto a third one, which costs six cards' worth of height and pushes the last
   house off the screen.
   
   It catches more phones than its width suggests. Android's Display size
   setting takes the same 1080 physical pixels and reports fewer CSS ones, so a
   phone that is 412 wide out of the box is 393 or 360 for anyone who has
   turned text up - which is exactly the person least served by a layout that
   scrolls.
   
   The clock keeps its time and loses its label. The time is the datum; the
   word in front of it is decoration, and the red border and dot already say
   when a tap is paused. */
@media (max-width: 24rem) {
  .tap__seen-label { display: none; }
}
