/* Archivo, the display face: headlines, the wordmark, card titles, prices and button labels.
   One variable file (weight 400-800, width 62-100%), Latin only, served by src/server.ts
   (licence: public/fonts/OFL.txt). Body text stays on the system font. */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 62% 100%;
  font-display: swap;
  src: url("/static/fonts/archivo-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* "Parts Counter": a white counter, near-black lettering and one petrol colour that means
   "do it". Petrol fills one control per screen (Take a photo, Buy, a sheet's submit) and is
   otherwise only links, two tags and the focus ring; never a price. Red, amber and green keep
   their status jobs. The berry and the leaf live only in the mark. Every colour is hex. */
:root {
  color-scheme: light dark;
  /* page and surfaces */
  --bg: #FFFFFF;
  --surface: #FFFFFF;
  --surface-muted: #F1F4F4;      /* photo wells, notices, nav hover */
  --surface-tonal: #E9EEEF;      /* Pass, Upload, the stepper, quick answers, switch tracks */
  --segment-on: #FFFFFF;         /* the chosen side of a switch */
  --well-listing: #F1F4F4;       /* behind a seller's catalogue shot, multiplied in */
  /* ink */
  --text: #111719;
  --text-2: #3B4549;             /* the lead, the delivery line, in-progress tags */
  --muted: #4F5A5F;
  /* lines */
  --border: #DCE2E4;             /* hairlines */
  --border-strong: #7E898E;      /* the 1.5px steel edge on controls and inputs: 3:1 in sun */
  /* the one action colour: petrol */
  --accent: #00606E;
  --accent-hover: #00505B;
  --accent-pressed: #00505B;
  --accent-ink: #00606E;         /* links, tag text */
  --accent-soft: #E0F1F3;        /* the Best match and Price ready tags */
  --on-accent: #FFFFFF;
  /* status */
  --success: #1B6E37;
  --success-soft: #E4F3E8;
  --warning: #8A5300;
  --warning-soft: #FFF1D6;
  --danger: #B3261E;
  --danger-soft: #FCEBEA;
  /* the mark: the app icon's glossy berry and mint leaf, on an ink tile in the header */
  --brand-tile: #111719;
  --brand-tile-edge: #11171900;
  --brand-mark: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='12%2018%2076%2074'%3E%3Cpath%20d='M38%2033%20a12%2012%200%200%201%2024%200'%20fill='none'%20stroke='%233CCB98'%20stroke-width='7.5'%20stroke-linecap='round'/%3E%3Cpath%20d='M23%2032%20H77%20a5%205%200%200%201%205%205%20L85%2082%20a7%207%200%200%201%20-7%207%20H22%20a7%207%200%200%201%20-7%20-7%20L18%2037%20a5%205%200%200%201%205%20-5%20Z'%20fill='%23E63E63'/%3E%3Cpath%20d='M39%2046%20V78%20M39%2046%20H53%20a8%208%200%200%201%200%2016%20H39%20M39%2062%20H56%20a8%208%200%200%201%200%2016%20H39'%20fill='none'%20stroke='%23FFFFFF'%20stroke-width='9'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E");
  /* overlays */
  --focus-halo: #00606E47;
  --stamp-bg: #FFFFFFEB;
  --scrim: #090D0E80;
  --toast-bg: #111719;
  --toast-text: #FFFFFF;
  --toast-action: #FFFFFF2E;
  --shimmer: #FFFFFF52;
  /* shape */
  --radius: 16px;                /* order rows, cards on the plain pages, tiles, tables */
  --radius-sm: 12px;             /* inputs, notices, errors, thumbnails */
  --radius-card: 20px;           /* swipe and waiting cards; the photo inside is 12px */
  --radius-sheet: 24px;          /* bottom sheets, top corners */
  --radius-tag: 8px;             /* tags: not pressable, so not pills */
  --edge: 1.5px;
  --shadow: 0 1px 2px #1117190F;
  --shadow-card: 0 1px 2px #1117190F, 0 12px 32px -14px #11171947;
  --shadow-sheet: 0 -8px 32px #1117192E;
  --shadow-toast: 0 6px 24px #00000040;
  /* type */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Archivo", var(--font);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0E1214;
    --surface: #161C1F;
    --surface-muted: #1E2629;
    --surface-tonal: #242D31;
    --segment-on: #3A454A;
    --well-listing: #E6EBEC;     /* a dimmed light well, so a catalogue shot doesn't glare */
    --text: #ECF1F2;
    --text-2: #C2CBCE;
    --muted: #9AA6AB;
    --border: #283135;
    --border-strong: #66737A;
    --accent: #66C6D4;
    --accent-hover: #52B6C4;
    --accent-pressed: #52B6C4;
    --accent-ink: #7FD3DF;
    --accent-soft: #0E2E33;
    --on-accent: #03191C;
    --success: #6CCB8A;
    --success-soft: #142B1C;
    --warning: #F0B455;
    --warning-soft: #33270F;
    --danger: #FF8A80;
    --danger-soft: #3A1A18;
    --brand-tile-edge: #3A454A;
    --focus-halo: #66C6D452;
    --stamp-bg: #161C1FEB;
    --scrim: #000000A6;
    --toast-bg: #ECF1F2;
    --toast-text: #0E1214;
    --toast-action: #0E12142E;
    --shimmer: #FFFFFF29;
    --shadow: 0 1px 2px #00000066;
    --shadow-card: 0 1px 2px #00000066, 0 16px 36px -16px #000000B3;
    --shadow-sheet: 0 -8px 32px #00000080;
    --shadow-toast: 0 6px 24px #00000080;
  }
}

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

[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

/* iPhone and iPad only: the root follows the reader's text size (17px at the default setting).
   The second condition keeps macOS Safari, where -apple-system-body is 13px, on 16px. */
@supports (font: -apple-system-body) and (-webkit-touch-callout: none) {
  html {
    font: -apple-system-body;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 1rem/1.45 var(--font);
  -webkit-font-smoothing: antialiased;
  /* Checkboxes and radios take the action colour, not the browser's own blue. */
  accent-color: var(--accent);
}

a {
  color: var(--accent-ink);
  text-underline-offset: 2px;
}

/* A number to call stays on one line: "(555)" at the end of one line and "010-0100" at the start
   of the next reads as two numbers. */
a[href^="tel:"] {
  white-space: nowrap;
}

img {
  display: block;
  max-width: 100%;
}

h1,
h2,
h3 {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-weight: 750;
  line-height: 1.12;
  letter-spacing: 0;
  font-stretch: 90%;
}

h1 {
  font-size: 1.75rem;
  font-weight: 800;
  letter-spacing: -0.005em;
  font-stretch: 85%;
}

h2 {
  font-size: 1.3125rem;
}

h3 {
  margin-top: 1rem;
  font-size: 1.0625rem;
}

p {
  margin: 0 0 0.75rem;
}

p:last-child {
  margin-bottom: 0;
}

code {
  padding: 0.05em 0.35em;
  border-radius: 5px;
  background: var(--surface-muted);
  font-size: 0.9em;
}

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

.small {
  font-size: 0.875rem;
}

.block {
  display: block;
}

.nowrap {
  white-space: nowrap;
}

.warn {
  color: var(--warning);
}

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

.icon {
  flex: none;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.2em;
}

/* ---------- top bar ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* Pages run edge to edge (viewport-fit=cover). In the iPhone app the bar grows by the
     status bar's inset, so its own background fills the strip behind the clock; held
     sideways in Safari, the content keeps clear of the notch. In a browser tab, upright,
     every inset is 0 and this is plain 8px 16px. Solid, not frosted: glass is for chrome
     over nothing you need to read. */
  padding: calc(8px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right)) 8px calc(16px + env(safe-area-inset-left));
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  /* As tall as the bar's links, so the name is a 44px target too; the bar's height is unchanged. */
  min-height: 44px;
  color: var(--text);
  font-family: var(--font-display);
  font-size: min(1.125rem, 20px);
  font-weight: 800;
  font-stretch: 80%;
  letter-spacing: 0;
  text-decoration: none;
}

.brand > span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.brand-mark {
  display: grid;
  flex: none;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--brand-tile) var(--brand-mark) center / 24px 24px no-repeat;
  box-shadow: inset 0 0 0 1px var(--brand-tile-edge);
}

/* The mark is drawn by the tile's background; the box icon in the markup stays hidden. */
.brand-mark .icon {
  display: none;
}

.nav {
  display: flex;
  flex: none;
  align-items: center;
  gap: 2px;
}

.nav form {
  margin: 0;
}

.nav a,
.nav .link-button {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 10px;
  border-radius: 999px;
  color: var(--text);
  font-size: min(0.9375rem, 16px);
  font-weight: 500;
  text-decoration: none;
}

/* A phone: the name and the links both shrink. A customer page never hides the name (its bar
   has "Snap", a link to /); an operator page hides it below 420px, under the rule after this. */
@media (max-width: 440px) {
  .brand {
    font-size: min(1rem, 18px);
    font-stretch: 75%;
  }

  .nav a,
  .nav .link-button {
    min-width: 44px;
    justify-content: center;
    padding: 0 6px;
    font-size: min(0.875rem, 15px);
  }

  .topbar:has(.nav > a[href="/"]) .brand > span:last-child {
    display: inline;
  }
}

/* An operator's four links (Operations, Activity, Settings, Sign out) leave room for the mark
   alone, rather than a name cut to "Berry T…". */
@media (max-width: 420px) {
  .topbar:has(.nav > :nth-child(4)) .brand > span:last-child {
    display: none;
  }
}

/* 375-393px phones with a customer's four links (Snap, Orders, Account, Sign out): the tile
   gives way, not the name. */
@media (max-width: 400px) {
  .topbar:has(.nav > a[href="/"]):has(.nav > :nth-child(4)) .brand-mark {
    display: none;
  }
}

/* 320px phones: the tile always gives way, and the bar's sizes stop following text size. */
@media (max-width: 359px) {
  .topbar {
    gap: 8px;
  }

  .brand-mark {
    display: none;
  }

  .brand {
    font-size: 15px;
  }

  .nav {
    gap: 0;
  }

  .nav a,
  .nav .link-button {
    padding: 0 4px;
    font-size: 13px;
  }
}

.nav a:hover,
.nav .link-button:hover {
  background: var(--surface-muted);
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.demo-banner {
  margin: 0;
  padding: 0.5rem 1rem;
  background: var(--warning-soft);
  color: var(--warning);
  font-size: 0.875rem;
  text-align: center;
}

/* ---------- layout ---------- */

.container {
  max-width: 760px;
  margin: 0 auto;
  padding: 1.25rem calc(1rem + env(safe-area-inset-right)) 3rem calc(1rem + env(safe-area-inset-left));
}

.container-wide {
  max-width: 1200px;
}

.stack {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* A tighter stack of short lines, each its own paragraph, with nothing between them but the gap. */
.stack-sm {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.stack-sm > p {
  margin: 0;
}

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

.card.narrow {
  max-width: 420px;
  margin: 1.5rem auto;
}

.card-attention {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

details.card summary {
  font-weight: 600;
  cursor: pointer;
}

details.card[open] summary {
  margin-bottom: 0.75rem;
}

/* Change the quote, folded on an order waiting to be bought (Mark purchased is that page's one
   accent): its summary is a 44px row to tap, drawn into the card's padding so the closed card is
   no taller than a line. It keeps its triangle, which says it opens. */
.quote-fold > summary {
  min-height: 2.75rem;
  padding-block: 0.625rem;
  margin-block: -0.625rem;
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

/* The status pill keeps to the right, and drops under the title on a phone rather than squeeze it. */
.page-head > .pill {
  margin-left: auto;
}

/* A status pill with a dispute pill beside it, kept to the right together. */
.page-head > .pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-left: auto;
}

.page-head h1 {
  margin-bottom: 0.15rem;
  overflow-wrap: anywhere;
}

.page-head p {
  margin: 0;
}

/* The picture of what a request is about beside its title, the size of the logo in the header. */
.page-head-main {
  display: flex;
  flex: 1 1 320px;
  align-items: center;
  gap: 0.9rem;
  min-width: 0;
}

.page-picture {
  flex: none;
  width: 72px;
  height: 72px;
  border-radius: var(--radius);
  background: var(--surface-muted);
  object-fit: cover;
}

.back {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  /* A 44px target; the height it adds under the words takes the place of most of the margin. */
  min-height: 44px;
  margin-bottom: 0.25rem;
  color: var(--muted);
  font-size: 0.925rem;
  text-decoration: none;
}

.back:hover {
  color: var(--text);
}

.empty {
  padding: 2.25rem 1rem;
  border: 1.5px dashed var(--border);
  border-radius: var(--radius);
  color: var(--muted);
  text-align: center;
}

.notice {
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--text);
}

.legal {
  max-width: 42rem;
}

.legal ul,
.legal ol {
  margin: 0 0 0.75rem;
  padding-left: 1.25rem;
}

.legal li {
  margin-bottom: 0.35rem;
}

.legal h2 {
  margin-top: 1.25rem;
}

/* Support's common questions, folded: each question a 44px row between hairlines, with a chevron that
   turns when it's open (no transition), and its answer under it. They sit in one block, so the page's
   stack puts no gap between the rows. A question that takes two lines on a phone splits them evenly
   rather than leaving a word on its own. Focus is the summary's ring, as everywhere. */
.faq {
  border-top: 1px solid var(--border);
}

.faq:last-of-type {
  border-bottom: 1px solid var(--border);
}

.faq > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  padding: 8px 0;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  list-style: none;
  text-wrap: balance;
}

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

.faq > summary::after {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  margin-right: 4px;
}

.faq[open] > summary::after {
  transform: rotate(-135deg);
}

.faq > p {
  margin: 0 0 0.75rem;
}

.message-body {
  white-space: pre-wrap;
}

/* A message on the Operations page that has been answered: still there to look back on, quieter
   than the ones that wait. */
.message-answered {
  color: var(--muted);
}

.flash {
  margin-bottom: 1rem;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius-sm);
  font-weight: 500;
}

.flash-success {
  background: var(--success-soft);
  color: var(--success);
}

.flash-error {
  background: var(--danger-soft);
  color: var(--danger);
}

.flash-info {
  background: var(--surface-muted);
  color: var(--text);
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 3rem;
  padding: 0.625rem 1.25rem;
  border: 1px solid #00000000;
  border-radius: 999px;
  font: inherit;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  font-stretch: 100%;
  line-height: 1.2;
  letter-spacing: 0;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.12s ease, background-color 0.12s ease;
}

.btn:not(:disabled):active {
  transform: scale(0.98);
}

.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* A button at work ("Placing order…", "Ordering 4 pieces…") is still, but not greyed: its words
   say what it's doing. Here rather than in swipe.css, so an order's own page has it too. */
.btn[aria-busy="true"]:disabled {
  opacity: 1;
  cursor: progress;
}

/* Flat and filled: the one petrol control on a screen. */
.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.btn-primary:not(:disabled):hover,
.btn-primary:not(:disabled):active {
  background: var(--accent-pressed);
}

/* Secondary: a tonal pill with a steel edge that holds 3:1 in sun. */
.btn-secondary {
  border: var(--edge) solid var(--border-strong);
  background: var(--surface-tonal);
  color: var(--text);
}

.btn-secondary:not(:disabled):hover {
  border-color: var(--text-2);
  background: var(--surface-tonal);
}

.btn-ghost {
  background: #00000000;
  color: var(--text-2);
}

.btn-danger {
  color: var(--danger);
}

.btn-lg {
  min-height: 3.5rem;
  font-size: 1.0625rem;
}

.btn-block {
  width: 100%;
}

/* Continue with Apple and Continue with Google (build 8 spec §6.7): Apple's first and the same size,
   at most Google's 400px; Apple's black (white in the dark), Google's white with its grey edge. */
.sign-in-with { gap: 10px; }
.btn-apple,
.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  max-width: 400px;
  min-height: 44px;
  margin-inline: auto;
  font-weight: 600;
}
.btn-apple { background: #000; color: #fff; border: 1px solid #000; }
.btn-google { background: #fff; color: #1f1f1f; border: 1px solid #747775; }
.sign-in-logo { width: 18px; height: 18px; flex: none; }
.btn-apple .sign-in-logo { margin-top: -2px; }
.google-button { display: flex; justify-content: center; min-height: 44px; }
.sign-in-or { display: flex; align-items: center; gap: 10px; margin: 0; color: var(--muted); font-size: 0.875rem; }
.sign-in-or::before,
.sign-in-or::after { content: ""; flex: 1; border-top: 1px solid var(--border); }
.sign-in-methods { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.sign-in-methods li { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.inline-form { display: inline; }
@media (prefers-color-scheme: dark) {
  .btn-apple { background: #fff; color: #000; border-color: #fff; }
}

/* In the iPhone app a long press on a control, or on the bar, is only a long press: iOS opens no
   menu for the link or the picture under the finger and selects none of the label's words. What
   people copy (an order's number, an address, a price, a note) is text outside these, and stays
   selectable. */
.topbar,
button,
.btn,
.link-button {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* One focus style everywhere: a 3px accent outline, 3px off the edge. */
.btn:focus-visible,
a:focus-visible,
summary:focus-visible,
.link-button:focus-visible,
.quick-answer:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

/* A label button (a card's Take a photo, a chat's Add a photo) is focused through the photo picker
   inside it, and only for the keyboard: :focus-within also matched after a tap, leaving a ring that
   reads as chosen. A rule of its own, so a browser without :has (iOS 15) still keeps the list above. */
label.btn:has(input:focus-visible) {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

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

  .btn:not(:disabled):active {
    transform: none;
  }
}

/* ---------- forms ---------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.9375rem;
  font-weight: 600;
}

/* Fields: 3.25rem tall with a steel edge, and 1rem text (17px on an iPhone), so iOS never
   zooms in on focus. The Stripe card box below matches them. */
.field input,
.field textarea,
.field select,
.money-input,
.ask-input {
  width: 100%;
  min-height: 3.25rem;
  padding: 0.75rem 1rem;
  border: var(--edge) solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 1rem;
  font-weight: 400;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field input::placeholder,
.field textarea::placeholder,
.ask-input::placeholder {
  color: var(--muted);
  opacity: 1;
}

.field textarea {
  resize: vertical;
}

.field input:focus,
.field textarea:focus,
.field select:focus,
.ask-input:focus,
.money-input:focus-within,
.card-field.StripeElement--focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-halo);
}

.money-input {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding-block: 0;
}

.field .money-input input {
  padding: 0.7rem 0;
  border: 0;
  background: #00000000;
  box-shadow: none;
}

.field-qty input {
  max-width: 9rem;
}

.check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9375rem;
}

/* Two or three radio buttons drawn as one switch, like the swipe card's: a tonal track with the
   steel edge every control has, and the chosen side raised on it inside a ring of the secondary
   text colour, so the choice reads without colour. */
.segmented {
  display: flex;
  margin: 0;
  padding: 3px;
  border: var(--edge) solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface-tonal);
}

.segmented label {
  flex: 1 1 0;
  position: relative;
}

.segmented input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.segmented span {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  padding: 4px 12px;
  border-radius: 999px;
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.15;
  text-align: center;
}

.segmented input:checked + span {
  background: var(--segment-on);
  color: var(--text);
  box-shadow: 0 0 0 var(--edge) var(--text-2), var(--shadow);
}

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

/* The same switch made of two buttons that each send their form (Confirm every buy on Account),
   the side in force pressed: a tap is the change, with nothing more to save. */
.segmented-buttons button {
  flex: 1 1 0;
  min-height: 2.75rem;
  padding: 4px 12px;
  border: 0;
  border-radius: 999px;
  background: #00000000;
  color: var(--text-2);
  font: inherit;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.15;
  cursor: pointer;
}

.segmented-buttons button[aria-pressed="true"] {
  background: var(--segment-on);
  color: var(--text);
  box-shadow: 0 0 0 var(--edge) var(--text-2), var(--shadow);
}

.segmented-buttons button:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.form-error {
  padding: 0.6rem 0.8rem;
  border-radius: var(--radius-sm);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: 0.9375rem;
}

/* ---------- landing ---------- */

.lead {
  max-width: 40rem;
  color: var(--muted);
  font-size: 1.1rem;
}

/* The pitch before the camera (sign in, create an account): the camera's lead in reading ink, then the small lines. */
.pitch .lead {
  color: var(--text-2);
  font-size: 1.0625rem;
}

/* Sign in and Create an account on a phone: the pitch and the form as one tight column, so the
   page's one petrol button (Create an account, or Create account) is on the first screen of a
   375x667 phone. The card starts under the bar, and its lines keep the gap alone, without the
   margins headings and paragraphs add elsewhere. */
@media (max-width: 480px) {
  .container:has(> .sign-wall) {
    padding-top: 0.75rem;
  }

  .card.narrow.sign-wall {
    margin-top: 0;
    padding: 1rem;
    gap: 0.75rem;
  }

  .sign-wall h1,
  .sign-wall > p,
  .sign-wall form p {
    margin: 0;
  }

  .sign-wall form.stack {
    gap: 0.75rem;
  }
}

/* The front door: / for a visitor who isn't signed in. The camera's headline at the camera's size,
   its lead, how long a price takes and what's in it, then Create an account (the page's one petrol
   control) and Sign in, all on the first screen of a 375x667 phone; then who does what, and three
   screens of the app, in a column on a phone and side by side from 720px. */
.front-door {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.front-door-hero {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.front-door-hero > p {
  margin: 0;
}

.front-door-title {
  margin: 0;
  font-size: min(19.5vw, 9.4vh, 5rem);
  font-weight: 800;
  font-stretch: 82%;
  line-height: 0.95;
  letter-spacing: -0.012em;
  text-wrap: balance;
}

.front-door .lead {
  max-width: 34ch;
  color: var(--text-2);
  font-size: 1.0625rem;
  line-height: 1.45;
}

.front-door-actions {
  display: grid;
  gap: 0.75rem;
  max-width: 420px;
  margin-top: 0.25rem;
}

.front-door-more {
  max-width: 40rem;
}

.front-door-screens {
  display: grid;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.front-door-screens figure {
  display: grid;
  gap: 0.625rem;
  max-width: 300px;
  margin: 0;
}

.front-door-screens img {
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-muted);
}

.front-door-screens figcaption {
  color: var(--text-2);
  font-size: 0.9375rem;
}

@media (min-width: 720px) {
  .front-door-screens {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* A phone: the page starts under the bar, as Sign in's does. */
@media (max-width: 480px) {
  .container:has(> .front-door) {
    padding-top: 0.75rem;
  }
}

/* The small links under a sign-in form (Forgot your password?, Email me a sign-in link): each a
   44px row to tap, side by side while they fit and one under the other on a narrow phone. */
.help-links {
  display: flex;
  flex-wrap: wrap;
  column-gap: 1.25rem;
}

.help-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

.how {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.75rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.how li {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  counter-increment: step;
}

.how li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  margin-bottom: 0.35rem;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-display);
  font-weight: 700;
}

.how span {
  color: var(--muted);
  font-size: 0.925rem;
}

/* ---------- photo capture ---------- */

.capture {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  margin-bottom: 1.75rem;
}

.capture h1 {
  font-size: 1.35rem;
}

/* ---------- request lists ---------- */

.request-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.request-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: inherit;
  text-decoration: none;
}

.request-row:hover {
  border-color: var(--border-strong);
}

.request-row-main {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
}

/* A part's name is the point of the row: two lines before it's cut. */
.request-row-title {
  display: -webkit-box;
  overflow: hidden;
  font-weight: 600;
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: normal;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* What tells it from another of the same make (the part number, the size): never cut, however
   many lines it takes, since the title above it can be. */
.request-row-specs {
  color: var(--text-2);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

/* Order IDs are drawn from 23456789ABCDEFGHJKLMNPQRSTUVWXYZ (src/db.ts), so there's no 0/O or
   1/I to tell apart, and tabular figures keep them in step. */
.request-row-meta {
  margin-top: 4px;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
}

/* The status leads the line, as a tag, with the day it got there after it: "Delivered Oct 19". */
.request-row-meta .pill {
  display: inline-block;
  padding: 0 0.45rem;
  line-height: 1.6;
}

/* When an order still coming should arrive or be ready: "Should arrive by Thu, Oct 29". It's what
   people come back to the list for, so it's in ink (7:1), not the muted line's grey. */
.request-row-next {
  margin-top: 2px;
  color: var(--text);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}

.thumb {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 12px;
  background: var(--surface-muted);
  object-fit: cover;
}

.thumb-empty {
  display: grid;
  place-items: center;
  color: var(--muted);
}

/* The seller's picture of a listing: shown whole on white, as a shop shows it, not cropped like a photo. */
.thumb-listing {
  border: 1px solid var(--border);
  background: #FFFFFF;
  object-fit: contain;
}

/* A seller's white catalogue shot is dimmed a little in dark mode, so it doesn't glare. */
@media (prefers-color-scheme: dark) {
  .thumb-listing,
  .listing img {
    filter: brightness(0.9);
  }
}

/* An offer on the operator's request page: the seller's picture of the listing beside its link and notes. */
.listing {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

/* ---------- badges ---------- */

.pill {
  display: inline-flex;
  flex: none;
  align-items: center;
  padding: 0.3rem 0.6rem;
  border-radius: var(--radius-tag);
  font-size: 0.8125rem;
  font-weight: 650;
  white-space: nowrap;
}

/* In-progress states are neutral; "Price ready" is the one that wants the customer. */
.pill-info {
  background: var(--surface-tonal);
  color: var(--text-2);
}

.pill-accent {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

.pill-success {
  background: var(--success-soft);
  color: var(--success);
}

.pill-warning {
  background: var(--warning-soft);
  color: var(--warning);
}

.pill-muted {
  background: var(--surface-muted);
  color: var(--muted);
}

.pill-danger {
  background: var(--danger-soft);
  color: var(--danger);
}

.tag {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  border-radius: 6px;
  background: var(--surface-muted);
  color: var(--muted);
  font-size: 0.8125rem;
  font-weight: 600;
  vertical-align: middle;
}

.tag-accent {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

/* ---------- request page ---------- */

/* The steps in ink: done and the one it's at are ink bars, the one it's at in bolder words (see
   below), and the ones to come hairlines. Never petrol, which isn't a status fill. */
.steps {
  display: flex;
  gap: 0.3rem;
  margin: 0 0 1rem;
  padding: 0;
  overflow-x: auto;
  list-style: none;
}

.steps li {
  flex: 1 1 0;
  min-width: 3.75rem;
  padding-top: 0.5rem;
  border-top: 4px solid var(--border);
  color: var(--muted);
  font-size: 0.8125rem;
  font-weight: 600;
  text-align: center;
}

.steps li.done {
  border-color: var(--text);
  color: var(--text);
}

.steps li.current {
  border-color: var(--text);
  color: var(--text);
}

/* An order's status card (see orderCard): the arrival day as its heading, what happens next, then
   its four steps, spaced by the card's own gap. Each step is as wide as its word at least, kept on
   one line, so the four fit one row inside the card at 320px; wider, they share it evenly. */
.order-status .steps {
  gap: 0.25rem;
  margin: 0;
}

.order-status .steps li {
  min-width: auto;
  white-space: nowrap;
}

/* The rows under the steps, and what was ordered in the Delivery & payment card under it: spaced
   by their card's gap. */
.order-status > .details,
.details.order-lines {
  margin: 0;
}

/* Problem with this order? Write to us, ending the status card while it's on its way: link text on
   a 44px row, which goes to the message box further down. */
.card-link {
  display: flex;
  align-items: center;
  min-height: 44px;
  align-self: flex-start;
  font-weight: 600;
  color: var(--accent-ink);
}

/* What you ordered, folded on an order on its way: the summary is the card's heading, a 44px row
   with a chevron that turns when it's open, and what we identified and the photos are its parts,
   each under an h3 with no frame of its own. No transition. */
.fold > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  list-style: none;
}

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

.fold > summary h2 {
  margin: 0;
}

.fold[open] > summary .icon {
  transform: rotate(180deg);
}

.fold h3 {
  margin-top: 0;
}

.fold > section + section {
  margin-top: 1.25rem;
}

.working {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

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

.spinner {
  flex: none;
  width: 22px;
  height: 22px;
  border: 3px solid var(--accent-soft);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation-duration: 3s;
  }
}

.price strong {
  font-family: var(--font-display);
  font-size: min(2.6rem, 46px);
  font-weight: 800;
  font-stretch: 85%;
  letter-spacing: -0.01em;
  font-variant-numeric: lining-nums proportional-nums;
}

.total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  font-size: 1.05rem;
}

.total strong {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 800;
  font-stretch: 85%;
  font-variant-numeric: lining-nums tabular-nums;
}

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 10px;
  margin-bottom: 1rem;
}

.tile {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.tile strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 800;
  font-stretch: 85%;
  line-height: 1.2;
  font-variant-numeric: lining-nums tabular-nums;
}

.tile span {
  font-size: 0.8rem;
  color: var(--muted);
}

.details {
  display: grid;
  grid-template-columns: minmax(6.5rem, max-content) 1fr;
  gap: 0.35rem 1rem;
  margin: 0.75rem 0 0;
}

.details div {
  display: contents;
}

.details dt {
  color: var(--muted);
  font-size: 0.9rem;
}

.details dd {
  margin: 0;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.details dd.negative {
  color: var(--danger);
}

.questions {
  margin: 0 0 0.75rem;
  padding-left: 1.2rem;
  font-weight: 500;
}

.plain-list {
  margin: 0.25rem 0 0;
  padding-left: 1.2rem;
}

.plain-list li {
  margin-bottom: 0.2rem;
}

.quote-sources {
  margin: 0.75rem 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.quote-sources h3 {
  margin-top: 0;
}

.quote-sources li {
  margin-bottom: 0.5rem;
}

.photos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 0.5rem;
}

.photos img {
  width: 100%;
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  object-fit: cover;
}

/* A tap opens the photo in the viewer below. A long press opens no menu, so nothing offers to open
   the link anywhere else; the viewer's photo keeps iOS's menu for saving or copying it. */
.photos a {
  -webkit-touch-callout: none;
}

/* An order's photo, whole, over its page (app.js): on the page's own colour, so it's the one thing
   on the screen in light or dark, above the bar, clear of the notch and the home indicator. Close
   sits over its top corner, and a tap anywhere beside the photo closes it too. */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--bg);
  animation: viewer-in 0.2s ease-out;
}

@keyframes viewer-in {
  from {
    opacity: 0;
  }
}

.viewer-close {
  position: absolute;
  top: calc(8px + env(safe-area-inset-top));
  right: calc(16px + env(safe-area-inset-right));
  min-height: 44px;
  padding: 0 1.125rem;
}

/* Centred at its own size, shrunk to fit under Close (8px, 44px, 8px) and inside the page's 16px. */
.viewer-photo {
  position: absolute;
  inset: calc(60px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
  max-width: calc(100% - 32px - env(safe-area-inset-left) - env(safe-area-inset-right));
  max-height: calc(100% - 76px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  margin: auto;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}

/* The page behind it doesn't scroll while it's open. */
html.viewer-open {
  overflow: hidden;
}

/* The question a form that can't be taken back asks first (Cancel order, Remove card, a refund; see
   askFirst in app.js), drawn as the swipe page's sheets are: on a phone the full width at the foot
   of the screen, its top corners rounded, clear of the home indicator; wider, a box in the middle.
   The question in the sheets' title type, what follows it muted under it, then two buttons the same
   size, neither petrol: yes, red on the tonal pill when the form's own button is red, and no. */
.confirm-dialog {
  width: 100%;
  max-width: 100%;
  max-height: 90vh;
  max-height: 90dvh;
  margin: auto 0 0;
  padding: 24px calc(20px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(20px + env(safe-area-inset-left));
  overflow: auto;
  border: 0;
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sheet);
}

/* The scrim the swipe page's sheets have, in hex: a backdrop doesn't take the page's colours in
   every browser. */
.confirm-dialog::backdrop {
  background: #090D0E80;
}

@media (prefers-color-scheme: dark) {
  .confirm-dialog::backdrop {
    background: #000000A6;
  }
}

@media (min-width: 601px) {
  .confirm-dialog {
    width: calc(100% - 32px);
    max-width: 28rem;
    margin: auto;
    padding: 24px;
    border-radius: var(--radius-sheet);
  }
}

.confirm-dialog-message {
  margin: 0;
}

/* The iPhone app's sheets (native.js) on the confirm dialog's look: the screen before iOS asks to
   allow notifications, and the deals question. A heading, a line, then the buttons stacked. */
.native-sheet h2 {
  margin: 0 0 0.5rem;
}

.native-sheet p {
  margin: 0 0 1.25rem;
}

/* "Tell me when it's priced" and "Get updates on this order", under a card's buttons. */
.push-offer-spot {
  display: flex;
  justify-content: center;
}

/* It takes focus only so a screen reader starts there and neither button is chosen; it isn't a
   control, so it gets no focus ring. */
.confirm-dialog-message:focus {
  outline: none;
}

.confirm-dialog-message strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 750;
  line-height: 1.12;
  font-stretch: 90%;
}

.confirm-dialog-message span {
  display: block;
  margin-top: 0.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .viewer {
    animation: none;
  }
}

.note {
  margin-top: 0.75rem;
}

/* The photo our team took of an item as bought: under the progress steps of the customer's order,
   and on the Purchase card in Operations. Shown whole on the muted well, never cropped. */
.bought {
  margin: 0;
}

.bought-photo {
  display: block;
  width: 100%;
  max-height: 22rem;
  object-fit: contain;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}

.bought figcaption {
  margin-top: 0.6rem;
  color: var(--text-2);
}

/* A photo field's own button, in the steel edge and tonal fill of a secondary control. */
.field input[type="file"]::file-selector-button {
  margin-right: 0.75rem;
  padding: 0.35rem 0.8rem;
  border: var(--edge) solid var(--border-strong);
  border-radius: var(--radius-tag);
  background: var(--surface-tonal);
  color: var(--text);
  font: inherit;
}

/* A request sent as words, not a photo: what they asked for, in the photos' place. */
.asked {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.timeline {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.timeline li {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 0.75rem;
  font-size: 0.925rem;
}

.timeline li.internal {
  color: var(--muted);
}

/* A note keeps its line breaks, and an operator's first name signs it on a line of its own. */
.timeline li > span {
  white-space: pre-line;
}

.timeline time {
  color: var(--muted);
  font-size: 0.85rem;
}

@media (max-width: 520px) {
  .timeline li {
    grid-template-columns: 1fr;
    gap: 0;
  }
}

/* ---------- operations ---------- */

/* The filter pills, on Orders and over the operations queue: each a 44px touch target, in one row
   that scrolls sideways inside itself if it must. */
.tabs {
  display: flex;
  gap: 0.35rem;
  margin-bottom: 1rem;
  padding-bottom: 0.25rem;
  overflow-x: auto;
}

.tab {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.4rem;
  /* A 44px target, with the side padding kept so three tabs still fit at 320px. */
  min-height: 44px;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.875rem;
  text-decoration: none;
}

.tab.active {
  border-color: var(--text);
  background: var(--text);
  color: var(--bg);
}

.tab .count {
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}

/* A learning setting's four fields (Mode, Starting value, Floor, Cap) side by side where they fit:
   stacked full width, ten such settings were 2300px of boxes for numbers like "480". */
@media (min-width: 600px) {
  .setting-fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
    align-items: end;
  }
}

@media (min-width: 900px) {
  .setting-fields {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.card .table-wrap {
  border-radius: var(--radius-sm);
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.925rem;
}

.table th {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
}

.table td {
  padding: 0.65rem 0.75rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.table tr:last-child td {
  border-bottom: 0;
}

.table .num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* A figure below zero, such as an order that loses money in the queue's Earned column. */
.table td.negative {
  color: var(--danger);
}

/* The To purchase tab: each seller's orders under a row naming the seller and what they come to,
   on the muted surface, wrapping on a narrow screen rather than widening the table. */
.table .seller-row th {
  padding-top: 0.75rem;
  background: var(--surface-muted);
  color: var(--text);
  font-size: 0.925rem;
  font-weight: 700;
  white-space: normal;
}

.table .seller-row .muted {
  font-weight: 400;
}

/* On a phone the table scrolls sideways inside its box, wider than the screen: the heading keeps
   to the part in view, so what the seller's orders come to never runs off past the edge. */
.table .seller-head {
  position: sticky;
  left: 0.75rem;
  display: block;
  max-width: calc(100vw - 3.75rem - env(safe-area-inset-left) - env(safe-area-inset-right));
}

/* The purchase form's Record it at a loss: the whole line is the box's label, a full touch target. */
[data-loss] .check {
  min-height: 2.75rem;
}

[data-loss] .check input {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
}

/* A table's totals: set off from the rows above by a firmer line, with the figures in bold. */
.table tfoot td {
  border-top: 1px solid var(--border-strong);
}

.table tfoot .num {
  font-weight: 700;
}

.table.compact th,
.table.compact td {
  padding: 0.4rem 0.6rem;
}

/* Activity's By campaign table: the campaign cell keeps a short name ("meta / pilot") on one line,
   and a long one wraps rather than pushing the two columns an ad is judged on off a phone's screen. */
.table td.campaign {
  min-width: 7rem;
}

/* The queue's Shipped tab: a narrow first column of boxes to tick for Mark selected delivered,
   each box big enough to tap and level with the middle of its row's 40px thumbnail. */
.table th[aria-label="Select"],
.table td:has(> input[type="checkbox"]) {
  width: 1%;
  padding-right: 0;
}

.table td > input[type="checkbox"] {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0.625rem 0 0;
}

/* Mark selected delivered sits under the table it acts on, set off from it and from what follows. */
#mark-delivered {
  margin: 1rem 0;
}

.row-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-width: 14rem;
  color: inherit;
  text-decoration: none;
}

.row-link .thumb {
  width: 40px;
  height: 40px;
}

.row-link:hover .row-title {
  color: var(--accent);
}

.row-title {
  display: block;
  font-weight: 600;
}

.offers td:nth-child(2) {
  min-width: 16rem;
}

.offers tr.chosen td {
  background: var(--accent-soft);
}

.offers a {
  font-weight: 500;
}

/* One column on a phone, which never grows past the screen: left to itself the column grew to the
   widest table, and the whole order page scrolled sideways. Wide tables scroll inside their
   .table-wrap instead. */
.ops-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 1rem;
}

@media (min-width: 960px) {
  .ops-grid {
    grid-template-columns: minmax(0, 1fr) 340px;
  }
}

/* The step an order waits on, above the rest of its Operations page: Buy it beside Record the
   purchase, or the purchase beside the shipment or the delivery. One column on a phone, Buy it
   first; two halves on a laptop, so the step's button is in sight. */
.ops-now {
  display: grid;
  align-items: start;
  gap: 1rem;
  grid-template-columns: minmax(0, 1fr);
  margin-bottom: 1rem;
}

@media (min-width: 960px) {
  .ops-now {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

/* The purchase form's fields in pairs once there's room, in their order: Bought from with Their
   order number, Total paid with Of which shipping, Product link with Seller takes returns. Its
   lines, the photo's rule and the buttons take the whole width, and so does the photo's field,
   whose file picker cut its own words short at half of it. */
@media (min-width: 600px) {
  #purchase {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: end;
  }

  #purchase > :not(.field),
  #purchase > .field:has(input[type="file"]) {
    grid-column: 1 / -1;
  }
}

/* The Buy it card on an order waiting to be bought: each value keeps its Copy button beside it on
   one line, and on a phone the button wraps under a value too long to share the line. */
.copy-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.625rem;
}

/* Each label on the baseline of its value, though the button makes the line taller. */
.copy-lines {
  align-items: baseline;
}

.copy-lines + .btn {
  margin-top: 1rem;
}

/* A Copy button: secondary, and small enough to sit on a line of text. On a phone it's 44px tall,
   for a finger. */
.btn-copy {
  min-height: 2.25rem;
  padding: 0.25rem 0.875rem;
  border: var(--edge) solid var(--border-strong);
  background: var(--surface-tonal);
  color: var(--text);
  font-size: 0.875rem;
}

.btn-copy:not(:disabled):hover {
  border-color: var(--text-2);
}

@media (max-width: 480px) {
  .btn-copy {
    min-height: 2.75rem;
  }
}

/* ---------- checkout: address and card ---------- */

.address-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem 0.75rem;
  /* How wide the fields are decides whether Country and Phone share a row (below). */
  container-type: inline-size;
}

.address-fields .span-2 {
  grid-column: span 2;
}

/* Half a row is too narrow for a country's name ("United Stat" on a 320px phone): Country and
   Phone take a row each. */
@container (max-width: 19rem) {
  .address-fields .field-country,
  .address-fields .field-phone {
    grid-column: span 2;
  }
}

/* The company, behind a link after the fields an address needs: Add a company name is a 44px row of
   link text that opens the field where it is, and goes once the field shows, so a company typed in
   is never folded away again unseen. */
.company-more > summary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  list-style: none;
}

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

.company-more[open] > summary {
  display: none;
}

.card-box {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Stripe's card field lives in a frame; the box around it looks like our inputs. */
.card-field {
  min-height: 3.25rem;
  padding: 0.95rem 1rem;
  border: var(--edge) solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
}

.card-on-file {
  margin: 0;
}

.address {
  margin: 0;
  line-height: 1.5;
}

/* Account's saved addresses: each with its name, the label it prints as, and what can be done with
   it; Edit and Add another address open the same fields the checkout sheet has. The list and Add
   another address are one column of rows: the last address's Edit and Remove and then Add another
   address are 44px rows one under the other, evenly spaced, with no wider gap before the last. */
.address-book {
  display: grid;
}

.address-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.address-item {
  display: grid;
  gap: 0.5rem;
  padding: 1rem 0;
  border-top: 1px solid var(--border);
}

.address-item:first-child {
  padding-top: 0;
  border-top: 0;
}

.address-item:last-child {
  padding-bottom: 0;
}

.address-item > form {
  margin: 0;
  justify-self: start;
}

.address-full {
  margin: 0.5rem 0 0;
}

.address-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.address-head h3 {
  margin: 0;
  font-size: 1.0625rem;
  overflow-wrap: anywhere;
}

/* The address orders go to, once there's more than one: a tag, not a pill, since it isn't pressed. */
.tag-current {
  background: var(--surface-tonal);
  color: var(--text-2);
}

/* Edit, then Remove: two quiet text rows, 44px each, one under the other. Remove is red text, not a
   button's fill: it's the one to reach for least. */
.address-actions {
  display: grid;
  justify-items: start;
}

.address-actions form {
  margin: 0;
}

.address-actions .address-edit {
  justify-self: stretch;
}

.link-danger {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--danger);
}

/* Account's Use a different card is one of these too: with a card on file, the field for another
   and its petrol Use this card instead wait behind it. */
.address-edit > summary,
.address-add > summary,
.card-change > summary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--accent-ink);
  font-weight: 600;
  cursor: pointer;
}

.address-edit[open] > summary,
.address-add[open] > summary,
.card-change[open] > summary {
  margin-bottom: 0.75rem;
}

/* ---------- footer ---------- */

/* The legal pages and how to reach us, under every page that isn't the swipe app. */
.site-footer {
  max-width: 760px;
  margin: 0 auto;
  /* The last thing on the page, so it keeps the home indicator's inset below it. */
  padding: 0 calc(1rem + env(safe-area-inset-right)) calc(2rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
  text-align: center;
}

.site-footer p {
  margin: 0;
}

/* The phone line, and who runs it and where, each stand a little apart from the line above. */
.site-footer p + p {
  margin-top: 0.5rem;
}

/* The number to call is a line of its own here, outside running text, so it's a 44px target: of
   the footer's links, it's the one most likely to be tapped. */
.site-footer a[href^="tel:"] {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* The phone line's hours go to the next line whole, never split mid-phrase ("weekdays 9 / AM"). */
.site-footer .hours {
  display: inline-block;
}

/* ----- invites and credit ----- */

/* The invite link on Account: the link, then Copy (and Share where the device has a share sheet). */
.invite-link {
  display: flex;
  gap: 8px;
}

.invite-link input {
  flex: 1;
  min-width: 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
}

.credit-left p,
.points-left p {
  margin: 0 0 0.35rem;
}

.credit-left meter,
.points-left meter {
  display: block;
  width: 100%;
  height: 10px;
}

/* What credit takes off an order, on its price card. */
.credit-line {
  margin: 0;
  padding: 0.4rem 0.65rem;
  border-radius: var(--radius-sm);
  background: var(--success-soft);
  color: var(--success);
  font-size: 0.9rem;
  font-weight: 600;
}


/* ----- added with the order follow-up work ----- */

/* A field the server turned down: the edge says which one. */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--danger);
  box-shadow: 0 0 0 1px var(--danger);
}

/* "It comes off a little at each order", under the credit an account has left. */
.credit-left .invite-tagline {
  margin: 0.5rem 0 0;
  color: var(--success);
  font-weight: 600;
}

/* Where the delivered email's link lands (#remind), the queue's links to its Messages and to an
   order's Add a note, How it works and Contact us on Support, and the Message us form the contact line
   links to: clear of the sticky top bar, the status bar's inset in the iPhone app included. */
#remind,
#messages,
#note,
#how-it-works,
#contact,
#message {
  scroll-margin-top: calc(4.5rem + env(safe-area-inset-top));
}

/* "Remind me to order it again", on a delivered order, or the reminder carried over to one on its way. */
.reminder-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.6rem;
}

.reminder-form .field {
  flex: 1 1 14rem;
}

/* How did it go?, on a delivered order: the four answers in a row, wrapping onto more rows on a
   narrow phone. */
.rating-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* The answer given, as the chosen side of a switch: lifted onto the card's own colour with an ink
   edge, never filled petrol, so Order again stays the page's one. */
.rating-choices .btn[aria-pressed="true"],
.rating-choices .btn[aria-pressed="true"]:not(:disabled):hover {
  border-color: var(--text-2);
  background: var(--segment-on);
  color: var(--text);
  box-shadow: var(--shadow);
}

/* The step the order is at, marked as such for screen readers too. */
.steps li[aria-current="step"] {
  font-weight: 750;
}

/* Activity's Check in list: a customer's name opens their order, and the queue's Read it opens its
   Messages, so the link is a full touch target, 44px high, without making its row or its line
   taller: the padding reaches into the cell's or the notice's own. */
.table td a.tap,
.notice a.tap {
  display: inline-block;
  padding: 0.6875rem 0;
  margin: -0.6875rem 0;
}

/* A room's drawing with its pieces in it, on its page in Operations (see opsRoomCard in views.ts). */
.room-drawing {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

/* The Deals screen (§3.5): one card a deal, the amount large. */
.deals { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.deal-amount { font-size: 2rem; font-weight: 700; line-height: 1.1; margin: 0; }
.deal-picked { outline: 2px solid var(--accent, currentColor); }
.camera-deal, .deal-line { margin: 0.25rem 0; }
