/* Components */

/* Home */

.home-hero {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: clamp(34px, 6vw, 64px) clamp(24px, 5vw, 64px);
  text-align: center;
  margin-bottom: 28px;
}
.home-hero h1 {
  font-size: clamp(30px, 5.2vw, 46px);
  margin-bottom: 12px;
}
.home-hero .lead {
  margin-inline: auto;
  margin-bottom: 28px;
}

.home-search {
  display: flex;
  gap: 10px;
  max-width: 540px;
  margin-inline: auto;
}
.home-search input {
  flex: 1;
  min-height: 54px;
  font-size: 16.5px;
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
  text-align: center;
}
.home-search .btn {
  min-height: 54px;
  padding-inline: 32px;
}
.home-search-note {
  min-height: 20px;
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--danger);
  font-weight: 600;
}
.home-alt {
  margin: 6px 0 0;
  font-size: 14.5px;
  color: var(--muted);
}
.home-alt a {
  font-weight: 600;
}

/* How it works */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--gap);
  margin-bottom: 28px;
}
.step {
  background: var(--surface);
  border-radius: var(--r);
  padding: 26px 28px;
  box-shadow: var(--shadow-sm);
}
.step-num {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--crimson-soft);
  color: var(--crimson);
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 14px;
}
.step h3 {
  margin-bottom: 6px;
}
.step p {
  margin: 0;
  color: var(--muted);
  font-size: 14.5px;
}

/* Driver entry point */
.driver-band {
  background: var(--crimson);
  color: #fff;
  border-radius: var(--r-lg);
  padding: clamp(28px, 4vw, 42px) clamp(24px, 4vw, 48px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  flex-wrap: wrap;
}
.driver-band-eyebrow {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.66);
  margin-bottom: 8px;
}
.driver-band h2 {
  color: #fff;
  font-size: clamp(20px, 3vw, 26px);
  margin-bottom: 8px;
}
.driver-band p {
  margin: 0;
  color: rgba(255, 255, 255, 0.78);
  font-size: 14.5px;
  max-width: 52ch;
}
.btn-invert {
  background: #fff;
  color: var(--crimson);
  flex-shrink: 0;
}
.btn-invert:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.9);
  color: var(--crimson);
}

@media (max-width: 560px) {
  .home-search {
    flex-direction: column;
  }
  .home-search .btn {
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   Status badge
   -------------------------------------------------------------------------- */

.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border-radius: var(--pill);
  padding: 5px 13px;
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
}
.status-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.status-active {
  background: var(--crimson-soft);
  color: var(--crimson);
}
.status-ok {
  background: var(--ok-bg);
  color: var(--ok);
}
.status-danger {
  background: var(--danger-bg);
  color: var(--danger);
}
.status-neutral {
  background: var(--surface-sunk);
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   Status hero, the top of the tracking page
   -------------------------------------------------------------------------- */

.hero {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: 30px 32px;
  margin-bottom: var(--gap);
}
.hero-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}
.hero-label {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: 6px;
}
.hero-status {
  font-family: var(--font-display);
  font-size: clamp(23px, 3.4vw, 29px);
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--ink);
  margin: 16px 0 4px;
  line-height: 1.1;
}
.hero-sub {
  color: var(--muted);
  font-size: 14.5px;
  margin: 0;
}
.hero-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

/* Progress rail: the nine steps, filled to the point reached. */
.rail {
  display: flex;
  gap: 5px;
  margin-top: 26px;
}
.rail-step {
  flex: 1;
  height: 5px;
  border-radius: var(--pill);
  background: var(--line);
}
.rail-step.is-done {
  background: var(--crimson);
}
.rail-step.is-failed {
  background: var(--danger);
}
.rail-caption {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 10px;
  font-size: 12px;
  color: var(--muted);
}

@media (max-width: 640px) {
  .hero {
    padding: 22px 20px;
  }
  .hero-actions {
    align-items: flex-start;
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   Timeline
   -------------------------------------------------------------------------- */

.timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}
.timeline-item {
  position: relative;
  padding: 0 0 20px 28px;
}
.timeline-item:last-child {
  padding-bottom: 0;
}
.timeline-item::before {
  content: "";
  position: absolute;
  left: 5px;
  top: 15px;
  bottom: -5px;
  width: 2px;
  background: var(--line);
}
.timeline-item:last-child::before {
  display: none;
}
.timeline-marker {
  position: absolute;
  left: 0;
  top: 4px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: inset 0 0 0 2px var(--line-strong);
}
.is-done .timeline-marker {
  background: var(--crimson);
  box-shadow: none;
}
.is-failed .timeline-marker {
  background: var(--danger);
  box-shadow: none;
}
.timeline-head {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
}
.timeline-label {
  font-weight: 600;
  font-size: 14.5px;
  color: var(--ink);
}
.is-future .timeline-label {
  color: var(--muted);
  font-weight: 500;
}
.is-failed .timeline-label {
  color: var(--danger);
}
.timeline-actor {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  background: var(--surface-sunk);
  border-radius: var(--pill);
  padding: 2px 8px;
}
.timeline-time,
.timeline-meta {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 2px;
}

/* --------------------------------------------------------------------------
   Key and value list. Rows are separated by hairlines rather than boxed.
   -------------------------------------------------------------------------- */

.kv {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(84px, max-content) 1fr;
  font-size: 14.5px;
}
.kv dt {
  color: var(--muted);
  font-size: 13px;
  padding: 10px 24px 10px 0;
  border-top: 1px solid var(--line);
}
.kv dd {
  margin: 0;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  color: var(--ink);
}
.kv dt:first-of-type,
.kv dd:first-of-type {
  border-top: 0;
  padding-top: 0;
}

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: start;
}
/* Centred reading widths. The page is fluid, but a form or a single input read
   badly across a full monitor, so these blocks cap and centre themselves. */
.narrow {
  max-width: 440px;
  margin-inline: auto;
}
.page-narrow {
  max-width: 720px;
  margin-inline: auto;
}
.field-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}
.field-row .field {
  flex: 1;
  min-width: 180px;
}
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 500;
  margin-bottom: 16px;
}
.back-link:hover {
  color: var(--crimson);
}
.count {
  display: inline-block;
  background: var(--surface-sunk);
  border-radius: var(--pill);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  padding: 1px 9px;
  margin-left: 6px;
  vertical-align: 2px;
}
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 34px 0 14px;
}
.section-head h2 {
  margin: 0;
}
.form-section {
  margin-bottom: 28px;
}
.form-section:last-of-type {
  margin-bottom: 0;
}

@media (max-width: 900px) {
  .split {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   QR block
   -------------------------------------------------------------------------- */

.qr-block {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  align-items: flex-start;
}
.qr-placeholder {
  width: 152px;
  height: 152px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  color: var(--muted);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.14em;
  background: var(--surface-sunk);
  box-shadow: inset 0 0 0 1px var(--line);
  flex-shrink: 0;
}
.qr-side {
  flex: 1;
  min-width: 250px;
}

/* Maps */

.map-link {
  color: var(--crimson);
  text-decoration: none;
  border-bottom: 1px solid var(--crimson-edge);
}
.map-link:hover {
  border-bottom-color: var(--crimson);
}
.map-link::after {
  content: "↗";
  font-size: 0.78em;
  margin-left: 3px;
  opacity: 0.6;
}

.map-embed {
  margin-top: 16px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-sunk);
  aspect-ratio: 16 / 10;
}
.map-embed iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Address fields with Google's suggestions */

.addr-box {
  position: relative;
}
.addr-suggest {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-md);
  max-height: 320px;
  overflow-y: auto;
}
.addr-suggest li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
  line-height: 1.4;
}
.addr-suggest li .ic {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  flex-shrink: 0;
  color: var(--crimson);
}
.addr-suggest li strong {
  display: block;
  font-weight: 600;
  font-size: 14.5px;
  color: var(--ink);
}
.addr-suggest li small {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
}
.addr-suggest li[aria-selected="true"],
.addr-suggest li:hover {
  background: var(--crimson-soft);
}
.addr-suggest .addr-empty {
  cursor: default;
  color: var(--muted);
  font-size: 13.5px;
}
.addr-suggest .addr-empty:hover {
  background: none;
}
.addr-status {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 7px 0 0;
  font-size: 13px;
  color: var(--muted);
}
.addr-status .ic {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.addr-undo {
  margin-left: 6px;
  padding: 1px 10px;
  border: 1px solid currentColor;
  border-radius: var(--pill);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
.addr-undo:hover {
  background: var(--ok-bg);
}
.addr-status.is-area {
  color: var(--warn);
  font-weight: 600;
}
.addr-suggest li .addr-kind {
  display: inline-block;
  margin-left: 7px;
  padding: 1px 7px;
  border-radius: var(--pill);
  background: var(--warn-bg);
  color: var(--warn);
  font-size: 11px;
  font-style: normal;
  font-weight: 600;
  vertical-align: 1px;
}
.addr-status.is-pinned {
  color: var(--ok);
  font-weight: 600;
}
.addr-preview {
  margin-top: 10px;
}

/* Location maps */

.card-map {
  margin-top: 16px;
}
.location-map {
  width: 100%;
  height: 300px;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-sunk);
}
.location-map.is-compact {
  height: 170px;
}
/* The map an address's pin is placed on: big enough to aim a finger at. */
.location-map.is-picker {
  height: 240px;
}
.location-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-top: 12px;
  font-size: 13px;
  color: var(--ink-soft);
}
.location-key {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.location-dot {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  flex-shrink: 0;
}
.location-open {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  color: var(--crimson);
  font-weight: 600;
  text-decoration: none;
}
.location-open .ic {
  width: 15px;
  height: 15px;
}
.location-open:hover {
  text-decoration: underline;
}
.location-info {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.45;
  max-width: 240px;
  color: var(--ink);
}

@media (max-width: 600px) {
  .location-map {
    height: 240px;
  }
  .location-map.is-compact {
    height: 150px;
  }
  .location-map.is-picker {
    height: 220px;
  }
  .location-open {
    margin-left: 0;
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   Photo grid
   -------------------------------------------------------------------------- */

.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 8px;
}
.photo-thumb {
  aspect-ratio: 1;
  border-radius: var(--r-sm);
  background: linear-gradient(140deg, #ece5e0, #ddd2ca);
}
.photo-thumb.has-image {
  background-size: cover;
  background-position: center;
}

/* A photograph on its way to the server. The thumbnail appears immediately,
   dimmed, so the driver can see the shot was taken while the upload is still
   running rather than waiting on a blank square. */
.photo-thumb.is-uploading {
  opacity: 0.45;
  position: relative;
}
.photo-thumb.is-uploading::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--crimson);
  animation: photo-pulse 1.1s ease-in-out infinite;
}

/* An upload that failed twice. It stays on screen, marked, because a photograph
   that silently vanished would leave the driver thinking it was sent. */
.photo-thumb.is-failed {
  position: relative;
  opacity: 0.5;
  outline: 2px solid var(--danger);
  outline-offset: -2px;
}
.photo-thumb.is-failed::after {
  content: "!";
  position: absolute;
  inset: auto 4px 4px auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--danger);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  display: grid;
  place-items: center;
}

@keyframes photo-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .photo-thumb.is-uploading::after {
    animation: none;
    opacity: 0.7;
  }
}

/* Photographs open full size in a new tab, so they behave like links. */
a.photo-thumb {
  display: block;
}

/* --------------------------------------------------------------------------
   QR holder
   -------------------------------------------------------------------------- */

.qr-placeholder img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 6px;
}
.qr-loading {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
  text-align: center;
  padding: 8px;
  line-height: 1.4;
}

/* --------------------------------------------------------------------------
   Scanner
   -------------------------------------------------------------------------- */

.scanner-frame {
  position: relative;
  width: 100%;
  max-width: 340px;
  margin-inline: auto;
  aspect-ratio: 1;
  border-radius: var(--r-lg);
  background: #191411;
  display: grid;
  place-items: center;
  margin-bottom: var(--gap);
}
/* The frame is the control. Tapping it starts the camera, tapping again stops:
   one large target instead of small buttons a driver has to aim at. */
button.scanner-frame {
  border: 0;
  padding: 0;
  cursor: pointer;
  font: inherit;
  display: grid;
  place-items: center;
  overflow: hidden;
  transition: box-shadow 0.2s ease;
}
button.scanner-frame:hover {
  box-shadow: 0 0 0 3px var(--crimson-soft);
}
button.scanner-frame.is-scanning {
  box-shadow: 0 0 0 3px var(--crimson-edge);
}

.scanner-cta {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: #fff;
  font-size: 14.5px;
  font-weight: 600;
  padding: 12px 22px;
  background: rgba(0, 0, 0, 0.55);
  border-radius: var(--pill);
  max-width: 86%;
  text-align: left;
}
.scanner-cta-icon {
  font-size: 16px;
  line-height: 1;
  color: #fff;
  opacity: 0.85;
}
.scanner-cta-icon.is-live {
  color: #ff6b6b;
  animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

/* --------------------------------------------------------------------------
   Scan result, shown in place of the scanner
   -------------------------------------------------------------------------- */

.result-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 20px;
}
.result-mark {
  width: 66px;
  height: 66px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 30px;
  line-height: 1;
  margin: 6px auto 18px;
}
.result-mark.is-good {
  background: var(--ok-bg);
  color: var(--ok);
}
.result-mark.is-bad {
  background: var(--danger-bg);
  color: var(--danger);
}
.result-mark.is-waiting {
  background: var(--crimson-soft);
  color: var(--crimson);
  animation: pulse 1.4s ease-in-out infinite;
}

.scanner-frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--r-lg);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.scanner-frame video.is-live {
  opacity: 1;
}
.scanner-corner {
  position: absolute;
  width: 32px;
  height: 32px;
  border: 3px solid rgba(255, 255, 255, 0.85);
}
.scanner-corner.tl {
  top: 20px;
  left: 20px;
  border-right: 0;
  border-bottom: 0;
  border-radius: 10px 0 0 0;
}
.scanner-corner.tr {
  top: 20px;
  right: 20px;
  border-left: 0;
  border-bottom: 0;
  border-radius: 0 10px 0 0;
}
.scanner-corner.bl {
  bottom: 20px;
  left: 20px;
  border-right: 0;
  border-top: 0;
  border-radius: 0 0 0 10px;
}
.scanner-corner.br {
  bottom: 20px;
  right: 20px;
  border-left: 0;
  border-top: 0;
  border-radius: 0 0 10px 0;
}

/* --------------------------------------------------------------------------
   Skeleton loading

   Placeholder blocks laid out inside the real cards, so the page holds its
   shape while the record loads and nothing jumps when it arrives. A single
   small spinner told the reader nothing about what was coming; these show the
   shape of the answer.

   Every skeleton is built from the same .hero, .card and .split classes as the
   real screen, so it inherits the responsive behaviour rather than needing its
   own breakpoints.
   -------------------------------------------------------------------------- */

.skeleton {
  background-color: var(--line);
  background-image: linear-gradient(
    90deg,
    var(--line) 0%,
    var(--surface-sunk) 40%,
    var(--line) 80%
  );
  background-size: 300% 100%;
  animation: skeleton-sweep 1.5s ease-in-out infinite;
  border-radius: var(--r-sm);
}

@keyframes skeleton-sweep {
  from { background-position: 150% 0; }
  to { background-position: -150% 0; }
}

/* A line of text. Widths vary so a block reads as prose rather than a bar chart. */
.sk-line {
  height: 12px;
  border-radius: var(--pill);
  margin-bottom: 10px;
}
.sk-line:last-child { margin-bottom: 0; }

.sk-w-30 { width: 30%; }
.sk-w-45 { width: 45%; }
.sk-w-60 { width: 60%; }
.sk-w-75 { width: 75%; }
.sk-w-90 { width: 90%; }

.sk-title { height: 26px; width: 55%; border-radius: var(--r-sm); margin-bottom: 14px; }
.sk-badge { height: 28px; width: 104px; border-radius: var(--pill); }
.sk-rail { height: 8px; border-radius: var(--pill); margin-top: 22px; }
.sk-qr { width: 124px; height: 124px; border-radius: var(--r-sm); flex-shrink: 0; }
.sk-button { height: 38px; width: 122px; border-radius: var(--pill); }

/* Spacing between stacked placeholder groups inside one card. */
.sk-group { margin-bottom: 22px; }
.sk-group:last-child { margin-bottom: 0; }

/* A row in a placeholder list, matching .delivery-row proportions. */
.sk-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--line);
}
.sk-row:last-child { border-bottom: 0; }
.sk-row-main { flex: 1; min-width: 0; }

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

/* --------------------------------------------------------------------------
   Copy button, attached to a value

   Sits beside the tracking number rather than under it, so the number and the
   way to copy it read as one thing. The number itself wraps on a narrow phone,
   so the button is aligned to the top of the line and never stretches.
   -------------------------------------------------------------------------- */

.copy-value {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.copy-value .tracking-number {
  min-width: 0;
}

.copy-btn {
  flex-shrink: 0;
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-top: -4px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.copy-btn:hover {
  color: var(--crimson);
  border-color: var(--crimson-edge);
  background: var(--crimson-soft);
}
.copy-btn:focus-visible {
  outline: none;
  border-color: var(--crimson);
  box-shadow: 0 0 0 3px var(--crimson-soft);
}
.copy-btn svg {
  width: 16px;
  height: 16px;
  display: block;
}

/* Held after a successful copy, so the confirmation is visible without a
   toast covering the record the reader just asked for. */
.copy-btn.is-copied {
  color: var(--ok);
  border-color: var(--ok);
  background: var(--ok-bg);
}

/* --------------------------------------------------------------------------
   Tracking hero with the QR beside it

   The QR sits to the right of the status and the progress rail rather than in
   a card further down. Two reasons: the rail no longer stretches the full page
   width, where it read as a loading bar rather than a nine step journey, and
   the code is the thing a sender most often wants from this page.

   On a narrow screen the column becomes a row below the progress, because the
   status is what a customer opened the page for and the code is what they act
   on afterwards. Document order already puts them that way, so the stacked
   case needs no reordering.
   -------------------------------------------------------------------------- */

.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 32px;
  align-items: start;
}

.hero-main {
  min-width: 0;
}

.hero-qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
}

/* The frame is the separation. A divider rule between the two columns did the
   same job less well: it drew a line through the card for the whole height of
   the hero, and the code still floated inside it with nothing holding it.
   Framing the code instead marks it as the one thing on this page meant to be
   detached, printed and stuck to a parcel.
   The border sits outside the quiet zone the generator already leaves around
   the code, so it cannot interfere with a scan. */
.hero-qr .qr-placeholder {
  width: 164px;
  height: 164px;
  padding: 9px;
  background: #fff;
  border: 2px solid var(--crimson);
  border-radius: var(--r-sm);
  box-shadow: none;
}
.hero-qr .row {
  justify-content: center;
}

@media (max-width: 780px) {
  .hero-split {
    grid-template-columns: 1fr;
    gap: 26px;
  }
}

/* --------------------------------------------------------------------------
   Next step panel, driver delivery screen

   Occupies the same place in the hero as the QR does on the customer tracking
   page: the right column on a wide screen, stacked under the progress on a
   phone. The first question a driver has on opening a delivery is not what
   state it is in but what to do about it, and the answer was previously only
   in a bar at the foot of the page.
   -------------------------------------------------------------------------- */

.hero-next {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 232px;
  max-width: 280px;
  padding: 18px 20px;
  border-radius: var(--r);
  background: var(--crimson-soft);
  box-shadow: inset 0 0 0 1px var(--crimson-edge);
}

.next-step {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1.25;
  font-weight: 600;
  color: var(--ink);
}

/* A finished delivery has no action, so the panel reports rather than asks. */
.hero-next .muted {
  margin: 0;
}

@media (max-width: 780px) {
  .hero-next {
    max-width: none;
    min-width: 0;
  }
}


/* --------------------------------------------------------------------------
   The current step in a timeline

   Between done and not yet. The driver screen shows all nine steps from the
   moment a delivery opens, so the one being asked for has to be findable
   without reading the whole list.
   -------------------------------------------------------------------------- */

.timeline-item.is-next .timeline-marker {
  background: var(--surface);
  border-color: var(--crimson);
  box-shadow: 0 0 0 4px var(--crimson-soft);
}
.timeline-item.is-next .timeline-label {
  color: var(--ink);
  font-weight: 700;
}
.timeline-item.is-next .timeline-time {
  color: var(--crimson);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 11px;
}

/* The action that completes the step, sitting under its label. Capped so a
   wide screen does not stretch it into a banner across the card. */
.timeline-action {
  margin-top: 12px;
  max-width: 320px;
}


/* A caution the reader should act on, distinct from an error that has already
   happened. Used where location is blocked before a step is taken. */
/*
 * A warning sitting straight on top of the button it qualifies reads as part of
 * the button. It is spaced only while it is shown, so a hidden one leaves no
 * gap above the action.
 */
.note-warn:not([hidden]) {
  margin-bottom: 12px;
}
.note-warn {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--warn-bg);
  color: var(--warn);
  font-size: 12.5px;
  line-height: 1.45;
  font-weight: 600;
}

/* The capture card is focused when the driver is sent to it, so a keyboard or
   screen reader user lands in the section rather than at the top of the page.
   The focus is programmatic, so it carries no visible ring: the scroll is what
   shows a sighted driver they have arrived. */
#capture:focus {
  outline: none;
}

/* The hero panel answers what to do next and nothing else, so its button
   stands alone with the step name above it. */
.hero-next .btn {
  margin-top: 4px;
}

/* --------------------------------------------------------------------------
   Driver delivery layout

   Two columns with the roles the driver actually has: the work on one side,
   the reference on the other. The action is first in the markup, so on a phone
   it comes before the route and the step history. A driver opening a delivery
   should reach the thing they have to do without scrolling past what they
   already know.

   On a wide screen it is placed in the right hand column instead, where the
   reference reads first and the action sits beside it.
   -------------------------------------------------------------------------- */

.driver-split {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: start;
}

/* No column reordering. The delivery reads first and the record second in the
   markup, which is the order they stack in on a phone: what to do now, then
   where it goes, then what has already happened. */

/* The action is what the driver is here for, so it is marked rather than left
   to look like one more card among four. */
.card.is-action {
  box-shadow: var(--shadow-md), inset 0 0 0 1px var(--crimson-edge);
}

/* Take a photo leads, choosing from the library is the way back. Side by side
   on a wide card, stacked where that would squeeze them. */
.photo-actions .btn {
  flex: 1;
  min-width: 150px;
}

@media (max-width: 900px) {
  .driver-split {
    grid-template-columns: 1fr;
  }
  .driver-record {
    /* The step history is reference. On a phone it belongs after the work. */
    margin-top: 0;
  }
}

/* --------------------------------------------------------------------------
   Action button width

   A primary button stretched across a card reads as a banner rather than
   something to press, and on a wide screen the eye travels the whole width to
   find the label. Capped and left aligned with the rest of the card.

   Full width returns on a phone, where the button is a thumb target and the
   card is barely wider than the button anyway.
   -------------------------------------------------------------------------- */

.card.is-action .btn-large,
.timeline-action .btn {
  max-width: 320px;
  /* Centred on the card's axis. A capped button pinned to the left edge of a
     wide card reads as unfinished, and the eye looks for the action in the
     middle of the panel it belongs to. */
  margin-inline: auto;
}

/* The photo pair sit side by side, capped together so they do not drift apart
   on a wide card. */
.photo-actions {
  max-width: 420px;
}

@media (max-width: 560px) {
  .card.is-action .btn-large,
  .timeline-action .btn,
  .photo-actions {
    max-width: none;
  }
}

/* --------------------------------------------------------------------------
   Photograph sets

   Each stage under its own heading with its own count. One combined strip made
   it impossible to tell which photograph belonged to which end of the journey,
   which is the only question anyone asks of them.
   -------------------------------------------------------------------------- */

.photo-set {
  margin-top: 18px;
}
.photo-set-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* A thumbnail is a button now, since it opens the photograph over the page. */
button.photo-thumb {
  position: relative;
  border: 0;
  padding: 0;
  cursor: pointer;
  font: inherit;
}
button.photo-thumb:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--crimson-soft), 0 0 0 1px var(--crimson);
}

/* Withdrawing a photograph taken by mistake. Only rendered while the step that
   produced it is still open. Sized as a real target rather than a decoration,
   because it is pressed with a thumb, outdoors, next to the thing it removes. */
.photo-remove {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(20, 16, 14, 0.72);
  color: #fff;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.photo-remove:hover {
  background: var(--danger);
}
.photo-remove:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--crimson-soft);
}

/* --------------------------------------------------------------------------
   Lightbox

   A proof photograph opened in a new tab takes the reader out of the record
   they were reading, and on a phone strands them in a second tab. This shows it
   over the page and gives the page back when it closes.
   -------------------------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  /*
   * Above the site header, which is fixed at z-index 900 and transparent. At a
   * lower layer the header still caught the clicks along the top of the screen,
   * which is exactly where Download and Close sit.
   */
  z-index: 1000;
  display: flex;
  flex-direction: column;
  background: rgba(20, 16, 14, 0.92);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  padding: max(12px, env(safe-area-inset-top)) 12px calc(12px + env(safe-area-inset-bottom));
}

.lightbox-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-shrink: 0;
  padding: 4px 4px 12px;
}
.lightbox-caption {
  color: rgba(255, 255, 255, 0.86);
  font-size: 13.5px;
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lightbox-tools {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.lightbox-btn {
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
  text-decoration: none;
}
.lightbox-btn:hover {
  background: rgba(255, 255, 255, 0.26);
}
.lightbox-btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}
.lightbox-btn svg {
  width: 20px;
  height: 20px;
}

/* The picture takes whatever room is left, on any screen, without ever
   overflowing it in either direction. */
.lightbox-stage {
  flex: 1;
  min-height: 0;
  display: grid;
  place-items: center;
}
.lightbox-stage img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
}

/* Scrolling the page behind a full screen overlay is disorienting, because the
   movement has no visible cause. */
body.has-lightbox {
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   Tracking page side column

   The receipt leads it. On a completed delivery the receipt is the reason the
   page is open, so it should not sit below a nine step timeline the reader has
   already finished with.

   On a phone the column is lifted above the timeline for the same reason, but
   only when there is a receipt in it. While a delivery is still running the
   progress is what matters and the order stays as it is.
   -------------------------------------------------------------------------- */

@media (max-width: 900px) {
  .split.has-receipt .track-side {
    order: -1;
  }
}

/* A button that should read as a link. Used where an action is real but should
   not compete with the buttons above it, such as asking for a fresh receipt
   link after the last one lapsed. */
.link-button {
  display: inline-block;
  margin-top: 10px;
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--crimson);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.link-button:hover {
  color: var(--crimson-bright);
}
.link-button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--crimson-soft);
  border-radius: var(--r-sm);
}

/* The two receipt actions share the row, so neither looks like the primary of
   a pair with the other as an afterthought. */
#receipt-actions {
  margin-top: 4px;
}
#receipt-actions .btn {
  flex: 1;
  min-width: 140px;
}

/* --------------------------------------------------------------------------
   Button pairs on a phone

   A row wraps once its contents no longer fit, which on a narrow screen leaves
   two buttons squeezed side by side at the width of their longest word rather
   than wrapping cleanly. Below this width every full sized button in a row
   takes a line of its own.

   Small buttons are excluded on purpose. Refresh and Sign out, or Download PNG
   and Print label, are secondary actions that read as a set and would look
   broken stacked. Stacking is for the buttons a thumb is meant to hit.
   -------------------------------------------------------------------------- */

@media (max-width: 560px) {
  .row > .btn:not(.btn-small),
  .row > label.btn:not(.btn-small) {
    flex: 1 1 100%;
    width: 100%;
    min-width: 0;
  }

  /* The pair is capped for a wide card. On a phone the card is the width the
     buttons should be. */
  .photo-actions {
    max-width: none;
  }
  .photo-actions .btn {
    min-width: 0;
  }
}

/* ---------------------------------------------------------------------------
   Waiting to send

   Shown only where the offline queue is switched on, and only while something
   is actually waiting. Fixed to the bottom, clear of the thumb, because a
   driver reads it between actions rather than acting on it.
   --------------------------------------------------------------------------- */
.outbox-badge {
  position: fixed;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  z-index: 60;

  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--line-strong, #d9cfc8);
  background: var(--surface, #fff);
  box-shadow: 0 2px 6px rgba(20, 16, 14, 0.06), 0 14px 34px -18px rgba(20, 16, 14, 0.22);

  font-size: 0.82rem;
  color: var(--muted, #857b75);
  white-space: nowrap;
}

/* A photograph the driver took with no signal. Held, not lost, and not yet
   proof of anything until it has been sent. */
.photo-thumb.is-queued {
  opacity: 0.72;
  border-style: dashed;
}

/* The steps a driver has taken that have not reached the server yet. */
.waiting-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line, #ece5e0);
}
.waiting-list li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line, #ece5e0);
  font-size: 0.92rem;
}

.suggest-list {
  position: absolute;
  z-index: 20;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  background: #fff;
  border: 1px solid var(--line, #ece5e0);
  border-radius: 10px;
  box-shadow: 0 10px 24px rgba(20, 16, 14, 0.12);
  padding: 6px;
  max-height: 220px;
  overflow: auto;
}
.suggest-item {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: transparent;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  font: inherit;
}
.suggest-item:hover {
  background: var(--surface-sunk, #faf7f5);
}


/* --------------------------------------------------------------------------
   Portal shell

   The signed-in surfaces for a client and for a driver. The account bar says
   who is signed in and offers the way out; the filter row carries the counts,
   refresh and search. There is no row of tiles above them: a tile repeating the
   number already on the button below it is a second thing to read for no second
   answer.
   -------------------------------------------------------------------------- */

.portal-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  padding: 14px 18px;
  margin-bottom: 16px;
}
.portal-who {
  display: flex;
  align-items: center;
  gap: 13px;
  min-width: 0;
}
.portal-avatar {
  width: 42px;
  height: 42px;
  border-radius: var(--pill);
  background: var(--crimson);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 15px;
  font-weight: 700;
  flex-shrink: 0;
}
.portal-name {
  display: block;
  font-size: 16px;
  font-weight: 650;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.portal-sub {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
}
.portal-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* A square, quiet button for an action whose icon says it. */
.icon-btn {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-soft);
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color 0.14s ease, color 0.14s ease, background 0.14s ease;
}
.icon-btn svg {
  width: 18px;
  height: 18px;
}
.icon-btn:hover {
  border-color: var(--crimson);
  color: var(--crimson);
}
.icon-btn:disabled {
  cursor: default;
  color: var(--muted);
}
.icon-btn.is-spinning svg {
  animation: portal-spin 0.7s linear infinite;
}
@keyframes portal-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .icon-btn.is-spinning svg {
    animation: none;
    opacity: 0.55;
  }
}

/* ---- Filter row ---- */

.portal-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.portal-toolbar > * {
  min-width: 0;
}
.portal-tools {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  justify-content: flex-end;
  min-width: 0;
}
.seg {
  display: inline-flex;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--pill);
  padding: 3px;
  gap: 2px;
}
.seg-btn {
  border: 0;
  background: transparent;
  border-radius: var(--pill);
  padding: 8px 15px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.14s ease, color 0.14s ease;
}
.seg-btn[aria-pressed="true"] {
  background: var(--surface);
  color: var(--crimson);
  box-shadow: var(--shadow-xs);
}
.portal-search {
  position: relative;
  flex: 1;
  min-width: 180px;
  max-width: 340px;
}
.portal-search input {
  width: 100%;
  padding: 10px 14px 10px 38px;
  border-radius: var(--pill);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  font: inherit;
  font-size: 14px;
  color: var(--ink);
}
.portal-search svg {
  position: absolute;
  left: 13px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--muted);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Portal rows

   A grid, not a flex row with a gap in the middle: the columns are fixed, so
   the status and the time sit in the same place on every row and the eye runs
   down them. The rail on the left carries the status colour, which is what lets
   the badge beside it stay quiet.
   -------------------------------------------------------------------------- */

/* The portal reads as a column. Left to fill a wide monitor, a row of short
   facts strands its status a screen away from its number. */
.portal {
  max-width: 1180px;
  margin-inline: auto;
}

.delivery-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.delivery-row {
  display: grid;
  grid-template-columns: 4px minmax(0, 1fr);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  box-shadow: var(--shadow-xs);
  transition: border-color 0.14s ease, box-shadow 0.14s ease, transform 0.14s ease;
}
.delivery-row:hover {
  transform: translateY(-1px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-md);
}
.row-rail {
  align-self: stretch;
  background: var(--line-strong);
}
.row-rail-active {
  background: var(--warn);
}
.row-rail-ok {
  background: var(--ok);
}
.row-rail-danger {
  background: var(--danger);
}
.row-rail-neutral {
  background: var(--line-strong);
}

.row-body {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 14px 18px;
  min-width: 0;
}

/* The number and the status share the top line, so a long status label pushes
   nothing: it grows into the space at the right rather than into the content. */
.row-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.row-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 190px) auto auto;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.delivery-row-main {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.delivery-row-number {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.delivery-row-item {
  font-size: 16px;
  font-weight: 650;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.delivery-row-route {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: var(--muted);
  min-width: 0;
}
.delivery-row-route span {
  /* A flex item will not shrink below its text without this, and the row would
     then set the width of the whole page on a phone. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.delivery-row-route .arrow {
  color: var(--line-strong);
  flex-shrink: 0;
}
.delivery-row-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 5px;
}
.meta-chip {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--pill);
  padding: 3px 9px;
  white-space: nowrap;
}
.delivery-row-when {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}
.chevron {
  color: var(--line-strong);
  font-size: 24px;
  line-height: 1;
}
.delivery-row:hover .chevron {
  color: var(--crimson);
}

.rail-mini {
  display: flex;
  gap: 3px;
  margin: 0;
  align-self: center;
}
.rail-mini .rail-step {
  height: 4px;
  min-width: 6px;
}

.portal-empty {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 44px 24px;
  text-align: center;
}
.portal-empty h2 {
  margin: 0 0 6px;
  font-size: 18px;
}
.portal-empty p {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}
/*
 * An empty list is where a first delivery is created, so the way to create one
 * is here and not only in the account bar above, which reads as chrome.
 */
.portal-empty-action {
  margin-top: 18px;
}

@media (max-width: 620px) {
  .portal-bar {
    align-items: flex-start;
  }
  .portal-who {
    width: 100%;
  }
  .portal-actions {
    width: 100%;
    justify-content: space-between;
  }
  .portal-toolbar {
    align-items: stretch;
  }
  .portal-tools {
    width: 100%;
    flex-direction: row-reverse;
  }
  .portal-search {
    max-width: none;
  }
  /*
   * The filters stack rather than scroll. A row that scrolls sideways hides
   * the filters you are not on, and nothing on the screen says they are there.
   * A grid that fits two across drops to one when even two will not fit, so
   * every filter is named and every one is a full tap target.
   */
  .seg {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 4px;
    width: 100%;
    border-radius: var(--r-sm);
  }
  .seg-btn {
    padding: 11px 12px;
    border-radius: calc(var(--r-sm) - 3px);
    white-space: normal;
  }

  /* One column: the bar drops under the content, where it keeps its width. */
  .row-content {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }
  .delivery-row-when,
  .chevron {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   Form feedback

   The banner sits with the form it belongs to, not at the top of the page: a
   save reported a screen away from the field that was saved is a save nobody
   sees.
   -------------------------------------------------------------------------- */

/*
 * The charges: two choices, then the breakdown one line each, as the receipt
 * prints it. The choices carry their own top margin because they cannot rely
 * on the field above having one: `.field:last-child` drops its bottom margin,
 * and inside a `.field-row` the last field is exactly what they follow.
 */
.charge-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 10px;
  margin: 20px 0 12px;
}
.charge-option {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.charge-option:hover {
  border-color: var(--crimson-edge);
}
.charge-option:has(input:checked) {
  border-color: var(--crimson);
  background: var(--crimson-soft);
}
.charge-option:has(input:focus-visible) {
  box-shadow: 0 0 0 3px var(--crimson-soft);
}
.charge-option input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  flex-shrink: 0;
  accent-color: var(--crimson);
  cursor: pointer;
}
.charge-option-text {
  display: grid;
  gap: 2px;
  flex: 1;
  min-width: 0;
}
.charge-option-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.charge-option-price {
  font-size: 13px;
  font-weight: 650;
  color: var(--crimson);
  white-space: nowrap;
}

.charge-breakdown {
  display: grid;
  gap: 7px;
  margin: 0 0 16px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  font-size: 13.5px;
  color: var(--muted);
}
.charge-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.charge-amount {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.charge-rate {
  color: var(--muted);
}
.charge-total {
  padding-top: 9px;
  border-top: 1px solid var(--line-strong);
  color: var(--ink);
  font-weight: 600;
}
.charge-total-only {
  padding-top: 0;
  border-top: 0;
}
.charge-total strong.charge-amount {
  font-size: 16px;
  font-weight: 650;
}
.charge-total .charge-amount.muted {
  color: var(--muted);
  font-weight: 500;
}

.form-saved {
  margin: 0 0 14px;
  padding: 10px 13px;
  border-radius: var(--r-sm);
  background: var(--ok-bg);
  border: 1px solid rgba(16, 105, 58, 0.18);
  color: var(--ok);
  font-size: 13px;
}

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

/** A required field says so once, in the label. */
.req {
  color: var(--crimson);
  font-weight: 700;
  margin-left: 1px;
}

/* --------------------------------------------------------------------------
   Icons, public tracking page

   Inline line icons drawn in currentColor, so each takes the colour of the
   text or control it sits in. Sizes step down on narrow phones.
   -------------------------------------------------------------------------- */

.ic {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  display: inline-block;
  vertical-align: middle;
}

.btn .ic {
  width: 17px;
  height: 17px;
}
.btn-small .ic {
  width: 15px;
  height: 15px;
}
.btn-large .ic {
  width: 20px;
  height: 20px;
}

/* A form label led by an icon. */
.field label.label-ic {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 7px;
}
.label-ic > .ic {
  width: 16px;
  height: 16px;
  color: var(--crimson);
}

/* The icon badge on a charge option, between the checkbox and its text. */
.charge-option-ic {
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  margin-top: -4px;
  background: var(--crimson-soft);
  color: var(--crimson);
  transition: background 0.16s ease, color 0.16s ease;
}
.charge-option-ic .ic {
  width: 16px;
  height: 16px;
}
.charge-option:has(input:checked) .charge-option-ic {
  background: var(--crimson);
  color: #fff;
}

.photo-set-title-ic {
  gap: 8px;
}
.photo-set-title-ic > .ic {
  width: 15px;
  height: 15px;
  color: var(--crimson);
}

/* Card headings */
.card-title-ic {
  display: flex;
  align-items: center;
  gap: 9px;
}
.card-title-ic .ic {
  width: 16px;
  height: 16px;
  color: var(--crimson);
}

/* Hero */
.hero-label-ic {
  display: flex;
  align-items: center;
  gap: 6px;
}
.hero-label-ic .ic {
  width: 13px;
  height: 13px;
}

.hero-headline {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 18px;
}
.hero-headline > div {
  min-width: 0;
}
.hero-headline .hero-status {
  margin: 0 0 5px;
}
.hero-status-ic {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  background-color: var(--crimson-soft);
  color: var(--crimson);
  box-shadow: inset 0 0 0 1px var(--crimson-edge);
}
.hero-status-ic .ic {
  width: 24px;
  height: 24px;
}
.hero-status-ic.is-ok {
  background-color: var(--ok-bg);
  color: var(--ok);
  box-shadow: none;
}
.hero-status-ic.is-failed {
  background-color: var(--danger-bg);
  color: var(--danger);
  box-shadow: none;
}

.hero-sub-ic {
  display: flex;
  align-items: center;
  gap: 6px;
}
.hero-sub-ic .ic {
  width: 15px;
  height: 15px;
}

.hero-status-ic.skeleton {
  box-shadow: none;
}

/* Timeline with icon markers. The markers grow from a dot to a circle holding
   the step's icon, so the connector and the body indent move with them. */
.timeline-iconic .timeline-item {
  padding-left: 46px;
  padding-bottom: 22px;
}
.timeline-iconic .timeline-item:last-child {
  padding-bottom: 0;
}
.timeline-iconic .timeline-item::before {
  left: 15px;
  top: 36px;
  bottom: 4px;
}
.timeline-iconic .timeline-item.is-done::before {
  background: var(--crimson-edge);
}
.timeline-iconic .timeline-marker {
  top: 0;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  background: var(--surface);
  color: var(--muted);
  box-shadow: inset 0 0 0 1.5px var(--line-strong);
}
.timeline-ic {
  width: 16px;
  height: 16px;
}
.timeline-iconic .is-done .timeline-marker {
  background: var(--crimson);
  color: #fff;
  box-shadow: none;
}
.timeline-iconic .is-failed .timeline-marker {
  background: var(--danger);
  color: #fff;
  box-shadow: none;
}
.timeline-iconic .timeline-item.is-next .timeline-marker {
  background: var(--surface);
  color: var(--crimson);
  box-shadow: inset 0 0 0 2px var(--crimson), 0 0 0 4px var(--crimson-soft);
}
.timeline-iconic .timeline-body {
  padding-top: 5px;
  min-width: 0;
}
.timeline-iconic .timeline-time,
.timeline-iconic .timeline-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 4px;
}
.timeline-meta-ic {
  display: inline-flex;
  flex-shrink: 0;
}
.timeline-meta-ic .ic {
  width: 13px;
  height: 13px;
}
.timeline-iconic .map-link {
  overflow-wrap: anywhere;
}

/* Key and value rows with an icon badge on each label. */
.kv-iconic dt {
  display: flex;
  align-items: center;
  gap: 10px;
}
.kv-iconic dd {
  display: flex;
  align-items: center;
  min-width: 0;
  overflow-wrap: anywhere;
}
.kv-ic {
  width: 28px;
  height: 28px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  background: var(--crimson-soft);
  color: var(--crimson);
}
.kv-ic .ic {
  width: 15px;
  height: 15px;
}

/* A note led by an icon. */
.note-ic {
  display: flex;
  align-items: flex-start;
  gap: 9px;
}
.note-ic .ic {
  width: 16px;
  height: 16px;
  margin-top: 1px;
}

@media (max-width: 640px) {
  .hero-headline {
    gap: 12px;
  }
  .hero-status-ic {
    width: 42px;
    height: 42px;
  }
  .hero-status-ic .ic {
    width: 20px;
    height: 20px;
  }
}

/* Narrow phones: the label sits over its value, the value indented to line up
   with the label text rather than the badge. */
@media (max-width: 420px) {
  .kv-iconic {
    grid-template-columns: 1fr;
  }
  .kv-iconic dt {
    padding-right: 0;
    padding-bottom: 4px;
  }
  .kv-iconic dd {
    border-top: 0;
    padding: 0 0 10px 38px;
  }
}

@media (max-width: 380px) {
  .timeline-iconic .timeline-item {
    padding-left: 40px;
  }
  .timeline-iconic .timeline-item::before {
    left: 13px;
    top: 32px;
  }
  .timeline-iconic .timeline-marker {
    width: 28px;
    height: 28px;
  }
  .timeline-ic {
    width: 14px;
    height: 14px;
  }
  .timeline-iconic .timeline-body {
    padding-top: 3px;
  }
}
