/* ==========================================================================
   PoultryPath — theme and layout

   A deep forest green for chrome and primary actions, a warm off-white page
   ground, a geometric sans for UI text, and a serif italic for the
   wordmark. Green because the work is agricultural and the app is read
   outdoors in bright light, where a dark saturated chrome holds contrast.

   Every colour is a variable in the :root block, so a rebrand is a
   single-block edit that touches nothing else in the stylesheet.

   Layout is mobile-first throughout. The primary user is a driver holding a
   phone in a truck cab, so the phone layout is the base case and the wider
   breakpoints are the additions, not the other way round.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Playfair+Display:ital,wght@1,500;1,600&display=swap');

:root {
  /* --- brand --- */
  --green: #24512f;
  --green-dark: #16351e;
  --green-mid: #35704a;
  --green-tint: #e9f0ea;
  --green-line: #c3d5c7;

  /* --- surfaces --- */
  --cream: #f6f3ea;
  --paper: #ffffff;
  --paper-dim: #faf8f2;

  /* --- text --- */
  --ink: #1e241f;
  --ink-soft: #5e655d;
  --ink-faint: #8a908a;
  --on-green: #ffffff;
  --on-green-soft: rgba(255, 255, 255, 0.76);

  /* --- lines --- */
  --line: #e2ddd0;
  --line-strong: #cdc6b4;

  /* --- status --- */
  --danger: #a63a28;
  --danger-tint: #fbeeeb;
  --warn: #b9791d;
  --warn-tint: #fbf1e0;
  --ok: #2f7d4f;
  /* Its own hue, distinct from --danger (delete/destructive) and --warn
     (skip notes, the "visiting" badge) — a rose-red rather than --danger's
     rust-orange, so a card showing both never reads as the same signal. */
  --reduced: #b3234f;
  --reduced-tint: #fbe9ee;

  /* --- shape --- */
  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(30, 36, 31, 0.06), 0 2px 8px rgba(30, 36, 31, 0.04);
  --shadow-lift: 0 6px 20px rgba(30, 36, 31, 0.18);

  /* Height of the fixed chrome, so sticky offsets stay in one place. */
  --appbar-height: 56px;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--cream);
  color: var(--ink);
  font-family: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 15px;
  line-height: 1.45;
  min-height: 100vh;
  /* Stops iOS Safari from inflating text in landscape. */
  -webkit-text-size-adjust: 100%;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
}

a {
  color: var(--green);
}

/* Anything that can be dragged must not also trigger the browser's
   text-selection or pull-to-refresh gestures. */
.no-select {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* ==========================================================================
   Chrome
   ========================================================================== */

.announce {
  background: var(--green-dark);
  color: var(--on-green);
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.02em;
  padding: 7px 12px;
}

/* --------------------------------------------------------------------------
   Test environment banner

   Deliberately ugly. It sits above the app bar, uses a colour that appears
   nowhere else in the palette, and does not scroll away. The failure it
   guards against is someone checking off a real morning's pickups on the
   test site and only noticing at the end, so being tasteful about it would
   be the wrong call. Production never renders it.
   -------------------------------------------------------------------------- */
.env-banner {
  position: sticky;
  top: 0;
  z-index: 60;
  background: repeating-linear-gradient(
    135deg,
    #8a1c1c,
    #8a1c1c 12px,
    #a32222 12px,
    #a32222 24px
  );
  color: #fff;
  text-align: center;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 8px 12px;
  /* Above the notch on a phone, so it is not the bit that gets cut off. */
  padding-top: max(8px, env(safe-area-inset-top));
}

/* The app bar is sticky too; without this it would slide up underneath the
   banner and the two would overlap while scrolling. */
body.has-env-banner .appbar {
  top: auto;
}

.appbar {
  background: var(--green);
  color: var(--on-green);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  height: var(--appbar-height);
  border-bottom: 3px solid var(--green-mid);
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.wordmark svg {
  flex: none;
  width: 26px;
  height: 26px;
}

.wordmark-text {
  font-family: 'Playfair Display', Georgia, serif;
  font-style: italic;
  font-weight: 600;
  font-size: 19px;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* On a phone the four nav buttons take 290px of a 375px bar, which leaves
   nothing for the wordmark — it collapsed to "Po…" with the sub-line cut
   off, which looks broken rather than branded. Below this width the mark
   stands alone and the announce strip directly above carries the name, so
   nothing is actually lost. */
@media (max-width: 560px) {
  .wordmark-text {
    display: none;
  }

  .wordmark {
    flex: none;
  }

  /* The mark is now the only brand element on the bar, so give it room to
     read as one rather than sitting cramped against the first button. */
  .wordmark svg {
    width: 28px;
    height: 28px;
  }
}

.wordmark-sub {
  display: block;
  font-family: 'Poppins', sans-serif;
  font-style: normal;
  font-weight: 500;
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-green-soft);
}

.icon-btn {
  background: none;
  border: 0;
  color: var(--on-green);
  font-size: 14px;
  font-family: inherit;
  font-weight: 500;
  padding: 8px;
  min-width: 40px;
  min-height: 40px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.icon-btn:hover,
.icon-btn:focus-visible {
  background: rgba(255, 255, 255, 0.14);
}

/* ==========================================================================
   Layout
   ========================================================================== */

main {
  max-width: 900px;
  margin: 0 auto;
  padding: 14px 12px 96px;
}

.center-wrap {
  min-height: calc(100vh - var(--appbar-height));
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 16px;
}

.hidden {
  display: none !important;
}

.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
}

.card + .card {
  margin-top: 12px;
}

.card h2 {
  font-size: 17px;
  color: var(--green);
  margin-bottom: 4px;
}

.card .sub {
  color: var(--ink-soft);
  font-size: 13px;
  margin: 0 0 16px;
}

.section-title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 22px 0 8px;
}

.row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.spacer {
  flex: 1;
}

/* ==========================================================================
   Date bar
   ========================================================================== */

.datebar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--cream);
  padding: 10px 0 8px;
  margin: -14px 0 4px;
  border-bottom: 1px solid var(--line);
}

.datebar-main {
  display: flex;
  align-items: center;
  gap: 8px;
}

.date-nav {
  background: var(--paper);
  border: 1px solid var(--line-strong);
  color: var(--green);
  width: 42px;
  height: 42px;
  border-radius: var(--radius-sm);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  flex: none;
}

.date-nav:hover {
  background: var(--green-tint);
}

.date-field {
  flex: 1;
  min-width: 0;
  position: relative;
}

.date-field input[type='date'] {
  width: 100%;
  height: 42px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--paper);
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  padding: 0 10px;
  /* iOS renders date inputs at a fixed intrinsic width unless this is set,
     which breaks the flex sizing above. */
  -webkit-appearance: none;
  appearance: none;
}

.datebar-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--ink-soft);
}

.progress-pill {
  background: var(--green-tint);
  color: var(--green);
  border: 1px solid var(--green-line);
  border-radius: 999px;
  padding: 3px 10px;
  font-weight: 600;
  font-size: 12px;
}

.progress-pill.complete {
  background: var(--green);
  color: var(--on-green);
  border-color: var(--green);
}

/* Deliberately the quietest thing on the bar — this is reassurance, not a
   warning. Neutral gray rather than any of the semantic colors already in
   use (amber for caution, red for reduced-production/danger, green for
   done), so it never reads as something wrong. */
.pending-pill {
  background: var(--paper-dim);
  color: var(--ink-soft);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 3px 10px;
  font-weight: 600;
  font-size: 12px;
}

/* ==========================================================================
   Route tabs
   ========================================================================== */

.tabs {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding: 10px 0;
  /* Hides the scrollbar on desktop without disabling the scroll itself. */
  scrollbar-width: none;
}

.tabs::-webkit-scrollbar {
  display: none;
}

.tab {
  flex: none;
  background: var(--paper);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  padding: 9px 14px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
}

.tab[aria-selected='true'] {
  background: var(--green);
  border-color: var(--green);
  color: var(--on-green);
  font-weight: 600;
}

.tab .count {
  opacity: 0.7;
  margin-left: 5px;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Stop cards
   ========================================================================== */

.stop-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}

.stop {
  /* Positioning context for the skipped cross overlay. Safe to add: no
     drag code measures offsetTop/offsetParent, only viewport rects. */
  position: relative;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 4px solid var(--green);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: grid;
  grid-template-columns: 42px 1fr auto;
  align-items: start;
  gap: 8px;
  padding: 10px 10px 10px 6px;
  /* Deliberately NOT touch-action: pan-x.
     It used to be, on the theory that a card had to refuse vertical panning
     so a drag beginning on the handle belonged to us. It does not: the
     handle sets touch-action: none for itself, and a drag can only start
     there. What the card-level rule actually did was refuse to scroll the
     page anywhere on a card — and the cards are the page. Scrolling the run
     meant finding the few pixels of background between them. */
}

.stop.picked {
  border-left-color: var(--ok);
  background: var(--paper-dim);
}

.stop.visiting {
  border-left-color: var(--warn);
}

/* --------------------------------------------------------------------------
   Skipped

   Skipped and collected both fade and both sink to the bottom of the list,
   which left two opposite outcomes looking nearly identical at arm's
   length. A cross through the whole card separates them.

   Amber, matching the badge and the left border a skip already uses —
   deliberately not the red reserved for a misplaced sick barn, which is a
   safety problem rather than a recorded decision.

   overflow is clipped only in this state, so the cross cannot escape the
   rounded corners while nothing else about a normal card changes.
   -------------------------------------------------------------------------- */
.stop.is-skipped {
  overflow: hidden;
  border-left-color: var(--warn);
}

.skip-cross {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.skip-cross line {
  stroke: var(--warn);
  stroke-width: 1.25;
  opacity: 0.55;
  /* Keeps the hairline even however far the viewBox is stretched. */
  vector-effect: non-scaling-stroke;
}

/* --------------------------------------------------------------------------
   A sick barn sitting ahead of a clean one

   Biosecurity: a sick barn is collected after every clean barn, so nothing
   is carried from it to a healthy one. When the run order breaks that, the
   whole card goes red — not a badge, not a border, the entire row. This is
   the one thing on the screen a driver must not scroll past, and it stays
   red until somebody drags the stop where it belongs.

   Deliberately louder than everything else here, including .is-settled's
   fade, which is why the opacity rule below is overridden for it. See
   ROU-018.
   -------------------------------------------------------------------------- */
.stop.sick-misplaced {
  border-color: var(--danger);
  border-left-color: var(--danger);
  border-width: 2px;
  border-left-width: 5px;
  background: var(--danger-tint);
}

.stop.sick-misplaced .stop-name {
  color: var(--danger);
  font-weight: 700;
}

/* The left column: drag handle above, position box below. */
.stop-order {
  /* One row now — the buttons moved inside the body, so body and checks
     are the only things the grid places. */
  grid-row: 1;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 2px;
  background: none;
  border: 0;
  color: var(--ink-faint);
  cursor: grab;
  padding: 0;
  min-height: 44px;
  border-radius: var(--radius-sm);
  touch-action: none; /* required: the handle owns the gesture, not the page */
}

.drag-handle:active {
  cursor: grabbing;
}

.drag-handle:hover,
.drag-handle:focus-visible {
  background: var(--green-tint);
  color: var(--green);
}

.drag-handle .bar {
  width: 14px;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}

/* An editable position, not a label. Typing 9 is far easier than dragging to
   ninth place on a phone, and it is the same operation. */
.stop-index {
  width: 100%;
  padding: 4px 0;
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  background: var(--paper-dim);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  /* Chrome and Safari add spinner arrows that would not fit in 42px and are
     useless on a touchscreen anyway. */
  appearance: textfield;
  -webkit-appearance: textfield;
}

.stop-index::-webkit-outer-spin-button,
.stop-index::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.stop-index:focus {
  outline: 2px solid var(--green-mid);
  outline-offset: 1px;
  background: var(--paper);
  color: var(--ink);
}

.stop-index:disabled {
  background: transparent;
  border-color: transparent;
  color: var(--ink-faint);
}

.stop-body {
  min-width: 0;
}

.stop-name {
  font-size: 15.5px;
  font-weight: 600;
  line-height: 1.25;
  margin: 0;
  word-break: break-word;
}

.stop.picked .stop-name {
  color: var(--ink-soft);
}

/* The name is a button for editors, and must look exactly like the <p> it
   replaces — the card is already dense enough without a control announcing
   itself on every row. It stays quiet at rest and shows the underline on
   hover and focus, which is where someone is actually asking "can I click
   this?". `inherit` on colour and font keeps it in step with .stop.picked
   and .sick-misplaced instead of needing a copy of each rule. */
.stop-name-edit {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  /* font-family only, never the `font` shorthand. The shorthand also resets
     font-size, font-weight and line-height, and this rule sits after
     .stop-name at equal specificity — it would quietly undo the name's 15.5px
     and its 600 weight, and the card would just look subtly wrong. */
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.stop-name-edit:hover,
.stop-name-edit:focus-visible {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.stop-name-edit:focus-visible {
  outline: 2px solid var(--green-mid);
  outline-offset: 2px;
  border-radius: 3px;
}

.stop-address {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 2px 0 0;
  word-break: break-word;
}

.stop-note {
  font-size: 12.5px;
  color: var(--warn);
  background: var(--warn-tint);
  border-radius: var(--radius-sm);
  padding: 5px 8px;
  margin-top: 7px;
}

.stop-meta {
  font-size: 11.5px;
  color: var(--ink-faint);
  margin-top: 6px;
}

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 6px;
}

.badge {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: 999px;
  border: 1px solid transparent;
}

.badge.visiting {
  background: var(--warn-tint);
  color: var(--warn);
  border-color: #e8d3ad;
}

.badge.away {
  background: var(--green-tint);
  color: var(--green);
  border-color: var(--green-line);
}

.badge.done {
  background: var(--green-tint);
  color: var(--ok);
  border-color: var(--green-line);
}

/* Skipped is not an error — a sick barn is the correct outcome, not a
   failure — so it reads as neutral-but-noted rather than red. */
.badge.skipped {
  background: var(--paper-dim);
  color: var(--ink-soft);
  border-color: var(--line-strong);
  text-transform: none;
  letter-spacing: 0.01em;
}

.badge.drop {
  background: #eceff5;
  color: #3c4a63;
  border-color: #c8d0de;
}

/* Not the same signal as skipped (a correct outcome) or visiting (a
   location fact) — this means "check before assuming a full pickup",
   which is closer to a caution than either of those, hence its own red. */
.badge.reduced {
  background: var(--reduced-tint);
  color: var(--reduced);
  border-color: #edc3d0;
  text-transform: none;
  letter-spacing: 0.01em;
}

/* Biosecurity. The loudest badge on the card, and solid rather than
   tinted — every other badge here is a tint, so a filled one reads as a
   different class of thing rather than another note. Matches .pill.sick in
   the address book, so the same fact looks the same on both screens.

   This was missing until 2026-08-13: only .pill.sick existed, so the day
   view fell through to the bare .badge rule and rendered as naked
   uppercase text beside properly styled pills. */
.badge.sick {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
  text-transform: none;
  letter-spacing: 0.01em;
}

/* A company sample site. Neutral rather than semantic — this is a fact
   about what kind of stop it is, not a warning or a state. */
.badge.sample {
  background: #eceff5;
  color: #3c4a63;
  border-color: #c8d0de;
  text-transform: none;
  letter-spacing: 0.01em;
}

/* INF-005. Saved on this phone, not yet on the server — same quiet
   neutral as .pending-pill, deliberately not any of the semantic colors
   above, since nothing is wrong here. */
.badge.pending {
  background: var(--paper-dim);
  color: var(--ink-soft);
  border-color: var(--line-strong);
  text-transform: none;
  letter-spacing: 0.01em;
}

/* Its own tint, distinct from visiting/skipped/drop — this is a standing
   fact about the farm ("collected Wed/Fri only"), not something that
   happened today, and should not visually blend with the ones that are. */
.badge.schedule {
  background: var(--green-tint);
  color: var(--green);
  border-color: var(--green-line);
  text-transform: none;
  letter-spacing: 0.01em;
}

/* --------------------------------------------------------------------------
   Completed stops

   They stay in the list and stay readable — a driver checks what they have
   already done — but recede, so the eye lands on the next outstanding stop.
   -------------------------------------------------------------------------- */
.stop.is-settled {
  opacity: 0.62;
}

.stop.is-settled .stop-name {
  text-decoration: line-through;
  text-decoration-color: var(--ink-faint);
  text-decoration-thickness: 1px;
}

/* --------------------------------------------------------------------------
   Cart drops
   -------------------------------------------------------------------------- */
.cart-drop {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin-top: 8px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  border: 1px dashed #c8d0de;
  background: #f4f6fa;
  font-size: 13px;
}

.cart-drop.delivered {
  border-style: solid;
  border-color: var(--green-line);
  background: var(--green-tint);
}

.cart-drop-text {
  font-weight: 600;
  color: #3c4a63;
}

.cart-drop.delivered .cart-drop-text {
  color: var(--ok);
}

.cart-drop-note {
  color: var(--ink-soft);
}

/* The check-off control. Deliberately oversized: this is tapped with a
   thumb, in a moving vehicle, sometimes with a glove on. */
/* Both checkboxes share one grid cell, stacked. Keeping them out of the
   button row is what lets Copy address / Call / Skip stay on a single line
   on a phone instead of wrapping.

   grid-row: 1, NOT 1 / span 2. Spanning two rows meant this column's height
   had to be absorbed by a second row that nothing else occupied — a 72px
   band of empty card on every stop, which is exactly what it looked like. */
.stop-checks {
  grid-column: 3;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

/* The label wraps the box and its caption, so the whole thing is the tap
   target — the visible square is 28px but the hit area stays ~46px tall,
   which is what matters with a glove on in a moving truck.

   margin: 0 is load-bearing. This is a <label>, so it was picking up the
   form-label rule's `margin: 12px 0 5px` — 17px of stray vertical space
   per box, invisible on its own and the single largest cause of the card
   looking half empty once there were two of them stacked. */
.check {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  cursor: pointer;
  padding: 3px 2px;
}

.check input {
  appearance: none;
  -webkit-appearance: none;
  width: 28px;
  height: 28px;
  margin: 0;
  border: 2px solid var(--line-strong);
  border-radius: 8px;
  background: var(--paper);
  cursor: pointer;
  position: relative;
  flex: none;
}

.check input:checked {
  background: var(--ok);
  border-color: var(--ok);
}

.check input:checked::after {
  content: '';
  position: absolute;
  left: 8px;
  top: 3px;
  width: 7px;
  height: 12px;
  border: solid #fff;
  border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}

.check input:focus-visible {
  outline: 3px solid var(--green-mid);
  outline-offset: 2px;
}

/* Sick is a warning, not a completion, so it must not read as another
   green tick. Red when set, and the label goes red with it. */
.check.sick input:checked {
  background: var(--danger);
  border-color: var(--danger);
}

.check.sick input:checked ~ .check-label {
  color: var(--danger);
}

/* A disabled box still has to be readable — a viewer needs to see that a
   barn is sick even though they cannot change it. */
.check input:disabled {
  cursor: default;
  opacity: 0.75;
}

.check-label {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Lives inside .stop-body now, under the address — not a grid row of its
   own. See the note in renderStopCard: as its own row it sat below the
   full height of the checkbox column, which is what left the card looking
   half empty. */
.nav-links {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 8px;
}

/* The second row is its own element rather than a wrap of the first, so
   Message and Call sit in the same place on every card whatever the row
   above happens to contain. Tighter than the gap above it: the two rows
   are one block of actions, not two separate things. */
.nav-links.contact {
  margin-top: 6px;
}

.nav-link {
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
  color: var(--green);
  background: var(--green-tint);
  border: 1px solid var(--green-line);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.nav-link:hover {
  background: var(--green-line);
}

.nav-link.tel {
  background: var(--paper);
  border-color: var(--line-strong);
  color: var(--ink);
}

/* A view-only action sitting among navigation links. Quieter than the map
   buttons on purpose — it changes nothing about the run, only this screen. */
.nav-link.subtle {
  background: transparent;
  border-color: var(--line);
  color: var(--ink-soft);
  font-weight: 500;
  cursor: pointer;
}

.nav-link.subtle:hover {
  background: var(--paper-dim);
  color: var(--ink);
}

/* ---- personal view controls ---- */

#view-controls {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 14px;
}

.hidden-stops {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper-dim);
  padding: 10px 12px;
}

.hidden-stops summary {
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
}

.hidden-stop-list {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.hidden-stop {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-top: 1px solid var(--line);
}

.hidden-stop-name {
  font-size: 14px;
  color: var(--ink-soft);
}

.view-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.link-button {
  background: none;
  border: none;
  padding: 6px 0;
  /* Comfortably tappable on a phone even though it reads as a link. */
  min-height: 34px;
  font-size: 13px;
  font-weight: 600;
  color: var(--green);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.link-button:hover {
  color: var(--green-dark);
}

/* ---- drag states ---- */

.stop.dragging {
  opacity: 0.92;
  box-shadow: var(--shadow-lift);
  /* Lifted out of the flow while following the pointer. */
  position: relative;
  z-index: 30;
}

.drop-placeholder {
  border: 2px dashed var(--green-line);
  border-radius: var(--radius);
  background: var(--green-tint);
  /* Height is set inline to match the card being dragged. */
}

/* ==========================================================================
   Buttons and forms
   ========================================================================== */

.btn {
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  border-radius: var(--radius-sm);
  border: 1px solid var(--green);
  background: var(--green);
  color: var(--on-green);
  padding: 11px 16px;
  min-height: 44px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.btn:hover:not(:disabled) {
  background: var(--green-dark);
  border-color: var(--green-dark);
}

.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.btn.secondary {
  background: var(--paper);
  color: var(--green);
  border-color: var(--line-strong);
}

.btn.secondary:hover:not(:disabled) {
  background: var(--green-tint);
  border-color: var(--green-line);
}

.btn.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}

.btn.danger:hover:not(:disabled) {
  filter: brightness(0.92);
}

.btn.small {
  font-size: 12.5px;
  padding: 7px 11px;
  min-height: 36px;
}

.btn.block {
  width: 100%;
}

label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 12px 0 5px;
}

input[type='text'],
input[type='email'],
input[type='password'],
input[type='tel'],
input[type='number'],
input[type='date'],
select,
textarea {
  width: 100%;
  font-family: inherit;
  /* 16px minimum, otherwise iOS Safari zooms the page on focus. */
  font-size: 16px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 10px 11px;
  min-height: 44px;
}

textarea {
  min-height: 72px;
  resize: vertical;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--green-mid);
  box-shadow: 0 0 0 3px rgba(53, 112, 74, 0.18);
}

.field-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 12px;
}

.help {
  font-size: 12px;
  color: var(--ink-faint);
  margin-top: 4px;
}

/* ==========================================================================
   Admin lists
   ========================================================================== */

.list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.list li {
  border-top: 1px solid var(--line);
  padding: 12px 0;
  display: flex;
  /* Wraps so the buttons drop onto their own line rather than squeezing the
     farm name. Without this, a fourth action shrank the name column to about
     100px on a phone and "Lambright" wrapped one letter at a time. */
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-start;
}

.list li:first-child {
  border-top: 0;
}

/* The 240px basis is the load-bearing part: it is a floor, not a width. The
   row keeps the name and the buttons side by side while they both fit, and
   wraps rather than crushing the name when they do not. */
.list .list-main {
  flex: 1 1 240px;
  min-width: 0;
}

.list .list-title {
  font-weight: 600;
  font-size: 14.5px;
  word-break: break-word;
}

.list .list-sub {
  font-size: 12.5px;
  color: var(--ink-soft);
  word-break: break-word;
}

.list .list-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  /* Grows to fill the line once it has wrapped onto one of its own. */
  flex: 1 1 auto;
}

.pill {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--green-tint);
  color: var(--green);
  border: 1px solid var(--green-line);
}

.pill.muted {
  background: var(--paper-dim);
  color: var(--ink-faint);
  border-color: var(--line);
}

.pill.warn {
  background: var(--warn-tint);
  color: var(--warn);
  border-color: #e8d3ad;
}

.pill.reduced {
  background: var(--reduced-tint);
  color: var(--reduced);
  border-color: #edc3d0;
}

/* Biosecurity, so this one is allowed to be the loudest thing in the list —
   solid rather than tinted. A driver reading past this and collecting a sick
   barn mid-run is the failure this exists to prevent. */
.pill.sick {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
}

/* Deliberately the quietest pill in the row. A sample site is a fact about
   what the stop is, not a warning — it sits beside the tag pills and must
   not compete with .pill.sick two lines up. Neutral blue-grey keeps it out
   of the green/amber/red vocabulary the rest of the app reads as status.
   Matches .badge.sample on the day view so the same idea looks the same in
   both places. */
.pill.sample {
  background: #eceff3;
  color: #4a5563;
  border-color: #d3d9e1;
}

/* ROU-016: the proposed order inside the suggestion dialog. Scrolls rather
   than growing the dialog past the screen — a fourteen-stop run on a phone
   would otherwise push the Cancel/Use buttons out of reach. */
.suggested-order {
  margin: 12px 0 0;
  padding-left: 22px;
  max-height: 45vh;
  overflow-y: auto;
  font-size: 13.5px;
  line-height: 1.9;
}

.suggested-order li {
  padding-right: 4px;
}

/* --------------------------------------------------------------------------
   Product tags

   Eggs, chicks and live haul. Three tints rather than three saturated hues:
   these sit next to the farm name in a long list and must read as a quiet
   category marker, not as a warning. A farm carrying all three should still
   look like a list row.

   Colours are keyed off the tag slug, so a fourth tag added to the database
   renders in the neutral .tag style until someone chooses a colour for it —
   an unstyled tag, not a broken one.
   -------------------------------------------------------------------------- */
.pill.tag {
  background: var(--paper-dim);
  color: var(--ink-soft);
  border-color: var(--line-strong);
  text-transform: none;
  letter-spacing: 0.01em;
}

.pill.tag-eggs {
  background: var(--warn-tint);
  color: #8a5a12;
  border-color: #e8d3ad;
}

.pill.tag-chicks {
  background: var(--green-tint);
  color: var(--green);
  border-color: var(--green-line);
}

.pill.tag-live_haul {
  background: #eceff5;
  color: #3c4a63;
  border-color: #c8d0de;
}

/* --------------------------------------------------------------------------
   Address book filters
   -------------------------------------------------------------------------- */
.filters {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.filter-search {
  width: 100%;
}

.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}

/* Each group is one question — status, tag, assignment — kept together so
   the row does not read as one long undifferentiated strip of buttons. */
.filter-group {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.chip {
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  color: var(--ink-soft);
  cursor: pointer;
  /* Comfortably tappable in a truck cab without making the bar enormous. */
  min-height: 32px;
}

.chip:hover {
  border-color: var(--green-line);
  color: var(--green);
}

.chip.on {
  background: var(--green);
  border-color: var(--green);
  color: var(--on-green);
}

.chip:focus-visible {
  outline: 2px solid var(--green-mid);
  outline-offset: 2px;
}

.count {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-faint);
  margin-left: 6px;
}

/* An inactive farm stays legible — it is a real record being looked at, not
   disabled chrome — but recedes against the farms currently being worked. */
.list li.is-inactive .list-title {
  color: var(--ink-soft);
}

.list li.is-inactive .list-sub {
  color: var(--ink-faint);
}

.list-sub.dim {
  color: var(--ink-faint);
  font-size: 12px;
}

/* --------------------------------------------------------------------------
   Checkbox groups in dialogs
   -------------------------------------------------------------------------- */
.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.checkbox-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--paper);
  cursor: pointer;
  /* Overrides the block form-label styling these would otherwise inherit. */
  font-weight: 500;
  font-size: 14px;
  color: var(--ink);
  margin: 0;
}

.checkbox-item:has(input:checked) {
  border-color: var(--green);
  background: var(--green-tint);
  color: var(--green);
}

.checkbox-item input {
  width: auto;
  margin: 0;
  accent-color: var(--green);
}

.empty {
  text-align: center;
  color: var(--ink-faint);
  font-size: 13.5px;
  padding: 28px 12px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper-dim);
}

/* ==========================================================================
   Dialog and toast
   ========================================================================== */

.backdrop {
  position: fixed;
  inset: 0;
  background: rgba(22, 53, 30, 0.5);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 100;
  padding: 0;
}

.dialog {
  background: var(--paper);
  border-radius: var(--radius) var(--radius) 0 0;
  width: 100%;
  max-width: 520px;
  max-height: 92vh;
  overflow-y: auto;
  padding: 20px 16px calc(20px + env(safe-area-inset-bottom));
  box-shadow: var(--shadow-lift);
}

.dialog h3 {
  font-size: 17px;
  color: var(--green);
  margin-bottom: 4px;
}

.dialog .sub {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 0 0 8px;
}

.dialog-actions {
  display: flex;
  gap: 8px;
  margin-top: 18px;
}

.dialog-actions .btn {
  flex: 1;
}

/* --------------------------------------------------------------------------
   Message sheet

   Full-width rows sized for a thumb, each naming a person and what they are
   to this stop. The role matters as much as the name: "LBB" means nothing
   at a glance, "Field tech" does.
   -------------------------------------------------------------------------- */
.msg-sendto {
  margin: 10px 0 2px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.msg-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 4px 0;
}

/* A green rail down the left of each row, the same green the app bar and
   primary buttons use. It is what makes this read as PoultryPath's own
   sheet in the half-second before the phone's messaging app takes over —
   the handoff itself is the OS's and cannot be styled, so the moment
   before it is the only one worth designing. */
.msg-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-decoration: none;
  background: var(--paper-dim);
  border: 1px solid var(--line);
  border-left: 4px solid var(--green-mid);
  border-radius: var(--radius-sm);
  padding: 11px 14px;
  min-height: 52px;
  justify-content: center;
  cursor: pointer;
}

.msg-item:hover,
.msg-item:focus-visible {
  background: var(--green-tint);
  border-color: var(--green-line);
  border-left-color: var(--green);
  outline: none;
}

.msg-who {
  font-size: 15.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.2;
}

/* The role is the part that actually identifies somebody — "LBB" means
   nothing, "Field tech" does — so it gets a chip rather than grey text
   under a name. */
.msg-role {
  align-self: flex-start;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--green);
  background: var(--green-tint);
  border: 1px solid var(--green-line);
  border-radius: 999px;
  padding: 2px 7px;
}

/* The all-recipients row is a different kind of action, so it reads as one:
   no rail, and a dashed edge that says "several" rather than "one". */
.msg-item.msg-all {
  border-left: 1px dashed var(--line-strong);
  border-color: var(--line-strong);
  border-left-style: dashed;
  background: var(--paper);
}

.msg-item.msg-all .msg-role {
  color: var(--ink-soft);
  background: var(--paper-dim);
  border-color: var(--line-strong);
  text-transform: none;
  letter-spacing: 0.01em;
  font-weight: 500;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(18px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  background: var(--green-dark);
  color: var(--on-green);
  font-size: 13.5px;
  font-weight: 500;
  padding: 11px 16px;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lift);
  z-index: 200;
  max-width: calc(100vw - 32px);
  text-align: center;
}

.toast.error {
  background: var(--danger);
}

.banner {
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-size: 13px;
  margin-bottom: 12px;
}

.banner.error {
  background: var(--danger-tint);
  color: var(--danger);
  border: 1px solid #eccdc6;
}

.banner.info {
  background: var(--green-tint);
  color: var(--green);
  border: 1px solid var(--green-line);
}

.banner.warn {
  background: var(--warn-tint);
  color: var(--warn);
  border: 1px solid #e8d3ad;
}

/* Screen-reader-only, for labels that would be redundant visually. */
.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;
}

.footer-note {
  text-align: center;
  color: var(--ink-faint);
  font-size: 11px;
  padding: 24px 12px;
}

/* ==========================================================================
   Wider screens
   ========================================================================== */

@media (min-width: 640px) {
  .field-row.two {
    grid-template-columns: 1fr 1fr;
  }

  .backdrop {
    align-items: center;
    padding: 20px;
  }

  .dialog {
    border-radius: var(--radius);
  }

  main {
    padding: 18px 20px 96px;
  }
}

@media (min-width: 900px) {
  .wordmark-text {
    font-size: 22px;
  }
}

/* Respect a reduced-motion preference: the drag lift is the only animation
   here, and it is purely decorative. */
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation: none !important;
  }
}

/* ---- Home base: the last card of the day ---------------------------------

   Deliberately quieter than a pickup card. It is not work — it is the end of
   the work, and it should read as a full stop rather than as one more thing
   demanding attention. Green rail rather than the amber and red the run uses
   for things that need deciding. */
.stop.home-base {
  border-left: 3px solid var(--green-mid);
  background: var(--paper-dim);
}

.stop.home-base .stop-index {
  background: transparent;
  border-color: transparent;
  color: var(--ink-faint);
}

/* Matches .badge.sample in weight: a statement of what this card is, not a
   warning. Green because arriving here is the good outcome.

   Defined at the same time as the badge that uses it. A badge class with no
   rule falls through to bare uppercase text, which is exactly how .badge.sick
   shipped looking like a mistake on 2026-08-13. */
.badge.home {
  background: var(--green-tint);
  color: var(--green-dark);
  border-color: var(--green-line);
}

/* ---- The home base picker on the account screen ---- */
#home-base-field {
  margin-bottom: 22px;
}

#home-base-field select {
  width: 100%;
}
