.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

/* The city field carries the perimeter line beneath its input — a sentence
   rather than a control, which reads better with a little more air than a
   label needs. */
.field--city {
  gap: var(--space-2xs);
}

/* A label short enough to sit beside its control instead of above it. The DPE
   scale is one line of colour; a label on its own line above would give it the
   weight of a section. */
.field--inline {
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

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

.field__hint {
  font-size: var(--text-xs);
  color: var(--color-text-soft);
}

.field__control {
  position: relative;
}

.field__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

/* Two labelled fields sharing a line rather than two controls of one field.
   They need more air between them than the row's own gap, or the four things
   run together as a single strip of boxes. */
.field__row--split {
  gap: var(--space-lg);
}

/* Inputs share the row and wrap rather than overflow the panel. */
.field__row > .input {
  flex: 1 1 8rem;
  min-width: 0;
}

/* Tinted and lightly outlined rather than white-on-white with a hard border:
   the fill is what separates one field from the next, so the border can be
   quiet. Focus reverses the pair — the field turns white and the border goes
   blue — which makes the active one the brightest thing in the column. */
.input {
  width: 100%;
  padding: 9px var(--space-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-field);
  font-size: var(--text-md);
  outline: none;
}

.input::placeholder {
  color: var(--color-text-faint);
}

.input:hover {
  border-color: var(--color-border-strong);
}

.input:focus,
.input:focus-within {
  border-color: var(--color-focus);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 3px rgb(37 99 235 / 0.12);
}

/* Six digits, read back at a glance and retyped from an email. Spaced and
   centred so a transposition is visible before it is submitted. */
.input--code {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.4em;
  text-align: center;
  /* The tracking is applied after each character, including the last, which
     would push the whole string off-centre to the left. */
  text-indent: 0.4em;
}

.input--select {
  flex: 0 0 auto;
  width: auto;
  min-width: 6rem;
  cursor: pointer;
}

/* Both of these size themselves rather than share the row out, and both have
   to out-specify `.field__row > .input` below to do it. */
.field__row > .input--select,
.field__row > .input--area {
  flex: 0 0 auto;
}

/* A unit glued to the right of a number field, e.g. "847 m²" */
.input--suffix {
  display: flex;
  align-items: center;
  gap: var(--space-3xs);
}

.input__field {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  outline: none;
  font-variant-numeric: tabular-nums;
}

/* A surface is five digits at most. Sized to the number rather than to the
   row, so the tolerance beside it stays beside it instead of being flung to
   the far edge of the panel. */
.input--area {
  width: 120px;
}

.input__suffix {
  color: var(--color-text-faint);
  font-size: var(--text-sm);
}

/* 16px, and not a fraction less, wherever the keyboard is drawn on the screen:
   under that, iOS zooms the whole page in when a field takes focus, and a zoomed
   page is one with its header cropped and its right-hand edge somewhere off to
   the side. Nothing else grows — a field is where the typing happens, so it can
   carry the extra half point on its own, and the code field above is bigger
   still and stays that way.
   The area boxes hand back a little of the width the larger type costs them, or
   the two surfaces stop sharing their line on a phone that could just fit them.
   Four pixels is all they can spare: five digits and a unit is what they are
   sized for, and at 16px that is what is left. */
@media (max-width: 52rem) {
  .input:not(.input--code) {
    font-size: 1rem;
  }

  .input--area {
    width: 116px;
  }
}

textarea.input {
  resize: vertical;
}

.autocomplete {
  position: absolute;
  z-index: 20;
  inset-inline: 0;
  top: calc(100% + var(--space-3xs));
  max-height: 15rem;
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-md);
}

.autocomplete[hidden] {
  display: none;
}

.autocomplete__item {
  padding: var(--space-xs) var(--space-sm);
  font-size: var(--text-md);
  cursor: pointer;
}

.autocomplete__item:hover,
.autocomplete__item.is-active {
  background-color: var(--color-land-soft);
}

/* A labelled input inside a row of several. */
.subfield {
  display: flex;
  flex: 1 1 8rem;
  flex-direction: column;
  gap: var(--space-4xs);
  min-width: 0;
}

/* Smaller than a field label, but not fainter: what it names is filled in as
   often as anything else on the form, and grey-on-white at 12 px was reading
   as a caption on the field above rather than as the name of the one below. */
.subfield__label {
  color: var(--color-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

/* Says what a label cannot, above the box rather than under it: below, it would
   come between the tag field and the suggestions that fill it. */
.subfield__hint {
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  line-height: 1.35;
}

.rating {
  border: none;
  padding: 0;
}

.rating__legend {
  padding: 0;
  color: var(--color-text-soft);
  font-size: var(--text-xs);
}

.rating__stars {
  /* Anchors the hidden radios below. Without it their containing block is the
     page itself, so giving one focus scrolls the whole view to the top. */
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-4xs);
  padding-top: var(--space-4xs);
}

.rating__input,
.rating__none {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.rating__star {
  color: var(--color-border-strong);
  font-size: 1.375rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.1s ease;
}

/* A star lights up when it is the chosen one, or when the chosen one comes
   after it. One rule, in one direction — nothing to out-specify. */
.rating__input:checked + .rating__star,
.rating__star:has(~ .rating__input:checked) {
  color: #f59e0b;
}

/* Hovering previews a value: clear the row, then light up to the pointer.
   Keyed on a star being pointed at rather than on the row, which the clear
   button shares: pointing at it was draining the colour out of a note it has
   not removed yet, so the row went grey before the click that empties it. */
.rating__stars:has(.rating__star:hover) .rating__star {
  color: var(--color-border-strong);
}

.rating__stars:has(.rating__star:hover) .rating__star:hover,
.rating__stars:has(.rating__star:hover) .rating__star:has(~ .rating__star:hover) {
  color: #f59e0b;
}

.rating__clear {
  margin-left: var(--space-2xs);
  color: var(--color-text-faint);
  font-size: var(--text-md);
  line-height: 1;
  cursor: pointer;
}

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



.tag-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4xs);
  padding-top: var(--space-4xs);
}

.tag-suggestion {
  padding: var(--space-4xs) var(--space-xs);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background-color: var(--color-surface);
  color: var(--color-text-soft);
  font-size: var(--text-xs);
}

.tag-suggestion:hover {
  border-color: var(--color-border-strong);
}

.tag-suggestion.is-active {
  border-color: var(--color-primary);
  background-color: var(--color-primary);
  color: #fff;
}

/* The energy scale as swatches. A <select> paints its options with the
   operating system's brush, so the colours everyone reads off a listing could
   never appear in it. */
.dpe-picker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  padding: 0;
  border: none;
}

.dpe-picker__option {
  cursor: pointer;
}

.dpe-picker__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Scoped to the picker so it outranks `.dpe`, which sizes the same swatch for
   the listings — a smaller badge, in a file the bundle loads after this one. */
.dpe-picker .dpe-picker__swatch {
  width: 30px;
  height: 30px;
}

.dpe-picker__swatch {
  display: inline-grid;
  place-items: center;
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  transition: border-color 0.12s ease, opacity 0.12s ease;
}

/* "No preference" is the answer seven times out of eight, so it is set apart
   from the scale rather than dropped into it: a denser grey, its own bit of
   space, and never faded — there is nothing to recede behind. */
.dpe-picker__swatch--any {
  background-color: #eef0f3;
  color: var(--color-text-soft);
  margin-right: var(--space-3xs);
}

/* Unpicked letters stay legible but recede, so the chosen one reads first. */
.dpe-picker__input:not(:checked) + .dpe-picker__swatch:not(.dpe-picker__swatch--any) {
  opacity: 0.45;
}

.dpe-picker__option:hover .dpe-picker__swatch {
  opacity: 1;
}

.dpe-picker__input:checked + .dpe-picker__swatch {
  border-color: var(--color-text);
}

.dpe-picker__input:focus-visible + .dpe-picker__swatch {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* Present to screen readers, absent from the page. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}
