/**
 * @file
 * Site search panel.
 *
 * The exposed search form (keyword, Free / Council / Featured, genre, venue,
 * date range) was rendering permanently expanded at the top of every page —
 * roughly 400px of form above the content on Home, Hubs, Submit an event and
 * every event page.
 *
 * On the outgoing site this was a disclosure: `#search-list` toggled
 * `.search-container-wrapper` open, and a "Close" link shut it again. That
 * behaviour is restored here, with the state and keyboard handling the old
 * jQuery version never had.
 *
 * The panel is `hidden` in the markup, so with JavaScript off it does not
 * render at all and the Search menu item stays an ordinary link to the search
 * page. js/search.js removes `hidden` and upgrades the menu link into the
 * toggle.
 */

/* ---------------------------------------------------------------------------
 * The toggle in the header
 * ------------------------------------------------------------------------ */

/**
 * The Search control.
 *
 * It was an outlined pill that changed colour on hover — correct, and easy to
 * read straight past. It reads as a control you can open now: a filled surface
 * that lifts under the pointer, the magnifier picking up the accent, and a
 * pressed state while the panel is open so the button and the panel are
 * obviously the same object.
 */
.search-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-m) var(--space-2xs) var(--space-s);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-primary);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}

/**
 * The control is a LINK in the template and a button once JavaScript has
 * upgraded it — both need the same box.
 *
 * It is server-rendered now. It used to be created by js/search.js, which meant
 * it did not exist until that file had run, and on this site that is behind
 * jQuery, CKEditor 5, Select2 and the rest of Drupal's script queue: the header
 * arrived without its Search control and gained one a second or two later.
 */
a.search-toggle {
  text-decoration: none;
  cursor: pointer;
}

.search-toggle__icon {
  display: inline-flex;
  flex: none;
}

.search-toggle svg {
  transition: color var(--duration-fast) var(--ease-out);
  color: var(--me-magenta-300);
}

.search-toggle:hover {
  border-color: color-mix(in srgb, var(--me-magenta) 70%, transparent);
  background: var(--surface-3);
  color: var(--me-white);
  box-shadow: 0 6px 18px -12px var(--me-magenta);
}

/* Open: the control is filled, so it reads as the panel's handle rather than
   as another thing to press. */
.search-toggle[aria-expanded="true"] {
  border-color: var(--accent-solid);
  background: var(--accent-solid);
  color: var(--me-white);
  box-shadow: none;
}

.search-toggle[aria-expanded="true"] svg {
  color: var(--me-white);
}

.search-toggle svg {
  inline-size: 0.95rem;
  block-size: 0.95rem;
  flex: none;
}

/* Below the primary-menu breakpoint the label is dropped to a round icon. */
@media (max-width: 63.999rem) {
  /*
   * A CIRCLE NEEDS EQUAL SIDES, WHICH PADDING ALONE DOES NOT GIVE IT.
   *
   * `border-radius: 50%` makes an ellipse of whatever box it is applied to. The
   * box here was `min-block-size: var(--input-height)` (46px) tall but only as
   * wide as its padding plus a 0.95rem icon — around 32px. So it rendered as a
   * tall rounded rectangle next to the MENU pill rather than a round button.
   *
   * Both axes are set explicitly, the padding dropped, and the content centred.
   * `aspect-ratio` is belt and braces for the case where something downstream
   * stretches one axis.
   */
  .search-toggle {
    justify-content: center;
    gap: 0;
    padding: 0;
    inline-size: var(--input-height);
    block-size: var(--input-height);
    min-block-size: var(--input-height);
    aspect-ratio: 1;
    flex: none;
    border-radius: 50%;
  }

  .search-toggle__label {
    position: absolute !important;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* A primary-menu "Search" link upgraded into the toggle keeps menu styling but
   gains the pressed state. */
.menu--main .menu__link[data-me-search-toggle][aria-expanded="true"] {
  color: var(--me-magenta-300);
  background: var(--surface-2);
}

/* ---------------------------------------------------------------------------
 * The panel — a dropdown, not a drawer
 * ------------------------------------------------------------------------ */

/**
 * WHAT CHANGED
 * ------------
 * This was a full-width drawer that expanded the page: a `grid-template-rows`
 * animation from 0fr to 1fr, pushing everything below it down as it grew. It
 * behaved like an accordion, which is not what a search control should do — the
 * page moved under the visitor's cursor, and on a phone the whole viewport
 * lurched.
 *
 * It is now an ordinary dropdown. Fixed to the viewport, hung under the header
 * and aligned to the right edge of the page container so it appears to come out
 * of the Search button, it is painted over the page rather than wedged into it:
 * nothing reflows when it opens, and closing it puts nothing back.
 *
 * POSITIONING
 * -----------
 * `--header-offset` is the measured height of the sticky header, written by
 * Drupal.behaviors.mosmanHeaderHeight, so the dropdown stays attached to the
 * header whatever it contains at that width.
 *
 * The inline-end offset is the page gutter, or half the space left over beside
 * `--wrapper-max`, whichever is larger. That is precisely the box
 * `.site-header__inner` uses, so the panel's right edge and the Search button's
 * right edge line up at every width without either measuring the other.
 */
.search-panel {
  position: fixed;
  z-index: 120;
  inset-block-start: calc(var(--header-offset) + var(--space-3xs));
  inset-inline-end: max(var(--gutter), calc((100vw - var(--wrapper-max)) / 2));
  inline-size: min(40rem, calc(100vw - var(--gutter) * 2));

  /* Never taller than the space under the header; the form scrolls inside. */
  max-block-size: calc(100svh - var(--header-offset) - var(--space-l));
  overflow-y: auto;
  overscroll-behavior: contain;

  background: var(--surface-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-3, var(--shadow-2));

  /* Closed. `visibility` rather than `display` so the transition runs, and
     `pointer-events` so nothing in a closed panel can be clicked or tabbed to
     through the page above it. */
  visibility: hidden;
  opacity: 0;
  transform: translateY(-0.5rem);
  pointer-events: none;
  transition:
    opacity var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out),
    visibility 0s linear var(--duration-fast);
}

.search-panel.is-open {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition:
    opacity var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out),
    visibility 0s;
}

/**
 * The sizer and clip elements are inert now.
 *
 * They existed only to animate the drawer's height. The markup keeps them —
 * js/search.js builds it, and a site may have a cached copy — but they carry no
 * behaviour: a dropdown has a size of its own and does not need one animated
 * for it.
 */
.search-panel__sizer,
.search-panel__clip {
  display: block;
  min-block-size: 0;
  overflow: visible;
}

.search-panel__inner {
  inline-size: auto;
  margin-inline: 0;
  padding: var(--space-m);
}

.search-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2xs) var(--space-m);
  margin-block-end: var(--space-m);
  padding-block-end: var(--space-2xs);
  border-block-end: 1px solid var(--border-subtle);
}

.search-panel__title {
  font-size: var(--step-0);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
}

/**
 * The panel's close control.
 *
 * It was the word CLOSE with a "✕" character in front of it, in a grey pill —
 * which read as a second, unexplained button beside the heading, and the glyph
 * sat wherever the font put it. It is a round icon button now, the same object
 * as the × on a filter pill: circle, accent edge, filling on hover, and the
 * cross drawn to its own box. The word is still there for a screen reader,
 * through the accessible name.
 */
.search-panel__close {
  /* Both children — the hidden label and the icon — are stacked in ONE cell, so
     nothing the button contains can push the icon off centre again. */
  display: grid;
  grid-template-areas: "icon";
  place-items: center;
  inline-size: 2rem;
  block-size: 2rem;
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--me-magenta) 40%, transparent);
  border-radius: 50%;
  background: transparent;
  color: var(--me-magenta-300);
  font-size: 0;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

/**
 * THE CROSS IS AN SVG, AND IT IS THE BUTTON'S ONLY CHILD.
 *
 * It was a `::before` drawn with two gradients, and it sat above centre — not
 * because the drawing was off, but because the button also contains the word
 * "Close" for screen readers. `place-items: center` on a grid with TWO items
 * centres each in its own ROW, so the cross was centred in the top half. The
 * word is inside a visually-hidden span now, which takes no space at all, and
 * the icon is the only thing being laid out.
 */
.search-panel__close > * {
  grid-area: icon;
}

.search-panel__close-icon {
  display: grid;
  place-items: center;
}

.search-panel__close svg {
  inline-size: 0.85rem;
  block-size: 0.85rem;
}

.search-panel__close:hover {
  border-color: var(--accent-solid);
  background: var(--accent-solid);
  color: var(--me-white);
}

.search-panel__close:focus-visible {
  outline: 2px solid var(--me-magenta);
  outline-offset: 2px;
}

/**
 * Narrow screens: a sheet, not a dropdown.
 *
 * Below 40rem a 40rem-wide popover anchored to one corner is just a panel with
 * awkward margins, so it spans the gutters instead and the fields stack — which
 * is what `auto-fit` in filters.css already does once the container is narrow.
 */
@media (max-width: 40rem) {
  .search-panel {
    inset-inline: var(--gutter);
    inline-size: auto;
    max-block-size: calc(100svh - var(--header-offset) - var(--space-m));
  }
}

/**
 * NOTHING INSIDE THE PANEL MAY SET ITS OWN WIDTH.
 *
 * A grid item's automatic minimum size is `auto`, which resolves to the
 * min-content width of what is inside it — so an item can be WIDER than the
 * track it sits in, and the exposed form is a grid inside a grid inside a grid.
 * In the drawer that never showed, because the drawer was as wide as the page.
 * In a 384px dropdown on a phone it did: the form laid itself out at 896px and
 * the Venue select and the "Featured" checkbox sat outside the panel, reachable
 * only by scrolling sideways.
 *
 * `min-inline-size: 0` lets each level shrink to the width it is given, which
 * is what makes `auto-fit` collapse the columns instead of overflowing.
 */
.search-panel :is(
  .exposed-form,
  .exposed-form .block,
  form,
  .form-item,
  .form-wrapper,
  fieldset,
  .fieldset-wrapper,
  .form-radios,
  .form-checkboxes,
  .form-actions
) {
  min-inline-size: 0;

  /*
   * And a hard cap. `min-inline-size: 0` lets a grid item shrink, but the form
   * is itself a grid whose `auto-fit` tracks were sized against a max-content
   * measurement made before the panel constrained it — it laid out at 896px
   * inside a 590px panel and stayed there. Capping every level at the width it
   * is given forces `auto-fit` to recount its columns against the real
   * container instead.
   */
  max-inline-size: 100%;
}

/**
 * One column below 40rem.
 *
 * `auto-fit` with a 14rem minimum still tries for two columns in a ~350px
 * panel, and two 14rem fields plus a gap do not fit in 350px. Stating one
 * column is clearer than tuning the minimum until the arithmetic works out.
 */
@media (max-width: 40rem) {
  .search-panel :is(
    .exposed-form,
    .exposed-form > .block,
    .exposed-form > .block > form,
    .exposed-form > form,
    .views-exposed-form
  ) {
    grid-template-columns: minmax(0, 1fr);
  }

  .search-panel .form-daterange {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* The checkbox group wraps rather than running off the side. */
.search-panel :is(.form-radios, .form-checkboxes) {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-m);
}

/* ---------------------------------------------------------------------------
 * The Webform search this panel replaces
 *
 * HIDDEN IN CSS, NOT IN JAVASCRIPT
 * --------------------------------
 * js/search.js hides it too, and that was the whole of it until now — which
 * meant the old form PAINTED FIRST and then vanished: a full-width stack of
 * checkboxes, two selects and two date fields flashing at the top of every page
 * before the scripts caught up. A block that is never going to be shown should
 * never be drawn, and CSS arrives with the page.
 *
 * The JavaScript stays as the fallback for a browser without `:has()`, and for
 * the console note telling whoever is looking that the block can be unplaced.
 * ------------------------------------------------------------------------ */

.webform-submission-search-form,
[data-drupal-selector="webform-submission-search-add-form"],
.block:has(> .webform-submission-search-form),
.block:has(> form[data-drupal-selector="webform-submission-search-add-form"]),
.block:has(> .content > .webform-submission-search-form) {
  display: none !important;
}

/* The region wrapper that held it takes no space either: a hidden form is
   still a form, so the "does this region have anything in it" test in
   layout.css would otherwise keep the padding and leave a band of empty
   canvas under the header. */
.section--region:has(.webform-submission-search-form),
.section--region:has([data-drupal-selector="webform-submission-search-add-form"]) {
  padding-block: 0;
  border: 0;
}

/* ---------------------------------------------------------------------------
 * The form
 *
 * The theme builds this markup now (js/search.js), so what follows styles known
 * elements rather than defending against whatever a Webform or an exposed
 * filter happened to emit. The previous version of this file was most of a page
 * of `:has()` rules undoing somebody else's form furniture; none of that is
 * needed once the form is ours.
 * ------------------------------------------------------------------------ */

.search-form {
  display: grid;
  gap: var(--space-s);
}

.search-form__row {
  display: grid;
  gap: var(--space-s);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.search-form__row--full {
  grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 34rem) {
  .search-form__row {
    grid-template-columns: minmax(0, 1fr);
  }
}

.search-form__field {
  display: grid;
  gap: var(--space-3xs);
  min-inline-size: 0;
}

.search-form__label {
  color: var(--text-secondary);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.search-form__input,
.search-form__select,
.datefield__input {
  inline-size: 100%;
  min-block-size: 2.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-s);
  background: var(--surface-2);
  color: var(--text-primary);
  font: inherit;
  font-size: var(--step--1);
}

.search-form__input {
  min-block-size: 3rem;
  font-size: var(--step-0);
}

/**
 * The browser's own clear button is dropped.
 *
 * WebKit draws a white "✕" inside a `type=search` box that cannot be themed —
 * a light glyph floating in a dark field, next to the panel's own Clear button,
 * which does the same job for the whole form. One clear control is enough, and
 * it should be the one that matches the interface it is in.
 */
.search-form__input::-webkit-search-cancel-button,
.search-form__input::-webkit-search-decoration {
  appearance: none;
  -webkit-appearance: none;
}

.search-form__input:focus-visible,
.search-form__select:focus-visible,
.datefield__input:focus-visible {
  outline: 2px solid var(--me-magenta);
  outline-offset: 1px;
  border-color: var(--me-magenta);
}

/* The native arrow is drawn by the OS and cannot be themed; this is the
   theme's, with the native one suppressed. */
.search-form__select {
  appearance: none;
  padding-inline-end: 2.25rem;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 1.1rem) 55%,
    calc(100% - 0.75rem) 55%;
  background-size: 0.36rem 0.36rem;
  background-repeat: no-repeat;
}

/* ---------------------------------------------------------------------------
 * The three flags, as chips
 * ------------------------------------------------------------------------ */

.search-form__flags {
  margin: 0;
  padding: 0;
  border: 0;
}

.search-form__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin-block-start: var(--space-3xs);
}

.search-form__chip {
  /* A chip names a thing; the field labels above are markers and are shouted,
     but this is not one of those. Stated because a bare `label` elsewhere in
     the theme's form styling is uppercased. */
  text-transform: none;
  letter-spacing: normal;
  font-weight: 500;

  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  min-block-size: 2.25rem;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-primary);
  font-size: var(--step--1);
  cursor: pointer;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out);
}

.search-form__chip:hover {
  background: var(--surface-3);
}

/* The checkbox stays — it is what a screen reader announces and what the
   keyboard drives — and `accent-color` paints it in the brand magenta rather
   than replacing it with a div that would have to reimplement both. */
.search-form__chip input {
  inline-size: 1rem;
  block-size: 1rem;
  margin: 0;
  accent-color: var(--me-magenta);
}

.search-form__chip:has(input:checked) {
  border-color: var(--me-magenta);
  background: color-mix(in srgb, var(--me-magenta) 18%, transparent);
}

.search-form__chip:has(input:focus-visible) {
  outline: 2px solid var(--me-magenta);
  outline-offset: 2px;
}

.search-form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  padding-block-start: var(--space-s);
  border-block-start: 1px solid var(--border-subtle);
}

@media (max-width: 34rem) {
  .search-form__actions .button {
    flex: 1 1 8rem;
  }
}

/**
 * A dot on the Search control when filters are applied.
 *
 * The drawer used to open by itself on a results page so the visitor could see
 * what had been searched for. A dropdown that opens by itself sits on top of
 * the results it is describing, so it does not — the control says so instead.
 */
/**
 * Filters are applied — a dot, and nothing else.
 *
 * This rule used to set the text colour too, and because it is written later
 * than `:hover` and `[aria-expanded="true"]` at the same specificity, it won
 * over both: the label stayed muted magenta on hover, and stayed muted magenta
 * on the solid fill when the panel was open, which is the "sometimes not
 * brighter" the client saw. It marks the control now and leaves the states to
 * the states.
 */
.search-toggle.has-filters {
  position: relative;
}

/* The resting colour, only while the control is neither hovered nor open. */
.search-toggle.has-filters:not(:hover):not([aria-expanded="true"]) {
  border-color: var(--me-magenta);
  color: var(--me-magenta-300);
}

.search-toggle.has-filters::after {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline-end: -1px;
  inline-size: 0.5rem;
  block-size: 0.5rem;
  border-radius: 50%;
  background: var(--me-magenta);
}

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

/**
 * The view's own "Close" control.
 *
 * The exposed form ships a bare "Close" link that the outgoing theme wired to
 * its own toggle. It is redundant next to the panel's close button, and as a
 * plain link it reads as stray text under the Search button — which is how it
 * appeared on the live site. It is hidden, and js/search.js still honours a
 * click on it if one gets through.
 */
.search-panel .exposed-form > a[href="#"],
.search-panel .form-actions + a {
  display: none;
}

/* ---------------------------------------------------------------------------
 * NOTHING SHOULD PAINT ONLY TO BE TAKEN AWAY
 *
 * js/search.js hides the old Webform search block — the one the header panel
 * replaces — in hideLegacy(). It does that when it runs, which on this site is
 * behind jQuery, CKEditor 5, Select2 and the rest of Drupal's script queue. So
 * the old form was drawing on every page load, sitting there for the better
 * part of a second, and then vanishing and taking its height with it. That is
 * not a slow script; it is a script being asked to do a job CSS can do before
 * the first paint.
 *
 * `html` carries `no-js` from the markup and an inline script in
 * html.html.twig removes it in the <head>, before anything renders. So this
 * rule applies from the first paint when JavaScript is on, and never applies
 * when it is off — where the old form is the only search there is and must
 * stay. js/search.js still hides it, for the case where the block is added to
 * the page after load.
 * ------------------------------------------------------------------------ */
html:not(.no-js) .webform-submission-search-form,
html:not(.no-js) form[data-drupal-selector*="search-add-form"],
html:not(.no-js) .block:has(> .webform-submission-search-form),
html:not(.no-js) .block:has(form[data-drupal-selector*="search-add-form"]) {
  display: none !important;
}

/* ---------------------------------------------------------------------------
 * The panel's own markup is built by the script and is `hidden` until it is
 * opened, so it never flashes. This is the one piece of it that exists in the
 * page template — the Search control in the header — and it is a real link to
 * the search page until the script upgrades it. Reserving its size here keeps
 * the header from reflowing when that happens.
 * ------------------------------------------------------------------------ */
.search-toggle {
  min-block-size: var(--input-height);
}
