/*
 * Meilisearch frontend styles (header searchbar).
 *
 * Plain CSS, no build step - this file is served as-is. The look follows the
 * reisswolf.com design language: square corners throughout (no border
 * radius anywhere), the brand blue for primary actions, magenta focus
 * outlines, quiet grey surfaces. Every color and spacing value is read from
 * a site-wide custom property with a built-in fallback, so a site package
 * can override the look by defining the same token names on :root (see
 * README, "Styling").
 *
 * Structure:
 *   1. Tokens (private aliases of the site-wide custom properties)
 *   2. Shared helpers (visually hidden, focus, spinner)
 *   3. Searchbar (inline header field + live-result dropdown)
 */

/* ------------------------------------------------------------------------
 * 1. Tokens
 *
 * The searchbar dropdown panel is reparented to <body> by searchbar.js, so
 * it needs to be a scope root of its own - it is no longer a descendant of
 * the ".meilisearch-searchbar" container at runtime.
 * ---------------------------------------------------------------------- */
.meilisearch-searchbar,
.meilisearch-searchbar__panel {
    --ms-color-primary: var(--color-primary-500, #004494);
    --ms-color-accent: var(--color-accent-500, #ba3286);
    --ms-color-surface: var(--color-neutral-0, #ffffff);
    --ms-color-light: var(--color-neutral-100, #f2f2f2);
    --ms-color-border: var(--color-neutral-300, #dadada);
    --ms-color-muted: var(--color-neutral-500, #6e6e6c);
    --ms-color-text: var(--color-neutral-700, #3e3d40);
    --ms-space: var(--spacing, 0.25rem);
    --ms-font-weight-bold: var(--font-weight-bold, 700);
    --ms-transition: 200ms;
    /* Above the site's sticky header, mega menu and lightboxes (which go up
       to 99999); the 2147483647 layer is reserved for cookie/consent tools. */
    --ms-dropdown-z-index: var(--z-index-modal, 100000);
    /* Width of the header search field while focused or filled. */
    --ms-searchbar-expanded-width: min(14rem, 45vw);
    --ms-shadow-panel: 0 5px 12px rgb(0 0 0 / 0.25), 0 0 20px rgb(0 0 0 / 0.15);
}

/* ------------------------------------------------------------------------
 * 2. Shared helpers
 * ---------------------------------------------------------------------- */

/* Visually hidden, still exposed to assistive technology. */
.meilisearch-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border-width: 0;
}

/* Keyboard focus: 2px magenta outline, as used for the site's popup close
   button. Applied to every interactive element the plugins render, except
   the header search field, which has its own focus underline (section 3). */
.meilisearch-searchbar__submit:focus-visible,
.meilisearch-searchbar__pager-button:focus-visible {
    outline: 2px solid var(--ms-color-accent);
    outline-offset: 2px;
}

/* Search-in-flight spinner of the searchbar dropdown. */
@keyframes meilisearch-spin {
    to {
        transform: rotate(360deg);
    }
}

.meilisearch-searchbar__spinner svg {
    animation: meilisearch-spin 0.8s linear infinite;
}

/* Native "x" of type=search: the header search field stays free of any
   input chrome. */
.meilisearch-searchbar__input::-webkit-search-decoration,
.meilisearch-searchbar__input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

/* Hit count of the searchbar column headings. */
.meilisearch-searchbar__column-count {
    color: var(--ms-color-muted);
    font-weight: 400;
}

/* Hit counts read as "Label (n)": searchbar.js renders label and count as
   sibling spans with no template hook for surrounding text. */
.meilisearch-searchbar__column-count::before {
    content: "(";
}

.meilisearch-searchbar__column-count::after {
    content: ")";
}

/* ------------------------------------------------------------------------
 * 3. Searchbar: inline header field + live-result dropdown
 * ---------------------------------------------------------------------- */

/* The plugin wrapper is a flex item of the site's head-nav row and gets
   stretched to the row height; center the form inside it so it lines up
   with the neighbouring header links. */
.meilisearch-searchbar {
    display: flex;
    align-items: center;
}

/* Shipped hidden, revealed by searchbar.js (no results page to fall back
   to without JavaScript). display: flex above would override the UA
   stylesheet's [hidden] rule. */
.meilisearch-searchbar[hidden] {
    display: none;
}

/* Header link look (same as the site's ".search" head-nav item: 15px icon,
   plain text, no form chrome, no hover effect): the magnifier submit button
   in front, the chrome-less field behind it. Colors are inherited from the
   surrounding site markup on purpose. */
.meilisearch-searchbar__form {
    display: inline-flex;
    align-items: center;
    gap: calc(var(--ms-space) * 2.5);
    margin: 0;
    padding: 0;
}

/* Magnifier submit button. "order" moves it in front of the field (the DOM
   order is input, submit - the natural tab order).
   !important on the resets: reisswolf.com styles every <button> globally as
   a blue pill (background, radius, margin, padding, bold 16px, hover colour)
   and that rule must never win here, whatever its specificity. */
.meilisearch-searchbar__submit,
.meilisearch-searchbar__submit:hover,
.meilisearch-searchbar__submit:focus {
    order: -1;
    display: inline-flex !important;
    align-items: center;
    flex-shrink: 0;
    width: auto !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 0 !important;
    background: none !important;
    box-shadow: none !important;
    color: inherit !important;
    font: inherit !important;
    line-height: inherit !important;
    text-decoration: none !important;
    opacity: 1 !important;
    transition: none !important;
    cursor: pointer;
}

.meilisearch-searchbar__icon {
    flex-shrink: 0;
    width: 15px;
    height: 15px;
}

/* Compact header (screens up to 650px, same breakpoint as
   COMPACT_MEDIA_QUERY in searchbar.js): just the magnifier, captioned like
   the site's other head-nav items on small screens (10px text below the
   icon). The field itself is hidden here; searchbar.js moves it into the
   dropdown panel. A media query rather than a class set by the script, so
   the header renders in its final shape from the first paint. */
.meilisearch-searchbar__submit-caption {
    display: none;
}

@media (max-width: 40.625rem) {
    .meilisearch-searchbar__form > .meilisearch-searchbar__label {
        display: none;
    }

    .meilisearch-searchbar__submit {
        flex-direction: column;
        gap: 5px;
    }

    .meilisearch-searchbar__submit-caption {
        display: block;
        color: var(--ms-color-muted);
        font-size: 10px;
        line-height: 100%;
        white-space: nowrap;
    }
}

/* The label is exactly as wide as its invisible sizer (a copy of the
   placeholder text), so the collapsed field takes the room the header link
   text would take, in every language. min-width widens it while it is
   focused or holds a term. "font: inherit" undoes reisswolf.com's bold
   <label> rule; the tight line-height (set after the font shorthand, which
   resets it) keeps the focus underline of the field close to the text. */
.meilisearch-searchbar__label {
    position: relative;
    display: block;
    min-width: 0;
    margin: 0;
    padding: 0;
    font: inherit;
    line-height: 1.5;
    transition: min-width var(--ms-transition);
}

.meilisearch-searchbar__label:focus-within {
    min-width: var(--ms-searchbar-expanded-width);
}

/* Separate rule on purpose: a browser without :has() would drop the whole
   selector list, including the focus rule above. */
.meilisearch-searchbar__label:has(.meilisearch-searchbar__input:not(:placeholder-shown)) {
    min-width: var(--ms-searchbar-expanded-width);
}

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

/* The end padding is a buffer: browsers reserve a few pixels inside a
   search input (caret, inner editor box), which would otherwise clip the
   placeholder's last letter. */
.meilisearch-searchbar__sizer {
    display: block;
    padding-inline-end: 0.4em;
    visibility: hidden;
    white-space: nowrap;
}

/* The field is stretched over the label and stripped of all input chrome,
   so it reads as plain header text.
   !important on the resets: site packages commonly style every <input>
   globally (border, padding, height, background, focus shadow). */
.meilisearch-searchbar__input,
.meilisearch-searchbar__input:hover,
.meilisearch-searchbar__input:focus {
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    height: 100% !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 0 !important;
    outline: 0 !important;
    background: none !important;
    box-shadow: none !important;
    color: inherit !important;
    font: inherit !important;
    line-height: inherit !important;
    text-align: left;
    appearance: none;
    -webkit-appearance: none;
    transition: box-shadow var(--ms-transition);
}

/* The placeholder stands in for the header link text: same colour as the
   surrounding links, dimmed once the field is focused and ready for input. */
.meilisearch-searchbar__input::placeholder {
    color: inherit;
    opacity: 1;
    transition: opacity var(--ms-transition);
}

.meilisearch-searchbar__input:focus::placeholder {
    opacity: 0.5;
}

/* Focus indicator: an underline in the text colour. An outline box would
   show on every click into the field and break the header link look. */
.meilisearch-searchbar__input:focus {
    box-shadow: 0 1px 0 0 currentColor !important;
}

/* Forced-colors mode drops box shadows; fall back to a real outline. */
@media (forced-colors: active) {
    .meilisearch-searchbar__input:focus {
        outline: 1px solid !important;
    }
}

/* Live-result dropdown: white "shadowbox" panel, as used for elevated
   content on the site. searchbar.js moves it to <body> (so the header's
   z-indexed layers cannot cover it) and sets top, left, max-width and
   max-height: below the search bar, between the layout grid's left edge
   and the site logo, which it must not cover (the 2rem below are its two
   side gutters on small screens). It is up to 24rem wide per result column
   (--ms-searchbar-columns, set by searchbar.js) and scrolls on its own
   once its height is capped. */
.meilisearch-searchbar__panel {
    position: fixed;
    z-index: var(--ms-dropdown-z-index);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: calc(var(--ms-space) * 4);
    width: min(calc(var(--ms-searchbar-columns, 1) * 24rem), calc(100vw - 2rem));
    padding: calc(var(--ms-space) * 4);
    overflow-y: auto;
    overscroll-behavior: contain;
    background-color: var(--ms-color-surface);
    color: var(--ms-color-text);
    box-shadow: var(--ms-shadow-panel);
}

/* display: flex above would override the UA stylesheet's [hidden] rule
   (author styles always beat the UA sheet) - the closed panel must win. */
.meilisearch-searchbar__panel[hidden] {
    display: none;
}

/* Compact mode (small screens, set by searchbar.js): the search field sits
   at the top of the panel instead of in the header, as a plain full-width
   field with a bottom rule. */
.meilisearch-searchbar__panel--compact > .meilisearch-searchbar__label {
    flex-shrink: 0;
    border-bottom: 1px solid var(--ms-color-border);
    font-size: 1rem;
    line-height: 2.5;
}

/* No display value on purpose: the spinner is a flex child of the panel
   anyway, and an explicit display would override its [hidden] attribute. */
.meilisearch-searchbar__spinner {
    align-self: center;
    color: var(--ms-color-muted);
}

/* Result columns (built by searchbar.js): one equally wide column per
   document type, side by side. The panel's width depends on the viewport
   and on the logo it has to spare, so the columns only stand side by side
   while all of them fit (at least 14rem each); otherwise they stack in a
   single column (never in between), and the panel scrolls. The track
   minimum is either one n-th of the row or the full row: the clamp() value
   is hugely negative while the row is wider than n * 14rem plus the gaps
   (clamped to its minimum, n columns) and hugely positive below that
   (clamped to 100%, one column). */
.meilisearch-searchbar__columns {
    --ms-searchbar-columns-gap: calc(var(--ms-space) * 6);
    --ms-searchbar-columns-n: var(--ms-searchbar-columns, 1);
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(clamp(
        calc((100% - (var(--ms-searchbar-columns-n) - 1) * var(--ms-searchbar-columns-gap)) / var(--ms-searchbar-columns-n)),
        calc((var(--ms-searchbar-columns-n) * 14rem + (var(--ms-searchbar-columns-n) - 1) * var(--ms-searchbar-columns-gap) - 100%) * 999),
        100%
    ), 1fr));
    flex-shrink: 0;
    gap: var(--ms-searchbar-columns-gap);
}

/* Below 1100px always a single column. */
@media (max-width: 68.74rem) {
    .meilisearch-searchbar__columns {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* display: grid above would override the UA stylesheet's [hidden] rule. */
.meilisearch-searchbar__columns[hidden] {
    display: none;
}

.meilisearch-searchbar__column {
    display: flex;
    flex-direction: column;
    gap: calc(var(--ms-space) * 2);
    min-width: 0;
}

/* Column heading: type label + hit count, underlined by a divider. */
.meilisearch-searchbar__column-heading {
    display: flex;
    align-items: baseline;
    gap: calc(var(--ms-space) * 1.5);
    padding: 0 calc(var(--ms-space) * 3) calc(var(--ms-space) * 2);
    border-bottom: 1px solid var(--ms-color-border);
    color: var(--ms-color-text);
    font-weight: var(--ms-font-weight-bold);
    line-height: 1.3;
}

.meilisearch-searchbar__results {
    display: flex;
    flex-direction: column;
    gap: calc(var(--ms-space) * 0.5);
    margin: 0;
    padding: 0;
    list-style: none;
    transition: opacity var(--ms-transition);
}

/* display: flex above would override the UA stylesheet's [hidden] rule. */
.meilisearch-searchbar__results[hidden] {
    display: none;
}

/* Column whose next page is being fetched (toggled by searchbar.js): the
   page that is still showing is dimmed until the new one arrives. */
.meilisearch-searchbar__column--loading .meilisearch-searchbar__results {
    opacity: 0.5;
}

/* Note of a column without hits, and of a search without any hits at all. */
.meilisearch-searchbar__column-empty,
.meilisearch-searchbar__no-results {
    margin: 0;
    padding: calc(var(--ms-space) * 3);
    color: var(--ms-color-muted);
}

.meilisearch-searchbar__column-empty {
    font-size: 0.875rem;
}

.meilisearch-searchbar__no-results {
    text-align: center;
}

/* Minimal pager below each column: "<  2 / 7  >". The auto margin pushes
   it to the column's bottom edge, so the pagers of all columns line up. */
.meilisearch-searchbar__pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: calc(var(--ms-space) * 3);
    margin-top: auto;
    padding-top: calc(var(--ms-space) * 2);
}

/* display: flex above would override the UA stylesheet's [hidden] rule. */
.meilisearch-searchbar__pager[hidden] {
    display: none;
}

/* Square ghost button without border; the hover background marks it.
   !important on the resets: reisswolf.com styles every <button> globally as
   a blue pill (background, radius, margin, padding, hover colour). */
.meilisearch-searchbar__pager-button,
.meilisearch-searchbar__pager-button:hover,
.meilisearch-searchbar__pager-button:focus {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: calc(var(--ms-space) * 9) !important;
    min-height: calc(var(--ms-space) * 9);
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 0 !important;
    background: var(--ms-color-surface) !important;
    color: var(--ms-color-text) !important;
    font: inherit;
    font-size: 1rem !important;
    font-weight: var(--ms-font-weight-bold) !important;
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--ms-transition) !important;
}

/* No page in that direction (aria-disabled, set by searchbar.js). */
.meilisearch-searchbar__pager-button[aria-disabled="true"] {
    opacity: 0.4;
    cursor: default;
}

.meilisearch-searchbar__pager-status {
    min-width: 4em;
    color: var(--ms-color-muted);
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

/* Every option has the same fixed shape: the title takes at most 2 lines,
   the description at most 3, both cut off with "...". On desktop (columns
   side by side, see the 1100px breakpoint above) their room is reserved
   even when the text is shorter or missing, so the titles of all columns
   line up row by row. Title: 1.3 line height in the option's font size;
   description: 0.875rem font size, 1.4 line height. */
.meilisearch-searchbar__option {
    --ms-option-title-height: calc(2 * 1.3em);
    --ms-option-description-height: calc(3 * 1.4 * 0.875rem);
    display: flex;
    align-items: flex-start;
    gap: calc(var(--ms-space) * 3);
    padding: calc(var(--ms-space) * 3);
    cursor: pointer;
    transition: background-color var(--ms-transition);
}

/* Keyboard-active option (aria-activedescendant), toggled by searchbar.js. */
.meilisearch-searchbar__option--active {
    background-color: var(--ms-color-light);
}

/* !important: the site's "img:not(.is_svg)" rule (higher specificity than
   a single class) forces width/height: auto and would render the indexed
   image at its intrinsic size. */
.meilisearch-searchbar__option-image {
    flex-shrink: 0;
    width: calc(var(--ms-space) * 12) !important;
    min-width: calc(var(--ms-space) * 12) !important;
    max-width: calc(var(--ms-space) * 12) !important;
    height: calc(var(--ms-space) * 12) !important;
    min-height: calc(var(--ms-space) * 12) !important;
    max-height: calc(var(--ms-space) * 12) !important;
    /* Moves the image's top edge down to the cap height of the title's
       first line (instead of the top of its line box). 0.27em is the gap
       between line box top and cap top of the site font (Nunito Sans:
       ascender 1011, descender 353, cap height 705 per 1000 units) at the
       title's 1.3 line height; same font size as the title, so em fits. */
    margin-top: 0.27em;
    object-fit: cover;
}

.meilisearch-searchbar__option-body {
    display: flex;
    flex-direction: column;
    gap: var(--ms-space);
    min-width: 0;
}

/* Titles in the brand blue, like the site's headlines. */
.meilisearch-searchbar__option-title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
    color: var(--ms-color-primary);
    font-weight: var(--ms-font-weight-bold);
    line-height: 1.3;
}

.meilisearch-searchbar__option-description {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
    overflow-wrap: anywhere;
    margin: 0;
    color: var(--ms-color-muted);
    font-size: 0.875rem;
    line-height: 1.4;
}

/* Desktop: fixed option height, see .meilisearch-searchbar__option. The
   body's min-height covers options without a description. */
@media (min-width: 68.75rem) {
    .meilisearch-searchbar__option-body {
        min-height: calc(var(--ms-option-title-height) + var(--ms-space) + var(--ms-option-description-height));
    }

    .meilisearch-searchbar__option-title {
        flex-shrink: 0;
        height: var(--ms-option-title-height);
    }

    .meilisearch-searchbar__option-description {
        flex-shrink: 0;
        height: var(--ms-option-description-height);
    }
}

/* Hover states only on devices that actually have a hover pointer, so
   touch devices don't get stuck in a hover state after a tap. */
@media (hover: hover) {
    .meilisearch-searchbar__option:hover {
        background-color: var(--ms-color-light);
    }

    .meilisearch-searchbar__pager-button:not([aria-disabled="true"]):hover {
        background: var(--ms-color-light) !important;
    }
}
