:root {
  --green: #2F5233;
  --green-light: #E8EFE6;
  --amber: #C97B2E;
  --bg: #F4F6F2;
  --text: #26302A;
  --muted: #6B7A70;
  --border: #D9E0D6;
  --white: #ffffff;
  --radius: 10px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

header {
  background: var(--green);
  color: white;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  position: sticky;
  top: 0;
  z-index: 10;
}

header h1 { font-size: 17px; margin: 0; flex: 1; }

#header-menu-btn {
  width: 40px;
  height: 40px;
  min-height: 0;
  flex: 0 0 auto;
  padding: 0;
  margin: 0;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 50%;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
}

#role-toggle {
  width: auto;
  flex: 0 0 auto;
  margin: 0;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.4);
  color: white;
  border-radius: 20px;
  padding: 6px 12px;
  font-size: 12px;
  white-space: nowrap;
}

header h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

#view-nav {
  display: flex;
  background: var(--white);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 68px; /* sits right below the header */
  z-index: 9;
}

.nav-tab {
  flex: 1;
  width: auto;
  margin-bottom: 0;
  border-radius: 0;
  background: var(--white);
  color: var(--muted);
  padding: 12px;
  font-size: 14px;
  border-bottom: 3px solid transparent;
}

.nav-tab.active {
  color: var(--green);
  font-weight: bold;
  border-bottom: 3px solid var(--green);
}

main { padding: 12px; max-width: 640px; margin: 0 auto; padding-bottom: 60px; }

.search-row {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.search-bar {
  flex: 1;
  min-width: 0; /* allow the input to shrink instead of pushing the button off-screen */
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 15px;
  background: var(--white);
}

.sort-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.sort-label {
  font-size: 12px;
  color: var(--muted);
}

.sort-toggle {
  width: auto;
  flex: 0 0 auto;
  margin-bottom: 0;
  padding: 6px 12px;
  font-size: 13px;
  background: var(--white);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 16px;
}

.sort-toggle.active {
  background: var(--green-light);
  color: var(--green);
  border-color: var(--green);
  font-weight: bold;
}

.btn-compact {
  flex: 0 0 auto;
  width: auto;
  min-width: 64px;
  min-height: 44px; /* Apple/Google's recommended minimum touch target size */
  padding: 0 18px;
  margin-bottom: 0;
  white-space: nowrap;
  display: flex;
  align-items: center;
  justify-content: center;
}

.customer-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 8px;
  cursor: pointer;
}

.card-top-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
}

.name-block { min-width: 0; }

.card-schedule-block {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  white-space: nowrap;
  padding-top: 1px;
}

/* Status label, not a button - no background fill at all (just colored,
   bold text), unlike the Route tab's Day# pill (.route-day-badge), which
   IS tappable (it's the visible face of the day picker). No fill
   consistently means "just information," not "you can act on this." */
.day-pill {
  display: inline-block;
  color: var(--green);
  font-size: 11px;
  font-weight: bold;
}

.schedule-line { font-size: 12px; color: var(--text); text-align: right; }
.schedule-label { color: var(--muted); }

.customer-card .name { font-weight: bold; font-size: 15px; }
.customer-card .sub { color: var(--muted); font-size: 13px; margin-top: 2px; }
.customer-card .badge {
  display: inline-block;
  background: var(--green-light);
  color: var(--green);
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 12px;
  margin-top: 6px;
}

.badge-pastdue {
  display: inline-block;
  background: #D32F2F;
  color: white;
  font-size: 11px;
  font-weight: bold;
  padding: 3px 10px;
  border-radius: 12px;
  margin-top: 6px;
}

.card-skip-reschedule {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.btn-back {
  width: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 12px;
  padding: 8px 16px;
  min-height: 40px;
  background: var(--white);
  color: var(--green);
  border: 1px solid var(--green);
  border-radius: 20px;
  font-size: 13px;
  font-weight: bold;
  cursor: pointer;
}

.section {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 12px;
}

.section h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); margin: 0 0 10px; }

.section-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}
.section-heading-row h2 { margin: 0; }

.btn-save-section {
  width: auto;
  flex: 0 0 auto;
  margin: 0;
  padding: 5px 14px;
  min-height: 0;
  font-size: 12px;
  font-weight: bold;
  background: #F2C94C;
  color: #4A3B00;
  border-radius: 14px;
}

.field-row-group { display: flex; gap: 8px; }
.field-row-group .field-row { min-width: 0; } /* allow inputs to shrink below content width on narrow phones */

.field-row { display: flex; flex-direction: column; margin-bottom: 10px; }
.field-row label { font-size: 12px; color: var(--muted); margin-bottom: 3px; }
.field-row input, .field-row select {
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
}
.field-row input:disabled, .field-row select:disabled {
  background: #F0F0EE;
  color: var(--muted);
}

/* The Reschedule-day picker isn't inside a .field-row (it's a standalone
   dropdown inside the reschedule panel), so it doesn't pick up the boxed
   native-select look above by default - give it the same treatment so
   every dropdown in the app (including its native up/down arrow) looks
   consistent. */
.f-reschedule-day {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
}

/* Any native <select> is a "tap this to open a menu of choices" control,
   the same kind of action as Start/Complete/Optimize/etc - give it the
   same light-green fill. The browser's own up/down arrow indicator is
   left alone (no appearance:none anywhere), so it stays visible on the
   new background exactly like on Billing interval. Disabled dropdowns
   (admin-locked fields) keep the existing greyed-out look below, since
   they aren't actually tappable. */
.field-row select,
.f-reschedule-day {
  background: var(--green-light);
  color: var(--green);
  border-color: var(--green-light);
}
.locked-note { font-size: 11px; color: var(--amber); margin-top: 3px; }

.phone-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  width: fit-content;
}
.phone-row > input {
  /* Direct-child selector, not a descendant one - the Cell checkbox is
     ALSO an <input> but nested one level deeper inside .phone-cell-toggle,
     and a descendant selector here was matching it too, stretching the
     checkbox itself to 16ch wide and ballooning the whole row (which then
     starved the Name field next to it). Fixed, non-shrinking width sized
     to fully fit a formatted US phone number like "(251) 802-5792" (14
     characters) - using ch instead of a magic px number so it stays
     correct if the font ever changes. Doesn't shrink even if its row gets
     tight, so the number never truncates; whatever it shares a row with
     (e.g. Name) gives way instead. */
  flex: 0 0 auto;
  width: 16ch;
  min-width: 16ch;
}

.phone-cell-toggle {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex: 0 0 auto;
  gap: 4px;
  font-size: 12px;
  color: var(--muted);
  margin-top: 0;
  white-space: nowrap;
}
.phone-cell-toggle input { width: auto; padding: 0; }

.phone-tag {
  display: inline-block;
  font-size: 11px;
  color: var(--green);
  background: var(--green-light);
  border-radius: 8px;
  padding: 1px 6px;
  vertical-align: middle;
}

button {
  font-family: inherit;
  font-size: 14px;
  border: none;
  border-radius: 8px;
  padding: 12px 16px;
  cursor: pointer;
  width: 100%;
  margin-bottom: 8px;
}

/* Same light-green fill as Start and the rest of the action-button family
   (Skip/Reschedule/Complete/Add Stop/Add Customer/etc.), rather than its
   own solid dark-green look. */
.btn-primary { background: var(--green-light); color: var(--green); font-size: 16px; padding: 6px 14px; }
.btn-secondary { background: var(--white); color: var(--green); border: 1px solid var(--green); }
.btn-danger { background: #B3441E; color: white; }
button:disabled { opacity: 0.5; cursor: not-allowed; }

.job-status {
  display: inline-block;
  font-size: 12px;
  padding: 3px 10px;
  border-radius: 12px;
  font-weight: bold;
}
.job-status.in_progress { background: #FDE9D9; color: #B3441E; }
.job-status.completed { background: var(--green-light); color: var(--green); }
.job-status.none { background: #EEE; color: var(--muted); }

.route-priority-tag {
  display: inline-block;
  font-size: 11px;
  font-weight: bold;
  padding: 2px 8px;
  border-radius: 12px;
  margin-top: 4px;
}
.route-priority-tag.must_be_first { background: #FDE9D9; color: #B3441E; }
.route-priority-tag.early { background: var(--green-light); color: var(--green); }
.route-priority-tag.late { background: #EEE; color: var(--muted); }

/* Shows as soon as at least one Start->Stop cycle has been logged for the
   day's visit (job_total_seconds > 0) - not gated on the job being marked
   Complete, so it updates live while the visit is still in progress
   (e.g. after a lunch-break Stop). Always the last line in the stop's
   info block, below Name/phone/address/tags. */
.route-stop-total-time {
  font-size: 12px;
  font-weight: bold;
  color: var(--muted);
  margin-top: 4px;
}

.photo-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.photo-grid img { width: 80px; height: 80px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); }

.photo-thumb {
  position: relative;
  width: 80px;
  height: 80px;
}
.photo-thumb img { width: 100%; height: 100%; }

.photo-remove-btn {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 22px;
  height: 22px;
  min-height: 0;
  padding: 0;
  margin: 0;
  border-radius: 50%;
  background: #B3441E;
  color: white;
  border: 2px solid var(--white);
  font-size: 14px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 1000;
}
.modal-card {
  background: var(--white);
  width: 100%;
  max-width: 480px;
  max-height: 80vh;
  overflow-y: auto;
  border-radius: 14px 14px 0 0;
  padding: 16px;
}
.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.modal-header h3 { margin: 0; }
.modal-add-photos-btn {
  display: inline-block;
  margin-top: 14px;
  text-align: center;
  cursor: pointer;
}

.route-nav-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.route-day-picker-wrap {
  position: relative;
  display: inline-block;
}

.route-day-select-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  border: none;
  cursor: pointer;
  /* Smaller font on the dropdown itself so the browser renders a shorter
     option list when it opens - with 11 options (Day 1-10 + All) this is
     what keeps them all visible without scrolling. */
  font-size: 13px;
}

.route-day-center {
  flex: 1;
  min-width: 0;
  text-align: center;
}

/* The Day# picker is now a real, visible <select> (not an invisible
   overlay behind a custom pill) - same light-green box + native up/down
   arrow as every other dropdown in the app (Billing interval, Route
   order, etc.), rather than a one-off look just for this control. */
.route-day-select {
  padding: 9px 10px;
  border: 1px solid var(--green-light);
  border-radius: 6px;
  font-size: 14px;
  font-weight: bold;
  background: var(--green-light);
  color: var(--green);
  cursor: pointer;
}
.route-day-select:disabled {
  background: #F0F0EE;
  color: var(--muted);
  border-color: var(--border);
}

/* Sits inside the same .section as .route-nav-row now, directly below the
   First/Prior/Next/Last arrows - Add Stop lines up under the left (First)
   arrow, Add Customer under the right (Last) arrow. */
.route-add-actions-row {
  display: flex;
  align-items: center;
  margin-top: 12px;
  /* Left button flush to the section's left padding edge, right button
     flush to its right padding edge - same edges the arrows above sit
     flush against, so the two rows line up. */
  justify-content: space-between;
}

/* Sized to match the (compact) Complete button on the route stop cards
   below, rather than stretching to fill the row - and same light-green
   fill as Start/the rest of the action-button family. */
.btn-route-add-action {
  width: auto;
  flex: 0 0 auto;
  margin: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 14px;
  min-height: 0;
  background: var(--green-light);
  color: var(--green);
  border-radius: 8px;
  font-size: 16px;
  font-weight: bold;
  cursor: pointer;
}

.btn-route-add-action:active {
  background: var(--green);
  color: #fff;
}

.route-add-action-icon {
  font-size: 13px;
  line-height: 1;
}

.route-stops-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.route-stops-heading-row h2 { margin: 0; }

.route-stops-heading-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}

.btn-add-stop-inline {
  width: auto;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  color: var(--green);
  font-size: 14px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
}

/* Tappable (it's the visible face of the day picker), so it uses the same
   rounded-rect shape as the other action buttons (Complete/Skip/
   Reschedule) instead of a full pill - shape now consistently signals
   "actionable" across the app, not just color. */
.route-day-badge {
  display: inline-block;
  background: var(--green-light);
  color: var(--green);
  font-weight: bold;
  font-size: 16px;
  padding: 6px 14px;
  border-radius: 8px;
}


.icon-btn-sm {
  width: 28px;
  height: 28px;
  font-size: 12px;
  color: var(--muted);
  background: transparent;
  border-color: transparent;
}

.route-stop {
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: 8px;
}

.route-stop-main {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.route-stop-extra {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

/* Wraps the Stop # circle so the "All" view can stack a Day # label above
   it - see .route-stop-day-label. Plain flex:0 0 auto in the normal
   single-day view, where no day label is rendered. */
.route-stop-number-col {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}

/* Same label styling as .day-pill on the Customers tab card - a status
   tag, not a button, so it deliberately does NOT look like the Route tab's
   tappable Day# pill (.route-day-badge): no background fill at all,
   instead of a full pill. */
.route-stop-day-label {
  display: inline-block;
  color: var(--green);
  font-size: 11px;
  font-weight: bold;
  white-space: nowrap;
}

.route-stop-date-label {
  font-size: 10px;
  color: var(--muted);
  white-space: nowrap;
}

.route-stop-number {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--green);
  color: white;
  font-weight: bold;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.route-stop-info { flex: 1; min-width: 0; padding-top: 2px; }
.route-stop-info .name { font-size: 15px; font-weight: bold; }

.route-stop-tap { cursor: pointer; }
.route-stop-tap .name { color: var(--green); }

.route-date-wrap {
  position: relative;
  display: inline-block;
  margin-top: 6px;
}

.route-date-text {
  font-size: 15px;
  color: var(--muted);
}

.route-date-text-admin {
  color: var(--green);
  font-weight: bold;
}

.route-date-select-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  border: none;
  cursor: pointer;
}

.route-stop-side-rail {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  flex: 0 0 auto;
}

/* Same color AND shape as the other action buttons (Complete/Skip/
   Reschedule) - light green fill, dark green text, the same rounded-rect
   (not a full pill), so every tappable control across the app reads as
   one consistent family. .btn-job-action-total (the "done" state below)
   inherits this same border-radius. */
.btn-job-action {
  width: auto;
  flex: 0 0 auto;
  margin: 0;
  padding: 6px 14px;
  font-size: 16px;
  min-height: 0;
  background: var(--green-light);
  color: var(--green);
  border-radius: 8px;
}

/* Once a job is Complete, the Start/Stop icon becomes a read-only-looking
   total (e.g. "2:11") that opens the time-log popup on tap - same "done"
   treatment as Complete/Send Invoice once finished: darker solid green
   instead of the light-green "still in progress" fill, even though it's
   still tappable (to view the log). */
.btn-job-action-total {
  background: var(--green);
  color: white;
  border: none;
}

.time-log-list { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.time-log-row { display: flex; gap: 8px; font-size: 14px; }
.time-log-index { color: var(--muted); min-width: 18px; }
.time-log-total { margin-top: 12px; font-weight: bold; font-size: 14px; }

.route-stop-side-rail .icon-btn {
  width: auto;
  height: 30px;
  padding: 0 8px;
  font-size: 12px;
}

.route-stop-actions {
  display: flex;
  gap: 4px;
  flex: 0 0 auto;
}

.icon-btn {
  width: 36px;
  height: 36px;
  min-height: 0;
  padding: 0;
  margin: 0;
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  font-size: 16px;
}

.icon-btn:disabled { opacity: 0.3; }
.icon-btn-danger { color: #B3441E; }

.message-preview {
  background: var(--green-light);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  margin-top: 10px;
  white-space: pre-wrap;
}

.route-action-row {
  display: flex;
  gap: 8px;
}

/* Same light-green fill as Start (.btn-job-action) - every button that
   performs an action (Skip, Reschedule, Complete before it's done, Send
   Invoice before it's sent, Not now) shares one consistent "you can tap
   this" color, rather than each one inventing its own. */
.btn-route-action {
  width: auto;
  flex: 1;
  margin: 0;
  padding: 6px 14px;
  min-height: 0;
  font-size: 16px;
  font-weight: bold;
  background: var(--green-light);
  color: var(--green);
  border-radius: 8px;
}

.btn-skip-reason {
  width: auto;
  flex: 1;
  margin: 0;
  padding: 8px 10px;
  min-height: 0;
  font-size: 12px;
  font-weight: bold;
  background: #FDE9D9;
  color: #B3441E;
  border-radius: 8px;
}

/* Complete stays in the same light-green "actionable" style as Skip/
   Reschedule until the job it represents is actually done - only then
   does it switch to the darker solid green, so that stronger color reads
   as "this is finished" rather than just being a generic action color.
   It's still tappable from here (to recover/undo), which is fine - the
   darker green signals state, not "you can't touch this". */
.btn-complete.is-complete {
  background: var(--green);
  color: white;
  border-color: var(--green);
}

/* Same "done" treatment as Complete above - stays light-green/actionable
   until the invoice has actually been sent, then switches to the darker
   solid green. */
.btn-send-invoice.is-complete {
  background: var(--green);
  color: white;
  border-color: var(--green);
}

/* Compact modifier - used on the Customers-tab card and Route-tab stop
   card, where the full-size buttons (as used on the customer detail
   screen) take up too much room. */
.route-action-row.compact .btn-skip-reason {
  padding: 5px 8px;
  font-size: 11px;
}

.mileage-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.mileage-table th {
  text-align: left;
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
}
.mileage-table td {
  padding: 8px 4px;
  border-bottom: 1px solid var(--border);
}

.toast {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--text);
  color: white;
  padding: 10px 18px;
  border-radius: 20px;
  font-size: 13px;
  opacity: 0;
  transition: opacity 0.2s;
  pointer-events: none;
}
.toast.show { opacity: 1; }

/* ── "Let's mow down this day!" splash ───────────────────────────────────
   A fun, capped easter egg: plays the first 5 times per day someone flips
   from Tenant Admin to Technician (see maybeShowMowingSplash() in app.js).
   Built as a CSS/JS animation layered over the static Mardi-Gras branded
   image (sunrise sky sweep, a subtle mowing bounce on the image itself, and
   a few "beads" tossed outward in staggered arcs) rather than a generated
   video - there's no video-generation tool available in this environment,
   this is the honest equivalent achievable with CSS keyframes. */
.mcm-splash-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
  background: #1a2a3a;
  animation: mcm-splash-fadein 0.35s ease-out;
}
.mcm-splash-overlay.mcm-splash-fadeout {
  animation: mcm-splash-fadeout 0.4s ease-in forwards;
}
@keyframes mcm-splash-fadein { from { opacity: 0; } to { opacity: 1; } }
@keyframes mcm-splash-fadeout { from { opacity: 1; } to { opacity: 0; } }

/* Sunrise made more pronounced (2026-08-18, per Allison). Previously this
   panned one gradient via background-position, but that pan actually
   revealed the DARKER end of the gradient over time (sky read as going
   duskier, not brighter - confirmed visually, not just in theory). Redone
   as two stacked layers instead: a fixed dark pre-dawn base, with a bright
   dawn-colored layer crossfading in on top - a much more legible
   night-to-daybreak transition, paired with the sun (below) rising and
   growing through it. */
.mcm-splash-sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, #0f0a20 0%, #1b1440 45%, #2c2350 100%);
}
.mcm-splash-sky-dawn {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, #3a2b6d 0%, #7597de 32%, #ffb56b 62%, #ff7b54 82%, #ffd27a 100%);
  opacity: 0;
  animation: mcm-sunrise-dawn 5.6s ease-out forwards;
}
@keyframes mcm-sunrise-dawn {
  0% { opacity: 0; }
  15% { opacity: 0; }
  100% { opacity: 1; }
}

/* Sun made more pronounced (2026-08-18, per Allison) - starts lower, smaller
   and dimmer, then climbs further and grows with a warm glow so the rise
   itself reads clearly rather than just fading in near the horizon. */
.mcm-splash-sun {
  position: absolute;
  left: 50%;
  bottom: -32%;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  background: radial-gradient(circle, #fffbe6 0%, #ffe28a 35%, #ffb347 60%, rgba(255,179,71,0) 78%);
  transform: translateX(-50%) scale(0.75);
  filter: blur(1px) drop-shadow(0 0 40px rgba(255, 209, 102, 0.55));
  opacity: 0.15;
  animation: mcm-sun-rise 5.6s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}
@keyframes mcm-sun-rise {
  0% { bottom: -32%; opacity: 0.15; transform: translateX(-50%) scale(0.75); }
  45% { opacity: 1; }
  100% { bottom: 46%; opacity: 1; transform: translateX(-50%) scale(1.1); }
}

/* Two stacked copies of the same photo rather than one - the bottom copy is
   the static "yard" that never moves; the top copy is clipped to a loose
   shape around just the rider + mower (with margin, so a few px of drift
   doesn't create a visible seam) and is the only thing that animates. This
   is an approximation, not a true pixel cutout - there's no image-
   segmentation tool available in this environment to isolate him cleanly,
   so the "background" underneath still has him drawn in it too; the clipped
   copy on top simply covers that spot and moves independently. */
.mcm-splash-img-wrap {
  position: relative;
  z-index: 2;
  width: min(90vw, 480px);
  aspect-ratio: 900 / 647;
  max-height: 62vh;
  box-shadow: 0 12px 40px rgba(0,0,0,0.5);
  border-radius: 14px;
}
.mcm-splash-img-bg,
.mcm-splash-img-rider {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 14px;
}
.mcm-splash-img-bg { z-index: 1; }
/* Static now (2026-08-18, per Allison - "remove the motion of the daily
   image"). Previously this clipped duplicate bounced independently via
   mcm-mow-bounce; the clip-path/layer structure is left in place since it's
   harmless sitting still (identical to the layer beneath it), in case
   motion on the rider is wanted again later. */
.mcm-splash-img-rider {
  z-index: 2;
  clip-path: polygon(
    30.2% 92.1%, 22.2% 88.4%, 20% 80.3%, 21.3% 68.6%, 24.9% 58.1%,
    35.6% 39.6%, 37.3% 29.7%, 40.9% 19.8%, 44.4% 11.1%, 46.2% 4.9%,
    49.8% 1.9%, 55.1% 3.7%, 58.7% 9.9%, 62.2% 17.3%, 67.6% 12.4%,
    73.8% 9.3%, 80% 10.5%, 82.7% 13.6%, 79.6% 19.8%, 74.2% 28.4%,
    72.9% 37.1%, 76.4% 41.4%, 77.3% 50.1%, 73.8% 54.4%, 80% 59.3%,
    81.8% 69.2%, 81.8% 80.3%, 76.4% 87.1%, 71.1% 81.6%, 67.6% 75.4%,
    60.4% 79.7%, 49.8% 80.3%, 39.1% 81.6%, 35.6% 86.5%
  );
}

/* Anchored near the character's raised, bead-tossing hand (upper-right of
   the image) - each bead is staggered via inline animation-delay in JS. */
.mcm-splash-beads {
  position: absolute;
  z-index: 3;
  top: 30%;
  right: 18%;
  width: 0;
  height: 0;
}
.mcm-bead {
  position: absolute;
  font-size: 26px;
  opacity: 0;
  animation: mcm-bead-toss 1.9s ease-out forwards;
}
@keyframes mcm-bead-toss {
  0% { opacity: 0; transform: translate(0, 0) scale(0.6) rotate(0deg); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--tx, 140px), var(--ty, 160px)) scale(1) rotate(220deg); }
}
.mcm-bead-1 { --tx: 150px; --ty: 110px; }
.mcm-bead-2 { --tx: 105px; --ty: 165px; }
.mcm-bead-3 { --tx: -30px; --ty: 185px; }
.mcm-bead-4 { --tx: 55px; --ty: 205px; }

/* Caption and the mileage panel below it share one bottom-anchored column so
   the panel appearing (once the image loads) pushes nothing off-screen and
   never overlaps the caption - see showMowingSplash() in app.js. */
.mcm-splash-bottom {
  position: absolute;
  bottom: 6%;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 0 12px;
}

.mcm-splash-caption {
  max-width: 90vw;
  text-align: center;
  font-size: 24px;
  font-weight: bold;
  letter-spacing: 0.02em;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0,0,0,0.55);
  background: linear-gradient(90deg, #C084FC, #F2C94C, #4ADE80);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  opacity: 0;
  animation: mcm-caption-in 0.6s ease-out 0.5s forwards;
}
@keyframes mcm-caption-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

.mcm-splash-hint {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 3;
  font-size: 11px;
  color: rgba(255,255,255,0.7);
}

/* Beginning-mileage quick-entry panel, revealed once the splash image has
   loaded (see revealMileagePanel() in app.js). Stacks below the caption
   inside .mcm-splash-bottom, cursor reset to default since the overlay
   itself is cursor:pointer for tap-to-skip - this panel is the one part of
   the splash you're meant to interact with rather than tap through. */
.mcm-splash-mileage {
  width: min(88vw, 360px);
  cursor: default;
  background: rgba(20, 30, 40, 0.72);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 12px;
  padding: 12px 14px;
  backdrop-filter: blur(2px);
  animation: mcm-caption-in 0.4s ease-out;
}
.mcm-splash-mileage label {
  display: block;
  font-size: 12px;
  color: rgba(255,255,255,0.75);
  margin-bottom: 6px;
}
.mcm-splash-mileage-row {
  display: flex;
  gap: 8px;
}
.mcm-splash-mileage-row input {
  flex: 1;
  min-width: 0;
  font-size: 16px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid rgba(255,255,255,0.3);
  background: rgba(255,255,255,0.95);
  color: #1a2a3a;
}
.mcm-splash-mileage-row button {
  flex: 0 0 auto;
  width: auto;
  margin-bottom: 0;
  background: var(--green-light, #C7E8CB);
  color: var(--green, #2F5233);
  font-weight: bold;
  white-space: nowrap;
}

/* Settings menu (hamburger, all roles - see showSettingsMenu() in app.js) */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
}
.settings-row-label { min-width: 0; }
.settings-row-label .name { font-weight: bold; font-size: 14px; }
.settings-row-label .sub { color: var(--muted); font-size: 12px; margin-top: 2px; }
.settings-row .btn-compact { flex: 0 0 auto; min-width: 0; }

/* Login screen (Epic 16, 2026-08-18) - shown in place of the app shell
   (header + nav hidden, see showLoginScreen()/showApp() in app.js) until a
   session is confirmed via /api/session or established via /api/login. */
.login-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  background: var(--bg);
}
.login-card {
  width: 100%;
  max-width: 340px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 24px;
  box-shadow: 0 4px 18px rgba(0,0,0,0.06);
  text-align: center;
}
.login-card h1 {
  margin: 0 0 4px;
  font-size: 20px;
  color: var(--green);
}
.login-sub {
  margin: 0 0 20px;
  color: var(--muted);
  font-size: 13px;
}
.login-card form {
  text-align: left;
}
.login-card .field-row input {
  font-size: 16px; /* avoids iOS auto-zoom on focus */
}
.login-card button[type="submit"] {
  margin-top: 6px;
  font-size: 16px;
}
.login-error {
  color: #B3441E;
  background: #FDE9D9;
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
  margin-bottom: 12px;
}
