/* The settings area: the shell around its sections (views/layouts/settings.php)
   and the grouped rows every section is built from, after MyPeptideApp's
   settings. Loaded after layout.css.

   One markup, three arrangements. From 1024 pixels, where the sidebar
   stands whole beside the page, a dialog over the page (at the end of this
   file). Below that the switch is a container query on the room the shell
   has, not a media query on the window:
     - narrow: /settings is the overview, the section list alone as grouped
       rows; every other address is its section alone, with "Settings" to go
       back.
     - wide (42rem of room and more): the list is a sticky column on the
       left, borderless and compact, the section on the right. The dialog
       keeps this arrangement inside its window.

   The pieces:
     .set-group          a group of rows, bordered like a card, no padding
     .set-group-title    the small heading above a group
     .set-group-note     a line under a group, for what its rows share
     .set-row            one row: icon, text (label and hint), status,
                         control, chevron. An <a>, <button>, <summary>, <li>
                         or <div>, whatever the row does.
     .set-row-link       leads somewhere, with a chevron
     .set-row-action     does something: a disclosure, a form's button
     .set-row-field      a label and a borderless text input
     .set-row-select     the chosen value, with the native select over it
     .set-row-segment    a segmented control, below the label when narrow
     .set-row-setting    a setting: label and description, control (a time,
                         .set-input-time, or a whole number, .set-input-number,
                         with its .set-row-unit), and a last line with its
                         state (.set-row-foot)
     .set-row-text       a long text: label and hint, the framed field
                         (.set-textarea) under them, what it has to cover
                         (.set-row-guide), and the last line with its state
     .set-row-danger     red text: sign out
     .set-row-value-wrap a value that is only shown, in full
     .set-status         saving, saved or not saved, inside the row, or in
                         the last line of a setting
     .set-row-error      the error of the row's field, under it
     .set-picture        one's own picture beside its form, in Profile
                         (.set-avatar-lg, .set-picture-forms,
                         .set-picture-actions, .set-picture-remove)

   Hover feedback sits behind (hover: hover), so a finger leaves no stuck
   highlight on a phone. */

/* ------------------------------------------------------------------------
   Shell
   ------------------------------------------------------------------------ */

.settings {
    container: settings / inline-size;
}

.settings-title {
    margin-bottom: var(--space-6);
    font-family: var(--font-display);
    font-size: clamp(var(--text-2xl), 1.2rem + 1vw, var(--text-3xl));
    font-weight: var(--weight-semibold);
    line-height: var(--leading-tight);
    letter-spacing: -0.025em;
}

/* The section beside the list keeps a line length made for reading; the
   audit log and the jobs, which are lists, take the room there is. */
/* A container of its own too, for rows that arrange themselves by the room
   the section has (the segmented control). */
.settings-section {
    min-width: 0;
    max-width: 44rem;
    container: section / inline-size;
}

.settings-section:has(.settings-wide) {
    max-width: none;
}

.settings-section-head {
    margin-bottom: var(--space-6);
}

/* The top title of the page or of the settings window, where it is an
   <h2>: in the display face either way (D102). */
.settings-section-title {
    font-family: var(--font-display);
    font-size: clamp(var(--text-2xl), 1.2rem + 1vw, var(--text-3xl));
    letter-spacing: -0.025em;
    overflow-wrap: anywhere;
}

.settings-section-text {
    max-width: 60ch;
    margin-top: var(--space-1);
    color: var(--color-text-muted);
}

.settings-section-head .readonly-notice {
    margin-top: var(--space-4);
}

@container settings (width < 42rem) {
    /* The overview is the list alone; a section is the section alone. A
       message the overview receives, such as that viewing as someone
       ended, still shows, above the list. */
    .settings.is-overview .settings-section > :not(.flash-stack),
    .settings:not(.is-overview) .settings-nav,
    .settings:not(.is-overview) .settings-title {
        display: none;
    }

    .settings.is-overview .settings-layout {
        display: flex;
        flex-direction: column;
    }

    .settings.is-overview .settings-section {
        order: -1;
    }
}

@container settings (width >= 42rem) {
    .settings-layout {
        display: grid;
        grid-template-columns: 13.5rem minmax(0, 1fr);
        align-items: start;
        gap: var(--space-10);
    }

    /* Sticky, and never taller than the window: on a phone held sideways
       the list would otherwise run past the bottom of the screen, its last
       sections out of reach until the section ends. */
    .settings-nav {
        position: sticky;
        top: var(--space-8);
        max-height: calc(100vh - var(--space-8) - var(--space-4));
        max-height: calc(100dvh - var(--space-8) - var(--space-4));
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .settings-back {
        display: none;
    }

    .settings-section-title {
        font-size: var(--text-xl);
        letter-spacing: -0.02em;
    }
}

@container settings (width >= 62rem) {
    .settings-layout {
        grid-template-columns: 15rem minmax(0, 1fr);
        gap: var(--space-12);
    }
}

/* ------------------------------------------------------------------------
   Groups
   ------------------------------------------------------------------------ */

.set-group-title {
    margin-bottom: var(--space-2);
    color: var(--color-text-subtle);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.set-group {
    margin-bottom: var(--space-6);
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface);
    box-shadow: var(--shadow-xs);
    list-style: none;
}

/* The hairline between two rows starts where the text does, as on iOS:
   after the padding, and after the icon in a row that has one. A
   background image rather than a border or pseudo element, so it works for
   every kind of child (a row, a list item, a form, a <details>) and a row
   under the pointer covers it with its own colour. The hidden CSRF field of
   a form that is itself the group is no row. */
.set-group > :not([type="hidden"]) + * {
    background-image: linear-gradient(var(--color-border), var(--color-border));
    background-position: right top;
    background-repeat: no-repeat;
    background-size: calc(100% - var(--space-4)) 1px;
}

.set-group > :not([type="hidden"]) + *:has(.set-row-icon) {
    background-size: calc(100% - var(--space-4) - 20px - var(--space-3)) 1px;
}

/* A list's ghost inside a group, such as Threads' accounts in Connectors
   before the first: less room under its words, inside the group's frame.
   [D77] */
.set-group .ghost-list {
    padding-bottom: var(--space-6);
}

/* Every form of the area keeps its fields in a fieldset, for disabling them
   while viewing as someone; here it draws nothing. */
.set-form fieldset {
    min-width: 0;
}

/* The Save button of a form that saves itself, for a browser without
   script. With script, app.js marks the form and it goes. */
.set-actions {
    display: flex;
    justify-content: flex-end;
    margin: calc(-1 * var(--space-3)) 0 var(--space-6);
}

.set-form[data-autosave-ready] .set-actions {
    display: none;
}

/* ------------------------------------------------------------------------
   Rows
   ------------------------------------------------------------------------ */

.set-row {
    /* The height of the label's line, which controls line up with. */
    --set-label-line: calc(var(--text-md) * 1.35);
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    width: 100%;
    min-height: 52px;
    padding: 10px var(--space-4);
    border: 0;
    background-color: transparent;
    color: var(--color-text);
    font: inherit;
    text-align: left;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: background-color var(--duration-fast) var(--ease-in-out);
}

.set-row-icon {
    flex: none;
    width: 20px;
    height: 20px;
    color: var(--color-text-subtle);
}

/* A zero basis, so a long hint wraps inside the text column instead of
   pushing the control onto a line of its own. */
.set-row-main {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    min-width: 0;
}

.set-row-label {
    color: var(--color-text);
    font-size: var(--text-md);
    font-weight: var(--weight-medium);
    line-height: 1.35;
}

.set-row-hint {
    margin-top: 2px;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.set-row-hint + .set-row-hint {
    margin-top: 0;
}

/* The green dot of something live before a hint's words: a person's device
   seen in the last 5 minutes (D118). */
.set-row-hint > .live-dot {
    margin-right: 6px;
    vertical-align: 1px;
}

.set-row-control {
    display: flex;
    flex: none;
    align-items: center;
    gap: var(--space-2);
    max-width: 60%;
}

.set-row-value {
    min-width: 0;
    overflow: hidden;
    color: var(--color-text-muted);
    font-size: var(--text-md);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.set-row-value.is-empty {
    color: var(--color-text-subtle);
}

/* A value that is only shown, such as the email or a value someone may not
   change, is read in full: it wraps instead of being cut, since nothing
   else on the page shows the rest. Beside the label of a field row it
   starts where the field's input would; elsewhere it keeps to the right. */
.set-row-value-wrap {
    overflow: visible;
    overflow-wrap: anywhere;
    white-space: normal;
}

.set-row:not(.set-row-field) .set-row-value-wrap {
    text-align: right;
}

/* Beside a label, a value keeps the height of the input it stands in for,
   so a row that shows and a row that edits are the same height. */
.set-row-field .set-row-value {
    display: flex;
    align-items: center;
    min-height: 32px;
}

/* The line under a group, for what its rows share, such as whom to ask to
   change them. */
.set-group-note {
    margin: calc(var(--space-2) - var(--space-6)) 0 var(--space-6);
    padding: 0 var(--space-4);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    line-height: 1.45;
}

.set-row-chevron {
    flex: none;
    width: 18px;
    height: 18px;
    color: var(--color-text-subtle);
}

/* Rows that do something when tapped. */
.set-row-link,
.set-row-action,
.set-row-select {
    cursor: pointer;
}

@media (hover: hover) {
    .set-row-link:hover,
    .set-row-action:not(:disabled):hover,
    .set-row-select:has(.set-select:not(:disabled)):hover {
        background-color: var(--color-surface-hover);
    }
}

.set-row-link:active,
.set-row-action:not(:disabled):active {
    background-color: var(--color-surface-selected);
}

/* Inside the row: the group clips anything outside its edges. */
.set-row:focus-visible,
.set-row-select:has(.set-select:focus-visible),
.set-row-field:focus-within {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

.set-row-action:disabled {
    cursor: not-allowed;
}

.set-row-action:disabled > * {
    opacity: 0.5;
}

.set-row-danger,
.set-row-danger .set-row-label,
.set-row-danger .set-row-icon {
    color: var(--color-danger-text);
}

/* A field in error names it in its label too. */
.set-row:has([aria-invalid="true"]) .set-row-label {
    color: var(--color-danger-text);
}

.set-row-error {
    display: flex;
    flex: 1 0 100%;
    order: 10;
    align-items: flex-start;
    gap: var(--space-1);
    color: var(--color-danger-text);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    line-height: 1.45;
}

.set-row-error .icon {
    flex: none;
    width: 1rem;
    height: 1rem;
    margin-top: 1px;
}

/* ------------------------------------------------------------------------
   A text input in the row: the label in a column of its own, the input
   without a frame beside it. The row's ring shows the focus.
   ------------------------------------------------------------------------ */

.set-row-field .set-row-main {
    flex: 0 0 7.5rem;
}

.set-row-field .set-row-control {
    flex: 1 1 0;
    max-width: none;
    min-width: 0;
}

/* The input starts right after the label, so its state goes to the end of
   the row, where a select row has its value. */
.set-row-field:not(.set-row-setting) .set-status {
    order: 1;
}

/* In a narrow section the label column is only as wide as its words, down
   to the width of a short one, so the input keeps the room. */
@container section (width < 34rem) {
    .set-row-field:not(.set-row-setting) .set-row-main {
        flex: 0 0 auto;
        min-width: 4.5rem;
    }
}

.set-input {
    width: 100%;
    min-width: 0;
    min-height: 32px;
    padding: 4px 0;
    border: 0;
    background: transparent;
    color: var(--color-text);
    font-size: var(--text-md);
}

.set-input:focus,
.set-input:focus-visible {
    outline: none;
}

.set-input::placeholder {
    color: var(--color-text-subtle);
    opacity: 1;
}

.set-input:disabled {
    color: var(--color-text-muted);
    cursor: not-allowed;
}

/* A time reads as a value, like the choice of a select row. */
.set-input-time {
    width: auto;
    min-width: 6rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.set-input-time::-webkit-calendar-picker-indicator {
    opacity: 0.55;
    cursor: pointer;
}

/* ------------------------------------------------------------------------
   A choice in the row. Without script the select shows in the row as a
   plain, frameless select. With script (the form is marked
   data-autosave-ready) it lies invisible over the whole row, so a tap
   anywhere opens the device's own picker, and the row shows the chosen
   value, which app.js keeps up to date.
   ------------------------------------------------------------------------ */

.set-select {
    width: 100%;
    min-width: 0;
    max-width: min(14rem, 100%);
    min-height: 32px;
    padding: 4px 24px 4px 0;
    border: 0;
    background: transparent var(--image-select-chevron) no-repeat right center / 16px;
    color: var(--color-text-muted);
    font-size: var(--text-md);
    text-align: right;
    text-overflow: ellipsis;
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
}

.set-select:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* As wide as the chosen option where the browser can size a select by its
   content, rather than as wide as the longest option in the list. */
@supports (field-sizing: content) {
    .set-select {
        width: auto;
        field-sizing: content;
    }
}

/* In a setting's row, where the control lines up with the label's first
   line (below). With script the select lies over the row instead. */
.set-row-setting .set-select {
    margin-block: calc((var(--set-label-line) - 32px) / 2);
}

/* Without script, on a phone, a select as wide as its longest option goes
   under the label, where the label and its hint keep the row's width. */
@supports not (field-sizing: content) {
    @container section (width < 22rem) {
        .set-form:not([data-autosave-ready]) .set-row-select .set-row-control {
            flex: 1 1 100%;
            max-width: none;
        }
    }
}

.set-row-select [data-select-value],
.set-row-select .set-select-chevron {
    display: none;
}

[data-autosave-ready] .set-row-select [data-select-value] {
    display: block;
}

[data-autosave-ready] .set-row-select .set-select-chevron {
    display: block;
    width: 16px;
    height: 16px;
}

[data-autosave-ready] .set-select {
    position: absolute;
    inset: 0;
    width: 100%;
    max-width: none;
    height: 100%;
    margin: 0;
    padding: 0;
    opacity: 0;
    /* At least 16 pixels even unseen: iOS zooms into a smaller select. */
    font-size: var(--text-md);
}

[data-autosave-ready] .set-select:focus-visible {
    outline: none;
}

[data-autosave-ready] .set-select:disabled {
    cursor: not-allowed;
}

/* What the row shows under the select stays clickable above it. */
.set-row-foot,
.set-row-error {
    position: relative;
    z-index: 1;
}

/* ------------------------------------------------------------------------
   A segmented control in the row. It keeps its look from components.css;
   a narrow section puts it under the label, at full width.
   ------------------------------------------------------------------------ */

.set-row-segment .set-row-control {
    max-width: none;
}

.set-row-segment .segmented {
    flex-wrap: nowrap;
}

/* Slimmer than the form control where the pointer is precise, so the row
   keeps the height of its neighbours. */
@media (pointer: fine) {
    .set-row-segment .segment {
        min-height: 30px;
        padding: 0 10px;
    }
}

@container section (width < 34rem) {
    .set-row-segment {
        row-gap: var(--space-3);
        padding-bottom: var(--space-3);
    }

    .set-row-segment .set-row-control {
        flex: 1 1 100%;
        max-width: none;
    }

    .set-row-segment .segmented {
        display: flex;
        width: 100%;
    }

    .set-row-segment .segment {
        flex: 1 1 0;
        justify-content: center;
        min-width: 0;
        padding-inline: var(--space-2);
    }
}

/* ------------------------------------------------------------------------
   A setting of the catalog: the description can run to a few lines, so the
   control sits at the top, and the last line says whether it has a value
   and when it last changed.
   ------------------------------------------------------------------------ */

.set-row-setting {
    align-items: flex-start;
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.set-row-setting .set-row-main {
    flex: 1 1 0;
}

.set-row-setting .set-row-control {
    flex: none;
    max-width: 55%;
}

/* The control lines up with the label's first line, not with the top of
   its taller box: the box reaches as far above that line as below it. */
.set-row-setting .set-input-time,
.set-row-setting .set-input-number {
    margin-block: calc((var(--set-label-line) - 32px) / 2);
}

/* A whole number reads as a value too, with its unit after it ("120
   minutes"), and without the browser's arrows, which a phone does not
   have either. [Phase 5, section 9.8] */
.set-input-number {
    width: 4.5rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    text-align: right;
    -moz-appearance: textfield;
    appearance: textfield;
}

.set-input-number::-webkit-inner-spin-button,
.set-input-number::-webkit-outer-spin-button {
    margin: 0;
    -webkit-appearance: none;
}

/* The unit is a label of its field: a tap on it puts the cursor there. */
.set-row-unit {
    color: var(--color-text-muted);
    font-size: var(--text-md);
    white-space: nowrap;
    cursor: text;
}

.set-row-foot {
    display: flex;
    flex: 1 0 100%;
    order: 11;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    flex-wrap: wrap;
    min-height: 28px;
    margin-top: var(--space-1);
}

.set-row-meta {
    color: var(--color-text-subtle);
    font-size: var(--text-sm);
}

.set-row-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

/* A quiet action inside a row, such as Clear. */
.set-text-button {
    min-height: 32px;
    padding: 0 var(--space-2);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-in-out),
                color var(--duration-fast) var(--ease-in-out);
}

@media (hover: hover) {
    .set-text-button:hover {
        background-color: var(--color-surface-muted);
        color: var(--color-text);
    }
}

/* A link looks exactly like the button: Exit setup, Add link. */
a.set-text-button {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    text-decoration: none;
}

@media (pointer: coarse) {
    .set-text-button {
        min-height: 44px;
    }
}

/* ------------------------------------------------------------------------
   A long text, such as a legal text of the link pages: the label and its
   hint, the field under them at the row's full width, then what the text
   has to cover, and the last line with its state, as a setting has. The
   field keeps its frame: a borderless area of many lines would not show
   where to type. Its error goes right under it, before the guide.
   ------------------------------------------------------------------------ */

.set-row-text {
    align-items: flex-start;
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.set-row-text .set-row-main,
.set-row-text .set-row-control {
    flex: 1 1 100%;
    max-width: none;
}

.set-row-text .set-row-control {
    display: block;
    margin-top: var(--space-2);
}

.set-row-text .set-row-error {
    order: 1;
}

/* Grows with its text where the browser can size a field by its content,
   up to most of a window, then scrolls; the rows attribute sizes it
   elsewhere. */
.set-textarea {
    min-height: 10rem;
    max-height: 70vh;
    max-height: 70dvh;
    line-height: var(--leading-normal);
}

@supports (field-sizing: content) {
    .set-textarea {
        field-sizing: content;
    }
}

.set-row-guide {
    flex: 1 1 100%;
    order: 2;
    margin-top: var(--space-2);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    line-height: 1.45;
}

.set-row-guide ul {
    margin: var(--space-1) 0 var(--space-2);
    padding-left: var(--space-5);
    list-style: disc;
}

.set-row-guide li + li {
    margin-top: 2px;
}

/* Markdown to copy, character by character: no ligatures, which would draw
   the // of an address and the ** of bold as other signs, and a break
   anywhere, since it has few spaces to break at. */
.set-row-guide code,
.set-group-note code {
    color: var(--color-text);
    font-variant-ligatures: none;
    overflow-wrap: anywhere;
}

@container settings (width >= 42rem) {
    .set-textarea {
        font-size: var(--text-base);
    }
}

/* ------------------------------------------------------------------------
   A row that opens a form below it: the password.
   ------------------------------------------------------------------------ */

.set-disclosure > summary {
    list-style: none;
}

.set-disclosure > summary::-webkit-details-marker {
    display: none;
}

.set-disclosure-chevron {
    transition: transform var(--duration-fast) var(--ease-in-out);
}

.set-disclosure[open] .set-disclosure-chevron {
    transform: rotate(180deg);
}

.set-disclosure-body {
    padding: var(--space-2) var(--space-4) var(--space-5);
}

/* In line with the row's text, past its icon, where there is room. */
@container settings (width >= 42rem) {
    .set-disclosure-body {
        padding-left: calc(var(--space-4) + 20px + var(--space-3));
    }
}

/* ------------------------------------------------------------------------
   The state of a row that saves itself (app.js). Never display: none: it is
   an aria-live region, which is announced only when it was in the page
   from the start. Empty, it takes no room, and its negative margin gives
   back the gap the row would put beside it.
   ------------------------------------------------------------------------ */

.set-status {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: var(--space-1);
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    white-space: nowrap;
    opacity: 0;
    transition: opacity var(--duration-normal) var(--ease-in-out);
}

.set-status:empty {
    width: 0;
    margin-inline-start: calc(-1 * var(--space-3));
}

.set-status.is-saving,
.set-status.is-saved,
.set-status.is-error {
    opacity: 1;
}

.set-status.is-error {
    color: var(--color-danger-text);
}

.set-status .icon {
    width: 14px;
    height: 14px;
}

/* In a setting's last line, beside its Clear, the gap is the line's own. */
.set-row-actions .set-status:empty {
    margin-inline-start: calc(-1 * var(--space-2));
}

/* A select row in a narrow section has no room to spare beside its value,
   and a status that takes some would wrap the text and move the row twice
   a save. There it sits under the value, out of the line. An error makes
   the row grow by its message anyway, and then the status goes back into
   the line, clear of the message. */
@container section (width < 34rem) {
    .set-row-select:not(.set-row-setting) .set-status {
        position: absolute;
        right: var(--space-4);
        bottom: var(--space-1);
        margin: 0;
        pointer-events: none;
    }

    .set-row-select:not(.set-row-setting):has(.set-row-error) .set-status {
        position: static;
    }
}

.set-spinner {
    width: 12px;
    height: 12px;
    border: 2px solid var(--color-border-strong);
    border-top-color: var(--color-text-muted);
    border-radius: var(--radius-full);
    animation: spin 0.7s linear infinite;
}

/* ------------------------------------------------------------------------
   The person at the top of the list.
   ------------------------------------------------------------------------ */

.set-me {
    min-height: 72px;
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.set-avatar {
    display: grid;
    place-items: center;
    flex: none;
    width: 44px;
    height: 44px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    background-color: var(--color-surface-muted);
    color: var(--color-text-muted);
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    letter-spacing: 0.02em;
}

.set-me .set-row-label {
    font-size: var(--text-lg);
    font-weight: var(--weight-semibold);
}

.set-me .set-row-label,
.set-me .set-row-hint {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------------------------------------------------------------------------
   Wide: the normal type size of the app in the rows, and the list as a
   column of navigation links, borderless and compact.
   ------------------------------------------------------------------------ */

@container settings (width >= 42rem) {
    .set-row {
        --set-label-line: calc(var(--text-base) * 1.35);
        min-height: 48px;
    }

    .set-row-label,
    .set-row-value,
    .set-input,
    .set-select {
        font-size: var(--text-base);
    }

    .set-row-field .set-row-main {
        flex-basis: 9rem;
    }

    .settings-nav .set-group {
        margin-bottom: var(--space-5);
        overflow: visible;
        border: 0;
        border-radius: 0;
        background-color: transparent;
        box-shadow: none;
    }

    .settings-nav .set-group > :not([type="hidden"]) + *,
    .settings-nav .set-group > :not([type="hidden"]) + *:has(.set-row-icon) {
        background-image: none;
    }

    .settings-nav .set-group-title {
        margin-bottom: var(--space-1);
        padding-left: var(--space-3);
    }

    .settings-nav .set-row {
        flex-wrap: nowrap;
        gap: 10px;
        min-height: 36px;
        margin-bottom: 1px;
        padding: 6px var(--space-3);
        border-radius: var(--radius-sm);
        color: var(--color-text-muted);
    }

    .settings-nav .set-row-icon {
        width: 18px;
        height: 18px;
    }

    .settings-nav .set-row-label {
        color: inherit;
    }

    .settings-nav .set-row-chevron {
        display: none;
    }

    .settings-nav .set-row-link:active,
    .settings-nav .set-row-action:not(:disabled):active {
        background-color: var(--color-canvas-selected);
    }

    /* The open section: grey, text and icon in the full text colour, as in
       the app's own navigation. The list sits on the canvas here, so its
       greys are the canvas's own, a step darker than the canvas. Marked by
       class, not aria-current, which /settings leaves out (see
       layouts/settings.php). */
    .settings-nav .set-row.is-current {
        background-color: var(--color-canvas-selected);
        color: var(--color-text);
    }

    .settings-nav .set-row.is-current .set-row-icon {
        color: var(--color-text);
    }

    .settings-nav .set-row-danger,
    .settings-nav .set-row-danger .set-row-icon {
        color: var(--color-danger-text);
    }

    .settings-nav .set-me {
        min-height: 0;
        padding: var(--space-2) var(--space-3);
    }

    .settings-nav .set-avatar {
        width: 32px;
        height: 32px;
        font-size: var(--text-xs);
    }

    .settings-nav .set-me .set-row-label {
        color: var(--color-text);
        font-size: var(--text-base);
    }

    .settings-nav .set-me .set-row-hint {
        margin-top: 0;
        font-size: var(--text-xs);
    }
}

@media (hover: hover) {
    @container settings (width >= 42rem) {
        .settings-nav .set-row-link:hover,
        .settings-nav .set-row-action:hover {
            background-color: var(--color-canvas-hover);
            color: var(--color-text);
        }

        .settings-nav .set-row.is-current:hover {
            background-color: var(--color-canvas-selected);
        }

        .settings-nav .set-row-danger:hover {
            color: var(--color-danger-text);
        }
    }
}

@media (pointer: coarse) {
    @container settings (width >= 42rem) {
        .settings-nav .set-row {
            min-height: 44px;
        }
    }
}

/* ------------------------------------------------------------------------
   The dialog. From 1024 pixels, where the sidebar stands whole beside the
   page, the settings are a window over the page, as in MyPeptideApp and in its measures: at
   most 960 by 720 pixels and 24 from every edge of a smaller window, the
   list in a column of its own and the section beside it, each scrolling in
   itself, over the page dimmed and blurred by a backdrop. app.js opens it
   over the page a settings link was clicked on; a settings page loaded by
   its address shows it over an empty page. Below 1024 pixels there is no
   backdrop and no X, and the settings are the page.

   Placed last: the rules of the wide arrangement above apply inside the
   dialog as well, and these win over the few that differ.
   ------------------------------------------------------------------------ */

.settings-backdrop,
.settings-close {
    display: none;
}

@media (min-width: 1024px) {
    /* Nothing behind the window scrolls while it is there. */
    html:has(.settings-dialog) {
        overflow: hidden;
    }

    .settings-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: var(--z-dialog);
        background-color: var(--color-overlay);
        -webkit-backdrop-filter: blur(var(--backdrop-blur));
        backdrop-filter: blur(var(--backdrop-blur));
        animation: settings-fade-in var(--duration-normal) var(--ease-in-out) both;
    }

    .settings {
        position: fixed;
        inset: 0;
        z-index: calc(var(--z-dialog) + 1);
        display: flex;
        flex-direction: column;
        width: min(960px, calc(100vw - 48px));
        height: min(720px, calc(100vh - 48px));
        height: min(720px, calc(100dvh - 48px));
        margin: auto;
        overflow: hidden;
        border: 1px solid var(--color-border);
        border-radius: var(--radius-dialog);
        background-color: var(--color-surface);
        box-shadow: var(--shadow-dialog);
        animation: settings-pop-in var(--duration-normal) var(--ease-out) both;
    }

    /* Taken away again by app.js, after these animations. */
    .settings-dialog.is-closing .settings-backdrop {
        animation: settings-fade-out var(--duration-fast) var(--ease-in-out) both;
    }

    .settings-dialog.is-closing .settings {
        pointer-events: none;
        animation: settings-pop-out var(--duration-fast) var(--ease-in-out) both;
    }

    /* Top right, over the corner of the section, which keeps it free. On
       the surface's own colour, so a section scrolled under it does not
       show through. */
    .settings-close {
        display: inline-flex;
        position: absolute;
        top: 14px;
        right: 14px;
        z-index: 1;
        background-color: var(--color-surface);
        color: var(--color-text-subtle);
    }

    .settings-section-head {
        padding-right: 44px;
    }

    .settings-section > .flash-stack {
        margin-right: 44px;
    }

    /* The dialog's name, for a screen reader: on screen, the list and the
       section say where one is. */
    .settings-title {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
        border: 0;
    }

    .settings-layout {
        display: grid;
        flex: 1;
        grid-template-columns: 232px minmax(0, 1fr);
        align-items: stretch;
        gap: 0;
        min-height: 0;
    }

    /* The list on the canvas grey, as the page beside a card, with the
       compact rows of the wide arrangement. */
    .settings-nav {
        position: static;
        min-height: 0;
        max-height: none;
        padding: var(--space-3);
        overflow-y: auto;
        overscroll-behavior: contain;
        scrollbar-width: thin;
        border-right: 1px solid var(--color-border);
        background-color: var(--color-canvas);
    }

    .settings-section {
        max-width: none;
        min-height: 0;
        padding: var(--space-6) var(--space-8) var(--space-10);
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    /* The next page of the settings is on its way (app.js). Only after a
       moment, so a quick answer does not flicker. */
    .settings-section[aria-busy="true"] {
        opacity: 0.55;
        transition: opacity var(--duration-fast) var(--ease-in-out) 150ms;
    }

    /* The window on its way over the page (app.js). */
    html[data-settings-opening],
    html[data-settings-opening] * {
        cursor: progress;
    }

    /* Without script the dialog stays inside the page, the only time this
       matches: the sidebar and the banner under the backdrop would be the
       first stops of the Tab key, before the window. app.js moves the
       dialog out of the page and makes them inert instead. */
    body:has(.app-content .settings-dialog) :is(.sidebar, .impersonation-banner) {
        visibility: hidden;
    }
}

@media (min-width: 1024px) and (hover: hover) {
    .settings-close:hover {
        background-color: var(--color-surface-muted);
    }
}

@media (min-width: 1024px) and (max-width: 1100px) {
    .settings-layout {
        grid-template-columns: 188px minmax(0, 1fr);
    }

    .settings-section {
        padding: var(--space-5) var(--space-5) var(--space-8);
    }
}

@keyframes settings-fade-in {
    from { opacity: 0; }
}

@keyframes settings-fade-out {
    to { opacity: 0; }
}

@keyframes settings-pop-in {
    from { opacity: 0; transform: translateY(12px) scale(0.98); }
}

@keyframes settings-pop-out {
    to { opacity: 0; transform: translateY(8px) scale(0.985); }
}

@media (prefers-reduced-motion: reduce) {
    .set-row,
    .set-status,
    .set-disclosure-chevron,
    .settings-section[aria-busy="true"] {
        transition: none;
    }

    .settings-backdrop,
    .settings,
    .settings-dialog.is-closing .settings-backdrop,
    .settings-dialog.is-closing .settings {
        animation: none;
    }

    .set-spinner {
        animation-duration: 1.4s;
    }
}

/* ------------------------------------------------------------------------
   One's own picture, first in Profile: the picture beside the photo field,
   its button under it, and "Remove picture". [Phase 4, section 8.15]
   ------------------------------------------------------------------------ */

.set-picture {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-4);
}

.set-avatar-lg {
    width: 72px;
    height: 72px;
    font-size: var(--text-2xl);
}

/* Beside the picture, not a row under it: no hairline. */
.set-group.set-picture > * {
    background-image: none;
}

.set-picture-forms {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    width: 100%;
    min-width: 0;
}

.set-picture-forms > .set-form {
    width: 100%;
}

.set-picture-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

@media (min-width: 640px) {
    .set-picture {
        flex-direction: row;
    }
}

/* ------------------------------------------------------------------------
   Settings, Connectors (views/settings/connectors*.php): the list of the
   connectors, each source's page, and the platforms' pages, Instagram's
   with its rhythm and runs, Threads' with its accounts too. Every class
   starts with cn-, besides two states of the rows of every section: a hint
   that needs the person (.set-row-hint.is-warning) and a row of what comes
   later (.set-row.is-off). [Phase 5, section 9.8, M10.12 and M11.8]

   .cn-notice          an alert above the groups, the missing vault key
   .cn-hiker           the top of HikerAPI's card (M4.9), padded as an
                       account's card: its fact (an .alert), its state in
                       one sentence (.cn-hiker-state) and its figures
                       (.cn-facts.is-stacked: one under the other in
                       a narrow section, three across from 34rem; a figure's
                       part on one line, .cn-facts-part; when it was
                       checked, quiet, .cn-facts-quiet; a figure not known
                       yet, the quiet dash, dd.is-none, never a 0); its rows
                       with their buttons (.cn-hiker-row: beside the words,
                       under them in a narrow section); its foot with Pause
                       or Resume and Remove key (.cn-hiker-actions); its
                       ghost (.cn-hiker-ghost, .cn-hiker-ghost-label: the
                       rows it will have, their names kept, their values
                       bars)
   .cn-account         a Threads account (M10.12): .cn-account-head with
                       its mark and .cn-account-text (.cn-account-name),
                       its reads (.cn-account-note, .is-warning) and its
                       newest post (.cn-post); the viewers' cards wore its
                       look until they left (M11)
   .cn-facts           figures as a list of terms (dt) and values (dd)
   .cn-actions         a row of buttons at a card's foot
   .cn-run             a run: .cn-run-time (a day before today wraps at
                       its comma in a narrow section), .cn-run-result
                       (.is-danger, .is-warning), .cn-run-meta
   .cn-fact            the line on how the secrets are kept, with its lock
   .cn-form            a form below the page, in its group, with its
                       groups of fields (.cn-fieldset)
   .cn-post            a Threads account's newest post (M10.12): its cover
                       (.cn-post-cover, a quiet tile .is-quiet for a text
                       post), its first line (.cn-post-line, one line),
                       its handle, time and kind (.cn-post-meta) and its
                       views (.cn-post-views, .is-none before a read)

   Since M10.12 the list has two groups, Sources and Platforms, and each
   source a page of its own; a platform's mark (a Glyphs brand) stands in
   a row as an icon does (.set-row-icon.glyph). Four figures go two by two
   where the section has the room (.cn-facts.is-stacked.is-pairs), and a
   setting typed as text reads as a value in its row (.set-input-text).
   ------------------------------------------------------------------------ */

.set-row-hint.is-warning {
    color: var(--color-warning-text);
}

/* Shown, not offered: nothing is behind it yet. */
.set-row.is-off {
    cursor: default;
}

.set-row.is-off .set-row-label,
.set-row.is-off .set-row-icon {
    color: var(--color-text-subtle);
}

.cn-notice {
    margin-bottom: var(--space-6);
}

/* HikerAPI's card: black, white and grey; the tones only in its alert.
   [Phase 5, M4.9] */
.cn-hiker {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
}

.cn-hiker-state {
    line-height: 1.45;
    overflow-wrap: anywhere;
}

/* Its figures are long: one under the other in a narrow section, three
   across where it has the room. */
.cn-facts.is-stacked {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

@container section (width >= 34rem) {
    .cn-facts.is-stacked {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--space-2) var(--space-4);
    }
}

/* A figure breaks at its dot, never inside a part. */
.cn-facts-part {
    white-space: nowrap;
}

.cn-facts-quiet {
    display: block;
    color: var(--color-text-subtle);
    font-size: var(--text-sm);
    font-weight: var(--weight-normal);
}

/* A figure not known yet: the quiet dash, never a 0. [D77] */
.cn-facts dd.is-none {
    color: var(--color-text-subtle);
    font-weight: var(--weight-normal);
}

/* Its buttons beside the words where the section has the room, under them
   where it has not, so a long hint is never squeezed beside two buttons. */
.cn-hiker-row .set-row-control {
    flex-wrap: wrap;
    justify-content: flex-end;
    max-width: none;
}

@container section (width < 34rem) {
    .cn-hiker-row .set-row-control {
        flex-basis: 100%;
        justify-content: flex-start;
    }
}

.cn-hiker-actions {
    padding: var(--space-4);
}

/* Its ghost, the ghost-list's look: the rows it will have, their names kept
   as the tiles' ghost keeps its labels, their values bars. [D77] */
.cn-hiker-ghost .ghost-list-rows > li {
    justify-content: space-between;
}

.cn-hiker-ghost-label {
    color: var(--color-text-subtle);
    font-size: var(--text-md);
    font-weight: var(--weight-medium);
}

.cn-hiker-ghost .ghost-list-rows .ghost-bar {
    flex: none;
    width: 112px;
}

.cn-hiker-ghost .ghost-list-rows > li:nth-child(2) .ghost-bar {
    width: 84px;
}

.cn-hiker-ghost .ghost-list-rows > li:nth-child(3) .ghost-bar {
    width: 64px;
}

/* Its rows keep their names, so its words stay below the last of them
   instead of coming up into it. */
.cn-hiker-ghost .ghost-list-body {
    margin-top: var(--space-2);
}

/* A Threads account's card. [M10.12] */
.cn-account {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
}

.cn-account-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}

.cn-account-text {
    min-width: 0;
}

.cn-account-name {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    font-size: var(--text-md);
    font-weight: var(--weight-semibold);
    overflow-wrap: anywhere;
}

.cn-facts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
}

.cn-facts div {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.cn-facts dt {
    color: var(--color-text-subtle);
    font-size: var(--text-xs);
}

.cn-facts dd {
    font-weight: var(--weight-medium);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.cn-account-note {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    line-height: 1.45;
}

.cn-account-note.is-warning {
    color: var(--color-warning-text);
}

.cn-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* A run: its time beside its result, who read and how much under it; side
   by side where the section has the room. */
.cn-run {
    display: grid;
    grid-template-columns: 4.5rem minmax(0, 1fr);
    gap: 2px var(--space-3);
    padding: 10px var(--space-4);
}

.cn-run-time {
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.cn-run-result {
    font-weight: var(--weight-medium);
    overflow-wrap: anywhere;
}

.cn-run-result.is-danger {
    color: var(--color-danger-text);
}

.cn-run-result.is-warning {
    color: var(--color-warning-text);
}

.cn-run-meta {
    grid-column: 2;
    color: var(--color-text-subtle);
    font-size: var(--text-sm);
}

@container section (width >= 34rem) {
    .cn-run {
        grid-template-columns: 6.5rem minmax(0, 1fr) auto;
        align-items: baseline;
    }

    .cn-run-meta {
        grid-column: 3;
        text-align: right;
    }
}

/* A run of a day before today names its day too, "18 Oct, 23:04": in a
   narrow section it wraps at its comma, so it never runs over its result;
   where the column is wider it fits on one line. [M4.10] */
@container section (width >= 34rem) {
    .cn-run-time time {
        white-space: nowrap;
    }
}

.cn-fact {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    line-height: 1.45;
}

.cn-fact .icon {
    flex: none;
    width: 18px;
    height: 18px;
    color: var(--color-text-subtle);
}

/* A form below the page, in its group. */
.cn-form {
    padding: var(--space-4);
}

.cn-fieldset {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    min-width: 0;
}

/* The group's name sits closer to its first field than fields to each other. */
.cn-fieldset > .field-label {
    margin-bottom: calc(-1 * var(--space-3));
}

@container settings (width >= 42rem) {
    .cn-form {
        padding: var(--space-5);
    }
}

/* A platform's mark in a row of the list, the colour of the icons beside
   it. [M10.12] */
.set-row-icon.glyph {
    fill: currentColor;
}

/* Four figures, ScrapeCreators': two by two where the section has the
   room, one under the other where it has not. [M10.12] */
@container section (width >= 34rem) {
    .cn-facts.is-stacked.is-pairs {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* A setting typed as text, Threads' ages of the view reads: a value in the
   row, as a number is, wide enough for six ages. [M10.12] */
.set-input-text {
    width: 13rem;
    max-width: 100%;
    color: var(--color-text-muted);
    text-align: right;
    text-overflow: ellipsis;
}

.set-row-setting .set-input-text {
    margin-block: calc((var(--set-label-line) - 32px) / 2);
}

/* A Threads account's newest post: its cover, 3 by 4 as Threads shows a
   picture, or a quiet tile, beside its words. [M10.12] */
/* A Threads account's last reads, one record, as tight as its post's lines. */
.cn-reads {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cn-post {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    min-width: 0;
}

.cn-post-cover {
    flex: none;
    width: 45px;
    height: 60px;
    border-radius: calc(var(--radius-sm) - 2px);
    background-color: var(--color-ghost);
    object-fit: cover;
}

.cn-post-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.cn-post-line {
    overflow: hidden;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cn-post-meta {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    overflow-wrap: anywhere;
}

.cn-post-views {
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
}

.cn-post-views.is-none {
    color: var(--color-text-subtle);
}
