/*
 * Buttons.
 *
 * A button names the action — "Create item", "Archive" — never "OK" or "Next". That is a
 * content rule, but it is why there is no "primary/secondary" pair of generic labels here:
 * the variant carries weight, the text carries meaning.
 *
 * Hover changes background and border colour only, over 120ms. No shift, no scale, no glow.
 * Pressed state is colour, never size.
 */

.app-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    height: var(--control);
    padding: 0 var(--inset-btn);
    border: 1px solid var(--border-control);
    border-radius: var(--radius-control);
    background: var(--surface);
    color: var(--text);
    /* Set, not inherited: a button inside a display-serif heading came out as thin serif on the
       accent and read blurred (owner, 23.10.2026); the old site's buttons were the UI sans at 600. */
    font-family: var(--font-ui);
    font-size: var(--fs-body);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-flat);
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
}

.app-btn:hover {
    background: var(--surface-2);
    border-color: var(--border-3);
    color: var(--text);
    text-decoration: none;
}

.app-btn--primary {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--surface);
}

.app-btn--primary:hover {
    border-color: var(--accent-press);
    background: var(--accent-press);
    color: var(--surface);
}

.app-btn--quiet {
    /* The accountant's «switch PRO account» line names the PRO by company or email: on a phone it wraps under the
       title instead of widening the page (core.md §5.5); only this modifier may wrap, so the height is a floor. */
    height: auto;
    min-height: var(--control);
    padding: 0 var(--inset-control);
    white-space: normal;
    border-color: transparent;
    background: transparent;
    color: var(--accent);
}

.app-btn--quiet:hover {
    border-color: transparent;
    background: var(--accent-soft);
    color: var(--accent);
}

.app-btn--danger {
    border-color: var(--negative);
    color: var(--negative);
}

.app-btn--danger:hover {
    border-color: var(--negative);
    background: var(--negative-soft);
    color: var(--negative);
}

.app-btn--danger-solid {
    border-color: var(--negative);
    background: var(--negative);
    color: var(--surface);
}

.app-btn--danger-solid:hover {
    border-color: var(--negative-press);
    background: var(--negative-press);
    color: var(--surface);
}

.app-btn--sm {
    height: var(--control-sm);
    padding: 0 var(--inset-control);
}

.app-btn--lg {
    height: var(--control-lg);
    padding: 0 var(--inset-btn-lg);
    font-size: var(--fs-text);
}

.app-btn--block {
    width: 100%;
}

.app-btn:disabled,
.app-btn[aria-disabled='true'] {
    border-color: var(--border);
    background: var(--surface-2);
    color: var(--text-disabled);
    cursor: not-allowed;
}

/* --- Button and links in one row ------------------------------------------------------- */

/*
 * One primary button and plain links (rules.md §1.1): the button at the start, the links pushed to
 * the end of the same row, never glued to the button's side. When the width runs out the links
 * wrap under the button and stay end-aligned, because the margin is on the group, not on a gap.
 * The class is the whole rule: a view that has a button and links in one row carries it, and
 * tests/Unit/Ui/AppActionsRowTest finds the row that does not.
 */
.app-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
}

.app-actions__links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    margin-inline-start: auto;
}

/* --- Icon button --------------------------------------------------------------------- */

/* A glyph alone is guessed, not read, so every icon button carries a tooltip; the markup
   helper refuses to render one without it. */
.app-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: var(--icon-btn);
    height: var(--icon-btn);
    padding: 0;
    border: 1px solid var(--border-control);
    border-radius: var(--radius-control);
    background: var(--surface);
    color: var(--text-2);
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition), color var(--transition);
}

.app-icon-btn:hover {
    background: var(--surface-2);
    border-color: var(--border-3);
    color: var(--text);
}

/* In a card header the button has no outline until the pointer arrives. */
.app-icon-btn--head {
    border-color: transparent;
    background: transparent;
}

.app-icon-btn--head:hover {
    border-color: var(--border-2);
    background: var(--surface-2);
}

/* An action that does not apply right now: shown, explained by its tooltip, and inert.
   aria-disabled rather than the disabled attribute — a disabled button takes no pointer
   events, and the explanation would be unreachable. */
.app-icon-btn[aria-disabled='true'] {
    border-color: var(--border);
    background: var(--surface-2);
    color: var(--text-disabled);
    cursor: not-allowed;
}

.app-icon-btn[aria-disabled='true']:hover {
    border-color: var(--border);
    background: var(--surface-2);
    color: var(--text-disabled);
}

/*
 * An empty slot in a row of actions.
 *
 * Glyphs in a list stand strictly one under another (core.md §4.4), so a row with
 * fewer actions than its neighbours keeps their places rather than shifting the column.
 */
.app-icon-btn--blank {
    visibility: hidden;
    pointer-events: none;
}

/* A gain and a loss keep the colours they have everywhere else in the project. */
.app-icon-btn--positive {
    color: var(--positive);
}

.app-icon-btn--positive:hover {
    border-color: var(--positive);
    background: var(--scale-positive-1);
    color: var(--positive);
}

.app-icon-btn--negative {
    color: var(--negative);
}

.app-icon-btn--negative:hover {
    border-color: var(--negative);
    background: var(--negative-soft);
    color: var(--negative);
}

/* Danger at rest (D-275): the destructive icon is red before the pointer arrives; hover adds the border and wash. */
.app-icon-btn--danger {
    color: var(--negative);
}

.app-icon-btn--danger:hover {
    border-color: var(--negative);
    background: var(--negative-soft);
    color: var(--negative);
}

/* --- Loading ring -------------------------------------------------------------------- */

.app-spinner {
    display: block;
    flex: none;
    width: 18px;
    height: 18px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: app-spin 700ms linear infinite;
}

/* --- Touch --------------------------------------------------------------------------- */

@media (pointer: coarse) {
    .app-btn {
        height: var(--control-touch);
        border-radius: var(--radius);
    }

    .app-icon-btn {
        width: var(--icon-btn-touch);
        height: var(--icon-btn-touch);
        border-radius: var(--radius);
    }

    .app-copy {
        min-height: var(--control-touch);
    }
}

/*
 * A value that copies itself when clicked.
 *
 * It looks like the text it carries, not like a button: what the owner wants is the number, and
 * the glyph beside it is the whole announcement that a click will do something. The tooltip says
 * what (core.md §16.1).
 */
.app-copy {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.app-copy .app-icon {
    color: var(--text-4);
    transition: color var(--transition);
}

.app-copy:hover .app-icon {
    color: var(--accent);
}

/*
 * One line under a page-level primary action: the condition or the side effect of pressing
 * it (core.md §9.10) — "takes about two minutes", "the current file will be replaced". Not a tooltip,
 * because the owner must see it before deciding to hover; not a dialog, because the action is
 * reversible. Quiet, one line, never wraps into a paragraph.
 */
.app-btn-note {
    max-width: var(--w-prose);
    margin: var(--space-1) 0 0;
    color: var(--text-3);
    font-size: var(--fs-caption);
    line-height: var(--lh-tight);
}
