* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Arial, sans-serif;
  background-color: #f4f7fa;
  color: #4a4a4a;
}

/* Dark Mode Style (as an example, it just inverts colors for simplicity) */
body.dark-mode {
  filter: invert(1);
  background-color: #1c2a36;
}

.fullscreen-app {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}

header {
  width: 100%;
  background-color: #f4f7fa;
  height: 60px; /* or any other suitable height */
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  transition: transform 0.3s;
  z-index: 1000;
  padding: 0 15px;
  box-shadow: 0px 4px 15px rgba(150, 150, 150, 0.2);
}

.logo {
  margin-left: 20px;
  font-size: 1.5em;
}

.mode-toggle,
.menu-toggle {
  margin-right: 10px;
  padding: 10px 15px;
  font-size: 1.2em;
  border: none;
  background-color: transparent;
  cursor: pointer;
}

.light-mode-emoji,
.dark-mode-emoji {
  font-size: 1.5em;
}

.menu-list {
  background-color: #f4f7fa;
  position: fixed;
  top: 60px; /* Height of the header */
  left: 0;
  border-right: 1px solid #333;
  transition: transform 0.3s;
  transform: translateX(-100%);
  z-index: 999;
}

.menu-list.active {
  transform: translateX(0);
}

.menu-list ul {
  list-style-type: none;
}

.menu-list li {
  padding: 15px;
  border-bottom: 1px solid #333;
}

main {
  flex: 1;
  height: auto; /* flex: 1 fills the space the retired footer freed (D-15) */
  overflow-y: auto; /* For scrollable content if it exceeds the height */
}

.button-presser,
.a-presser {
  font-family: 'Open Sans', sans-serif;
  letter-spacing: 2px;
  text-decoration: none;
  text-transform: uppercase;
  color: #000;
  cursor: pointer;
  border: 3px solid;
  padding: 0.25em 0.5em;
  box-shadow: 1px 1px 0px 0px, 2px 2px 0px 0px, 3px 3px 0px 0px, 4px 4px 0px 0px,
    5px 5px 0px 0px;
  position: relative;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

.button-presser:active,
.a-presser:active {
  box-shadow: 0px 0px 0px 0px;
  top: 5px;
  left: 5px;
}

@media (min-width: 768px) {
  .button-presser,
  .a-presser {
    padding: 0.25em 0.75em;
  }
}

/* Specific styles for .a-presser */
.a-presser {
  display: inline-block;
  border-color: #000; /* Specify a border color */
  background-color: #fff; /* Set a background color */
  transition: box-shadow 0.2s, top 0.2s, left 0.2s;
}

.a-presser:hover {
  text-decoration: underline;
  background-color: #f4f4f4;
}

.leaflet-container {
  cursor: crosshair;
}

/* Honest-failure banners (D-08): unmistakable when something fails. The fixed
   wrapper sits below the 60px header and above the map so the Leaflet container
   can't clip it; individual banners are static blocks inside it, so multiple
   simultaneous failures stack vertically instead of overlapping. Deep red +
   white text stays high-contrast in dark mode, where the global body.dark-mode
   filter: invert(1) flips it to a readable inverted tone. */
.error-banner-stack {
  position: fixed;
  top: 60px;
  left: 0;
  right: 0;
  z-index: 1100;
}

.data-error-banner {
  background-color: #b00020;
  color: #ffffff;
  font-weight: bold;
  text-align: center;
  padding: 12px 16px;
  box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.3);
}

/* Result-popup typography (03-UI-SPEC): the 0–10 sub-score is the single most
   prominent element — accent #0b6e4f is reserved for the score VALUE only
   (constant colour, no traffic-light scale). 8px vertical rhythm between popup
   rows. Under body.dark-mode filter: invert(1) the deep green flips to a
   legible light pink-mauve tone — confirm at UAT. */
.popup-name {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.2;
  margin: 8px 0;
}

.popup-score-line {
  margin: 8px 0;
}

.popup-score {
  color: #0b6e4f;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
}

.popup-score-outof {
  font-size: 14px;
  font-weight: 400;
}

.popup-travel {
  font-size: 14px;
  line-height: 1.5;
  margin: 8px 0;
}

.popup-meta {
  font-size: 12px;
  line-height: 1.4;
  margin: 8px 0;
}

/* Criteria panel (D-01/D-05): a right slide-in DISCLOSURE — never a modal. It
   mirrors .menu-list's translateX slide mechanics from the right edge. z-index
   950 keeps it below the header (1000) and banners (1100), above the map. Under
   body.dark-mode filter: invert(1) the #f4f7fa surface flips to a deep slate —
   selection meaning lives in border weight, never hue, so it survives the
   invert (WCAG 1.4.1) — confirm legibility at UAT. */
.criteria-panel {
  position: fixed;
  top: 60px; /* Height of the header */
  right: 0;
  bottom: 0;
  width: 320px;
  background-color: #f4f7fa;
  transform: translateX(100%);
  transition: transform 0.3s;
  z-index: 950;
  overflow-y: auto;
  padding: 16px;
}

.criteria-panel.active {
  transform: translateX(0);
}

@media (max-width: 767px) {
  .criteria-panel {
    width: 100%;
    left: 0;
  }
}

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

/* Panel chrome (D-01): the header trigger keeps the .button-presser look; the
   ✕ close button holds the 44×44 minimum touch target. */
.panel-toggle {
  margin-right: 10px;
  font-size: 1.2em;
  background-color: #fff;
}

.panel-close {
  min-width: 44px;
  min-height: 44px;
  background-color: #fff;
  cursor: pointer;
}

.panel-heading {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.2;
}

/* Headline block (D-05: pinned at the panel top; SCORE-01). Accent #0b6e4f is
   reserved for score NUMBERS only (D-07) — under invert(1) it flips to a
   legible pink-mauve, same as the popup score. 24px margin-bottom is the lg
   gap between the headline block and the breakdown/chip body. */
.panel-headline {
  padding: 16px;
  margin-bottom: 24px;
}

.headline-live {
  line-height: 1.2;
}

.headline-score {
  color: #0b6e4f;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
}

.headline-outof {
  font-size: 14px;
  font-weight: 400;
}

.headline-note {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
}

/* Breakdown rows (D-05/D-08): one white card per selected criterion, 8px
   vertical rhythm, 44px minimum touch height (the row is a button — tapping
   pans to its marker, D-06). Error states use #b00020 text — visibly distinct
   from the neutral NO_POI row (SCORE-05/D-20). */
.breakdown-rows {
  margin-bottom: 24px;
}

.breakdown-row {
  display: block;
  width: 100%;
  text-align: left;
  background-color: #fff;
  border: 1px solid #ccc;
  margin-bottom: 8px;
  padding: 8px;
  min-height: 44px;
  font-family: inherit;
  cursor: pointer;
}

.row-name {
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
}

.row-travel {
  font-size: 14px;
  line-height: 1.5;
}

.row-subscore {
  color: #0b6e4f;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.2;
}

.row-state-note {
  font-size: 12px;
  line-height: 1.4;
}

.row-error {
  color: #b00020;
}

/* Chip grid (D-02/D-03): emoji + Irish label per criterion, grouped by theme.
   Selection is border WEIGHT (1px #ccc → 3px #4a4a4a), never hue — meaning
   survives dark-mode invert(1) (D-07/WCAG 1.4.1). 44×44 minimum touch targets;
   all gaps on the 4px scale. */
.chip-groups {
  margin-bottom: 16px;
}

.chip-group {
  margin-bottom: 16px;
}

.chip-group-heading {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.2;
  margin-bottom: 8px;
}

.chip-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chip {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 44px;
  min-height: 44px;
  padding: 4px;
  background-color: #fff;
  border: 1px solid #ccc;
  font-family: inherit;
  cursor: pointer;
}

.chip.selected {
  border: 3px solid #4a4a4a;
}

.chip-emoji {
  font-size: 24px;
}

.chip-label {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  /* Custom-place names truncate by CSS — the stored name renders via
     textContent only (D-21), never markup (Plan 05-05). */
  max-width: 88px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Weight dots (D-03): three weight toggle buttons per selected chip (WR-09:
   aria-pressed toggles, not radios). Dots are text ●/○ in
   currentColor — fill carries the meaning, so invert(1) keeps it legible.
   Visible dots are small; the hit area never drops below 44×44. */
.weight-dots {
  display: flex;
  gap: 8px;
}

.weight-dot {
  min-width: 44px;
  min-height: 44px;
  background-color: transparent;
  border: none;
  color: currentColor;
  font-size: 16px;
  font-family: inherit;
  cursor: pointer;
}

/* Headline pill (D-05 mobile surfacing): fixed bottom-center over the map when
   the panel is closed and a score exists; tap reopens the panel. z-index 940 —
   below the panel (950). Accent stays reserved for the score number inside. */
.headline-pill {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  background-color: #fff;
  border: 1px solid #ccc;
  min-height: 44px;
  padding: 8px 16px;
  z-index: 940;
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
}

/* Emoji criterion markers (D-06/D-12): one L.divIcon per scored criterion —
   the criterion's emoji at 24px on a transparent tile. The html: sink receives
   ONLY dev-authored emoji constants from criteria-defs.js (D-21). */
.poi-emoji-icon {
  font-size: 24px;
  background: transparent;
  border: none;
  text-align: center;
  line-height: 32px;
}

/* .storage-error-banner (research Pitfall 7) is a MARKER class for the corrupt
   storage banner's single-instance guard — its visual style comes entirely from
   the shared .data-error-banner rule above. */
.storage-error-banner {
  text-align: center;
}

/* Pin-drop + custom places (D-09/D-11/D-12, UI-SPEC P1-P4). Every new control
   keeps the 44px minimum touch target; destructive confirm states use #b00020
   text — never hue-only meaning, the swapped copy carries it too (D-07). */

/* Add-place CTA (P1): 44px minimum target; disabled at the 10-place cap with
   the 'uasmhéid 10 n-áit' hint beside it (D-11). */
.add-place {
  min-width: 44px;
  min-height: 44px;
  background-color: #fff;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.5;
  cursor: pointer;
}

.add-place:disabled {
  cursor: not-allowed;
}

/* The action area at the end of the custom grid: hosts the CTA, the armed
   hint + cancel, or the inline name form — full width so it never competes
   with chips for a grid cell. */
.add-place-area {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  width: 100%;
}

/* Armed-mode hint strip (P2, mobile): fixed over the map, same surface family
   as the headline pill (#fff, 1px #ccc, z-index 940), 44px minimum height. */
.pin-drop-hint {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  background-color: #fff;
  border: 1px solid #ccc;
  min-height: 44px;
  padding: 8px 16px;
  z-index: 940;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  max-width: calc(100vw - 32px);
}

.pin-drop-hint button {
  min-width: 44px;
  min-height: 44px;
  background-color: #fff;
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
}

/* CR-02 out-of-bounds refusal hint: warn colour on the hint surfaces (same
   #b00020 as the delete/reset confirm affordances; under dark mode's invert(1)
   it renders as its inverse — same treatment, no special-casing). */
.hint-warn {
  color: #b00020;
}

/* Inline name form (P3): 16px internal padding, Body 14/400 input, 44px-min
   buttons (save disabled until the trimmed name is non-empty). */
.place-name-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 16px;
  background-color: #fff;
  border: 1px solid #ccc;
}

.place-name-form input {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  padding: 8px;
  border: 1px solid #ccc;
  font-family: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
}

.place-name-form button {
  min-width: 44px;
  min-height: 44px;
  background-color: #fff;
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
}

.place-name-form button:disabled {
  cursor: not-allowed;
}

/* Address-search combobox (INPUT-02, 06-UI-SPEC Component A). A WAI-ARIA
   editable input + listbox pinned at the TOP of the panel, above the headline.
   White input/rows on the #f4f7fa panel surface; 24px lg gap below the block.
   Mirrors .place-name-form input (16px padding, 1px solid #ccc, min-height 44px).
   Active-option distinction is border/background WEIGHT, never accent hue
   (WCAG 1.4.1) — the reserved score green #0b6e4f never appears here. Survives
   body.dark-mode filter: invert(1) like every other white-on-panel surface. */
.combobox {
  margin-bottom: 24px;
}

.combobox-input {
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  padding: 16px;
  border: 1px solid #ccc;
  background-color: #fff;
  font-family: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
}

.combobox-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background-color: #fff;
  border: 1px solid #ccc;
  border-top: none;
}

.combobox-option {
  display: block;
  min-height: 44px;
  padding: 8px;
  margin: 0;
  border-bottom: 1px solid #eee;
  cursor: pointer;
}

.combobox-option:last-child {
  border-bottom: none;
}

/* Active descendant (arrow-key target): border/background weight only — no
   accent fill, so meaning survives invert(1) and never collides with the score
   green (WCAG 1.4.1, D-18). */
.combobox-option.active {
  background-color: #e8eef5;
  border-left: 4px solid #333;
  padding-left: 4px;
}

/* The no-results in-list row is informational, not selectable. */
.combobox-option.no-results {
  cursor: default;
  font-style: italic;
}

.combobox-option-primary {
  display: block;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
}

.combobox-option-secondary {
  display: block;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
}

/* Geocoder-down banner (state 5): a marker class on the shared honest-failure
   banner — distinct visible state from the no-results in-list row (D-18). It
   reuses .data-error-banner's colour entirely; no new hue is introduced. */
.geocoder-error-banner {
  /* intentionally empty — all styling inherited from .data-error-banner */
}

/* Custom-chip delete × (D-11): 44×44 hit area; the two-tap confirm state
   swaps the text to 'scrios? / delete?' in the destructive colour. */
.chip-delete {
  min-width: 44px;
  min-height: 44px;
  background-color: transparent;
  border: none;
  font-family: inherit;
  font-size: 16px;
  line-height: 1.2;
  cursor: pointer;
}

.chip-delete.confirming {
  color: #b00020;
  font-size: 12px;
}

/* Garda 24/7 sub-toggle (D-15): checkbox + Label 12/400 inside the selected
   garda chip cell; the row keeps the 44px minimum touch height. */
.garda-247-toggle {
  display: flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  cursor: pointer;
}

/* Reset (D-16): destructive two-tap button at the panel bottom — restores the
   starter set, never touches custom places. Confirm state shares the
   destructive colour. */
.reset-button {
  min-width: 44px;
  min-height: 44px;
  margin-top: 24px;
  background-color: #fff;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.5;
  cursor: pointer;
}

.reset-button.confirming {
  color: #b00020;
}

/* Isochrone controls (MAP-02, 06-UI-SPEC Component B). A toggle + walk/drive
   segmented switch + legend, sitting below .breakdown-rows with a 24px lg gap
   above. EXTENDS the panel system — no chrome restyle. The band hue/opacity are
   NOT here: they live in panel.js's L.geoJSON style options (opacity carries
   meaning so it survives body.dark-mode filter: invert(1), D-12). Active mode =
   border WEIGHT + aria-pressed, never an accent fill (WCAG 1.4.1) — the reserved
   score green #0b6e4f never appears in this block. */
.isochrone-controls {
  margin-top: 24px;
}

.iso-heading {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.2;
  margin: 0 0 8px;
}

.iso-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  background-color: #fff;
  border: 1px solid #ccc;
  font-family: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  padding: 0 16px;
  cursor: pointer;
}

/* Pressed (overlay on) = heavier border, never an accent fill (WCAG 1.4.1). */
.iso-toggle[aria-pressed='true'] {
  border-width: 2px;
}

/* Unavailable (no point scored, D-11): visibly disabled; the honest hint sits
   beside it via .iso-needs-point. */
.iso-toggle:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.iso-needs-point {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  margin-left: 8px;
}

/* Segmented walk/drive switch (D-10): two buttons, 8px gap, one mode at a time.
   Active = border weight + aria-pressed/aria-checked, NOT a fill. */
.iso-mode {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}

.iso-mode-btn {
  min-width: 44px;
  min-height: 44px;
  background-color: #fff;
  border: 1px solid #ccc;
  font-family: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  padding: 0 16px;
  cursor: pointer;
}

.iso-mode-btn[aria-pressed='true'],
.iso-mode-btn[aria-checked='true'] {
  border-width: 2px;
  font-weight: 700;
}

/* Legend caption (Label 12/400): states the "denser = closer" opacity meaning
   in words, defeating the colour-only-meaning trap (D-12). */
.iso-legend {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  margin-top: 8px;
}

/* Isochrone-failed banner (state 6): its OWN marker class on the shared
   honest-failure banner — a distinct visible state from the per-row
   routing-failed and the geocoder-down banner (D-18). All colour inherited from
   .data-error-banner; no new hue introduced. */
.isochrone-error-banner {
  /* intentionally empty — all styling inherited from .data-error-banner */
}
