/*
 * Plegoo Search layout.
 *
 * The query is the primary object, so the interface is arranged around it: on the results page
 * the header is a thin bar and everything below it is results. There are no cards, no shadows,
 * no gradients and no decorative panels, because on a search page the only things worth the
 * user's attention are the query, the results, and the way to change either.
 *
 * Every colour here is a token from tokens.css. Nothing in this file names a raw colour, which
 * is what lets the dark theme be a second set of meanings rather than an inversion.
 */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* The OS theme is the only theme source; nothing is stored or scripted. */
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.5;
  /* Long URLs and unbroken tokens wrap rather than forcing a horizontal scrollbar. */
  overflow-wrap: break-word;
}

a {
  color: var(--color-accent);
  text-decoration: none;
}

a:hover {
  color: var(--color-accent-hover);
  text-decoration: underline;
}

/* One focus treatment for the whole product, always visible, never hue-only. */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* THE RING FOLLOWS THE WORDS, NOT THE 44px BOX
 *
 * A target that reaches 44px through padding has that padding above and below the text: 10px
 * on a result title, 14px on a footer link. Drawing the ring around the 44px box leaves it
 * floating 10 to 14px away from the words it is announcing, and where the padding reaches a
 * neighbouring line the ring strikes through that line - a focus indicator that obscures the
 * page is a focus indicator that hides the thing it is pointing at.
 *
 * So the ring is pulled back in by the padding the target itself added, and by nothing more:
 * each offset below is the target's own vertical padding less 2px, so the ring sits 2px
 * outside the text and never inside it. The area that answers to a press is unchanged at 44px,
 * because `outline-offset` moves the indicator and not the box.
 */
.result__title a:focus-visible {
  outline-offset: -8px;
}

.footer a:focus-visible,
.home__supporting a:focus-visible,
.header__nav a:focus-visible {
  outline-offset: -12px;
}

/* The clear affordance's glyph is 28px inside a 44px target, so the same 8px of padding, less
   2px. The ring lands on the circle rather than around the empty margin. */
.searchfield__clear:focus-visible {
  outline-offset: -6px;
}

/* The chips that grew to 44px rather than being padded out to it take the ring inside the box,
   so the indicator follows the pill's own border instead of hanging off the edge of it. */
.searchfield__submit:focus-visible,
.filters__item:focus-visible,
.result__action:focus-visible,
.button:focus-visible {
  outline-offset: -2px;
}

/* THE HIT AREA, AND HOW A COMPACT DESIGN PAYS FOR IT
 *
 * Every interactive target below reaches 44x44 CSS px. Where the target is a painted control -
 * a button with a background, a bordered chip - the control itself grows, and that is the one
 * place the interface gives up a little air. Where the target is text sitting in a line, the
 * type does not move at all: the extra pixels are padding on the target, and the padding is
 * handed straight back to the flow with a matching negative margin, so the line box, the row
 * and the surrounding spacing are byte-for-byte what they were before.
 *
 * That is the whole technique. A 44px target on a compact design is bought with padding and
 * with hit area; it is never bought by making the design bigger, and no type size, weight,
 * colour or radius in this file moves to pay for it.
 */

/* Visible to a screen reader, invisible on screen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: var(--space-2);
  top: var(--space-2);
  z-index: 10;
  display: inline-flex;
  align-items: center;
  min-width: var(--target-min);
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface);
  color: var(--color-text);
  border: var(--border-hairline) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transform: translateY(-200%);
}

/* `:focus` rather than `:focus-visible`, deliberately. A skip link only exists for a keyboard
 * user, so the state that brings it back has to be the one the browser is certain about: on a
 * browser whose heuristics ever decided this link was not a keyboard target, the link would
 * stay off-screen with the focus ring drawn around nothing. */
.skip-link:focus {
  transform: translateY(0);
}

/* ---------------------------------------------------------------- brand */

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  /* The wordmark is 30px of type in a 44px row. The row was already this tall - the search
     field beside it is - so the hit area costs the header nothing at all. */
  min-width: var(--target-min);
  min-height: var(--target-min);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--color-text);
  flex: none;
}

.brand:hover {
  color: var(--color-text);
  text-decoration: none;
}

/* The mark is Plegoo's own: a ring with a lens, drawn in CSS, no copied asset. */
.brand__mark {
  width: 22px;
  height: 22px;
  flex: none;
  color: var(--color-accent);
}

/* ---------------------------------------------------------------- home */

.home {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(3rem, 14vh, 8rem) var(--space-4) var(--space-6);
  min-height: 100dvh;
  box-sizing: border-box;
}

.home__inner {
  width: 100%;
  max-width: 34rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
}

/* The home page's heading, and it is the wordmark.
 *
 * The mark and the word were already the largest thing on this page, at 2rem and semibold, in
 * the middle of the column. Turning that same lockup into the page's <h1> costs the layout
 * nothing: the same 48px line, the same 22px ring, the same accent, the same place. The
 * difference is that it is a heading rather than a link to the page you are on, which is what
 * it always was - a link from the home page to the home page, which is not a destination
 * anyone was ever going to need.
 */
.home__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: 2rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

.home__title__mark {
  width: 22px;
  height: 22px;
  flex: none;
  color: var(--color-accent);
}

.home__form {
  width: 100%;
}

.home__supporting {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2) var(--space-4);
  font-size: var(--text-metadata);
  color: var(--color-text-tertiary);
}

.home__note {
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  text-align: center;
  max-width: 30rem;
}

/* ---------------------------------------------------------------- search field */

/* The form is the row: the field takes the remaining width and the submit button sits beside
   it. Without this the button is a block sibling of the field and wraps onto its own line,
   which turns a one-line search header into two and puts the primary action under the input. */
.searchfield-form {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
}

.searchfield-form .searchfield {
  flex: 1 1 auto;
  min-width: 0;
}

.searchfield-form .searchfield__submit {
  flex: none;
}

.searchfield {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: 0 var(--space-2) 0 var(--space-3);
  background: var(--color-surface);
  border: var(--border-hairline) solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  transition: border-color var(--duration-fast) var(--easing-standard);
}

.searchfield:hover {
  border-color: var(--color-text-tertiary);
}

.searchfield:focus-within {
  border-color: var(--color-accent);
  /* The inner ring is what actually reads as focus; the border colour reinforces it. */
  box-shadow: 0 0 0 3px var(--color-selected-bg);
}

.searchfield__icon {
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--color-text-tertiary);
}

.searchfield__input {
  flex: 1 1 auto;
  /* The floor, not the `0` a flex item normally carries. `min-width: 0` is what lets a field
     shrink below its intrinsic width, and 44px is far below the width of any column this
     interface puts one in - the narrowest is 320px of viewport - so the field still shrinks as
     far as it needs to and then stops at a target a finger can hit. */
  min-width: var(--target-min);
  /* 44px of field. The padding below is what produced 42.5px, and the padding is not reduced
     to get back under the floor: the floor is a floor. */
  min-height: var(--target-min);
  padding: 0.625rem 0;
  font: inherit;
  font-size: var(--text-body);
  color: var(--color-text);
  background: transparent;
  border: 0;
}

.searchfield__input:focus {
  outline: none;
}

.searchfield__input::placeholder {
  color: var(--color-text-tertiary);
}

/* The clear affordance is a 28px circle inside the pill, and it stays 28px.
 *
 * A 44px circle in a 46px pill is not a clearer affordance, it is a grey disc. So the painted
 * circle keeps its size and the *hit area* grows instead: `content-box` puts the 8px of
 * padding outside the 28px the icon is drawn in, and the matching -8px margin hands those same
 * 16 pixels straight back to the row, so the pill is exactly as tall as it was. The target
 * measures 44x44; the design does not move.
 */
.searchfield__clear {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: content-box;
  width: 28px;
  height: 28px;
  padding: 8px;
  margin: -8px;
  color: var(--color-text-tertiary);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--easing-standard);
}

.searchfield__clear:hover {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

.searchfield__submit {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* The primary action reaches the floor too. This is the one control whose painted box does
     grow, and it grows into a row that is already this tall: the field beside it is 44px, so
     the row was never sized by this button and still is not. */
  min-width: var(--target-min);
  min-height: var(--target-min);
  padding: 0.5rem 1rem;
  font: inherit;
  font-size: var(--text-metadata);
  font-weight: 500;
  color: var(--color-accent-contrast);
  background: var(--color-accent);
  border: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--easing-standard);
}

.searchfield__submit:hover {
  background: var(--color-accent-hover);
}

.searchfield__submit:disabled {
  cursor: default;
  opacity: 0.6;
}

/* The application root, sized before the module runs.
 *
 * This was an inline <style> block in the shell. The server sends style-src 'self', so the
 * page's own policy refused it: every load logged a blocked-inline-style error and the rule
 * never applied. A render-blocking <link> in the head is parsed before the first paint, so
 * stating it here keeps the property the rule existed for - an empty #app cannot collapse the
 * page to a white flash - without asking the security control to make an exception.
 */
#app {
  min-height: 100dvh;
}

/* ---------------------------------------------------------------- results page */

.page {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.header {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-bg);
  border-bottom: var(--border-hairline) solid var(--color-border);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  max-width: var(--measure-page);
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
}

.header__form {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 36rem;
}

.header__nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-left: auto;
  font-size: var(--text-metadata);
  color: var(--color-text-secondary);
}

/* ---------------------------------------------------------------- controls */

.filters {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  /* An explicit width, because this element is a flex item in a column container and
     `overflow-x: auto` alone does not constrain it: without a width it sized itself to its
     content and pushed the whole page wider than a phone viewport, so the category bar scrolled
     the document instead of scrolling itself. */
  width: 100%;
  max-width: var(--measure-page);
  margin: 0 auto;
  /* 2px of vertical padding, not 8. The chips below are 44px tall so that a fingertip lands on
     one, and the padding here is what gives that height back: the bar is 49px tall, which is
     the 48px it has always been. The space did not appear; it moved from the outside of the
     bar to the inside of the chips, which is where a finger is going to be. */
  padding: 0.125rem var(--space-4);
  border-bottom: var(--border-hairline) solid var(--color-border);
  overflow-x: auto;
  scrollbar-width: thin;
}

.filters__label {
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-tertiary);
  margin-right: var(--space-2);
  flex: none;
}

.filters__item {
  flex: none;
  /* 44x44, and "All" is the reason the width is there: the label is 42px, so a chip only ever
     as wide as its word was 1.9px short of the floor on the one control a person is most
     likely to tap. */
  min-width: var(--target-min);
  min-height: var(--target-min);
  padding: 0.3125rem 0.75rem;
  font: inherit;
  font-size: var(--text-metadata);
  color: var(--color-text-secondary);
  background: transparent;
  border: var(--border-hairline) solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--duration-fast) var(--easing-standard);
}

.filters__item:hover:not(:disabled) {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

.filters__item[aria-current="true"] {
  color: var(--color-accent);
  background: var(--color-selected-bg);
  border-color: var(--color-accent);
  font-weight: 500;
}

/* A filter with no backend is visibly unavailable, so it cannot be mistaken for working. */
.filters__item:disabled {
  cursor: not-allowed;
  color: var(--color-text-tertiary);
  opacity: 0.7;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.results {
  flex: 1 1 auto;
  width: 100%;
  max-width: var(--measure-page);
  margin: 0 auto;
  padding: 0 var(--space-4) var(--space-7);
}

/* The results page's heading: the page is about one query, and it says so.
 *
 * Not a banner. It is the same type as a result title, because a page of results and the
 * first result are the same kind of thing, and it sits directly above the count line rather
 * than in a panel of its own. The count keeps its own hairline and its own muted weight, so
 * the heading and the count read as two different jobs: what this page is, and how much is in
 * it. */
.results__title {
  margin: 0;
  /* The horizontal padding is not decoration: it is what puts the heading on the same measure
     as the count line and the result titles under it, which the results component insets by
     its own --space-4 inside this region. Without it the page's heading would sit 16px to the
     left of the first thing it is a heading for. */
  padding: var(--space-3) var(--space-4) 0;
  font-size: var(--text-result-title);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

.results__count {
  margin: 0;
  padding: var(--space-2) 0 var(--space-3);
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  border-bottom: var(--border-hairline) solid var(--color-border);
}

/* ---------------------------------------------------------------- result */

.result {
  padding: var(--space-4) 0;
  border-bottom: var(--border-hairline) solid var(--color-border);
}

.result:last-child {
  border-bottom: 0;
}

.result__source {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
  font-size: var(--text-metadata);
  color: var(--color-text-tertiary);
}

.result__favicon {
  width: 16px;
  height: 16px;
  flex: none;
  border-radius: var(--radius-sm);
  background: var(--color-surface-hover);
  border: var(--border-hairline) solid var(--color-border);
}

.result__domain {
  color: var(--color-text-secondary);
  /* A long domain truncates rather than pushing the layout wide. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.result__url {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  overflow-wrap: anywhere;
}

.result__title {
  margin: 0 0 var(--space-1);
  font-size: var(--text-result-title);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

/* The result title is the primary action of this page and the largest target on it.
 *
 * `inline-block` rather than `inline` for one reason: min-width does not apply to an inline
 * box, and a one-word title has to reach the same 44px as a long one. The long title still
 * wraps exactly as it did - the box shrinks to the column and the words break inside it - so
 * this is the hit area changing and not the line breaking. The padding is 10px top and bottom
 * and the margin is the same 10px back, so the line box is unchanged and the target is 44.7px
 * tall: the pressable area reaches 10px above and below the text and nothing on screen moves.
 */
.result__title a {
  display: inline-block;
  min-width: var(--target-min);
  min-height: var(--target-min);
  padding: 0.625rem 0;
  margin: -0.625rem 0;
  color: var(--color-accent);
}

.result__snippet {
  margin: 0;
  max-width: var(--measure-result);
  font-size: var(--text-body);
  color: var(--color-text-secondary);
  /* A long snippet is clamped, so one verbose result cannot push the rest off screen. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.result__snippet--missing {
  color: var(--color-text-tertiary);
  font-style: italic;
}

.result__type {
  align-self: center;
  padding: 0.0625rem 0.4375rem;
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-sm);
  flex: none;
}

/* Secondary actions stay hidden until the result is engaged, so the primary
   action is the only thing competing for attention. */
.result__actions {
  display: flex;
  gap: var(--space-1);
  margin-top: var(--space-2);
  /* The row's height is 44px once the buttons reach the floor, and the result's own bottom
     padding is 16px. Handing that 16px back here means every result is exactly as tall as it
     was before the targets grew: the button is drawn 44px tall, starting at the top of the
     row, and reaches exactly as far as the rule above the next result. */
  margin-bottom: calc(-1 * var(--space-4));
  opacity: 0;
  transition: opacity var(--duration-fast) var(--easing-standard);
}

.result:hover .result__actions,
.result:focus-within .result__actions {
  opacity: 1;
}

@media (hover: none) {
  /* Touch devices have no hover, so the actions are simply always present. */
  .result__actions {
    opacity: 1;
  }
}

.result__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--target-min);
  min-height: var(--target-min);
  padding: 0.25rem 0.5rem;
  font: inherit;
  font-size: var(--text-caption);
  color: var(--color-text-secondary);
  background: transparent;
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.result__action:hover {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

/* ---------------------------------------------------------------- status, empty, error */

.status {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-6) 0;
  color: var(--color-text-secondary);
  font-size: var(--text-body);
}

.status__spinner {
  width: 16px;
  height: 16px;
  flex: none;
  border: 2px solid var(--color-border-strong);
  border-top-color: var(--color-accent);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}

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

.placeholder {
  padding: var(--space-7) 0;
  text-align: center;
}

.placeholder__title {
  margin: 0 0 var(--space-2);
  font-size: 1.125rem;
  font-weight: 500;
}

.placeholder__body {
  margin: 0 auto;
  max-width: 28rem;
  color: var(--color-text-secondary);
  font-size: var(--text-body);
}

.placeholder__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--target-min);
  min-width: var(--target-min);
  padding: 0.4375rem 0.875rem;
  font: inherit;
  font-size: var(--text-metadata);
  font-weight: 500;
  color: var(--color-text);
  background: var(--color-surface);
  border: var(--border-hairline) solid var(--color-border-strong);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--easing-standard);
}

.button:hover {
  background: var(--color-surface-hover);
}

.button--primary {
  color: var(--color-accent-contrast);
  background: var(--color-accent);
  border-color: var(--color-accent);
}

.button--primary:hover {
  background: var(--color-accent-hover);
}
/* ---------------------------------------------------------------- footer */

.footer {
  max-width: var(--measure-page);
  margin: 0 auto;
  padding: var(--space-4);
  border-top: var(--border-hairline) solid var(--color-border);
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
}

/* TEXT LINKS REACH THE FLOOR WITHOUT MOVING.
 *
 * A link in a line of text is 16.5px of 11px type, and "Home" is 32px wide. Padding gets both
 * of those to 44: 14px above and below puts the footer link's target at 44.5px, and
 * `min-width` covers the width. The margin is the same 14px back, so the flex row is still
 * 16.5px tall and the footer's own height is untouched.
 *
 * The pressable area therefore reaches further than the text, which is what a hit area is, and
 * every one of these rows has empty space above and below it: the footer's own padding, the
 * 24px gap between the home page's supporting row and the note below it. Nothing a person
 * would have aimed at is now owned by a link instead.
 */
.footer a,
.home__supporting a,
.header__nav a {
  min-width: var(--target-min);
  min-height: var(--target-min);
  padding: 0.875rem 0;
  margin: -0.875rem 0;
}

/* ---------------------------------------------------------------- responsive */

.mobile-only {
  display: none;
}

@media (max-width: 40rem) {
  .header__inner {
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
  }

  /* On a narrow screen the brand and the field share one row rather than
     stacking, so the field stays above the fold. */
  .header__form {
    order: 3;
    flex-basis: 100%;
    max-width: none;
  }

  .header__nav {
    gap: var(--space-3);
    font-size: var(--text-caption);
  }

  .results {
    padding: 0 var(--space-3) var(--space-6);
  }

  /* The heading follows the results onto the narrower measure rather than staying on the
     desktop one and hanging 4px outside the column it heads. */
  .results__title {
    padding-left: var(--space-3);
    padding-right: var(--space-3);
  }

  .filters {
    padding: var(--space-2) var(--space-3);
  }

  .result {
    padding: var(--space-3) 0;
  }

  .result__title {
    font-size: 1.0625rem;
  }

  /* On one line at this width the source row had to truncate the domain to "exa…" and wrap the
     date onto three lines, so the row is allowed to wrap and the URL takes its own line. Which
     domain a result came from is the first thing worth reading; it should not be the first
     thing sacrificed to a date. */
  .result__source {
    flex-wrap: wrap;
    row-gap: var(--space-1);
  }

  .result__domain {
    flex: 0 1 auto;
  }

  .result__url {
    flex: 1 1 100%;
    order: 3;
  }

  .home {
    padding-top: 22vh;
  }
}

/* Touch targets: 44px is the floor, and it is not conditional.
 *
 * This used to be a `@media (pointer: coarse)` block that raised .searchfield__clear,
 * .result__action, .button and .filters__item to 44px only for a touch device, and left
 * .searchfield__input, .brand and every text link below the floor for everyone else - which is
 * how a Firefox run on a desktop found three targets short. The floor is now --target-min and
 * every control resolves it unconditionally, so the block has nothing left to say; keeping it
 * would be a second place where the size of a control is decided, and the second one is the
 * one that gets out of date. */

@media print {
  .header,
  .filters,
  .result__actions,
  .footer {
    display: none;
  }
}

/* The region that holds whichever result state is current. It owns no padding of its own: the
   state components inside it bring their own, and doubling it is what pushed the results out of
   alignment with the header. */
.results-area {
  flex: 1 1 auto;
  width: 100%;
  max-width: var(--measure-page);
  margin: 0 auto;
  padding: 0 var(--space-4) var(--space-7);
  /* A floor for the region, so the transition from loading to results does not collapse the
     page and then push it back down. Without it the results area is one line tall while a
     search is in flight and full height a moment later, which on a phone moves the footer and
     everything under the finger; on a desktop it is the visible jump people read as jank. The
     floor is deliberately modest - enough to hold the page still, not so much that a page
     with two results is padded out to look empty. */
  min-height: 60vh;
}

/* The skip link's destination, and the one place focus is drawn on a non-interactive region.
 *
 * This used to be `outline: none`, on the grounds that the region is a container rather than a
 * control. But the skip link moves focus here, and with nothing drawn the person who used the
 * skip link - the person most likely to need it - was told nothing about where they had landed.
 *
 * `:focus` rather than `:focus-visible` deliberately, because the focus arrives by fragment
 * navigation rather than by the keyboard and the browser's own heuristic for "was this a
 * keyboard interaction" is not reliable there. Nothing else can focus this element: it is not
 * tabbable, and it has no handler, so the only way focus arrives is the skip link. It is the
 * same 2px accent as every other focus ring, inset so it does not sit on top of the header.
 */
.results-area:focus {
  outline: 2px solid var(--color-focus);
  outline-offset: -2px;
  border-radius: 0;
}
