/*
 * Filament fixes
 * ----------------------------------------------------------------------------
 *
 * Loaded into both panels from their PanelsRenderHook::HEAD_END hook, AFTER
 * Filament's own stylesheets, so these rules win on equal specificity without
 * needing !important.
 *
 * NOT a republished vendor asset and not a custom theme. The install runs
 * hand-modified vendor files that were never published through Composer, so
 * anything that regenerates public/css/filament/** destroys work that cannot be
 * recovered from a package. This file sits beside them and overrides.
 */

/* ---------------------------------------------------------------------------
 * Select dropdowns near the foot of the page
 *
 * Filament builds its non-native selects on Choices.js and configures it with
 * position: "auto", which means Choices decides for itself whether to open
 * downward or upward and adds the class `is-flipped` to the outer container
 * when it chooses upward.
 *
 * Filament's Tailwind build then ships NO rules for `is-flipped`. Choices
 * flips, the class lands, and nothing acts on it: the panel keeps top: 100%,
 * opens downward anyway, hangs past the bottom of the document and grows the
 * scrollable page. That is the bug where reaching the foot of a form and
 * opening a long dropdown pushes the page longer instead of scrolling inside
 * the list.
 *
 * These are the positioning rules Choices' own stylesheet carries and
 * Filament's does not.
 * ------------------------------------------------------------------------- */

.choices.is-flipped .choices__list--dropdown,
.choices.is-flipped .choices__list[aria-expanded] {
    top: auto;
    bottom: 100%;
    margin-top: 0;
    margin-bottom: 0.5rem;
}

/*
 * The height ceiling, bound at BOTH levels.
 *
 * Filament already caps the nested scroller at 15rem. On this install it is not
 * binding: the list opens far taller than 240px, which is why flipping it
 * upward on its own made things worse rather than better — the panel stopped
 * extending the page and started covering the fields above it instead.
 *
 * Rather than guess which element carries the scroll, both are capped:
 *
 *   inner   the nested list, where Filament intends the scroll to happen and
 *           where it keeps the search box pinned above it. !important because
 *           something on this install is beating the shipped rule and the
 *           point of this file is to be the last word.
 *
 *   outer   the dropdown panel itself, set two rem LARGER so it never engages
 *           while the inner rule is working. It is the backstop for a markup
 *           shape the inner selector does not match, and it costs a search box
 *           that scrolls with the list, which is worth it against a dropdown
 *           with no ceiling at all.
 *
 * Explicitly not display:flex on the panel. Choices toggles the dropdown by
 * switching display between none and block, and a flex layout here would hold
 * a closed dropdown open.
 */
.choices__list--dropdown > .choices__list,
.choices__list[aria-expanded] > .choices__list {
    max-height: min(18rem, 45vh) !important;
    overflow-y: auto !important;
    overscroll-behavior: contain;
}

.choices__list--dropdown,
.choices__list[aria-expanded] {
    max-height: min(20rem, 50vh);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* ---------------------------------------------------------------------------
 * An empty select must not be shorter than a full one
 *
 * Choices renders the chosen value into a single-item list inside the box. With
 * nothing chosen AND no placeholder to fall back on, that list holds no text
 * node at all, so it contributes no line box and the whole control collapses to
 * roughly two thirds the height of its neighbours. On a row of dropdowns the
 * odd one out reads as broken rather than as empty.
 *
 * The figure is not a guess. Filament's forms.css gives .choices__inner
 * line-height 1.5rem with 0.375rem of padding above and below, the ring is a
 * box-shadow rather than a border so it adds no layout, and box-sizing is
 * border-box throughout. A filled control is therefore exactly
 * 1.5 + 0.375 + 0.375 = 2.25rem tall, and asking for that as a minimum makes an
 * empty one match it to the pixel while leaving every filled one alone.
 *
 * Set on the box rather than on the inner list because that list is an
 * inline-block: giving an empty inline-block a height leaves the line box that
 * contains it taller than the text it stands in for, which would overshoot in
 * the other direction.
 * ------------------------------------------------------------------------- */

.choices[data-type*='select-one'] .choices__inner {
    min-height: 2.25rem;
}

/*
 * Everything above is the floor, not the finished behaviour.
 *
 * filament-fixes.js measures the room between the field and the edge of the
 * window each time a dropdown opens and overwrites both ceilings with the real
 * figure, so the list runs to the bottom of the page instead of stopping at an
 * arbitrary height. CSS cannot ask that question, which is the only reason the
 * script exists.
 *
 * These rules are what a member sees if the script fails to load: a bounded,
 * scrolling dropdown rather than one that grows the page. Deliberately kept
 * conservative for that reason.
 */

/* ---------------------------------------------------------------------------
 * AN OPEN DROPDOWN OUTRANKS EVERYTHING (owner, 2026-08-27)
 *
 * Filament gives the panel z-index 10, which wins against ordinary siblings and
 * loses to anything that raises itself: repeater row actions, sticky headers,
 * a section that establishes its own stacking context. The symptom is a delete
 * button or a reorder handle painted straight through the middle of the open
 * list.
 *
 * z-index is only ever compared INSIDE one stacking context, so a number on the
 * dropdown alone cannot answer this: if an ancestor of the field sits below the
 * ancestor of the button, no figure here changes the outcome. The number below
 * settles every contest within the field's own context, and filament-fixes.js
 * carries the same figure up the ancestor chain for the ones it cannot reach.
 *
 * The value is 2147483000 rather than the signed 32-bit maximum so there is
 * still room above it for anything that genuinely has to win — a modal overlay,
 * a toast — without those having to match an unbeatable number.
 * ------------------------------------------------------------------------- */

.choices.is-open {
    position: relative;
    z-index: 2147483000;
}

.choices.is-open .choices__list--dropdown,
.choices.is-open .choices__list[aria-expanded] {
    z-index: 2147483000;
}

/*
 * The field wrapper the select sits in, for the commonest case the script would
 * otherwise have to reach: Filament lays form fields out on a grid, and a grid
 * item takes a z-index while still position: static — so this lifts the whole
 * field without giving it a position it did not have, which would re-anchor
 * anything absolutely positioned inside it.
 */
.fi-fo-component-ctn:has(.choices.is-open),
[class*='fi-fo-field-wrp']:has(.choices.is-open) {
    z-index: 2147483000;
}

/*
 * ── IMAGE UPLOADS AS TILES, NOT FULL-WIDTH ROWS ─────────────────────────────
 *
 * FilePond lays every file out as a row spanning the whole panel: its own rule
 * is `.filepond--item { left: 0; right: 0 }`. With an image preview inside,
 * that gives a picture stranded in a wide band of empty grey, and five saved
 * avatar photos turn a form section into a wall of them.
 *
 * There is no option for this. FilePond's stylePanelLayout accepts only
 * integrated, compact and circle — passing "grid" sets an attribute that
 * nothing styles. A grid is made by giving the ITEM a width; FilePond reads
 * that width and does its own layout maths from it, which is why the absolute
 * positioning above is left alone.
 *
 * Five across on a wide panel, stepping down as it narrows. No height or
 * width is put on the picture itself: the tile bounds it, and each one keeps
 * its own shape inside that.
 *
 * Scoped to .ai-upload-tiles rather than applied to every FilePond, because a
 * list of documents SHOULD be full-width rows — it is only pictures that want
 * tiling. The class is put on by ->extraAttributes() at each image upload.
 */
.ai-upload-tiles .filepond--item {
    width: calc(20% - 0.5em);
}

/* Fewer across as the panel narrows, so a tile never becomes a postage stamp. */
@media (max-width: 1279px) {
    .ai-upload-tiles .filepond--item {
        width: calc(25% - 0.5em);
    }
}

@media (max-width: 1023px) {
    .ai-upload-tiles .filepond--item {
        width: calc(33.333% - 0.5em);
    }
}

@media (max-width: 767px) {
    .ai-upload-tiles .filepond--item {
        width: calc(50% - 0.5em);
    }
}

/*
 * The name and size sit ON the tile now rather than beside it, so they are
 * given a readable ground and kept to one line instead of pushing the tile
 * taller than the picture it describes.
 */
.ai-upload-tiles .filepond--file-info {
    min-width: 0;
}

.ai-upload-tiles .filepond--file-info .filepond--file-info-main,
.ai-upload-tiles .filepond--file-info .filepond--file-info-sub {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * ── AND THE TILE STAYS INSIDE ITS PANEL ─────────────────────────────────────
 *
 * Two things the grid needs beyond the item width. FilePond draws the preview
 * into a fixed-height box and letterboxes anything that does not match, which
 * on a dark panel reads as a grey slab around the picture; and the drop label
 * above needs clearing, or the first row of tiles sits under it.
 *
 * The picture is told to COVER its tile instead of fitting inside it: at five
 * across a tile is wide enough that a portrait fills it, and cropping a little
 * off the top and bottom of a preview costs nothing — the file itself is
 * untouched, this is only what the member looks at while choosing.
 */
.ai-upload-tiles .filepond--image-preview-wrapper,
.ai-upload-tiles .filepond--image-preview-overlay,
.ai-upload-tiles .filepond--image-preview {
    background: transparent;
}

.ai-upload-tiles .filepond--image-preview img,
.ai-upload-tiles .filepond--image-preview canvas {
    height: 100%;
    object-fit: cover;
    width: 100%;
}

/*
 * The item panel behind a letterboxed preview, which is the grey the tiles
 * were sitting on. Dark enough to disappear into the form on either theme.
 */
.ai-upload-tiles .filepond--item-panel {
    background-color: rgb(63 63 70 / 0.6);
}
