.panel__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* The three faces of the panel — the form, its answer, the addresses kept from
   every answer before it — behind one row of tabs at the top of the panel. */
.panes {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.panes .tabs {
  padding-inline: var(--space-md);
}

/* Chaque volet fait son propre défilement, et la rangée d'onglets, restée en
   dehors, ne quitte jamais l'écran : au fond d'une liste de candidats, les
   deux autres volets demeurent à un clic. C'est aussi ce qui dispense les
   barres épinglées des volets — filtres, communes — de compter sa hauteur. */
.pane {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.pane[hidden] {
  display: none;
}

/* The form brings its own padding; the two lists are inset from the panel edge
   so their rows can carry a border of their own. Rien au-dessus : un padding
   haut sur le volet qui défile décalerait d'autant la ligne d'épinglage des
   barres sticky, et une bande de contenu passerait entre elles et les onglets.
   La respiration en tête de liste appartient au premier élément — au récap. */
.pane--list {
  padding: 0 var(--space-xs) var(--space-xl);
}

/* Turbo marks the frame busy while a search is being replayed. The cadastre
   takes a second or two to read, and a panel that sits there unchanged reads
   as a click that missed. */
.panel__body[aria-busy="true"] {
  opacity: 0.55;
}

/* Tighter than a page form: now that each field is tinted, the fill does the
   separating and the gap no longer has to. Closing it up buys the results a
   line or two at the bottom of the panel. */
.search-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-md);
  border-bottom: 1px solid var(--color-border);
}

/* Sous le bouton de recherche, au centre et sans largeur : un geste
   d'entretien, pas une action du même rang que chercher. Le gap du
   formulaire l'espacerait comme un champ ; recollé au bouton. */
.search-form__reset {
  align-self: center;
  margin-top: calc(-1 * var(--space-2xs));
  color: var(--color-text-soft);
}

/* The perimeter of the search, told as a sentence under the city rather than
   folded away at the foot of the form. Stated even when nothing is restricted:
   "toute la commune" is an answer, and the old disclosure never gave it. */
.zone {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 0 2px;
  color: var(--color-text-soft);
  font-size: var(--text-xs);
}

.zone__value {
  color: var(--color-text);
  font-weight: var(--weight-semibold);
}

.zone__action {
  margin-left: auto;
  color: var(--color-land);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.zone__action:hover {
  text-decoration: underline;
}

/* A point on the map means nothing until the map has flown to a commune, so
   the offer waits for the city field. */
.zone__action[disabled] {
  color: #bcc2cb;
  cursor: not-allowed;
  text-decoration: none;
}

/* Restricted: the sentence gives way to a box holding the three things that
   make up a neighbourhood — the point, how to move it, and how far around it.
   In that order, which is the order they are chosen in. */
.zone--active {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-xs);
  padding: 9px var(--space-sm);
  border: 1px solid #bfdbfe;
  border-radius: var(--radius-md);
  background-color: var(--color-land-soft);
}

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

.zone__dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background-color: var(--color-land);
}

.zone__label {
  flex: 1;
  color: var(--color-text);
}

.zone__clear {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}

.zone__clear:hover {
  color: var(--color-danger);
}

.zone__hint {
  color: var(--color-text-soft);
  font-size: 11px;
}

.zone__radii {
  display: flex;
  gap: var(--space-3xs);
}

.zone__radius {
  flex: 1;
  padding: 5px 0;
  border: 1px solid #dbe4f5;
  border-radius: 8px;
  background-color: var(--color-surface);
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  text-align: center;
}

.zone__radius[aria-pressed="true"] {
  border-color: var(--color-primary);
  background-color: var(--color-primary);
  color: #fff;
  font-weight: var(--weight-semibold);
}

/* What was asked, at the head of what it answered: one line of criteria and the
   way back to the form holding them. A card rather than a bar, because it sits
   inside the results list and reads as its heading, not as a second toolbar. */
.recap {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-block: var(--space-2xs);
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  /* Tinted, unlike the form it summarises: a search in hand is a state, and the
     panel should say so before anything is read. */
  background-color: var(--color-surface-sunken);
}

.recap__search {
  min-width: 0;
  flex: 1;
}

/* A button, because the town recentres the map — see searches/_recap. It reads
   as the heading it replaced: the reset already hands it the panel's font, so
   only the button's own padding and centring have to go. Sized to its own text
   rather than to the card — a button as wide as the line would take the click
   from half a centimetre past the name — and clipped like the criteria under
   it, since a commune whose name runs long must not wrap the card open. */
.recap__city {
  display: block;
  overflow: hidden;
  width: fit-content;
  max-width: 100%;
  padding: 0;
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  line-height: 1.3;
  white-space: nowrap;
  text-align: left;
  text-overflow: ellipsis;
}

.recap__city:hover {
  color: var(--color-land);
  text-decoration: underline;
}

/* One line, clipped rather than wrapped: the block's height is what buys the
   results their room, and a fifth criterion must not spend it. Text flow rather
   than a flex row, so the overflow falls off the end — a row of flex items
   shrinks them all, and six half-ellipsed figures say less than three whole
   ones followed by a "…". */
.recap__criteria {
  overflow: hidden;
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Separated by a dot rather than a space alone — the figures are all numbers
   and units, and run together otherwise. */
.recap__figure + .recap__figure::before {
  content: "· ";
}

/* Smaller than in the list, where the letter is the thing being compared. Here
   it sits in a line of small print and should not set that line's height. */
.recap__criteria .dpe {
  width: 1.125rem;
  height: 1.125rem;
}

/* L'annonce, sous les critères qu'on y a lus — voir searches/_recap. Décollée
   d'un cheveu seulement : c'est la même petite ligne grise, et un vrai blanc
   entre les deux ferait deux blocs là où il n'y a qu'une origine et ses
   chiffres. */
.recap__search .listing-link {
  margin-top: var(--space-3xs);
}

.recap__edit {
  flex: 0 0 auto;
}

/* The ghost button hovers to the sunken grey, which is the colour of the bar it
   sits on — so here it lifts to white instead of vanishing into it. */
.recap__edit:hover {
  --btn-background: var(--color-surface);
}

/* The pencil takes the small button's type size rather than the component's
   default, which was drawn for a full-size label. */
.recap__edit .btn__icon {
  width: 0.9375rem;
  height: 0.9375rem;
}

.search-form__errors {
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-md);
  background-color: var(--color-building-soft);
  color: var(--color-danger);
  font-size: var(--text-sm);
}

/* The searches either side of this one, walked one at a time. Under the recap
   because it moves between recaps: the criteria above are what change when an
   arrow is pressed. */
.replay {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 0 var(--space-3xs) var(--space-xs);
}

.replay__step {
  padding: 1px var(--space-xs) 3px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  color: var(--color-text);
  font-size: var(--text-sm);
  line-height: 1.2;
  text-decoration: none;
}

.replay__step:hover {
  border-color: var(--color-border-strong);
  background-color: var(--color-surface-sunken);
}

/* Kept on the screen at the ends of the list rather than taken off it: an arrow
   that disappears moves the other one under the pointer. */
.replay__step--spent {
  color: #bcc2cb;
  cursor: not-allowed;
}

.replay__position {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}

.replay__age {
  white-space: nowrap;
}

.results__note {
  padding: var(--space-xs) var(--space-sm);
  margin-bottom: var(--space-xs);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-sunken);
  color: var(--color-text-soft);
  font-size: var(--text-xs);
}

.results__empty {
  padding: var(--space-md) var(--space-sm);
  color: var(--color-text-soft);
  font-size: var(--text-sm);
}

/* The plots a diagnosis vouches for and the terrain contradicts. Below a rule
   and under their own heading, never blended into the list above: that list
   answers everything that was asked and this one does not, and a reader
   scanning it quickly must not be able to take one for the other. */
.partials {
  margin-top: var(--space-lg);
  padding-top: var(--space-xs);
  border-top: 1px solid var(--color-border);
}

.partials__title {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-sm);
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.partials__count {
  padding: 0 var(--space-2xs);
  border-radius: var(--radius-full);
  background-color: var(--color-surface-sunken);
  font-variant-numeric: tabular-nums;
  letter-spacing: normal;
}

.partials__note {
  padding: 0 var(--space-sm) var(--space-xs);
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}

/* The searches already run, under the form that would run them again. Reopening
   one is free, and the list is where that is said — so it is a list of offers,
   not a log: every row is a target, and the whole block reads at a glance. */
.history {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-md) var(--space-xl);
}

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

.history__title {
  flex: 1;
  color: var(--color-text-faint);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.history__note {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}

.history__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  list-style: none;
}

.history__row {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-sunken);
  transition: background-color 0.12s ease, border-color 0.12s ease;
}

/* Hover and the row already on screen read alike, as they do in the parcel
   list: one is where the pointer is, the other where the panel is, and both
   mean "this one". Marked rather than dropped from the list — a list that
   reshuffles under the pointer is a list you cannot aim at. */
/* A row reached by keyboard joins them: the outline sits on the label alone,
   which is a poor answer to "where am I" in a list of ten. */
.history__row:hover,
.history__row.is-current,
.history__row:has(.history__replay:focus-visible) {
  border-color: var(--color-land);
  background-color: var(--color-land-soft);
}

/* The link that reopens the search is the row. It carries the label, and its
   overlay covers everything beside it — criteria, age, and the gaps between —
   so the whole box stays one target, as it was when the row itself was an
   anchor. Only the listing below lifts itself back out. */
.history__replay {
  color: inherit;
  text-decoration: none;
}

.history__replay::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-md);
}

.history__what {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.history__label {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

/* One line, clipped: what a search of the same town differs on comes first, and
   a fourth criterion must not push the row into two lines. */
.history__criteria {
  overflow: hidden;
  color: var(--color-text-faint);
  font-size: var(--text-xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* The line under the criteria, holding whatever leads out of the row: the
   advert, and the badge for the addresses kept from this search. They wrap
   rather than squeeze — on a phone the two together leave the advert seventy
   pixels, which is enough for the site and nothing of the reference at the end,
   and the reference is the whole reason the advert is printed. */
.history__leads {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3xs) var(--space-2xs);
  min-width: 0;
  margin-top: 2px;
}

/* The advert the search was run from is `.listing-link`, the block the ledger
   prints too — see components/listing-link.css. */

/* The right-hand column: how many parcels answered, then how long ago. Stacked
   and right-aligned so the figures line up down the list — reading that column
   alone tells you which evening's search was the one that narrowed. */
.history__meta {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  text-align: right;
}

/* The count reads before the age it sits above: it is the reason the row is
   worth reopening, and the age only says when. */
.history__count {
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A search that came back with nothing is still worth printing — it is what
   stops you reopening it a second time — but it is not worth reading first, so
   it recedes to the weight of the date beside it. */
.history__count--none {
  color: var(--color-text-faint);
  font-weight: var(--weight-regular);
}

.history__when {
  flex: 0 0 auto;
  color: var(--color-text-faint);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.saved-group {
  margin-bottom: var(--space-md);
}

/* Sticks under the filter bar, whose height the controller publishes, so the
   commune you are looking at stays named while you scroll through it. */
.saved-group__title {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-sm);
  position: sticky;
  top: var(--filters-height, 0px);
  z-index: 2;
  border-bottom: 1px solid var(--color-border);
  background-color: var(--color-surface);
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.saved-group__count {
  padding: 0 var(--space-2xs);
  border-radius: var(--radius-full);
  background-color: var(--color-surface-sunken);
  font-variant-numeric: tabular-nums;
  letter-spacing: normal;
}

/* Filtering the saved addresses, kept at the top of the panel. */
.filters {
  position: sticky;
  top: 0;
  z-index: 4;
  padding: var(--space-xs) var(--space-sm);
  border-bottom: 1px solid var(--color-border);
  background-color: var(--color-surface);
}

.filters__count {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.filters__reset {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}

.filters__reset:hover {
  color: var(--color-danger);
  text-decoration: underline;
}

.saved-group[hidden] {
  display: none;
}


.saved-group__city {
  padding: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.saved-group__city:hover {
  color: var(--color-land);
  text-decoration: underline;
}
