/* Talio design tokens.
 *
 * The default is Slate & Basil: a blue-grey ground with a fresh green.
 * palettes.css holds this same set under [data-palette="slate"] and three
 * alternatives; the two copies of slate must move together, and a test
 * pins that they do.
 *
 * The one hard rule: colour never carries meaning alone. Every authority
 * level has a shape or a label as well as a hue, because the person reading
 * this is walking, holding a phone in one hand, in bad supermarket lighting.
 */

:root {
  color-scheme: light;

  --paper:        #f7f9fa;
  --surface:      #ffffff;
  --surface-2:    #eef2f5;
  --surface-3:    #e0e7ec;

  --ink:          #1e262b;
  --ink-2:        #4a565e;
  --muted:        #667179;
  --line:         #dde5ea;
  --line-strong:  #8c949a;

  /* Text on a filled button. Not a constant across palettes. */
  --on-primary:   #ffffff;
  --on-accent:    #161412;

  /* Each hue twice: the fill, and the same hue darkened enough to read as
     12px type on paper, on surface, and on its own -soft background. Text
     rules use -ink; fills use the base. See palettes.css. */
  --primary:        #2e7d5b;
  --primary-ink:    #2b7656;
  --primary-soft:   #e0f0e8;
  --accent:         #d1584a;
  --accent-ink:     #ae493e;
  --accent-soft:    #fbe8e5;
  --warn:           #b07a10;
  --warn-ink:       #90640d;
  --warn-soft:      #f8f0dc;
  --maybe:          #6a63a8;
  --maybe-ink:      #665fa1;
  --maybe-soft:     #eaeaf6;
  --meal:           #2b6a9c;
  --meal-ink:       #2b6a9c;
  --meal-soft:      #e3eff7;

  --radius:       14px;
  --radius-sm:    9px;
  --radius-lg:    22px;

  --shadow-sm:    0 1px 2px rgba(43, 39, 36, .06), 0 1px 3px rgba(43, 39, 36, .04);
  --shadow:       0 2px 8px rgba(43, 39, 36, .07), 0 8px 24px rgba(43, 39, 36, .05);
  --shadow-lg:    0 8px 32px rgba(43, 39, 36, .14);

  --sans: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont,
          "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;

  --nav-h: 4.25rem;
  --safe-b: env(safe-area-inset-bottom, 0px);

  /* The scanner draws its chrome over a live camera, which has no colour this
     file can know about. So it brings its own plate rather than borrowing a
     palette surface, and the plate is deliberately opaque: a half-transparent
     bar is legible over a dark shelf and gone over a white fridge door, which
     is the half of the day nobody tests.

     These are the same in all four palettes and in both modes on purpose --
     a camera view is a camera view. They are checked as a pair in
     tests/test_contrast.py like every other colour here. */
  --scrim:    #10151a;
  --on-scrim: #f2f5f7;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --paper:        #0f1518;
    --surface:      #161e22;
    --surface-2:    #1f292e;
    --surface-3:    #2b373d;

    --ink:          #eaf1f4;
    --ink-2:        #b9c7cf;
    --muted:        #86959e;
    --line:         #2b373d;
    --line-strong:  #5f6b72;

    --on-primary:   #06180f;
    --on-accent:    #161412;

    --primary:        #63c295;
    --primary-ink:    #63c295;
    --primary-soft:   #143024;
    --accent:         #f0806f;
    --accent-ink:     #f0806f;
    --accent-soft:    #3a1f1b;
    --warn:           #e0b95e;
    --warn-ink:       #e0b95e;
    --warn-soft:      #332c15;
    --maybe:          #9a92e0;
    --maybe-ink:      #9a92e0;
    --maybe-soft:     #22203c;
    --meal:           #6bb0e0;
    --meal-ink:       #6bb0e0;
    --meal-soft:      #16283a;

    --shadow-sm:    0 1px 2px rgba(0, 0, 0, .35);
    --shadow:       0 2px 10px rgba(0, 0, 0, .4);
    --shadow-lg:    0 10px 36px rgba(0, 0, 0, .55);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #0f1518; --surface: #161e22; --surface-2: #1f292e; --surface-3: #2b373d;
  --ink: #eaf1f4; --ink-2: #b9c7cf; --muted: #86959e;
  --line: #2b373d; --line-strong: #5f6b72;
  --on-primary: #06180f; --on-accent: #161412;
  --primary: #63c295; --primary-ink: #63c295; --primary-soft: #143024;
  --accent: #f0806f; --accent-ink: #f0806f; --accent-soft: #3a1f1b;
  --warn: #e0b95e; --warn-ink: #e0b95e; --warn-soft: #332c15;
  --maybe: #9a92e0; --maybe-ink: #9a92e0; --maybe-soft: #22203c;
  --meal: #6bb0e0; --meal-ink: #6bb0e0; --meal-soft: #16283a;
  --shadow-sm: 0 1px 2px rgba(0,0,0,.35);
  --shadow: 0 2px 10px rgba(0,0,0,.4);
  --shadow-lg: 0 10px 36px rgba(0,0,0,.55);
}

* { box-sizing: border-box; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

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

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}

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

h1, h2, h3 { margin: 0; font-weight: 640; letter-spacing: -.015em; }

/* --------------------------------------------------------------------- */
/* Shell                                                                  */
/* --------------------------------------------------------------------- */

#app {
  min-height: 100dvh;
  padding-bottom: calc(var(--nav-h) + var(--safe-b) + 1rem);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem 1rem .7rem;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s;
}

.topbar--scrolled { border-bottom-color: var(--line); }

.topbar--recipe { gap: .35rem; }
.topbar--recipe .iconbtn { flex: none; }

.topbar__title {
  flex: 1;
  min-width: 0;
  font-size: 1.35rem;
  font-weight: 680;
  letter-spacing: -.02em;
}

.topbar__sub {
  display: block;
  font-size: .78rem;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0;
}

.view { padding: 0 1rem; max-width: 44rem; margin: 0 auto; }

/* --------------------------------------------------------------------- */
/* Bottom navigation                                                      */
/* --------------------------------------------------------------------- */

.nav {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 50;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: .15rem;
  padding: .4rem .4rem calc(.4rem + var(--safe-b));
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: saturate(180%) blur(18px);
  border-top: 1px solid var(--line);
}

.nav__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .18rem;
  padding: .45rem .2rem .35rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--muted);
  font-size: .68rem;
  font-weight: 560;
  letter-spacing: .01em;
  cursor: pointer;
  transition: color .15s, background .15s;
}

.nav__item svg { width: 23px; height: 23px; }
.nav__item:hover { color: var(--ink-2); }

.nav__item--on {
  color: var(--primary-ink);
  background: var(--primary-soft);
}

.nav__badge {
  position: absolute;
  transform: translate(.85rem, -.4rem);
  min-width: 1.05rem;
  height: 1.05rem;
  padding: 0 .28rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: .63rem;
  font-weight: 700;
  line-height: 1.05rem;
  text-align: center;
}

/* --------------------------------------------------------------------- */
/* Buttons                                                                */
/* --------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  padding: .62rem 1.05rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: .9rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform .1s, background .15s, border-color .15s;
}

.btn:active { transform: scale(.97); }
.btn svg { width: 17px; height: 17px; }

/* Contrast against --primary is not a constant across four palettes, so the
   text colour is a token each one sets rather than a hardcoded white. Light
   palettes use a dark primary and white text; dark palettes lighten the
   primary and flip the text to near-black. */
.btn--primary {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

.btn--accent { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn--ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn--ghost:hover { background: var(--surface-2); color: var(--ink); }
.btn--sm { padding: .4rem .75rem; font-size: .82rem; }
.btn--block { width: 100%; }
.btn:disabled { opacity: .45; cursor: default; }

.iconbtn {
  display: inline-grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border: 0;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--ink-2);
  cursor: pointer;
  transition: background .15s, transform .1s;
}
.iconbtn:active { transform: scale(.94); }
.iconbtn:hover { background: var(--surface-3); }
.iconbtn svg { width: 19px; height: 19px; }

/* --------------------------------------------------------------------- */
/* Quick add                                                              */
/* --------------------------------------------------------------------- */

.quickadd {
  display: flex;
  gap: .5rem;
  align-items: center;
  margin: .25rem 0 1rem;
  padding: .3rem .3rem .3rem 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
  transition: border-color .15s, box-shadow .15s;
}

.quickadd:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.quickadd input {
  flex: 1;
  min-width: 0;
  padding: .55rem 0;
  border: 0;
  background: none;
  outline: none;
  font-size: 1rem;
}

.quickadd input::placeholder { color: var(--muted); }

/* --------------------------------------------------------------------- */
/* Aisle groups and items                                                 */
/* --------------------------------------------------------------------- */

.aisle { margin-bottom: 1.35rem; }

.aisle__head {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  margin: 0 .25rem .5rem;
}

.aisle__name {
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}

.aisle__count {
  font-size: .74rem;
  font-weight: 600;
  /* Was --line-strong, which is a border colour and read at 1.6:1 -- all but
     invisible. "3 left" is information, not decoration. */
  color: var(--muted);
}

.items {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.item {
  display: flex;
  align-items: flex-start;
  gap: .8rem;
  padding: .7rem .9rem;
  border-bottom: 1px solid var(--line);
  transition: background .15s, opacity .2s;
}

.item:last-child { border-bottom: 0; }
.item:hover { background: var(--surface-2); }
.item--bought { opacity: .42; }
.item--bought .item__name { text-decoration: line-through; }

.check {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.55rem;
  height: 1.55rem;
  margin-top: .1rem;
  border: 2px solid var(--line-strong);
  border-radius: 50%;
  background: none;
  color: transparent;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, transform .1s;
}

.check:active { transform: scale(.88); }
.check svg { width: 13px; height: 13px; }

/* The tick is ink on a fill, so it takes the fill's ink token rather than a
 * hardcoded white. White reads fine on the dark greens the light palettes
 * use and all but disappears on the lightened ones the dark palettes use --
 * 1.9:1 at worst, under even the 3.0 a graphical object needs. Identical to
 * #fff in all four light sets, so only dark mode changes. */
.check--on {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

.item__body { flex: 1; min-width: 0; }

.plan__thumb {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.65rem;
  height: 2.65rem;
  border-radius: .65rem;
  background-color: var(--surface-3);
  background-size: cover;
  background-position: center;
  color: var(--muted);
  overflow: hidden;
}

.plan__day {
  min-height: 3.25rem;
  padding: .25rem 0;
  border-radius: var(--radius);
  transition: background .15s, box-shadow .15s;
}

.plan__undecided {
  padding: .65rem .5rem .75rem;
  border: 1px solid var(--line);
  background: var(--surface-2);
}

.plan__undecided .section__note { margin-bottom: .75rem; }

.plan__day--drop-target {
  background: var(--primary-soft);
  box-shadow: 0 0 0 2px var(--primary);
}

.plan__entry[draggable="true"] { cursor: grab; }

.plan__entry--dragging {
  opacity: .42;
  background: var(--surface-2);
}

.plan__drag-handle {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.65rem;
  margin: 0 -.25rem 0 -.35rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--muted);
  cursor: grab;
  touch-action: none;
}

.plan__drag-handle:hover,
.plan__drag-handle:focus-visible {
  background: var(--surface-3);
  color: var(--ink);
}

.plan-is-dragging,
.plan-is-dragging * {
  cursor: grabbing !important;
  user-select: none;
}

.item__line {
  display: flex;
  align-items: baseline;
  gap: .45rem;
  flex-wrap: wrap;
}

.item__name {
  font-size: 1rem;
  font-weight: 560;
  letter-spacing: -.005em;
}

.item__qty {
  font-size: .84rem;
  font-weight: 640;
  color: var(--primary-ink);
  font-variant-numeric: tabular-nums;
}

/* The quiet intelligence lives on this line. Brand memory, pantry doubt and
 * repeat asks are all annotations -- never dialogs, never blocking. */
.item__hints {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
  margin-top: .12rem;
  font-size: .78rem;
  color: var(--muted);
}

.hint { display: inline-flex; align-items: center; gap: .22rem; }
.hint svg { width: 12px; height: 12px; opacity: .75; }
.hint--brand { color: var(--meal-ink); font-weight: 560; }
.hint--optional { color: var(--warn-ink); }
.hint--repeat { color: var(--accent-ink); font-weight: 560; }

.who {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .76rem;
  font-weight: 560;
  color: var(--muted);
}

.who__dot {
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: currentColor;
}

/* Meal and restock tags identify why a row is on the list.
 * Requests from children show the requester without an extra label. */

.tag {
  display: inline-flex;
  align-items: center;
  padding: .1rem .42rem;
  border-radius: 5px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .045em;
  text-transform: uppercase;
}

.tag--recipe     { background: var(--meal-soft); color: var(--meal-ink); }
.tag--staple     { background: var(--warn-soft); color: var(--warn-ink); }

/* --------------------------------------------------------------------- */
/* Cards, sections, empty states                                          */
/* --------------------------------------------------------------------- */

.card {
  padding: 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.section { margin: 1.6rem 0; }

.section__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  margin: 0 .25rem .6rem;
}

.section__title { font-size: 1.02rem; font-weight: 660; }

.section__note {
  font-size: .8rem;
  color: var(--muted);
  margin: -.3rem .25rem .6rem;
}

.section--checked {
  margin-top: 2.5rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
}

.empty {
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--muted);
}

.empty svg { width: 46px; height: 46px; opacity: .3; margin-bottom: .85rem; }
.empty h3 { font-size: 1.08rem; color: var(--ink-2); margin-bottom: .3rem; }
.empty p { margin: 0 0 1.1rem; font-size: .9rem; }

/* --------------------------------------------------------------------- */
/* Progress                                                               */
/* --------------------------------------------------------------------- */

.progress {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin: 0 .25rem 1.1rem;
}

.progress__track {
  flex: 1;
  height: .42rem;
  border-radius: 999px;
  background: var(--surface-3);
  overflow: hidden;
}

.progress__fill {
  height: 100%;
  border-radius: 999px;
  background: var(--primary);
  transition: width .35s cubic-bezier(.4, 0, .2, 1);
}

.progress__label {
  font-size: .78rem;
  font-weight: 640;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------- */
/* Recipe cards                                                           */
/* --------------------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: .8rem;
}

.rcard {
  display: block;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: transform .12s, box-shadow .18s;
}

.rcard:active { transform: scale(.985); }
.rcard:hover { box-shadow: var(--shadow); }

.rcard__img {
  aspect-ratio: 4 / 3;
  background: var(--surface-3);
  background-size: cover;
  background-position: center;
  display: grid;
  place-items: center;
  color: var(--muted);
}

.rcard__img svg { width: 32px; height: 32px; }
.rcard__body { padding: .6rem .7rem .75rem; }

.rcard__title {
  font-size: .92rem;
  font-weight: 620;
  line-height: 1.25;
  letter-spacing: -.01em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.rcard__meta {
  margin-top: .3rem;
  font-size: .75rem;
  color: var(--muted);
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------- */
/* Recipe detail                                                          */
/* --------------------------------------------------------------------- */

.hero {
  margin: 0 -1rem 1rem;
  aspect-ratio: 16 / 10;
  background: var(--surface-3);
  overflow: hidden;
}

.hero img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.recipe-photo-editor {
  display: flex;
  align-items: center;
  gap: .8rem;
}

.recipe-photo-editor__preview {
  display: grid;
  place-items: center;
  flex: none;
  width: 5.5rem;
  height: 4.25rem;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--muted);
}

.recipe-photo-editor__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.recipe__title {
  font-family: var(--serif);
  font-size: 1.9rem;
  line-height: 1.15;
  letter-spacing: -.02em;
  margin-bottom: .4rem;
}

.recipe__meta {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  font-size: .84rem;
  color: var(--muted);
  margin-bottom: 1rem;
}

.ing {
  display: flex;
  gap: .7rem;
  padding: .5rem .2rem;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}

.ing:last-child { border-bottom: 0; }
.ing--on { opacity: .4; text-decoration: line-through; }
.ing__qty { flex: none; min-width: 4.6rem; font-weight: 640; color: var(--primary-ink); font-variant-numeric: tabular-nums; }
.ing__note { color: var(--muted); font-size: .86rem; }

.step {
  display: flex;
  gap: .85rem;
  padding: .8rem 0;
  border-bottom: 1px solid var(--line);
}

.step__n {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  font-size: .8rem;
  font-weight: 700;
}

.scaler {
  display: inline-flex;
  align-items: center;
  gap: .1rem;
  padding: .2rem;
  background: var(--surface-2);
  border-radius: 999px;
}

.scaler button {
  width: 1.9rem; height: 1.9rem;
  border: 0; border-radius: 50%;
  background: none; color: var(--ink-2);
  font-size: 1.05rem; font-weight: 600; cursor: pointer;
}

.scaler button:hover { background: var(--surface-3); }
.scaler span { min-width: 3.4rem; text-align: center; font-size: .85rem; font-weight: 640; }

/* --------------------------------------------------------------------- */
/* Sending a recipe to the list                                           */
/* --------------------------------------------------------------------- */

/* The picker is a decision screen, so the bottom bar goes and the Add button
 * takes its place -- same spot on the thumb, one thing to do. */

.picker__servings {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .9rem 0 .2rem;
  font-size: .88rem;
}

.picker__label {
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--primary-ink);
}

.view--picker { padding-bottom: 1rem; }

.pick {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .62rem .2rem;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.pick:last-child { border-bottom: 0; }
.pick__body { flex: 1; min-width: 0; }

/* Unticked rows dim rather than strike through. A struck row reads as done;
 * these are simply not coming, and half of them are one tap from coming. */
.pick--off .item__name,
.pick--off .item__qty { color: var(--muted); font-weight: 560; }

.pick .check { margin-top: 0; }

.actionbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 50;
  padding: .7rem 1rem calc(.7rem + var(--safe-b));
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: saturate(180%) blur(18px);
  border-top: 1px solid var(--line);
}

.actionbar .btn--block { display: flex; max-width: 42rem; margin: 0 auto; padding: .78rem 1.05rem; }

/* --------------------------------------------------------------------- */
/* Cook mode                                                              */
/* --------------------------------------------------------------------- */

/* A different register from the rest of the app on purpose: full bleed, no
 * bottom nav, and type sized to be read at arm's length across a counter
 * rather than held six inches from your face. */

.cook {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  padding-bottom: var(--safe-b);
}

.cook__bar {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .7rem .8rem;
  border-bottom: 1px solid var(--line);
}

.cook__pips {
  flex: 1;
  display: flex;
  gap: .25rem;
  align-items: center;
  min-width: 0;
}

.pip {
  flex: 1;
  height: .3rem;
  min-width: .35rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--surface-3);
  cursor: pointer;
  transition: background .2s;
}

.pip--done { background: var(--primary-soft); }
.pip--on { background: var(--primary); }

.cook__count {
  font-size: .8rem;
  font-weight: 660;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.cook__body {
  flex: 1;
  overflow-y: auto;
  padding: 1.6rem 1.4rem 2rem;
  max-width: 40rem;
  width: 100%;
  margin: 0 auto;
}

.cook__section {
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--primary-ink);
  margin-bottom: .9rem;
}

/* The ingredients this step actually uses, above the instruction. This is
 * the whole reason cook mode beats scrolling a recipe. */
.cook__uses {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: .85rem 1rem;
  background: var(--primary-soft);
  border-radius: var(--radius);
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1.1rem;
}

.cook__uses li {
  font-size: .95rem;
  font-weight: 580;
  color: var(--primary-ink);
}

.cook__text {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.5rem, 5.5vw, 2.1rem);
  line-height: 1.35;
  letter-spacing: -.015em;
}

.cook__timers {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: 2rem;
}

.timer {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 2.9rem;
  padding: .55rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: 1rem;
  font-weight: 640;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  overflow: hidden;
}

.timer__face {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  color: inherit;
  padding: 0;
}

.timer__x {
  display: grid;
  place-items: center;
  width: 1.4rem;
  height: 1.4rem;
  margin-left: .15rem;
  border: 0;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--muted);
  cursor: pointer;
}

.timer__track {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: .2rem;
  background: transparent;
}

.timer__fill {
  height: 100%;
  background: var(--primary);
  transition: width 1s linear;
}

.timer--running { border-color: var(--primary); color: var(--primary-ink); }
.timer--paused { opacity: .7; }

.timer--done {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-ink);
  animation: nudge .6s ease 3;
}

.timer--done .timer__fill { background: var(--accent); }

@keyframes nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  75% { transform: translateX(3px); }
}

.cook__nav {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: .6rem;
  padding: .8rem 1rem calc(.8rem + var(--safe-b));
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.cook__nav .btn { min-height: 3.1rem; font-size: 1rem; }

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

.seg {
  display: inline-flex;
  padding: .18rem;
  background: var(--surface-2);
  border-radius: 999px;
}

.seg button {
  padding: .32rem .7rem;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s, color .15s;
}

.seg button[aria-pressed="true"] {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}

/* --------------------------------------------------------------------- */
/* Palette picker                                                          */
/* --------------------------------------------------------------------- */

.pal {
  display: flex;
  align-items: center;
  gap: .85rem;
  width: 100%;
  padding: .7rem .8rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition: border-color .15s, transform .1s;
}

.pal:active { transform: scale(.99); }
.pal--on { border-color: var(--primary); }

/* The swatch paints itself with the palette's own paper and line colours, so
   each row previews the whole thing rather than three dots floating on the
   background of whichever palette happens to be on. */
.pal__chips {
  flex: none;
  display: flex;
  gap: .22rem;
  padding: .4rem .45rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
}

.pal__chip {
  width: .95rem;
  height: 1.5rem;
  border-radius: 3px;
  background: var(--surface-3);
}

.pal__text { flex: 1; min-width: 0; }
.pal__name { display: block; font-weight: 620; font-size: .95rem; }

.pal__blurb {
  display: block;
  font-size: .78rem;
  color: var(--muted);
  line-height: 1.3;
}

.pal__tick { flex: none; color: var(--primary-ink); display: grid; place-items: center; }

/* --------------------------------------------------------------------- */
/* Sheets, toasts, forms                                                  */
/* --------------------------------------------------------------------- */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(30, 26, 22, .45);
  backdrop-filter: blur(3px);
  animation: fade .18s ease;
}

.sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 91;
  max-height: 86dvh;
  overflow-y: auto;
  padding: 1rem 1rem calc(1.4rem + var(--safe-b));
  background: var(--surface);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-lg);
  animation: rise .26s cubic-bezier(.22, 1, .36, 1);
}

.sheet__grip {
  width: 2.4rem; height: .26rem;
  margin: 0 auto .9rem;
  border-radius: 999px;
  background: var(--line-strong);
}

.sheet__title { font-size: 1.15rem; font-weight: 660; margin-bottom: .2rem; }
.sheet__sub { font-size: .85rem; color: var(--muted); margin-bottom: 1rem; }

.action-list {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.action-list__item {
  display: flex;
  align-items: center;
  gap: .8rem;
  width: 100%;
  min-height: 3.25rem;
  padding: .75rem .9rem;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.action-list__item:last-child { border-bottom: 0; }
.action-list__item:hover { background: var(--surface-3); }
.action-list__item:disabled { opacity: .5; cursor: default; }
.action-list__item svg { flex: none; color: var(--muted); }
.action-list__item--danger, .action-list__item--danger svg { color: var(--accent-ink); }
.action-list__item strong { display: block; font-weight: 620; }
.action-list__item small { display: block; margin-top: .1rem; color: var(--muted); }

.voice-recorder {
  display: grid;
  justify-items: center;
  gap: .4rem;
  padding: 1rem 0 1.4rem;
}

.voice-recorder__mic {
  display: grid;
  place-items: center;
  width: 4.25rem;
  height: 4.25rem;
  margin-bottom: .35rem;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  animation: voice-pulse 1.6s ease-in-out infinite;
}

.voice-recorder__time {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.voice-transcript {
  margin-bottom: 1rem;
  padding: .75rem .85rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: .85rem;
}

.voice-transcript p { margin: .25rem 0 0; }

@keyframes voice-pulse {
  50% { transform: scale(1.06); box-shadow: 0 0 0 .5rem var(--primary-soft); }
}

.manage-items {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.manage-item {
  display: flex;
  align-items: center;
  gap: .8rem;
  width: 100%;
  min-height: 3.5rem;
  padding: .7rem .9rem;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.manage-item:last-child { border-bottom: 0; }
.manage-item:hover { background: var(--surface-2); }
.manage-item > svg { flex: none; color: var(--muted); }
.manage-item__body { flex: 1; min-width: 0; }
.manage-item__hint { display: block; margin-top: .15rem; color: var(--muted); font-size: .8rem; }

@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { transform: translateY(100%); } }

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--nav-h) + var(--safe-b) + 1rem);
  z-index: 95;
  transform: translateX(-50%);
  max-width: calc(100vw - 2rem);
  padding: .65rem 1.1rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
  font-size: .87rem;
  font-weight: 560;
  box-shadow: var(--shadow-lg);
  animation: rise .22s cubic-bezier(.22, 1, .36, 1);
}

.field { margin-bottom: .9rem; }

.field label {
  display: block;
  margin-bottom: .3rem;
  font-size: .78rem;
  font-weight: 640;
  color: var(--muted);
  letter-spacing: .02em;
}

.field input, .field textarea, .field select {
  width: 100%;
  padding: .62rem .8rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}

.field input:focus, .field textarea:focus, .field select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.field textarea { min-height: 7rem; resize: vertical; line-height: 1.5; }
.row { display: flex; gap: .6rem; }
.row > * { flex: 1; }

/* --------------------------------------------------------------------- */
/* Sign in                                                                */
/* --------------------------------------------------------------------- */

.signin {
  display: grid;
  place-items: center;
  min-height: 100dvh;
  padding: 2rem 1.25rem;
}

.signin__inner { width: 100%; max-width: 22rem; text-align: center; }

.signin__mark {
  font-family: var(--serif);
  font-size: 2.5rem;
  letter-spacing: -.03em;
  margin-bottom: .2rem;
}

.signin__tag { color: var(--muted); font-size: .9rem; margin-bottom: 2rem; }

.people {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  gap: .7rem;
  margin-bottom: 1.2rem;
}

.person {
  padding: 1rem .6rem;
  border: 2px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  transition: border-color .15s, transform .1s;
}

.person:active { transform: scale(.97); }
.person[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); }
.person__emoji { font-size: 1.7rem; line-height: 1; }
.person__name { margin-top: .35rem; font-size: .85rem; font-weight: 620; }

.pin {
  width: 100%;
  padding: .8rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 1.4rem;
  letter-spacing: .5em;
  text-align: center;
  outline: none;
}

.pin:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }

/* --------------------------------------------------------------------- */
/* Utility                                                                */
/* --------------------------------------------------------------------- */

/* The fill hue as 12.8px type is the mistake this palette is built to avoid:
 * --warn on --warn-soft is 2.81:1 in the light sets. Of everything in the
 * app this is the worst place for it -- the bar only exists when somebody is
 * offline in a store, which is when reading it actually matters. */
.offline {
  padding: .45rem 1rem;
  background: var(--warn-soft);
  color: var(--warn-ink);
  font-size: .8rem;
  font-weight: 620;
  text-align: center;
}

.muted { color: var(--muted); }
.spread { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.stack { display: flex; flex-direction: column; gap: .55rem; }
.wrap { display: flex; gap: .5rem; flex-wrap: wrap; }
.center { text-align: center; }
.hidden { display: none !important; }

/* Photographing several pages -- a long receipt, a recipe across facing
   pages -- is deliberately a sequence, not a file picker that happens to
   accept several files. A phone camera hands back one picture per trip
   through the input anyway, and numbered previews make the order visible
   before any slow reading starts. */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(5.25rem, 1fr));
  gap: .55rem;
  margin: .8rem 0 1rem;
}

.photo-tile {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--ink);
}

.photo-tile img { width: 100%; height: 100%; object-fit: cover; }

.photo-tile__number {
  position: absolute;
  left: .35rem;
  top: .35rem;
  display: grid;
  place-items: center;
  min-width: 1.55rem;
  height: 1.55rem;
  padding: 0 .25rem;
  border-radius: 999px;
  background: var(--scrim);
  color: var(--on-scrim);
  font-size: .75rem;
  font-weight: 700;
}

.photo-tile__remove {
  position: absolute;
  right: .25rem;
  top: .25rem;
  width: 2rem;
  height: 2rem;
  background: var(--scrim);
  color: var(--on-scrim);
}

.photo-tile__remove:hover { background: var(--scrim); color: var(--on-scrim); }
.photo-grid--compact { grid-template-columns: repeat(auto-fit, minmax(4.5rem, 7rem)); }
.photo-actions { margin: 1rem 0 2rem; }
.receipt-lines { border-top: 1px solid var(--line); }

.receipt-line {
  padding: .65rem 0;
  border-bottom: 1px solid var(--line);
}

.receipt-line__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 5.25rem 2.4rem;
  gap: .4rem;
  align-items: center;
}

.receipt-line input {
  min-width: 0;
  padding: .55rem .65rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

.receipt-line input:focus {
  outline: 0;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.receipt-line__price { text-align: right; font-variant-numeric: tabular-nums; }
.receipt-line__raw { display: block; margin: .3rem .1rem 0; color: var(--muted); font-size: .75rem; }

.receipt-history__item {
  width: 100%;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.receipt-history__item > svg { flex: none; color: var(--muted); align-self: center; }
.receipt-history__total { font-weight: 720; font-variant-numeric: tabular-nums; }
.receipt-history__grand-total { margin-top: 1.2rem; }
.receipt-line__match { display: block; margin: .3rem .1rem 0; color: var(--primary); font-size: .72rem; }
.receipt-line--summary { display: flex; justify-content: space-between; gap: 1rem; }
.receipt-reader { margin-top: 1.5rem; }
.receipt-reader__list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.receipt-reader__list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: .15rem .7rem;
  padding: .55rem 0;
  border-bottom: 1px solid var(--line);
  font-size: .8rem;
}
.receipt-reader__list strong { overflow-wrap: anywhere; }
.receipt-reader__list small { grid-column: 2; color: var(--muted); text-align: right; }

.spin {
  width: 1.1rem; height: 1.1rem;
  border: 2px solid var(--line-strong);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

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

/* ---------------------------------------------------------------------------
   The scanner

   Full bleed, like cook mode, and for the same reason: pointing a camera at a
   packet is not a browsing task, so it takes the screen rather than sitting in
   a panel inside one.

   The chrome is two solid plates with the camera showing between them. That is
   a design decision rather than a shortcut -- text laid straight over live
   video reads perfectly against a dark cupboard and disappears against a white
   fridge door, and the fridge door is most of the day.
   --------------------------------------------------------------------------- */

.scan {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--scrim);
  color: var(--on-scrim);
  overflow: hidden;
}

.scan__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Behind the chrome, and behind the reticle. */
  z-index: 0;
}

/* The corners of the read zone. Corners rather than a full rectangle because
   a closed box invites people to fit the whole barcode inside it, and the
   decoder wants the barcode BIGGER than that, not neatly contained. */
.scan__frame {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(78vw, 22rem);
  height: 34vh;
  max-height: 13rem;
  z-index: 1;
  pointer-events: none;
}

.scan__frame span {
  position: absolute;
  width: 1.6rem;
  height: 1.6rem;
  border: 3px solid var(--on-scrim);
  opacity: .9;
}

.scan__frame span:nth-child(1) { top: 0; left: 0; border-right: 0; border-bottom: 0; border-top-left-radius: var(--radius-sm); }
.scan__frame span:nth-child(2) { top: 0; right: 0; border-left: 0; border-bottom: 0; border-top-right-radius: var(--radius-sm); }
.scan__frame span:nth-child(3) { bottom: 0; left: 0; border-right: 0; border-top: 0; border-bottom-left-radius: var(--radius-sm); }
.scan__frame span:nth-child(4) { bottom: 0; right: 0; border-left: 0; border-top: 0; border-bottom-right-radius: var(--radius-sm); }

.scan__top {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: calc(.7rem + env(safe-area-inset-top, 0px)) .8rem .7rem;
  background: var(--scrim);
}

.scan__chip {
  color: var(--on-scrim);
  flex: none;
}

.scan__chip[aria-pressed="true"] { color: var(--warn); }

.scan__hint {
  flex: 1;
  margin: 0;
  text-align: center;
  font-size: .9rem;
  font-weight: 600;
  color: var(--on-scrim);
  /* The hint changes on every scan. Reserving its line stops the whole bar
     jumping a few pixels each time somebody reads a packet. */
  min-height: 1.3rem;
}

/* The camera window. Nothing is drawn here -- it is the gap between the two
   plates, and the video shows through it. */
.scan__top + .scan__frame { pointer-events: none; }

.scan__tray {
  position: relative;
  z-index: 2;
  margin-top: auto;
  max-height: 40vh;
  overflow-y: auto;
  background: var(--scrim);
  padding: 0 .8rem;
}

.scan__tray:not(:empty) { padding: .5rem .8rem; }

.scan__row {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .55rem .2rem;
  border-bottom: 1px solid color-mix(in srgb, var(--on-scrim) 14%, transparent);
  font-size: .95rem;
}

.scan__row:last-child { border-bottom: 0; }

.scan__row-name {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  color: var(--on-scrim);
}

.scan__row-brand {
  display: block;
  font-size: .78rem;
  font-weight: 500;
  opacity: .72;
}

.scan__row .iconbtn { color: var(--on-scrim); flex: none; opacity: .8; }

.scan__bottom {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .7rem .8rem calc(.7rem + var(--safe-b));
  background: var(--scrim);
}

/* The way out for anything with no barcode on it -- loose fruit, a bakery bag.
   Ghost weight because it is the second answer, not the main one. */
.scan__shutter {
  color: var(--on-scrim);
  border-color: color-mix(in srgb, var(--on-scrim) 30%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
}

.scan__done { min-height: 3.1rem; font-size: 1rem; }

/* --------------------------------------------------------------------- */
/* Stores and money                                                        */
/* --------------------------------------------------------------------- */

/* A store's worth of the list. Only drawn when the errand visits more than
   one, so this is a section heading rather than permanent chrome. */
/* Store filter. Scrolls sideways rather than wrapping: on a narrow phone a
   second row of chips pushes the first aisle off the screen, and the aisle is
   what somebody came here to read. */
.storefilter {
  display: flex;
  gap: .4rem;
  overflow-x: auto;
  padding: .1rem .1rem .85rem;
  margin: 0 -.1rem;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.storefilter::-webkit-scrollbar { display: none; }

.storefilter__chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  flex: 0 0 auto;
  padding: .34rem .7rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: .82rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}

/* The selected chip is a filled control, so it takes the pair the contrast
   suite already checks for one. --accent-ink is not that pair: it is the same
   hue as --accent, and in dark mode the identical value. */
.storefilter__chip[aria-pressed="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

.storefilter__count {
  font-size: .74rem;
  font-weight: 700;
  opacity: .75;
  font-variant-numeric: tabular-nums;
}

.storegroup { margin-bottom: 1.4rem; }

.storegroup__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .6rem;
  padding: .35rem .1rem .5rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: .5rem;
  cursor: pointer;
}

.storegroup__name {
  font-size: 1.02rem;
  font-weight: 680;
  color: var(--ink);
  letter-spacing: -0.01em;
}

.storegroup__meta { font-size: .78rem; color: var(--muted); }

/* Lines nobody has bought before. Set apart rather than hidden -- they are
   not a problem, just things you pick up wherever you see them. */
.storegroup--loose .storegroup__name { color: var(--muted); font-weight: 600; }

.field__hint {
  margin: .35rem 0 0;
  font-size: .76rem;
  color: var(--muted);
  line-height: 1.4;
}

/* --------------------------------------------------------------------- */
/* Stores, and how each one is walked                                       */

.storelist { list-style: none; margin: 0 0 1rem; padding: 0; }

.storerow {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .2rem .35rem .2rem .1rem;
  border-bottom: 1px solid var(--line);
}

.storerow:last-child { border-bottom: 0; }

.storerow__main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .12rem;
  padding: .7rem .6rem;
  border: 0;
  background: none;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
}

.storerow__name { font-weight: 640; }
.storerow__sub { font-size: .76rem; color: var(--muted); }
.storerow__acts { display: flex; align-items: center; gap: .15rem; }

.addstore { display: flex; gap: .5rem; align-items: center; }

.addstore input {
  flex: 1;
  padding: .62rem .8rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  outline: none;
}

.addstore input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* A smaller icon button, for the row of controls beside a store or an aisle.
   Two of these plus a name has to fit a phone without wrapping. */
.iconbtn--sm {
  width: 2rem;
  height: 2rem;
  font-size: .7rem;
  line-height: 1;
}

.iconbtn--sm:disabled { opacity: .3; cursor: default; }

.walknote { color: var(--muted); font-size: .84rem; margin-bottom: .9rem; }

.walk { list-style: none; margin: 0 0 1rem; padding: 0; }

.walkrow {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .3rem .35rem;
  border-bottom: 1px solid var(--line);
}

.walkrow:last-child { border-bottom: 0; }
.walkrow__moves { display: flex; gap: .1rem; }
.walkrow__name { flex: 1; font-size: .92rem; }


/* The number on the list's own aisle heading. It is the thing you read while
   looking for the aisle, so it carries the accent rather than the muted grey
   the rest of the heading uses. */
.aisle__no {
  display: inline-block;
  min-width: 1.35rem;
  margin-right: .4rem;
  padding: 0 .28rem;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-ink);
  text-align: center;
}

/* Where a line gets bought, shown on the flat list only. Reads as one more
   annotation under the name, never as a heading. */
.hint--store { color: var(--primary-ink); }

/* The aisle a store has no place for. It is a prompt to go and map the
   category, so it is marked rather than hidden. */
.aisle--loose .aisle__name { color: var(--warn-ink); }

/* One aisle in the store editor: move handles, then the aisle itself. */
.walkrow--aisle { align-items: stretch; }

.walkrow__open {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  padding: .55rem .6rem;
  border: 0;
  background: none;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
}

.walkrow__title { font-weight: 640; font-size: .95rem; }

/* What the aisle holds. Allowed to run long and wrap: seeing that Bread has
   both bakery and breakfast in it is the point of the row. */
.walkrow__holds {
  font-size: .76rem;
  color: var(--muted);
  line-height: 1.35;
}

/* Categories this store has nowhere to put. A gap to close, not an error, so
   it is marked in the warning colour rather than the danger one. */
.unplaced {
  margin-bottom: .9rem;
  padding: .6rem .75rem;
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  color: var(--warn-ink);
  font-size: .82rem;
  line-height: 1.45;
}

.cats { list-style: none; margin: 0; padding: 0; max-height: 46vh; overflow-y: auto; }

.cat {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .45rem .2rem;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}

.cat:last-child { border-bottom: 0; }
.cat input { width: 1.1rem; height: 1.1rem; flex: none; }
.cat__name { flex: 1; }

/* Which other aisle currently claims this category. Ticking it here moves it,
   so the note is a warning before the fact rather than a report after. */
.cat__owner {
  font-size: .74rem;
  color: var(--muted);
  font-style: italic;
}

.receipt-reading { text-align: center; padding-top: 4rem; }
.receipt-reading__spinner {
  display: block; width: 2.5rem; height: 2.5rem;
  margin: 0 auto 1.5rem; border-width: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .receipt-reading__spinner { animation: none; }
}
