/*
    Styling for the LabeledDropdown component: a small gray label above a dropdown button, and the
    list of options that opens below the button.

    A page can set these CSS custom properties on an element around the dropdown; each has a
    default:
    - --control-height: the button's height, read by the shared dropdown button.
    - --dropdown-button-hit-reach-top, -right, -bottom and -left: how far past its edges the button
      takes clicks, also read by the shared dropdown button.
    - --labeled-dropdown-active-option-ring-color: a ring inside the edge of the option the pointer
      or keyboard is on, so it stands out beside the filled chosen option. None by default.
    - --labeled-dropdown-compact-button-gap, --labeled-dropdown-compact-button-padding,
      --labeled-dropdown-compact-font-size and --labeled-dropdown-compact-line-height: the compact
      button's spacing and text size.
    - --labeled-dropdown-compact-list-font-size: the compact dropdown's list's text size, the text
      size around the dropdown by default.
*/
.labeled-dropdown
{
    position: relative;
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;

    /* Styling for the label above the button. */
    .labeled-dropdown-label
    {
        color: var(--neutral-surface-low-emphasis-contrast-color);
        font-size: 0.8rem;
    }

    /* A label kept for screen readers only. */
    .labeled-dropdown-label-hidden
    {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        /* Insetting the clip by half the box's size from every edge leaves nothing of it visible. */
        clip-path: inset(50%);
        white-space: nowrap;
    }

    /* The shown option and the hidden texts of every option share one grid cell, so the button is
       as wide as its widest option. A button whose width matches the shown option has no hidden
       texts. */
    .labeled-dropdown-button-text
    {
        display: inline-grid;
        justify-items: start;

        > *
        {
            grid-area: 1 / 1;
            white-space: nowrap;
        }
    }

    .labeled-dropdown-reserved-text
    {
        visibility: hidden;
    }

    /* A button that can't be used is dimmed, with the arrow cursor, and doesn't brighten on hover or
       when pressed. */
    .labeled-dropdown-button-disabled
    {
        opacity: 0.5;
        cursor: default;

        &:hover
        {
            background: var(--neutral-medium-emphasis-surface-color);
        }

        &:active
        {
            filter: none;
        }
    }

    /* Styling for the list of options below the button, a rounded panel lighter than the page. */
    .labeled-dropdown-list
    {
        position: absolute;
        /* The list's top is the dropdown's full height (100%) below the dropdown's top, which is the
           button's bottom edge, plus 0.25rem, the same as the gap between the label and the button. */
        top: calc(100% + 0.25rem);
        left: 0;
        z-index: var(--popup-z-index);
        min-width: 100%;
        margin: 0;
        padding: 0.25rem;
        list-style: none;
        border-radius: 8px;
        outline: none;
        color: var(--neutral-surface-high-emphasis-contrast-color);
        background: var(--neutral-high-emphasis-surface-color);
        /* A shadow offset 2px right and 2px down, blurred over 5px, in black at 50% opacity. */
        box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
        /* The list fades in and drops into place as it opens, and back out as it closes, in the time
           the script sets, for which it keeps a closing list on screen. */
        animation: labeled_dropdown_list_open var(--dropdown-list-motion-duration) ease-out;

        &.labeled-dropdown-list-closing
        {
            pointer-events: none;
            animation: labeled_dropdown_list_close var(--dropdown-list-motion-duration) ease-in forwards;
        }
    }

    /* A list placed in the window at the button, whose place the script sets, so no scrolling
       container around the dropdown cuts it off. It is as wide as its options, since the window,
       not the dropdown, is now the box its width would be a share of. */
    .labeled-dropdown-list.labeled-dropdown-list-in-window
    {
        position: fixed;
        right: auto;
        min-width: 0;
    }

    /* Styling for an option. */
    .labeled-dropdown-option
    {
        display: flex;
        align-items: center;
        padding-top: 0.25rem;
        padding-right: 0.75rem;
        padding-bottom: 0.25rem;
        padding-left: 0.75rem;
        border-radius: 4px;
        white-space: nowrap;
        cursor: pointer;

        /* The option the pointer or keyboard is on is lighter, with the ring the page asks for. */
        &.labeled-dropdown-option-active
        {
            background: var(--neutral-higher-emphasis-surface-color);
        }
        &.labeled-dropdown-option-active:not(.labeled-dropdown-option-selected)
        {
            /* An inset shadow with no offset and no blur, spread 1.5px, draws the ring as a solid
               line inside the option's edge. */
            box-shadow: inset 0 0 0 1.5px var(--labeled-dropdown-active-option-ring-color, transparent);
        }

        /* The chosen option is filled in the primary color, and brightens when the pointer or
           keyboard is on it. */
        &.labeled-dropdown-option-selected
        {
            color: var(--primary-higher-emphasis-contrast-color);
            background: var(--primary-higher-emphasis-color);
        }
        &.labeled-dropdown-option-selected.labeled-dropdown-option-active
        {
            filter: brightness(115%);
        }

        &:active
        {
            filter: brightness(130%);
        }

        /* An option that can't be picked is in low-emphasis text, with the arrow cursor, and doesn't
           brighten when pressed. */
        &.labeled-dropdown-option-disabled
        {
            color: var(--neutral-surface-low-emphasis-contrast-color);
            cursor: default;
        }
        &.labeled-dropdown-option-disabled:active
        {
            filter: none;
        }
    }

    /* A list whose options have their text in parts lines the parts up in columns: the list is a grid
       with a column per part, as many as the script sets, and each option, and the tooltip trigger
       around an option's text, is a row sharing its columns; an option's text in one piece spans
       them. The gap between columns is about a space's width, so a part reads as the next word. */
    .labeled-dropdown-list.labeled-dropdown-list-in-columns
    {
        display: grid;
        grid-template-columns: repeat(var(--labeled-dropdown-text-column-count), max-content);
        column-gap: 0.3em;

        .labeled-dropdown-option,
        .labeled-dropdown-option > .tooltip-trigger
        {
            /* A grid line of -1 is the last one, so 1 / -1 spans every column. */
            grid-column: 1 / -1;
            display: grid;
            grid-template-columns: subgrid;
            align-items: center;
        }
        .labeled-dropdown-option-whole-text
        {
            grid-column: 1 / -1;
        }
    }

    /* A turned dropdown's list turns back upright about its top-left corner, by the turn the script
       sets, to hang below the button. */
    .labeled-dropdown-list.labeled-dropdown-list-turned-upright
    {
        transform-origin: top left;
        transform: rotate(var(--labeled-dropdown-list-turn));
    }
    @media (prefers-reduced-motion: no-preference)
    {
        .labeled-dropdown-list.labeled-dropdown-list-turned-upright
        {
            animation-name: labeled_dropdown_list_turn_open;
        }
        .labeled-dropdown-list.labeled-dropdown-list-turned-upright.labeled-dropdown-list-closing
        {
            animation-name: labeled_dropdown_list_turn_close;
        }
    }

    /* A compact dropdown: a small boxed button whose text and arrow turn the primary color on hover,
       setting it apart from a hover around it, such as a table header's. Its list keeps the
       left-aligned text and line height of a line of its own, wherever the dropdown sits. */
    &.labeled-dropdown-compact
    {
        .labeled-dropdown-button
        {
            gap: var(--labeled-dropdown-compact-button-gap, 0.3rem);
            /* The padding is a shorthand a page can set: 0.1rem at the top and bottom, and 0.4rem
               at the right and left by default. */
            padding: var(--labeled-dropdown-compact-button-padding, 0.1rem 0.4rem);
            border-radius: 4px;
            font-size: var(--labeled-dropdown-compact-font-size, 0.95em);
            line-height: var(--labeled-dropdown-compact-line-height, 1.3);

            &:hover
            {
                color: var(--primary-higher-emphasis-color);
            }
        }

        .labeled-dropdown-list
        {
            font-size: var(--labeled-dropdown-compact-list-font-size, inherit);
            line-height: normal;
            text-align: left;
        }
    }
}

/* The list starts transparent and 0.25rem above its place. */
@keyframes labeled_dropdown_list_open
{
    from
    {
        opacity: 0;
        translate: 0 -0.25rem;
    }
}

/* The list ends transparent and 0.25rem above its place. */
@keyframes labeled_dropdown_list_close
{
    to
    {
        opacity: 0;
        translate: 0 -0.25rem;
    }
}

/* A turned dropdown's list turns out from the dropdown's angle as it opens, fading in, and back as
   it closes, fading out. Each gives only its invisible, unturned end; the other end is the list's
   own opacity and turn. */
@keyframes labeled_dropdown_list_turn_open
{
    from
    {
        opacity: 0;
        transform: rotate(0deg);
    }
}

@keyframes labeled_dropdown_list_turn_close
{
    to
    {
        opacity: 0;
        transform: rotate(0deg);
    }
}

/* The list opens and closes at once when the user's system asks for less motion. */
@media (prefers-reduced-motion: reduce)
{
    .labeled-dropdown .labeled-dropdown-list,
    .labeled-dropdown .labeled-dropdown-list.labeled-dropdown-list-closing
    {
        animation: none;
    }
}
