/*
  QRCodeGenerator — shared components (docs/08-UI-SPEC.md §9.1, @layer components).

  The things more than one page needs and that are too specific to be primitives:
  a labelled field, a button, an inline message. They are here rather than in a
  scoped *.razor.css because a control that looks different on the sign-in page
  from how it looks in the client editor is the drift §9.2 exists to stop.

  Tokens only. A raw colour, space or radius in this file fails DesignSystemTests.
*/

@layer components {
    /* ── Fields ────────────────────────────────────────────────────────────
       Label above control, hint below, one stack. The label is a real <label>
       with a `for`, never a placeholder: a placeholder disappears the moment
       somebody starts typing, which is when they most need to know what the
       box is (§9.7, "every input labelled").
    */
    .field {
        display: flex;
        flex-direction: column;
        gap: var(--space-2);
    }

    .field > label {
        font-size: var(--text-sm);
        font-weight: var(--weight-medium);
    }

    .field input,
    .field select,
    .field textarea {
        min-block-size: var(--control-h);
        padding-inline: var(--space-3);

        border: 1px solid var(--border-strong);
        border-radius: var(--r-md);
        background: var(--surface);
        color: var(--text);

        transition: border-color var(--dur-instant) var(--ease-out),
                    box-shadow var(--dur-instant) var(--ease-out);
    }

    .field input:hover,
    .field select:hover,
    .field textarea:hover {
        border-color: var(--accent);
    }

    /* Blazor writes `invalid` onto a control its validator refused. */
    .field input.invalid,
    .field textarea.invalid {
        border-color: var(--err);
    }

    .field__hint,
    .field__error {
        font-size: var(--text-xs);
    }

    .field__error {
        color: var(--err);
    }

    .field__required {
        color: var(--err);
        margin-inline-start: var(--space-1);
    }

    /* A flag reads as one control: the box and its words on one line, and the
       whole thing clickable because they are inside the <label>. */
    .field--flag > .flag {
        display: flex;
        align-items: center;
        gap: var(--space-2);
        min-block-size: var(--control-h);
        cursor: pointer;
        font-size: var(--text-sm);
        font-weight: var(--weight-medium);
    }

    /* ── Nested groups and repeatable lists ────────────────────────────────
       A real <fieldset> with a <legend>: that is what tells a screen reader
       the controls inside belong together, which a styled div with a heading
       does not (docs/08-UI-SPEC.md §3, §9.7).
    */
    .group,
    .list,
    .map {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);

        margin: 0;
        padding: var(--space-4);
        border: 1px solid var(--border);
        border-radius: var(--r-md);
        background: var(--surface-2);
    }

    .group > legend,
    .list > legend,
    .map > legend {
        padding-inline: var(--space-2);
    }

    .group__hint {
        margin: 0;
        font-size: var(--text-xs);
    }

    .group__fields,
    .list__items,
    .map__rows {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
        margin: 0;
        padding: 0;
        list-style: none;
    }

    /* The entry, then its remove button: aligned to the top so the button sits
       beside the first field of a tall group rather than floating in its middle. */
    .list__item,
    .map__row {
        display: flex;
        align-items: flex-start;
        gap: var(--space-2);
    }

    .list__body {
        flex: 1;
        min-inline-size: 0;
    }

    .map__row > .field {
        flex: 1;
        min-inline-size: 0;
    }

    .list__remove:hover,
    .map__remove:hover {
        color: var(--err);
        border-color: var(--err);
    }

    /* ── Buttons ───────────────────────────────────────────────────────────
       One shape, three weights. Height is the 40 px touch minimum of §9.4.
    */
    .button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: var(--space-2);

        min-block-size: var(--control-h);
        padding-inline: var(--space-4);

        border: 1px solid var(--border-strong);
        border-radius: var(--r-md);
        background: var(--surface);
        color: var(--text);
        cursor: pointer;

        font-size: var(--text-sm);
        font-weight: var(--weight-medium);

        transition: background-color var(--dur-instant) var(--ease-out),
                    border-color var(--dur-instant) var(--ease-out),
                    color var(--dur-instant) var(--ease-out);
    }

    .button:hover {
        border-color: var(--accent);
        color: var(--accent);
    }

    .button--primary {
        border-color: transparent;
        background: var(--accent);
        color: var(--accent-contrast);
    }

    .button--primary:hover {
        background: color-mix(in oklch, var(--accent) 88%, var(--text));
        border-color: transparent;
        color: var(--accent-contrast);
    }

    /* A control that is a control and looks like text: the account menu's summary,
       the copy buttons of task 6.12. */
    .button--ghost {
        border-color: transparent;
        background: transparent;
        color: var(--text-muted);
    }

    /* ── Chips ─────────────────────────────────────────────────────────────
       A verdict in one line: an icon, a figure and a word. Three signals, so
       colour is never the only one (§9.7) — the contrast readout of §9.6 is
       the first of them and the capacity gauge follows the same shape.
    */
    .chip {
        display: inline-flex;
        align-items: center;
        gap: var(--space-2);

        margin: 0;
        padding: var(--space-1) var(--space-3);
        border-radius: var(--r-full);

        font-size: var(--text-xs);
        font-weight: var(--weight-medium);
    }

    .chip--ok {
        background: color-mix(in oklch, var(--ok) 14%, transparent);
        color: var(--ok);
    }

    .chip--warn {
        background: color-mix(in oklch, var(--warn) 16%, transparent);
        color: var(--warn);
    }

    .chip--err {
        background: color-mix(in oklch, var(--err) 14%, transparent);
        color: var(--err);
    }

    /* ── Colour control ────────────────────────────────────────────────────
       A swatch and the hex beside it, editing one value. The swatch is what
       somebody picks with; the hex is what they paste a brand colour into,
       and it is what ends up in the API request they copy afterwards.
    */
    .colorField__controls {
        display: flex;
        align-items: center;
        gap: var(--space-2);
    }

    .colorField__swatch {
        inline-size: var(--control-h);
        block-size: var(--control-h);
        padding: var(--space-1);
        border: 1px solid var(--border-strong);
        border-radius: var(--r-md);
        background: var(--surface);
        cursor: pointer;
    }

    .colorField__hex {
        flex: 1;
        min-inline-size: 0;
    }

    .colorField__clear {
        flex: none;
        padding-inline: var(--space-2);
    }

    /* ── Inline messages ───────────────────────────────────────────────────
       Colour is never the only signal (§9.7), so each carries its own icon and
       its own words; the tint is the third signal, not the first.
    */
    .alert {
        display: flex;
        align-items: flex-start;
        gap: var(--space-3);

        padding: var(--space-3) var(--space-4);
        border: 1px solid var(--border);
        border-radius: var(--r-md);
        background: var(--surface-2);

        font-size: var(--text-sm);
    }

    .alert--error {
        border-color: var(--err);
        color: var(--err);
    }

    .alert--ok {
        border-color: var(--ok);
        color: var(--ok);
    }

    .alert--warn {
        border-color: var(--warn);
        color: var(--warn);
    }

    /* ── Destructive button ────────────────────────────────────────────────
       Revoking a key and disabling a client are the two actions in this product
       that cannot be undone from the screen that started them, so they are the
       two that look different. The confirmation dialog is the real guard; the
       colour is the warning before it (§5).
    */
    .button--danger {
        border-color: transparent;
        background: var(--err);
        color: var(--accent-contrast);
    }

    .button--danger:hover {
        background: color-mix(in oklch, var(--err) 88%, var(--text));
        border-color: transparent;
        color: var(--accent-contrast);
    }

    /* ── Tables ────────────────────────────────────────────────────────────
       The client list, the key list and the usage breakdowns are all the same
       table: figures right-aligned with tabular numerals so a column of numbers
       can be compared down its length (§9.3), and a sortable header that is a
       real button rather than a clickable cell.
    */
    .table {
        inline-size: 100%;
        border-collapse: collapse;
        font-size: var(--text-sm);
    }

    .table th,
    .table td {
        padding: var(--space-2) var(--space-3);
        border-block-end: 1px solid var(--border);
        text-align: start;
        vertical-align: middle;
    }

    .table thead th {
        color: var(--text-muted);
        font-size: var(--text-xs);
        font-weight: var(--weight-medium);
        white-space: nowrap;
    }

    .table tbody tr:hover {
        background: var(--surface-2);
    }

    .table__number {
        text-align: end;
        font-variant-numeric: tabular-nums;
    }

    .table__sort {
        display: inline-flex;
        align-items: center;
        gap: var(--space-1);

        padding: 0;
        border: 0;
        background: none;
        color: inherit;
        cursor: pointer;

        font: inherit;
    }

    .table__sort:hover {
        color: var(--accent);
    }

    .table__sort[aria-sort='ascending']::after {
        content: '↑';
    }

    .table__sort[aria-sort='descending']::after {
        content: '↓';
    }

    /* ── Stat tile ─────────────────────────────────────────────────────────
       One figure and what it is. The figure is the largest thing in the tile and
       carries tabular numerals, so a row of tiles lines up down the column and a
       number that changes does not shift its neighbours (§9.3).
    */
    .stat {
        display: flex;
        flex-direction: column;
        gap: var(--space-1);
        margin: 0;
    }

    .stat__label {
        color: var(--text-muted);
        font-size: var(--text-xs);
    }

    .stat__value {
        font-size: var(--text-xl);
        font-weight: var(--weight-medium);
        font-variant-numeric: tabular-nums;
        line-height: 1.15;
    }

    /* ── Modal ─────────────────────────────────────────────────────────────
       Rendered from server state rather than through <dialog>.showModal(), so a
       confirmation and the one-time key display need no script to appear — the
       circuit is already open, and a guard that depends on JavaScript is a guard
       that fails open.
    */
    .modal {
        position: fixed;
        inset: 0;
        z-index: var(--z-modal);

        display: grid;
        place-items: center;
        padding: var(--space-4);

        background: color-mix(in oklch, var(--text) 40%, transparent);
    }

    .modal__panel {
        inline-size: min(34rem, 100%);
        max-block-size: 85vh;
        overflow-y: auto;
        padding: var(--space-6);
        box-shadow: var(--shadow-lg);
    }

    .modal__actions {
        justify-content: flex-end;
    }
}
