/* ==========================================================================
   Settings: a preferences-page rendering of a form.

   A `.settings-group` is a titled card of `.setting` rows. Each row puts
   the field's name and a sentence on what it decides on the left, and its
   control on the right; `setting--stack` drops the control under the text
   for anything that needs the full width. The rows are rendered by
   `django_crispy_custom/setting.html`. Colors are tokens only.
   ========================================================================== */

/* --- Group ------------------------------------------------------------- */

/* The title and its sentence sit above the rows, on the page itself; the
   rows are the box. */
.settings-group {
    margin-bottom: 1.75rem;
}

.settings-group__header {
    padding: 0 0.25rem 0.6rem;
}

.settings-group__title {
    margin: 0;
    font-size: 1rem;
    font-weight: var(--font-weight-heading);
    letter-spacing: var(--heading-tracking);
    color: var(--text-primary);
}

.settings-group__desc {
    margin: 0.15rem 0 0;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--text-tertiary);
    text-wrap: pretty;
}

/* --- Row --------------------------------------------------------------- */

.setting {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
    column-gap: 2rem;
    row-gap: 0.75rem;
    align-items: center;
    padding: 1rem 1.25rem;
    background: var(--surface-1);
    border: 1px solid var(--border-subtle);
    border-top-width: 0;
}

.settings-group__header + .setting {
    border-top-width: 1px;
    border-radius: 10px 10px 0 0;
}

.setting:last-child {
    border-radius: 0 0 10px 10px;
}

.settings-group__header + .setting:last-child {
    border-radius: 10px;
}


.setting--stack {
    grid-template-columns: minmax(0, 1fr);
}

.setting__text {
    min-width: 0;
}

/* The row's label is a name, not the uppercase eyebrow `.form-group`
   labels get: it sits beside a sentence, and reads at body size. */
.setting__label {
    display: block;
    margin: 0;
    font-size: 0.9375rem !important;
    font-weight: var(--font-weight-strong);
    line-height: 1.4;
    color: var(--text-primary) !important;
}

.setting__label .asteriskField {
    margin-left: 0.2rem;
    color: var(--color-red);
}

/* The provider keyword the row sets, so a tuned value can be matched to
   a recorded call and to the provider's own docs. A tinted code chip:
   it reads as an identifier rather than prose, and the pink keeps it
   distinct from the label above and the sentence below without
   competing with either. --color-pink-rgb resolves per theme, so the
   tint and the text track the background. */
.setting__param {
    display: inline-block;
    margin: 0.25rem 0 0;
    padding: 0.05rem 0.35rem;
    border-radius: 4px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--color-pink);
    background-color: rgba(var(--color-pink-rgb), 0.12);
    overflow-wrap: anywhere;
}

.setting__help {
    margin: 0.2rem 0 0;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--text-tertiary);
    text-wrap: pretty;
}

.setting__control {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-width: 0;
}

.setting--switch .setting__control {
    align-items: flex-end;
}

.setting--stack .setting__control {
    width: 100%;
}

/* The message spans both columns, under the label and the control. */
.setting__error {
    grid-column: 1 / -1;
    margin: -0.25rem 0 0;
    font-size: 0.875rem;
}

/* Only the erroring row is marked: its own border, drawn over the
   neighbors' shared edge, and a faint tint. */
.setting--invalid {
    position: relative;
    z-index: 1;
    border: 1px solid rgba(var(--color-red-rgb), 0.6);
    margin-top: -1px;
    background: rgba(var(--color-red-rgb), 0.05);
}

.setting--invalid .setting__label {
    color: var(--color-red) !important;
}

/* The controls keep the app's own look; only their size is pinned so a
   row of numbers, selects, and switches shares one height. */
.setting__control .form-control,
.setting__control .custom-select,
.setting__control .select2-container .select2-selection--single {
    min-height: 2.5rem;
    font-size: 0.9375rem;
}

.setting__control textarea.form-control {
    min-height: 5rem;
    line-height: 1.5;
}

.setting__control input[type="number"] {
    font-variant-numeric: tabular-nums;
}

/* --- Switch ------------------------------------------------------------ */

.setting__switch {
    padding-left: 3rem;
    min-height: 1.5rem;
}

.setting__switch .custom-control-input,
.setting__switch .custom-control-label {
    cursor: pointer;
}

.setting__switch .custom-control-label::before {
    left: -3rem;
    width: 2.75rem;
    height: 1.5rem;
    border-radius: 1rem;
    background: var(--surface-3);
    border-color: var(--border-emphasis);
    transition: background-color 150ms ease-out, border-color 150ms ease-out;
}

.setting__switch .custom-control-label::after {
    top: calc(0.25rem + 3px);
    left: calc(-3rem + 3px);
    width: calc(1.5rem - 6px);
    height: calc(1.5rem - 6px);
    border-radius: 50%;
    background: var(--text-secondary);
    transition: transform 150ms ease-out, background-color 150ms ease-out;
}

.setting__switch .custom-control-input:checked ~ .custom-control-label::before {
    background: rgb(var(--color-blue-fill-rgb));
    border-color: rgb(var(--color-blue-fill-rgb));
}

.setting__switch .custom-control-input:checked ~ .custom-control-label::after {
    background: #fff;
    transform: translateX(1.25rem);
}

.setting__switch .custom-control-input:focus-visible ~ .custom-control-label::before {
    box-shadow: 0 0 0 3px rgba(var(--color-blue-rgb), 0.35);
}

/* --- Slider ------------------------------------------------------------ */

.setting-slider {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.75rem;
}

/* `--fill` is the filled fraction of the track, kept current by
   js/components/settings-slider.js. */
.setting-slider__range {
    --fill: 0%;
    width: 100%;
    height: 1.5rem;
    margin: 0;
    background: transparent;
    appearance: none;
    cursor: pointer;
}

.setting-slider__range:focus {
    outline: none;
}

.setting-slider__range::-webkit-slider-runnable-track {
    height: 4px;
    border-radius: 2px;
    background: linear-gradient(
        to right,
        rgb(var(--color-blue-fill-rgb)) var(--fill),
        var(--surface-3) var(--fill)
    );
}

.setting-slider__range::-moz-range-track {
    height: 4px;
    border-radius: 2px;
    background: var(--surface-3);
}

.setting-slider__range::-moz-range-progress {
    height: 4px;
    border-radius: 2px;
    background: rgb(var(--color-blue-fill-rgb));
}

.setting-slider__range::-webkit-slider-thumb {
    appearance: none;
    width: 1rem;
    height: 1rem;
    margin-top: -6px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid rgb(var(--color-blue-fill-rgb));
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    transition: transform 120ms ease-out;
}

.setting-slider__range::-moz-range-thumb {
    width: 1rem;
    height: 1rem;
    border-radius: 50%;
    background: #fff;
    border: 2px solid rgb(var(--color-blue-fill-rgb));
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.setting-slider__range:hover::-webkit-slider-thumb,
.setting-slider__range:active::-webkit-slider-thumb {
    transform: scale(1.15);
}

/* The number box. When there is a unit, the box draws the input's chrome
   and the unit sits in flow after a transparent input, so the value ends
   the same short distance from the unit whatever the unit's length. */
.setting-slider__box,
.setting__unit-box {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.setting-slider__box .form-control,
.setting__unit-box .form-control {
    text-align: right;
}

.setting-slider__box .form-control {
    width: 6rem;
}

/* The chrome copied off `.form-control` in components/forms.css: keep the
   two in step. */
.setting-slider__box--unit {
    height: 38px;
    padding-right: 0.75rem;
    background: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 6px;
    box-shadow: var(--input-inset);
    transition: all 0.2s ease;
}

.setting-slider__box--unit:focus-within {
    background: var(--input-bg-focus);
    border-color: var(--input-border-focus);
    box-shadow: var(--input-focus-ring);
}

.setting-slider__box--unit:has(.form-control:disabled) {
    background: var(--input-bg-disabled);
    border-color: var(--input-border-disabled);
}

/* forms.css pins `.form-control` chrome and padding with !important at
   specificity (0,4,0) through its `:not()` chain; this repeats the chain
   and adds a class so the box's own chrome wins. */
.setting-slider__box--unit .form-control:not(.form-control-sm):not(textarea):not(.custom-file) {
    height: 100% !important;
    min-height: 0;
    padding-right: 0.25rem !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
}

/* Same font size and line-height as the input's text (the control
   metrics block in components/forms.css), so the two share a baseline. */
.setting-slider__unit {
    flex: none;
    pointer-events: none;
    font-size: 14px;
    line-height: 36px;
    color: var(--text-tertiary);
}

/* The spinners crowd a right-aligned number. */
.setting-slider__box input[type="number"],
.setting__unit-box input[type="number"] {
    appearance: textfield;
    -moz-appearance: textfield;
}

.setting-slider__box input[type="number"]::-webkit-inner-spin-button,
.setting__unit-box input[type="number"]::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
}

/* --- Narrow screens ---------------------------------------------------- */

@media (max-width: 767.98px) {
    .setting {
        grid-template-columns: minmax(0, 1fr);
        row-gap: 0.6rem;
    }

    .setting--switch {
        grid-template-columns: minmax(0, 1fr) auto;
    }
}
