/* Zoolama, "Feira": the hortifruti stall. Lettuce-green actions, a mango total tag and tomato for warnings,
   on a fresh leafy white (deep green-black at night). Shelf-tag numerals and small raised cents throughout.
   test/contrast.test.js checks every text/background pair below in both themes. */

@font-face {
  font-family: 'Barlow Condensed';
  src: url('./fonts/barlow-condensed-700.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

/* Roboto at double height (tools/double-height.py), for Altura dupla. */
@font-face {
  font-family: 'Zoolama Altura Dupla';
  src: url('./fonts/zoolama-double-400.woff2') format('woff2');
  font-display: swap;
}

:root {
  --paper: #f4faef;
  --surface: #ffffff;
  --ink: #1d2b1f;
  --muted: #5c6b5e;
  --rule: #d5e5cf;
  --stripe: #e8f2e3; /* every other step of the update log, a tint of the page */
  --tag: #ffcf33;
  --tag-ink: #1d2b1f;
  --dear: #c43d1a;
  --good: #237a3c;
  --focus: #1d5fd1;
  --primary: #237a3c;
  --primary-ink: #ffffff;
  --pill: #237a3c;
  --pill-ink: #ffffff;
  --over: #c0391b;
  --num: 'Barlow Condensed', 'Avenir Next Condensed', 'Roboto Condensed', 'Arial Narrow', sans-serif-condensed,
    sans-serif;
  --text: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --radius: 6px;
  color-scheme: light;
}

/* Dark follows the system unless the toggle forced light; the toggle can also force dark. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --paper: #0e1a11;
    --surface: #16261a;
    --ink: #e8f4e2;
    --muted: #9db59d;
    --rule: #25392a;
    --stripe: #0e1a11;
    --tag-ink: #14210f;
    --dear: #ff7a59;
    --good: #5fd07f;
    --focus: #7fa8ff;
    --primary: #5fd07f;
    --primary-ink: #0e1a11;
    --pill: #5fd07f;
    --pill-ink: #0e1a11;
    --over: #c0391b;
    color-scheme: dark;
  }
}

:root[data-theme='dark'] {
  --paper: #0e1a11;
  --surface: #16261a;
  --ink: #e8f4e2;
  --muted: #9db59d;
  --rule: #25392a;
  --stripe: #0e1a11;
  --tag-ink: #14210f;
  --dear: #ff7a59;
  --good: #5fd07f;
  --focus: #7fa8ff;
  --primary: #5fd07f;
  --primary-ink: #0e1a11;
  --pill: #5fd07f;
  --pill-ink: #0e1a11;
  --over: #c0391b;
  color-scheme: dark;
}

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

html,
body {
  margin: 0;
  height: 100%;
}

/* The app is a fixed frame: header, the scrolling <main>, and the dock (total + tabs). The page itself never scrolls,
   bounces or pulls to refresh, so nothing can move the header or the tabs off screen; only <main> scrolls. */
html {
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.4 var(--text);
  -webkit-tap-highlight-color: transparent;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  touch-action: manipulation;
}

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

[hidden] {
  display: none !important;
}

/* ---------- header ---------- */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(env(safe-area-inset-top) + 10px) 16px 10px;
  border-bottom: 1px solid var(--rule);
}

.brand {
  margin: 0;
  line-height: 0;
}

.wordmark {
  display: block;
  width: auto;
  height: 36px;
}

.brand-btn {
  display: block;
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: none;
}

/* The About page full screen, opened from the header logo: the page's own colour, scrolling as one, with the logo
   large at the top. Its content is the Sobre tab's #about-content, borrowed while open (src/ui/about-screen.js). The
   logo's transform origin is its top-left corner, which the FLIP from the header's box is worked out from. */
.about-view {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--paper);
  color: var(--ink);
}

.about-view::backdrop {
  background: transparent;
}

.about-view .about {
  padding-bottom: calc(24px + env(safe-area-inset-bottom));
}

.about-view .about-logo {
  padding-top: calc(env(safe-area-inset-top) + 64px); /* clear of the ✕ */
}

.about-view .about-logo .wordmark {
  width: min(88vw, 560px);
  height: auto;
  transform-origin: 0 0;
}

/* The ✕ (top left, as Android's full-screen dialogs have it) and the header's language flags, borrowed while open
   and pinned where they sit in the header, stay put while the page scrolls under them, on the page colour. */
.about-close,
.about-view .lang {
  position: fixed;
  top: calc(env(safe-area-inset-top) + 10px);
  z-index: 1;
  background: var(--paper);
}

.about-close {
  left: 16px;
}

.about-view .lang {
  right: 16px;
}

.bar-tools {
  display: flex;
  align-items: center;
  gap: 8px;
}

.theme-btn,
.double-height-btn,
.magnifier-btn,
.magnifier-torch,
.about-close {
  display: grid;
  place-items: center;
  width: 44px;
  height: 43px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
}

.theme-btn svg,
.double-height-btn svg,
.magnifier-btn svg,
.magnifier-torch svg,
.about-close svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Under 412px the header holds every tool but one while the browser offers Install, before the app is installed:
   Altura dupla steps aside until then. Installed, Install is gone and it always shows. */
@media (max-width: 411px) {
  .bar-tools:has(#install:not([hidden])) .double-height-btn {
    display: none;
  }
}

/* Altura dupla on: its button pressed, as a sort button is. */
.double-height-btn[aria-pressed='true'] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

/* Altura dupla (src/ui/double-height.js): the reading text twice as tall at the same width; with the font's own line
   height, lines and fields make room for it. Buttons, tabs, labels and prices stay as they are. */
:root[data-double-height] :is(.line-name, .entry-name, .option-label, .plan-chip, .trip-item-name) {
  font-family: 'Zoolama Altura Dupla', var(--text);
  line-height: normal;
}

/* The icon shows the theme you would switch to. */
.theme-btn[data-showing='dark'] .moon,
.theme-btn[data-showing='light'] .sun {
  display: none;
}

.install-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 43px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  font-size: 14px;
  font-weight: 700;
}

.install-btn svg,
.share-glyph {
  width: 19px;
  height: 19px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Most phones: icon only, the label stays for screen readers. With the magnifier, Altura dupla, theme and language
   tools beside it, the labelled button needs about 480px of header. */
@media (max-width: 479px) {
  .install-btn {
    width: 44px;
    padding: 0;
    justify-content: center;
  }

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

/* Photo viewer, and the magnifier's frame: always dark, like any photo view, whatever the app theme. It borrows the
   Feira dark tokens, but keeps a neutral black behind the photo so the price tag's colours read true. */
.viewer {
  --ink: #e8f4e2;
  --muted: #9db59d;
  --rule: #25392a;
  --dear: #ff7a59;
  --good: #5fd07f;
  --focus: #7fa8ff;
  --primary: #5fd07f;
  --primary-ink: #0e1a11;
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: #0b0c0e;
  color: var(--ink);
}

.viewer[open] {
  display: flex;
  flex-direction: column;
}

.viewer::backdrop {
  background: #000;
}

.viewer > img {
  flex: 1;
  width: 100%;
  min-height: 0;
  object-fit: contain;
}

.viewer-bar {
  display: grid;
  gap: 12px;
  padding: 14px 16px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--rule);
}

.viewer-caption {
  display: grid;
  gap: 4px;
}

.viewer-caption h2 {
  margin: 0;
  font: 700 22px/1.1 var(--num);
}

.viewer .tag-price {
  color: var(--tag);
  font-size: 48px;
}

.viewer-charged {
  font-weight: 700;
}

.viewer-charged.dear {
  color: var(--dear);
}

.viewer-charged.good {
  color: var(--good);
}

.viewer-caption p {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}

.viewer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.viewer-actions button {
  min-height: 44px;
  padding: 0 14px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: inherit;
  font-weight: 600;
}

.viewer-actions form {
  margin-left: auto;
}

.viewer-actions [aria-pressed='true'] {
  border-color: var(--tag);
  color: var(--tag);
}

.viewer-actions .primary {
  border-color: var(--primary);
  background: var(--primary);
  color: var(--primary-ink);
}

/* Magnifier (lupa): the live camera picture fills the view. Where the camera can't zoom, src/ui/magnifier-ui.js sets
   --zoom and the picture is enlarged on screen instead. */
.magnifier-view {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  touch-action: none; /* two fingers zoom the picture, not the page */
}

.magnifier-view video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(var(--zoom, 1));
}

.magnifier-msg {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 24px;
  text-align: center;
  font-weight: 600;
}

/* The exposure and zoom rows: an icon, the slider taking whatever room is left, and the value. */
.magnifier-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* The torch is an icon button among the text ones, so it keeps the header buttons' square shape. */
.viewer-actions .magnifier-torch {
  padding: 0;
}

/* The ☀ and ⊕ that mark the exposure and zoom sliders share a 44px column, so the two sliders line up. */
.magnifier-mark {
  flex: none;
  width: 44px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  color: var(--muted);
}

.magnifier-row input {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  margin: 0;
  accent-color: var(--primary);
}

.magnifier-row output {
  flex: none;
  min-width: 4ch;
  font: 700 22px/1 var(--num);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.sheet {
  max-width: min(340px, calc(100vw - 32px));
  padding: 20px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
}

.sheet::backdrop {
  background: rgb(0 0 0 / 0.45);
}

.sheet h2 {
  margin: 0 0 12px;
  font: 700 24px/1.1 var(--num);
}

.sheet ol {
  display: grid;
  gap: 10px;
  margin: 0 0 18px;
  padding-left: 1.3em;
}

.sheet li span {
  margin-right: 4px;
}

.share-glyph {
  display: inline-block;
  vertical-align: -3px;
}

#ios-install .primary {
  width: 100%;
}

/* ---------- finishing a trip ---------- */

.cart-actions {
  display: flex;
  gap: 8px;
  margin: 16px;
}

.cart-actions .primary {
  flex: 1;
}

.share-btn {
  display: flex;
  align-items: center;
  gap: 6px;
}

.finish-total {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.finish-total .tag-price {
  font-size: 44px;
}

#finish-count {
  color: var(--muted);
  font-size: 14px;
}

#finish-form label {
  display: block;
  margin-bottom: 2px;
  color: var(--muted);
  font-size: 14px;
}

.finish-store {
  width: 100%;
  margin-bottom: 18px;
  padding: 10px 0;
  border: 0;
  border-bottom: 1.5px solid var(--rule);
  background: transparent;
}

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

.month {
  padding: 0 16px;
}

.month-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 20px 0 4px;
  font: 700 22px/1.1 var(--num);
}

.month-head span:first-child::first-letter {
  text-transform: uppercase;
}

.month-total {
  font-variant-numeric: tabular-nums;
}

/* Each past trip is a receipt: a paper slip with a torn zigzag bottom, like a cupom fiscal. */
.trip {
  position: relative;
  margin: 10px 0 20px;
  padding: 0 14px 6px;
  border-radius: 6px 6px 0 0;
  background: var(--surface);
}

.trip::after {
  position: absolute;
  right: 0;
  bottom: -8px;
  left: 0;
  height: 8px;
  background: var(--surface);
  content: '';
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M0 0h12L6 8z'/%3E%3C/svg%3E") 0 0 / 12px 8px repeat-x;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M0 0h12L6 8z'/%3E%3C/svg%3E") 0 0 / 12px 8px repeat-x;
}

.trip > summary {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 12px;
  padding: 12px 0;
  cursor: pointer;
  list-style: none;
}

.trip > summary::-webkit-details-marker {
  display: none;
}

.trip-store {
  font-weight: 700;
}

.trip-store::before {
  display: inline-block;
  width: 1.1em;
  color: var(--muted);
  content: '▸';
}

.trip[open] .trip-store::before {
  content: '▾';
}

.trip-total {
  font: 700 22px/1 var(--num);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.trip-meta {
  display: flex;
  flex-wrap: wrap;
  grid-column: 1 / -1;
  gap: 0 12px;
  padding-left: 1.1em;
  color: var(--muted);
  font-size: 14px;
}

.trip-meta .over {
  color: var(--dear);
  font-weight: 700;
}

.trip-items {
  margin: 0;
  padding: 0 0 0 1.1em;
  list-style: none;
}

.trip-items li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 12px;
  padding: 6px 0;
  border-top: 1px dashed var(--rule);
  font-size: 14px;
}

.trip-items .each {
  color: var(--muted);
}

.trip-items .sub {
  grid-row: 1 / span 2;
  grid-column: 2;
  align-self: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.trip-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 14px 1.1em;
}

.lang {
  display: flex;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}

.lang button {
  display: grid;
  place-items: center;
  min-width: 44px;
  min-height: 40px;
  border: 0;
  background: transparent;
}

/* A flag can't invert like text, so the chosen one gets an ink ring and the other one fades. */
.flag {
  width: 26px;
  height: 18px;
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15);
  opacity: 0.4;
  transition: opacity 120ms ease-out;
}

.lang button[aria-pressed='true'] .flag {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  opacity: 1;
}

main {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ---------- entry ---------- */

.entry {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px 14px;
  align-items: end;
  padding: 14px 16px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
}

.entry label {
  display: block;
  margin-bottom: 2px;
  color: var(--muted);
  font-size: 14px;
}

.money-field {
  display: flex;
  align-items: baseline;
  gap: 6px;
  border-bottom: 2px solid var(--ink);
  font-family: var(--num);
  font-weight: 700;
}

.money-field span {
  font-size: 22px;
}

.money-field input {
  width: 100%;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  font-size: 40px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.money-field input:focus-visible {
  outline: none;
}

.money-field:focus-within {
  border-bottom-color: var(--focus);
}

.money-field input[aria-invalid='true'] {
  color: var(--dear);
}

.field-error {
  min-height: 1.2em;
  margin: 4px 0 0;
  color: var(--dear);
  font-size: 14px;
}

/* Weighed items: price per kg × weight, with the line price previewed before Add. */
.weight-field {
  width: 6.5ch;
  padding: 0;
  border: 0;
  border-bottom: 2px solid var(--ink);
  background: transparent;
  font: 700 34px/1.1 var(--num);
  font-variant-numeric: tabular-nums;
}

.weight-field:focus-visible {
  outline: none;
  border-bottom-color: var(--focus);
}

.weight-preview {
  min-height: 1.2em;
  margin: 4px 0 0;
  font: 700 18px/1.1 var(--num);
}

.weight-btn {
  min-height: 44px;
  padding: 0 12px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  font: 700 20px/1 var(--num);
  font-variant-numeric: tabular-nums;
}

.weight-input {
  width: 6.5ch;
  padding: 2px 0;
  border: 0;
  border-bottom: 2px solid var(--focus);
  background: transparent;
  font: 700 22px/1.1 var(--num);
  font-variant-numeric: tabular-nums;
}

.weight-input:focus-visible {
  outline: none;
}

.tag-price .per {
  align-self: flex-end;
  margin-bottom: 0.3em;
  margin-left: 2px;
  font-size: 0.34em;
}

.entry-qty {
  align-self: start;
}

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

.stepper button {
  width: 44px;
  height: 44px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 22px;
  line-height: 1;
}

.stepper input {
  width: 3ch;
  border: 0;
  background: transparent;
  text-align: center;
  font: 700 26px/1 var(--num);
  font-variant-numeric: tabular-nums;
}

.entry-name {
  min-width: 0;
  padding: 10px 0;
  border: 0;
  border-bottom: 1px solid var(--rule);
  background: transparent;
}

.name-hint {
  grid-column: 1 / -1;
  margin: -2px 0 0;
  color: var(--muted);
  font-size: 14px;
}

.name-hint:empty {
  display: none;
}

.entry-name::placeholder,
.line-name::placeholder {
  color: var(--muted);
}

.entry-actions {
  display: flex;
  gap: 8px;
}

.entry-actions .primary {
  flex: 1;
}

/* Camera buttons: a dashed frame until a photo fills them. */
.photo-btn,
.line-photo {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  overflow: hidden;
  padding: 0;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}

.photo-btn {
  width: 48px;
  height: 48px;
}

.photo-btn img,
.line-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.camera {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.primary {
  min-height: 48px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--radius);
  background: var(--primary);
  color: var(--primary-ink);
  font-weight: 700;
}

/* ---------- cart lines ---------- */

.sort-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 12px 16px 0;
}

.sort-bar > span {
  margin-right: 2px;
  color: var(--muted);
  font-size: 14px;
}

.sort-bar button {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 40px;
  padding: 0 12px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  font-size: 14px;
  font-weight: 600;
}

.sort-bar button[aria-pressed='true'] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

.sort-bar .dir:empty {
  display: none;
}

.empty {
  margin: 0;
  padding: 28px 16px;
  color: var(--muted);
}

/* ---------- shopping list ---------- */

.plan {
  margin: 8px 16px 0;
}

.plan summary {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  font: 700 20px/1 var(--num);
  cursor: pointer;
  list-style: none;
}

.plan summary::-webkit-details-marker {
  display: none;
}

/* The same open/closed marker as a trip in History. */
.plan summary::before {
  width: 0.8em;
  color: var(--muted);
  content: '▸';
}

.plan[open] summary::before {
  content: '▾';
}

.plan-progress {
  color: var(--muted);
  font: 400 14px/1 var(--text);
}

.plan-items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 4px;
  padding: 0;
  list-style: none;
}

.plan-chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1.5px solid var(--rule);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
}

/* Already in the cart: struck through, and nothing to tap. */
.plan-chip.bought {
  border-style: dashed;
  background: transparent;
  color: var(--muted);
  text-decoration: line-through;
}

.plan-clear {
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 14px;
  text-decoration: underline;
}

/* ---------- checkout mode ---------- */

.start-check {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: calc(100% - 32px);
  min-height: 48px;
  margin: 12px 16px 0;
  border: 1.5px solid var(--ink);
  border-radius: var(--radius);
  background: transparent;
  font-weight: 700;
}

.start-check svg,
.tick-mark {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.check-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
}

.check-head h2 {
  margin: 0;
  font: 700 26px/1 var(--num);
}

.check-head p {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 14px;
}

.line.check {
  grid-template-columns: 44px 44px 1fr auto;
  grid-template-areas:
    'tick photo name sub'
    'tick photo each ne';
  cursor: pointer;
}

.line.check .line-name {
  overflow: hidden;
  padding: 4px 0;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Ticked lines fade but stay put, so the list doesn't jump while the cashier scans. A mismatch stays at full
   strength: it's the one thing on a ticked line you still need to see. The fade stops where the text still reads at
   4.5:1 (a ticked line is still tapped, to untick it or note a charge), and grey text, which can hardly fade at all,
   turns ink; test/contrast.test.js checks both themes. */
.line.checked > :not(.tick, .line-charged) {
  opacity: 0.65;
}

.line.checked > :is(.line-each, .line-note) {
  color: var(--ink);
}

.tick {
  display: grid;
  grid-area: tick;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1.5px solid var(--rule);
  border-radius: 50%;
  background: transparent;
  color: var(--primary-ink);
}

.tick[aria-pressed='true'] {
  border-color: var(--primary);
  background: var(--primary);
}

/* A fresh tick snaps in and draws its check mark. */
.tick.snap {
  animation: tick-snap 320ms cubic-bezier(0.3, 1.6, 0.6, 1);
}

.tick.snap .tick-mark path {
  stroke-dasharray: 1;
  animation: tick-draw 260ms 60ms ease-out both;
}

@keyframes tick-snap {
  0% {
    transform: scale(0.6);
  }
  60% {
    transform: scale(1.12);
  }
}

@keyframes tick-draw {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

.tick:not([aria-pressed='true']) .tick-mark {
  opacity: 0;
}

.charge-btn {
  grid-area: ne;
  justify-self: end;
  width: 44px;
  height: 40px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  font: 700 22px/1 var(--num);
}

.charge-btn.set {
  border-color: var(--ink);
}

.line-charged {
  display: flex;
  flex-wrap: wrap;
  grid-area: each;
  gap: 0 8px;
  font-size: 14px;
  font-weight: 700;
}

.line-charged.dear {
  color: var(--dear);
}

.line-charged.good {
  color: var(--good);
}

.charge-input {
  grid-area: each;
  width: 100%;
  min-width: 0;
  padding: 2px 0;
  border: 0;
  border-bottom: 2px solid var(--focus);
  background: transparent;
  font: 700 22px/1.1 var(--num);
  font-variant-numeric: tabular-nums;
}

.charge-input:focus-visible {
  outline: none;
}

.check-summary {
  display: grid;
  gap: 2px;
  padding: 8px 16px;
  background: var(--surface);
  border-top: 1px solid var(--rule);
}

.check-summary p {
  margin: 0;
}

/* ---------- atacado offers ---------- */

.stepper .offer-btn {
  margin-left: 4px;
  font: 700 22px/1 var(--num);
}

.entry-deal {
  display: flex;
  grid-column: 1 / -1;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  padding-left: 12px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  color: var(--good);
  font-weight: 700;
}

.entry-deal-clear {
  width: 44px;
  height: 40px;
  border: 0;
  background: none;
  color: var(--muted);
}

.sheet-field {
  margin-bottom: 12px;
}

.sheet-field label,
.deal-fields label,
.deal-fields legend {
  color: var(--muted);
  font-size: 14px;
}

.deal-fields {
  margin: 0 0 4px;
  padding: 0;
  border: 0;
}

.deal-fields > legend {
  margin-bottom: 6px;
  padding: 0;
  font-weight: 700;
}

.deal-kind {
  margin-bottom: 10px;
}

.deal-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px 12px;
  align-items: end;
}

.deal-num {
  width: 100%;
  padding: 0;
  border: 0;
  border-bottom: 2px solid var(--ink);
  background: transparent;
  color: var(--ink);
  font: 700 26px/1.2 var(--num);
}

.deal-fields .money-field input,
.sheet-field .money-field input {
  font-size: 26px;
}

.line-note {
  grid-column: 3 / -1; /* under the name: a checkout line has the tick and the photo before it */
  color: var(--muted);
  font-size: 13px;
}

/* ---------- receipt check ---------- */

.receipt {
  display: grid;
  gap: 4px;
  margin: 16px 16px 0;
  color: var(--muted);
  font-size: 14px;
}

.receipt .money-field {
  color: var(--ink);
}

.receipt .money-field input {
  font-size: 30px;
}

.receipt p {
  margin: 0;
}

.receipt-verdict {
  font: 700 18px/1.2 var(--num);
}

.receipt-verdict.dear {
  color: var(--dear);
}

.receipt-verdict.good {
  color: var(--good);
}

.check-summary .over {
  color: var(--dear);
  font: 700 20px/1.1 var(--num);
}

.check-summary .law {
  color: var(--muted);
  font-size: 13px;
}

.check-summary .favor {
  color: var(--good);
  font: 700 18px/1.1 var(--num);
}

.lines {
  margin: 0;
  padding: 0 16px;
  list-style: none;
}

.line {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    'photo name sub'
    'photo each ctl';
  gap: 2px 12px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
}

.line-photo {
  grid-area: photo;
  width: 44px;
  height: 44px;
  align-self: center;
}

.line-photo.empty {
  border-style: dashed;
  background: transparent;
  color: var(--muted);
}

.line-name {
  grid-area: name;
  min-width: 0;
  padding: 4px 0;
  border: 0;
  background: transparent;
}

.line-sub {
  grid-area: sub;
  font: 700 26px/1 var(--num);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.line-each {
  grid-area: each;
  color: var(--muted);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* On an editable line, the arithmetic is also the way to correct the price. */
button.line-each {
  justify-self: start;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  text-align: left;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

.tier-nudge {
  grid-column: 2 / -1;
  justify-self: start;
  min-height: 36px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--good);
  font-size: 14px;
  text-align: left;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

/* "+7% desde a última vez", under a line that costs more than it did on the last trip. */
.line-rise {
  grid-column: 2 / -1;
  color: var(--dear);
  font-size: 13px;
}

.line-ctl {
  grid-area: ctl;
  display: flex;
  align-items: center;
  gap: 6px;
}

.line-ctl .stepper span {
  min-width: 2.5ch;
  text-align: center;
  font: 700 22px/1 var(--num);
  font-variant-numeric: tabular-nums;
}

.remove {
  width: 44px;
  height: 44px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 18px;
}

/* ---------- dock: toast + tally ---------- */

.dock {
  position: relative;
}

.toast {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 16px;
  right: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 8px 8px 14px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--tag-ink); /* always dark, so the yellow Undo keeps its contrast in both themes */
  color: #e8f4e2;
}

.toast button {
  min-height: 40px;
  padding: 0 12px;
  border: 0;
  background: transparent;
  color: var(--tag);
  font-weight: 700;
}

.tally {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 16px 12px;
  background: var(--tag);
  color: var(--tag-ink);
}

.tally-tag.pop {
  transform-origin: left bottom;
  animation: total-pop 320ms cubic-bezier(0.3, 1.6, 0.6, 1);
}

@keyframes total-pop {
  40% {
    transform: scale(1.06);
  }
}

.tally-tag {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Over budget, the whole tag turns red; the line under the total says by how much. */
.tally.over {
  background: var(--over);
  color: #ffffff;
}

.budget-line {
  align-self: flex-start;
  min-height: 36px;
  margin-top: 2px;
  padding: 0;
  border: 0;
  background: transparent;
  font-size: 14px;
  font-weight: 700;
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.sheet-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}

.budget-field {
  margin-bottom: 4px;
}

.budget-field input {
  font-size: 34px;
}

.tally-label {
  font: 700 18px/1 var(--num);
}

.tally-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  font-size: 14px;
}

.on-tag {
  min-height: 44px;
  padding: 0 14px;
  border: 1.5px solid currentColor;
  border-radius: var(--radius);
  background: transparent;
  font-weight: 600;
}

.on-tag:disabled {
  opacity: 0.45;
  cursor: default;
}

/* A shelf-tag price: currency small, reais large, cents small and raised. */
.tag-price {
  display: flex;
  align-items: flex-start;
  font-family: var(--num);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 0.95;
  white-space: nowrap;
}

.tag-price .cur {
  align-self: flex-end;
  margin-right: 4px;
  margin-bottom: 0.3em;
  font-size: 0.34em;
}

.tag-price .cents {
  margin-top: 0.08em;
  font-size: 0.45em;
}

.tally .tag-price {
  font-size: clamp(48px, 15vw, 64px);
}

/* While the keyboard is up (src/ui/shell.js), the tag shrinks to one slim row: the total stays in view, the count,
   budget and Clear wait until it's down, and the list keeps the room. Over budget, the tag still turns red. */
:root[data-keyboard='open'] .tally {
  align-items: center;
  padding: 4px 16px;
}

:root[data-keyboard='open'] .tally-tag {
  flex-direction: row;
  align-items: baseline;
  gap: 10px;
}

:root[data-keyboard='open'] .tally .tag-price {
  font-size: 30px;
}

:root[data-keyboard='open'] .budget-line,
:root[data-keyboard='open'] .tally-meta {
  display: none;
}

/* ---------- compare ---------- */

.options {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 16px 16px 0;
  list-style: none;
}

.option {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 14px 12px;
  border: 1.5px solid var(--rule);
  border-radius: 3px;
  background: var(--surface);
  color: var(--ink);
  transition: background-color 160ms ease-out, border-color 160ms ease-out;
}

/* The winning tag turns shelf-tag yellow; re-point the tokens so everything inside follows. */
.option.winner {
  --ink: var(--tag-ink);
  --primary: var(--tag-ink);
  --primary-ink: var(--tag);
  --muted: #574b00;
  --rule: #c9a800;
  --focus: #1d5fd1;
  border-color: var(--tag);
  background: var(--tag);
}

.option.flip {
  transform-origin: top center;
  animation: tag-flip 560ms cubic-bezier(0.3, 1.25, 0.5, 1);
}

@keyframes tag-flip {
  from {
    transform: perspective(800px) rotateX(-80deg);
  }
}

.option-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 32px;
}

.option-title {
  font: 700 18px/1 var(--num);
}

.option-head .remove {
  width: 40px;
  height: 36px;
  margin-right: -10px;
}

.option-label {
  min-width: 0;
  padding: 6px 0;
  border: 0;
  border-bottom: 1px solid var(--rule);
  background: transparent;
}

.option-label::placeholder {
  color: var(--muted);
}

.option-fields {
  display: grid;
  grid-template-columns: 1fr 1fr; /* the quantity shares its half with the × key */
  gap: 12px;
  align-items: end;
}

.option-fields label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  color: var(--muted);
  font-size: 14px;
}

.option .money-field {
  color: var(--ink);
}

.option .money-field input,
.option .qty-field {
  font-size: 30px;
}

.qty-field {
  width: 100%;
  min-width: 0;
  padding: 0;
  border: 0;
  border-bottom: 2px solid var(--ink);
  background: transparent;
  color: var(--ink);
  font-family: var(--num);
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

/* Unit radios as one segmented row, like the PT|EN toggle. The input stays real (keyboard, screen
   readers) but invisible; the span is what you see and tap. */
.unit-choice {
  display: flex;
  grid-column: 1 / -1;
  margin: 0;
  padding: 0;
  border: 0;
}

.unit-choice label {
  position: relative;
  display: flex;
  flex: 1;
}

.unit-choice input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.unit-choice span {
  display: grid;
  flex: 1;
  place-items: center;
  min-height: 44px;
  border: 1.5px solid var(--rule);
  border-left-width: 0;
  color: var(--ink);
  font: 700 20px/1 var(--num);
}

.unit-choice label:first-of-type span,
.unit-choice .new-family span {
  border-left-width: 1.5px;
  border-radius: var(--radius) 0 0 var(--radius);
}

.unit-choice label:has(+ .new-family) span,
.unit-choice label:last-of-type span {
  border-radius: 0 var(--radius) var(--radius) 0;
}

.unit-choice .new-family {
  margin-left: 8px;
}

.unit-choice input:checked + span {
  border-color: var(--primary);
  background: var(--primary);
  color: var(--primary-ink);
}

.option.winner .unit-choice input:checked + span {
  color: var(--tag);
}

.unit-choice input:focus-visible + span {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

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

/* The quantity field shares its row with the × key for multipacks. */
.qty-pack {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  min-width: 0;
}

.qty-pack label {
  flex: 1;
}

.pack-key {
  flex: none;
  width: 44px;
  height: 44px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  font: 700 30px/1 var(--num);
}

.pack-total {
  margin-bottom: 4px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.option-result {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 4px 12px;
  min-height: 40px;
}

.option-result:empty {
  display: none;
}

.unit-price {
  display: flex;
  align-items: flex-end;
}

.unit-price .tag-price {
  font-size: 36px;
}

.unit-price .per {
  margin-left: 2px;
  margin-bottom: 4px;
  font: 700 18px/1 var(--num);
}

.verdict {
  margin-bottom: 4px;
  font-weight: 700;
}

.verdict.dear {
  color: var(--dear);
}

.add-winner {
  flex-basis: 100%;
  min-height: 44px;
  border: 0;
  border-radius: var(--radius);
  background: var(--tag-ink);
  color: var(--tag);
  font-weight: 700;
}

.compare-msg {
  margin: 0;
  padding: 12px 16px 0;
  color: var(--muted);
}

.compare-msg:empty {
  display: none;
}

.compare-msg.error {
  color: var(--dear);
}

/* ---------- history summary ---------- */

.insights {
  margin: 12px 16px 4px;
  padding: 0 14px 12px;
  border-radius: var(--radius);
  background: var(--surface);
}

.insights > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  font: 700 20px/1 var(--num);
  cursor: pointer;
  list-style: none;
}

.insights > summary::-webkit-details-marker {
  display: none;
}

/* The same open/closed marker as a trip. */
.insights > summary::before {
  width: 0.8em;
  color: var(--muted);
  content: '▸';
}

.insights[open] > summary::before {
  content: '▾';
}

.insights-head {
  margin: 12px 0 6px;
  color: var(--muted);
  font: 700 15px/1.2 var(--text);
}

.insights p {
  margin: 6px 0 0;
}

/* One bar per month, all one hue: a single series. The tapped month is marked by shape (a ring and a bold label),
   not by colour, and read out underneath. */
.month-bars {
  display: flex;
  gap: 6px;
}

.month-bar {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 44px;
  padding: 4px 0 0;
  border: 0;
  background: none;
  color: var(--muted);
}

.month-track {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: 96px;
  border-bottom: 1px solid var(--rule);
}

.month-fill {
  width: 60%;
  border-radius: 4px 4px 0 0;
  background: var(--primary);
}

.month-bar[aria-pressed='true'] .month-fill {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.month-bar[aria-pressed='true'] .month-label {
  color: var(--ink);
  font-weight: 700;
}

.month-label {
  font-size: 13px;
}

.month-value {
  font: 700 18px/1.2 var(--num);
}

.avg-trip {
  color: var(--muted);
}

.store-stats {
  margin: 0;
  padding: 0;
  list-style: none;
}

.store-stats li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 12px;
  padding: 8px 0;
  border-top: 1px solid var(--rule);
}

.store-name {
  font-weight: 700;
}

.store-total {
  font: 700 18px/1.2 var(--num);
  font-variant-numeric: tabular-nums;
}

.store-line {
  grid-column: 1 / -1;
  color: var(--muted);
  font-size: 14px;
}

/* ---------- history backup ---------- */

.backup {
  padding: 8px 16px 24px;
}

.backup p {
  margin: 0 0 10px;
  color: var(--muted);
}

.backup-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* ---------- about ---------- */

.about {
  padding: 8px 16px 24px;
}

.about-logo {
  display: grid;
  place-items: center;
  padding: 16px 0 8px;
}

.about-logo .wordmark {
  height: 72px;
}

.about-lede {
  margin: 0;
  text-align: center;
}

/* Each section a framed card, its head inside (index.html): the copyrights the last. */
.about-card {
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
}

/* Section heads as in History's summary. */
.about h2 {
  margin: 0 0 2px;
  color: var(--muted);
  font: 700 15px/1.2 var(--text);
}

.about h2 + p {
  margin: 0;
}

/* The space in use, then its parts, each size at the right edge, then the rest of what the browser says. */
.about-usage {
  display: grid;
  gap: 6px;
  margin-top: 12px;
}

.about-usage p,
.about-storage-parts {
  margin: 0;
}

.about-storage-parts {
  padding-left: 12px;
  border-left: 2px solid var(--rule);
}

.about-storage-parts div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.about-storage-parts dt {
  color: var(--muted);
}

.about-storage-parts dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.about-version {
  margin: 0;
  font: 600 15px/1.4 ui-monospace, 'Roboto Mono', monospace;
}

.about-update {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-top: 8px;
}

.about-update-result {
  margin: 0;
  color: var(--muted);
}

.about-links {
  margin: 0;
  padding: 0;
  list-style: none;
}

.about-links li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 6px;
  min-height: 44px; /* a thumb-sized row for every link */
}

.about-links a {
  color: inherit;
  font-weight: 600;
  text-underline-offset: 3px;
}

/* Each copyright is a sentence and its licence's link: a gap keeps one from running into the next. */
.about-copyrights li + li {
  margin-top: 12px;
}

.about-share {
  margin-top: 8px;
}

.compare-actions {
  display: flex;
  gap: 12px;
  padding: 12px 16px 24px;
}

.secondary {
  min-height: 44px;
  padding: 0 16px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  font-weight: 600;
}

/* ---------- tabs ---------- */

.tabs {
  display: flex;
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface);
  border-top: 1px solid var(--rule);
}

.tabs button {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-height: 60px;
  padding: 6px 0 4px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
}

.tab-icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 60px;
  height: 30px;
  border-radius: 15px;
}

.tab-icon svg {
  width: 23px;
  height: 23px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tabs button[aria-selected='true'] {
  color: var(--ink);
}

/* Item count on the Cart tab; the surface-coloured ring keeps it legible on the bar and on the yellow pill. */
.badge {
  position: absolute;
  top: -3px;
  left: calc(50% + 5px);
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: var(--ink);
  color: var(--paper);
  box-shadow: 0 0 0 2px var(--surface);
  font: 700 14px/20px var(--num);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.badge.bump {
  animation: badge-bump 260ms cubic-bezier(0.3, 1.6, 0.6, 1);
}

@keyframes badge-bump {
  from {
    transform: scale(1.5);
  }
}

/* The active tab wears a little shelf tag; it pops in when tapped. */
.tabs button[aria-selected='true'] .tab-icon {
  background: var(--pill);
  color: var(--pill-ink);
  animation: tag-pop 200ms cubic-bezier(0.3, 1.4, 0.6, 1);
}

@keyframes tag-pop {
  from {
    transform: scaleX(0.4);
    opacity: 0;
  }
}

/* Celebration after finishing a trip: little price tags (pointed end, like the app icon). */
.burst {
  position: fixed;
  inset: 0;
  z-index: 20;
  overflow: hidden;
  pointer-events: none;
}

.burst-tag {
  position: absolute;
  width: 16px;
  height: 10px;
  border-radius: 2px;
  clip-path: polygon(28% 0, 100% 0, 100% 100%, 28% 100%, 0 50%);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* The update log in About: small print, for finding where an update stopped. */
.about-log {
  flex-basis: 100%; /* a row of its own under the button, all of it, however short its steps */
  margin-top: 8px;
  color: var(--muted);
  font-size: 13px;
}

/* Up to 40 steps, newest first: a framed box nine rows tall, scrolled within. about-view.js keeps the view where it
   is when a step comes in, so the browser's own anchoring is off. */
.about-log-steps {
  box-sizing: content-box; /* max-height counts text rows alone */
  max-height: 9lh;
  margin: 6px 0 0;
  padding: 0;
  overflow-y: auto;
  overscroll-behavior: contain; /* at either end, the page doesn't scroll on instead */
  overflow-anchor: none;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  font: 12px/1.5 ui-monospace, 'Roboto Mono', monospace;
  list-style: none;
}

/* Zebra stripes, a step to each: one that wraps onto a second row keeps its one stripe. */
.about-log-steps li {
  padding: 0 8px;
  white-space: pre-wrap;
}

.about-log-steps li:nth-child(even) {
  background: var(--stripe);
}
