/*
 * The collection and its pages.
 *
 * One result set is rendered twice — a table and a list of cards — and exactly
 * one of them is displayed at any width (design §7.4). `display: none` removes
 * the other from the accessibility tree too, so a screen reader is read one
 * list rather than two.
 */

.places-table {
  display: none;
}

.places-cards {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-4);
}

.place-card {
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.place-card__name {
  margin: 0 0 var(--space-2);
  font-size: 1.125rem;
}

.place-card p {
  margin: 0 0 var(--space-1);
  color: var(--ink-quiet);
}

/* Wide enough for columns to be read across rather than guessed at. */
@media (min-width: 48rem) {
  .places-table {
    display: table;
    width: 100%;
    border-collapse: collapse;
  }

  .places-cards {
    display: none;
  }

  .places-table th,
  .places-table td {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
  }

  .places-table thead th {
    border-bottom-width: 2px;
  }

  /* A summary, cut short; quieter than the columns read across. */
  .places-table__hours {
    max-width: 14rem;
    color: var(--ink-quiet);
    font-size: 0.875rem;
  }

  /* The headers sort the table, so the select that stands in for them on
     cards is not needed. Hidden, its fields still carry the order. */
  .filters__sort {
    display: none;
  }
}

/* A sortable column's header: the name, and an arrow for the direction in
   force — or a faint double arrow saying the column can be sorted at all. */
.sort-link {
  display: inline-flex;
  gap: var(--space-1);
  align-items: baseline;
  color: inherit;
  text-decoration: none;
}

.sort-link:hover {
  color: var(--accent);
}

.sort-link__arrow {
  opacity: 0.35;
}

.sort-link:hover .sort-link__arrow,
.sort-link--active .sort-link__arrow {
  opacity: 1;
}

.sort-link--active .sort-link__arrow {
  color: var(--accent);
}

.filters {
  margin-bottom: var(--space-5);
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.filters__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-end;
}

.filters__row .field {
  flex: 1 1 10rem;
  margin-bottom: 0;
}

.filters__row .filters__search,
.filters__row .filters__sort {
  flex: 2 1 16rem;
}

.filters__sort-controls {
  display: flex;
  gap: var(--space-2);
}

/* Sits on the line of the fields, as tall as their inputs. */
.filters__clear {
  flex: 0 0 auto;
  line-height: inherit;
}

/* The tag filter: a row of tag toggles under a legend. */
.filters__tags {
  min-width: 0;
  margin: var(--space-4) 0 0;
  padding: 0;
  border: 0;
}

.filters__tags legend {
  margin-bottom: var(--space-2);
  padding: 0;
  font-weight: 600;
}

.filters__hint {
  margin-left: var(--space-2);
  color: var(--ink-quiet);
  font-size: 0.875rem;
  font-weight: 400;
}

/* A row of tags to pick from: the filters, and the place form. */
.tag-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.field-group .tag-toggles {
  margin-bottom: var(--space-3);
}

/* Positioned, so the hidden checkbox sits with its badge and focusing it
   does not scroll the page somewhere else. */
.tag-toggle {
  position: relative;
}

/* A tag to pick is the same badge as everywhere else. Off, it is dimmed;
   on, it is at full strength with a tick before its name, so the state does
   not rest on colour alone. Hovering brightens one that is off. */
.tag-toggle__chip {
  cursor: pointer;
  user-select: none;
}

.tag-toggle__input:not(:checked) + .tag-toggle__chip {
  opacity: 0.55;
}

.tag-toggle__input:not(:checked) + .tag-toggle__chip:hover,
.tag-toggle__input:not(:checked):focus-visible + .tag-toggle__chip {
  opacity: 0.85;
}

.tag-toggle__input:checked + .tag-toggle__chip::before {
  content: "✓" / "";
  margin-right: calc(-1 * var(--space-1));
  color: var(--tag-edge, currentColor);
  font-weight: 700;
}

.tag-toggle__input:focus-visible + .tag-toggle__chip {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* The title, and the way into or out of the archive. */
.collection__header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}

.collection__header h1 {
  margin: 0;
}

.collection__frame {
  display: block;
}

/* While a filter change is loading. Delayed, so a quick answer does not
   flicker the results. */
.collection__results {
  transition: opacity 0.15s;
}

.collection__frame[busy] .collection__results {
  opacity: 0.6;
  transition-delay: 0.2s;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  margin-top: var(--space-5);
}

.pagination__position {
  color: var(--ink-quiet);
}

/* Detail */

.place__header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
}

.place__title {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: center;
  min-width: 0;
}

.place__title h1 {
  margin: 0;
  overflow-wrap: anywhere;
}


.place__controls {
  display: flex;
  gap: var(--space-2);
}

.place__facts {
  display: grid;
  grid-template-columns: minmax(8rem, max-content) 1fr;
  gap: var(--space-2) var(--space-4);
  margin: var(--space-5) 0;
}

.place__facts dt {
  font-weight: 600;
  color: var(--ink-quiet);
}

.place__facts dd {
  margin: 0;
}

/* Opening hours and prices are free text and may run to several lines, so they
   are rendered as paragraphs. Their default margins would pull the value away
   from the term beside it. */
.place__facts dd p {
  margin: 0;
}

.place__facts dd p + p {
  margin-top: var(--space-2);
}

.links ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.links__item {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.links__kind {
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

/* Kind icons (app/helpers/places_helper.rb). Sized in `em` in the markup, so
   they follow the reader's text size; this only keeps them from being squashed
   by the flex row and sits them on the line rather than above it. */
.icon {
  flex: none;
  vertical-align: -0.125em;
}

.description {
  max-width: var(--measure);
}

/* Forms */

.place-form__form {
  max-width: var(--measure);
}

.place-form__form input[type="submit"] {
  margin-top: var(--space-4);
}

.place-form__optional summary {
  cursor: pointer;
  font-weight: 600;
  padding: var(--space-2) 0;
}

.links-fields__rows {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-4);
}

.link-fields {
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.link-fields__controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.tags-page__list {
  max-width: 52rem;
  margin: 0 0 var(--space-5);
  padding: var(--space-2) var(--space-4);
  list-style: none;
}

.tags-page__list li {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
}

.tags-page__list li:last-child {
  border-bottom: 0;
}

/* A tag as a pill: its name, and how many places carry it as a badge inside
   the same link. */
.tag-chip {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
  max-width: 100%;
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-3);
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}

/* A badge that is a link fills in on hover. A badge that is a toggle does
   not: filled would read as "selected". */
a.tag-chip:hover {
  background: var(--accent);
  color: var(--accent-ink);
}

/* A coloured tag is tinted with its colour, with a stronger border. The name
   switches to the ordinary ink, so it stays readable whatever colour was
   picked. The border leans 30% towards the ink, so a near-black colour still
   shows on the dark theme and a pale one on the light theme. `--tag-color` is
   set by the tag-color controller; until it is, the badge looks like any
   other. */
.tag-chip--colored {
  --tag-edge: color-mix(in srgb, var(--tag-color) 70%, var(--ink));

  border-color: var(--tag-edge, var(--accent));
  background: color-mix(in srgb, var(--tag-color, transparent) 18%, var(--surface));
  color: var(--ink);
}

a.tag-chip--colored:hover {
  background: color-mix(in srgb, var(--tag-color, var(--accent)) 35%, var(--surface));
  color: var(--ink);
}

a.tag-chip--colored:hover .tag-chip__count {
  background: var(--page);
  color: var(--ink-quiet);
}

.tag-chip__name {
  overflow-wrap: anywhere;
}

.tag-chip__count {
  flex-shrink: 0;
  padding: 0 var(--space-2);
  border-radius: 999px;
  background: var(--page);
  color: var(--ink-quiet);
  font-size: 0.8125rem;
  font-weight: 400;
}

a.tag-chip:hover .tag-chip__count {
  background: var(--accent-ink);
  color: var(--accent);
}

/* Tags on a place: on its page, in the table, and on its card. */
.tag-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.places-table .tag-badges,
.place-card .tag-badges {
  gap: var(--space-1);
}

.place-card .tag-badges {
  margin: var(--space-2) 0;
}

/* Smaller, where many sit side by side: a place's tags, and the tags to
   pick from. With a count, the count's pill takes the right-hand padding. */
.tag-chip--compact {
  padding: 0.125rem var(--space-3);
  font-size: 0.875rem;
}

.tag-chip--compact:has(.tag-chip__count) {
  padding-right: 0.125rem;
}

.tag-chip--compact .tag-chip__count {
  font-size: 0.75rem;
}

.tag-chip--empty {
  border-style: dashed;
  border-color: var(--line);
  color: var(--ink-quiet);
}

.tags-page__controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

/* The colour menu: a swatch button opening onto presets and a custom
   picker. */
.color-menu {
  position: relative;
}

.color-menu__summary {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  list-style: none;
}

.color-menu__summary::-webkit-details-marker {
  display: none;
}

.color-menu[open] > .color-menu__summary {
  border-color: var(--accent);
}

/* "No colour" is an empty dashed ring. */
.color-menu__none {
  stroke: var(--ink-quiet);
  stroke-width: 1.5;
  stroke-dasharray: 3 2;
}

.color-menu__panel {
  position: absolute;
  right: 0;
  z-index: 1000;
  width: 17rem;
  margin-top: var(--space-1);
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 0.15);
}

.color-menu__presets {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: var(--space-1);
  margin-bottom: var(--space-3);
}

.color-menu__preset {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 50%;
  background: none;
}

/* A thin outline on every swatch, or white would vanish on the light theme
   and black on the dark one. */
.color-menu__preset circle,
.color-menu__summary circle:not(.color-menu__none) {
  stroke: var(--ink-quiet);
  stroke-opacity: 0.45;
  stroke-width: 1;
}

.color-menu__preset:hover {
  border-color: var(--line);
}

/* The current colour is ringed, and announced as pressed. */
.color-menu__preset[aria-pressed="true"] {
  border-color: var(--ink);
}

.color-menu__clear {
  grid-column: 1 / -1;
  padding: var(--space-1) var(--space-2);
  font-size: 0.875rem;
}

.color-menu__clear[aria-pressed="true"] {
  border-color: var(--ink);
}

.color-menu__custom {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
  font-size: 0.875rem;
}

.color-menu__custom input[type="color"] {
  width: 2rem;
  height: 2rem;
  padding: 0.125rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
}

/* On a phone the controls sit under the tag, so the menu opens to the
   right of its button rather than off the left edge. */
@media (max-width: 47.99rem) {
  .color-menu__panel {
    right: auto;
    left: 0;
  }
}

.tags-page__rename {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

/* Renaming is the rare action on this page, so its button stays quiet
   rather than taking the primary style every submit button gets. */
.tags-page__color input[type="submit"],
.tags-page__rename input[type="submit"] {
  padding: var(--space-1) var(--space-3);
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
  font-weight: 400;
}

/* Adding a tag: name, colour, and Add on one line above the list. */
.tags-page__new {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  max-width: 52rem;
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
}

.tags-page__new input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

.tags-page__new input[type="submit"] {
  flex: 0 0 auto;
}

/* The colour for a new tag: the colour menu, with radios for buttons. It
   sits near the end of its line, so it always opens towards the left. */
/* As tall as the field and button beside it. */
.tags-page__new .color-menu__summary {
  width: calc(1.5em + 2 * var(--space-2) + 2px);
  height: calc(1.5em + 2 * var(--space-2) + 2px);
}

.color-choice .color-menu__panel {
  right: 0;
  left: auto;
}

.color-choice__options {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.color-choice .color-menu__presets {
  margin-bottom: 0;
}

.color-choice .color-menu__preset,
.color-choice .color-menu__clear {
  cursor: pointer;
}

.color-choice .color-menu__clear {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: center;
}

.color-choice .color-menu__preset:has(input:checked),
.color-choice .color-menu__clear:has(input:checked) {
  border-color: var(--ink);
}

.color-choice .color-menu__preset:has(input:focus-visible),
.color-choice .color-menu__clear:has(input:focus-visible) {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.tags-page__rename input[type="text"] {
  width: 14rem;
  max-width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

/* Maps.
 *
 * Leaflet's own stylesheet is vendored and loaded before this one, so what is
 * here is only the frame around it: the canvas, the pins (CSS dots rather than
 * images, so nothing is fetched to draw one), and the picker. */

.map {
  margin: var(--space-5) 0;
}

.map__canvas {
  height: 60vh;
  min-height: 20rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/* The map page is the map: it takes whatever height the window has left
   under the filters, so the whole of it is in view without scrolling. The
   page becomes a column the height of the window, and the map grows into
   the space the header and filters leave. Leaflet follows the window
   as it is resized. */
body:has(.collection--map) {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

.collection--map {
  display: flex;
  flex: 1;
  flex-direction: column;
  width: 100%;
  padding-bottom: var(--space-4);
}

.collection--map .map {
  display: flex;
  flex: 1;
  flex-direction: column;
  /* The filters above already keep their distance. */
  margin: 0;
}

.collection--map .map__canvas {
  flex: 1;
  height: auto;
}

.map--picker .map__canvas {
  height: 18rem;
  min-height: 0;
}

.map__status {
  margin: var(--space-2) 0 0;
  color: var(--ink-quiet);
}

.map-pin {
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--surface);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.4);
}

.map-pin--chosen {
  background: var(--alert);
}

/* Leaflet paints its controls, popups, and attribution pure white whatever
   the page theme; these put them on the theme's own surface and ink. Scoped
   to the map element so they win whichever stylesheet loads last: Turbo
   appends Leaflet's after this one when a map page is reached by a visit. */
.map__canvas.leaflet-container .leaflet-bar a,
.map__canvas.leaflet-container .leaflet-popup-content-wrapper,
.map__canvas.leaflet-container .leaflet-popup-tip {
  background: var(--surface);
  color: var(--ink);
}

.map__canvas.leaflet-container .leaflet-bar a {
  border-bottom-color: var(--line);
}

.map__canvas.leaflet-container .leaflet-bar a:hover {
  background: var(--page);
}

.map__canvas.leaflet-container .leaflet-control-attribution {
  background: color-mix(in srgb, var(--surface) 85%, transparent);
  color: var(--ink-quiet);
}

.map__canvas.leaflet-container a.leaflet-popup-close-button {
  color: var(--ink-quiet);
}

.leaflet-popup-content .map-popup {
  color: var(--ink);
  display: grid;
  gap: var(--space-1);
}

.leaflet-popup-content .map-popup p {
  margin: 0;
}

.location__lookup {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.location__lookup input {
  flex: 1;
}

.location__results {
  margin: var(--space-2) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-1);
}

.location__results button {
  text-align: left;
  width: 100%;
}

.location__status:empty {
  display: none;
}
