/* ---------------------------------------------------------------------
   Scrap Tracker styles
   Palette confirmed for this project: sustainability green primary,
   warm orange accent, carried-over neutrals and status colors from
   SewTracker for cross-project consistency. Montserrat throughout.
   Layout follows SewTracker's pattern: a clean white header holding
   brand + primary links + account, and a left rail for secondary,
   less-frequent navigation.
   --------------------------------------------------------------------- */

:root {
  --color-primary: #138A43;
  --color-primary-dark: #0f6f36;
  --color-accent: #E67E22;
  --color-accent-dark: #cf6d15;

  --color-gray: #718096;
  --color-warning: #ed8936;
  --color-info: #17a2b8;
  --color-danger: #c53030;

  --color-bg: #f7f8f6;
  --color-card-bg: #ffffff;
  --color-text: #1a202c;
  --color-text-muted: #4a5568;
  --color-border: #e2e8f0;

  --font-body: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --radius: 12px;
  --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.06);

  /* Chart series colors, Group 4. Distinct from the semantic UI palette
     above, since the 8 Scraplanta categories need 8 visually distinct
     hues rather than reusing status/neutral colors. */
  --chart-color-1: #138A43;
  --chart-color-2: #E67E22;
  --chart-color-3: #2B6CB0;
  --chart-color-4: #805AD5;
  --chart-color-5: #D53F8C;
  --chart-color-6: #319795;
  --chart-color-7: #D69E2E;
  --chart-color-8: #4A5568;
}

* {
  box-sizing: border-box;
}

html {
  height: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  font-family: var(--font-body);
  background: var(--color-bg);
  color: var(--color-text);
  line-height: 1.5;
}

a {
  color: var(--color-primary);
}

h1, h2, h3 {
  font-weight: 700;
  margin: 0 0 8px;
}

/* ---------------------------------------------------------------------
   Top header: brand + primary links on the left, account on the right
   --------------------------------------------------------------------- */

.app-nav {
  background: var(--color-card-bg);
  border-bottom: 1px solid var(--color-border);
}

.app-nav-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px 20px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}

.app-nav-brand-block {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.app-nav-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--color-text);
  text-decoration: none;
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}

/* The trademark sign after the app's name, see appNameHtml(). */
.tm {
  font-weight: 400;
}

.brand-mark {
  flex-shrink: 0;
}

.app-nav-primary {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.app-nav-primary a {
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: 0.88rem;
  font-weight: 600;
}

.app-nav-primary a:hover {
  color: var(--color-primary);
}

.nav-sep {
  color: var(--color-border);
  font-size: 0.8rem;
}

.app-nav-account-block {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

.app-nav-date {
  color: var(--color-text);
  font-weight: 600;
  font-size: 0.88rem;
  white-space: nowrap;
}

.app-nav-logout {
  color: var(--color-gray);
  text-decoration: none;
  font-size: 0.82rem;
}

.app-nav-logout:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

/* ---------------------------------------------------------------------
   Shell: left rail + main content
   --------------------------------------------------------------------- */

.app-shell {
  max-width: 1200px;
  margin: 0 auto;
  padding: 28px 20px;
  display: flex;
  align-items: flex-start;
  gap: 24px;
  min-height: 100vh;
  min-height: 100dvh;
}

.app-rail {
  width: 220px;
  flex-shrink: 0;
  background: var(--color-card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 20px 16px;
}

.app-main {
  flex: 1;
  min-width: 0;
}

.rail-section {
  margin-bottom: 20px;
}

.rail-heading {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-gray);
  margin: 0 0 8px;
}

.rail-link {
  display: block;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--color-text);
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 500;
}

.rail-link:hover {
  background: var(--color-bg);
}

.rail-link.is-active {
  background: #e8f6ee;
  color: var(--color-primary-dark);
  font-weight: 700;
}

.rail-footer {
  margin-top: 4px;
  padding-top: 16px;
  border-top: 1px solid var(--color-border);
  text-align: center;
}

.rail-footer a {
  font-size: 0.85rem;
  color: var(--color-gray);
  text-decoration: none;
}

.rail-footer a:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

/* ---------------------------------------------------------------------
   Page content, cards
   --------------------------------------------------------------------- */

.page {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.auth-page {
  max-width: 420px;
  margin: 0 auto;
  padding: 64px 20px 32px;
  min-height: 100vh;
  min-height: 100dvh;
}

.card {
  background: var(--color-card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 28px;
}

.auth-card {
  text-align: center;
}

.auth-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}

.auth-title {
  color: var(--color-text);
  margin: 0;
}

.auth-subtitle,
.page-subtitle {
  color: var(--color-text-muted);
  margin-top: 0;
}

/* A secondary link belonging to a page subtitle, dropped onto its own
   line and a step smaller so it reads as an aside rather than part of
   the sentence above it. Kept inside the subtitle's own <p> rather than
   added as a second paragraph, which would stack two paragraph margins
   and open a full line of gap. */
.page-subtitle-link {
  display: block;
  font-size: 0.82rem;
  margin-top: 2px;
}

/* ---------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------- */

.form {
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-align: left;
  margin-top: 16px;
}

.form label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text-muted);
  margin-top: 10px;
}

.form input,
.form select,
.form textarea {
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: #fff;
  color: var(--color-text);
}

.form textarea {
  resize: vertical;
  line-height: 1.5;
}

.form input:focus,
.form select:focus,
.form textarea:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

/* A field filled from a customer record and locked, on the Log Donation
   form. Safari and Chrome grey disabled text out on their own but not
   identically, so the colors are set here rather than left to each
   browser's default, which can drop the value close to unreadable. */
.form input:disabled,
.form select:disabled {
  background: var(--color-bg);
  color: var(--color-text-muted);
  cursor: not-allowed;
  -webkit-text-fill-color: var(--color-text-muted);
  opacity: 1;
}

/* A checkbox and its wording on one line. Every other .form input is a
   full-width block under its own label, which turns a checkbox into a
   stretched grey slab, so this one opts out rather than the rule being
   loosened for all of them. */
.form .checkbox-field {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-text);
  cursor: pointer;
}

.form .checkbox-field input[type="checkbox"] {
  width: 18px;
  height: 18px;
  padding: 0;
  flex: none;
  accent-color: var(--color-primary);
  cursor: pointer;
}

/* Explains a locked group of fields, sitting directly under them. */
.form-note {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin: 6px 0 0;
}

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

.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  border: none;
  border-radius: 999px;
  padding: 12px 22px;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  color: #fff;
}

.btn-block {
  display: block;
  width: 100%;
  margin-top: 18px;
}

/* A submit button that has been handed to the server and is waiting on
   it. The label swap is what actually tells somebody that; the ring is
   decoration, which is why it is a pseudo-element and why the global
   prefers-reduced-motion rule at the end of this file can stop it
   spinning without taking the meaning with it. */
.btn.is-busy {
  cursor: progress;
  opacity: 0.75;
}

.btn.is-busy::before {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-right: 0.5em;
  vertical-align: -0.1em;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}

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

.btn-primary {
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
}

.btn-primary:hover {
  filter: brightness(1.05);
}

.btn-accent {
  background: linear-gradient(135deg, var(--color-accent), var(--color-accent-dark));
}

/* ---------------------------------------------------------------------
   Alerts and flash messages
   --------------------------------------------------------------------- */

.alert,
.flash {
  border-radius: 8px;
  padding: 12px 16px;
  font-size: 0.9rem;
  margin: 0 0 12px;
}

.alert ul {
  margin: 0;
  padding-left: 18px;
}

.alert-error,
.flash-error {
  background: #fdecea;
  color: var(--color-danger);
  border: 1px solid #f5c2c0;
}

.flash-success {
  background: #e8f6ee;
  color: var(--color-primary-dark);
  border: 1px solid #bfe6cd;
}

.flash {
  max-width: 1200px;
  margin: 16px auto 0;
}

/* ---------------------------------------------------------------------
   Filter bar (donations list, search/filter controls)
   --------------------------------------------------------------------- */

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 14px;
  margin: 18px 0 22px;
  padding: 16px;
  background: var(--color-bg);
  border-radius: var(--radius);
}

.filter-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.filter-field .form-note {
  margin: 0;
  max-width: 22rem;
}

.form-note-warn {
  color: var(--color-danger);
}

.filter-field label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-text-muted);
}

.filter-field input,
.filter-field select {
  font-family: var(--font-body);
  font-size: 0.92rem;
  padding: 8px 10px;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: #fff;
  color: var(--color-text);
}

.filter-field input:focus,
.filter-field select:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.filter-field-actions {
  flex-direction: row;
  gap: 8px;
}

/* ---------------------------------------------------------------------
   Buttons: small size + secondary/danger variants, for row and toolbar
   actions alongside the existing full-size primary/accent CTAs
   --------------------------------------------------------------------- */

.btn-sm {
  padding: 7px 14px;
  font-size: 0.82rem;
}

.btn-secondary {
  background: #fff;
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

.btn-secondary:hover {
  border-color: var(--color-gray);
  color: var(--color-text);
}

/* Green outline: a real button, but one step below the filled primary
   so it doesn't compete with the form's own submit. Used for "Look up a
   returning donor" on Log Donation, which intake kept missing as a
   text link. */
.btn-outline {
  background: #fff;
  color: var(--color-primary-dark);
  border: 2px solid var(--color-primary);
}

.btn-outline:hover {
  background: var(--color-primary);
  color: #fff;
}

/* A page heading with a button on its right, like "Look up a returning
   donor" beside Log a donation. Wraps the button under the heading on a
   narrow phone instead of squeezing the heading. */
.page-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin-bottom: 8px;
}

.page-title-row h1 {
  margin: 0;
}

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

.btn-danger:hover {
  filter: brightness(1.08);
}

/* ---------------------------------------------------------------------
   Tables (Recent Donations, and future list screens)
   --------------------------------------------------------------------- */

.table-wrap {
  overflow-x: auto;
  margin-top: 4px;
}

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

.table th,
.table td {
  text-align: left;
  padding: 12px 10px;
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.table th {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-gray);
}

/* Sortable column headers (Customers). The link inherits the header's
   small caps look; the arrow marks the column in use. */
.table-sort {
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}

.table-sort:hover,
.table-sort:focus-visible {
  color: var(--color-text);
  text-decoration: underline;
}

.table-sort.is-active {
  color: var(--color-text);
}

.table tbody tr:hover {
  background: var(--color-bg);
}

.table-subtext {
  display: block;
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.table-actions {
  text-align: right;
  white-space: nowrap;
}

.table-actions form {
  display: inline;
}

.table-actions > a,
.table-actions form {
  margin-left: 6px;
}

.table-actions > a:first-child,
.table-actions form:first-child {
  margin-left: 0;
}

/* Placeholder text in a table cell, like Anonymous where a donor name
   would be. Plain muted text rather than a pill, for the same reason
   as .status below. */
.table-muted {
  font-style: italic;
  color: var(--color-text-muted);
}

/* ---------------------------------------------------------------------
   Status (Active / Inactive on list screens). Plain text with a dot,
   deliberately not a pill: buttons are pills too, and a status pill
   next to a row's Edit and Deactivate buttons reads as clickable.
   --------------------------------------------------------------------- */

.status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text);
  white-space: nowrap;
}

.status::before {
  content: '';
  box-sizing: border-box;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary);
}

.status-inactive {
  font-weight: 500;
  color: var(--color-text-muted);
}

.status-inactive::before {
  background: transparent;
  border: 1.5px solid var(--color-gray);
}

/* ---------------------------------------------------------------------
   Empty state, pagination
   --------------------------------------------------------------------- */

.empty-state {
  text-align: center;
  color: var(--color-text-muted);
  padding: 32px 0;
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 20px;
}

.pagination-status {
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

/* ---------------------------------------------------------------------
   Group 4: dashboard stat cards, hand-rolled bar and pie charts
   --------------------------------------------------------------------- */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 16px;
  margin-top: 16px;
}

.stat-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
}

.stat-value {
  font-size: 28px;
  font-weight: 700;
  color: var(--color-primary-dark);
}

.stat-label {
  font-size: 13px;
  color: var(--color-text-muted);
}

.chart-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.metric-toggle {
  display: inline-flex;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  overflow: hidden;
}

.metric-toggle-link {
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  text-decoration: none;
}

.metric-toggle-link.is-active {
  background: var(--color-primary);
  color: #fff;
}

.bar-chart {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  margin-top: 16px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.bar-chart-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 0 64px;
  min-width: 64px;
}

.bar-chart-value {
  font-size: 13px;
  color: var(--color-text-muted);
  margin-bottom: 8px;
  white-space: nowrap;
}

.bar-chart-track {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  width: 100%;
  max-width: 56px;
  height: 200px;
  background: var(--color-bg);
  border-radius: 8px 8px 0 0;
  overflow: hidden;
}

.bar-chart-fill {
  display: block;
  width: 100%;
  border-radius: 8px 8px 0 0;
}

.bar-chart-label {
  font-size: 13px;
  color: var(--color-text);
  margin-top: 8px;
  text-align: center;
  word-break: break-word;
}

/* ---------------------------------------------------------------------
   Map (Leaflet), replacing the earlier hand-rolled SVG heat map
   --------------------------------------------------------------------- */

.donation-map {
  height: 420px;
  border-radius: 12px;
  overflow: hidden;
  margin-top: 16px;
}

/* Names the six colors the markers borrow from the dashboard's By zip
   chart. Without it the colors are decoration: nothing else on the page
   says which zip owns which hue. Laid out as a wrapping flex row rather
   than a grid so it collapses to one column on a phone by itself.
   Swatch colors are NOT set here; heatmap.php writes them into a
   nonce'd <style> block from CHART_COLORS, the single PHP-side copy of
   these hexes. */
.map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  list-style: none;
  margin: 16px 0 0;
  padding: 16px 0 0;
  border-top: 1px solid var(--color-border);
  font-size: 13px;
}

.map-legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.map-legend-rank {
  font-size: 11px;
  font-weight: 700;
  color: var(--color-gray);
  font-variant-numeric: tabular-nums;
  min-width: 10px;
}

.map-legend-swatch {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid transparent;
  flex: none;
}

/* Hollow, like the Other bar on the dashboard, which is outlined rather
   than filled for the same reason: it is a sum of many rows, not a peer
   of the six named above it. */
.map-legend-swatch-other {
  background: transparent;
  border-color: var(--color-gray);
}

.map-legend-zip {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.map-legend-value {
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.heatmap-attribution {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-top: 12px;
}

/* ---------------------------------------------------------------------
   Site footer, every page
   --------------------------------------------------------------------- */

.site-footer {
  text-align: center;
  padding: 20px;
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

/* Logged in, the footer sits under the app shell rather than inside it,
   so it mirrors the shell's width and steps past the rail (220px plus
   the 24px gap) to center under the main column instead of the page. */
.site-footer-in-shell {
  max-width: 1200px;
  margin: 0 auto;
  padding-left: 264px;
}

.site-footer-heart {
  font-size: 0.9em;
}

.site-footer a {
  color: var(--color-text-muted);
  font-weight: 700;
  text-decoration: underline;
}

.site-footer a:hover {
  color: var(--color-primary);
}

/* ---------------------------------------------------------------------
   Responsive
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Appointments: the public booking page and its slot picker.

   /schedule and /cancel-appointment are the only pages in this app a
   donor sees, and when nobody is logged in there is no header and no
   rail around them, so .public-page supplies the page's own margins
   the way .app-main does everywhere else. Both pages add the class
   only when logged out: a staff member booking over the phone already
   has the app shell, and this would narrow it a second time.
   --------------------------------------------------------------------- */

.public-page {
  max-width: 640px;
  margin: 0 auto;
  padding: 32px 20px;
}

.public-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.public-brand-name {
  font-size: 1.1rem;
  font-weight: 700;
}

/* The date and time of a booking, wherever it is the answer the reader
   came for: the confirmation screen and the cancel screen. */
.booking-when {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--color-primary-dark);
  margin: 0 0 12px;
}

.slot-picker {
  border: 0;
  padding: 0;
  margin: 8px 0 16px;
}

.slot-picker legend {
  padding: 0;
  font-size: 0.9rem;
  font-weight: 600;
}

.slot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
  gap: 10px;
  margin-top: 10px;
}

/* A radio styled as a tile, with the input kept in the page rather than
   hidden: it stays reachable by keyboard and by a screen reader, and
   the tile is its label, so a tap anywhere on it selects. */
.slot-choice {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 12px 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-card-bg);
  cursor: pointer;
}

.slot-choice:hover {
  border-color: var(--color-primary);
}

.slot-choice:has(input:checked) {
  border-color: var(--color-primary);
  background: rgba(19, 138, 67, 0.06);
}

.slot-choice:has(input:focus-visible) {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.slot-time {
  font-weight: 600;
  white-space: nowrap;
}

.slot-note {
  font-size: 0.72rem;
  color: var(--color-accent-dark);
}

@media (max-width: 720px) {
  .app-shell {
    flex-direction: column;
  }

  .app-rail {
    width: 100%;
  }

  .site-footer-in-shell {
    padding-left: 20px;
  }

  .filter-bar {
    flex-direction: column;
    align-items: stretch;
  }

  .bar-chart-track {
    height: 140px;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation: none !important;
  }
}
