/* ===========================================================================
   field.css — form controls and validation
   ---------------------------------------------------------------------------
   Markup contract (rendered by src/View/ui.php → ui_field()):

     <div class="field" data-state="error">
       <label class="field__label" for="qty">
         Quantity <span class="field__req" aria-hidden="true">*</span>
       </label>
       <div class="field__control">
         <input id="qty" class="input num" aria-describedby="qty-hint qty-err">
         <span class="field__affix">USDT</span>
       </div>
       <p class="field__hint" id="qty-hint">Minimum 0.001</p>
       <p class="field__error" id="qty-err" role="alert">Above available balance</p>
     </div>

   Validation is driven by data-state on .field, not by :invalid. Native
   :invalid fires while the user is still typing, which flags a field red on
   its first keystroke; the product marks errors on blur and on submit only
   (see core/form.js).
   =========================================================================== */

.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;   /* lets a field shrink inside a grid without overflowing */
}

.field__label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caps);
    cursor: pointer;
}

.field__req {
    color: var(--danger);
    font-weight: var(--weight-bold);
}

/* A secondary action inside the label row — "Forgot password?", "Max". */
.field__label-aside {
    margin-inline-start: auto;
    text-transform: none;
    letter-spacing: normal;
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
}

/* ---------------------------------------------------------------------------
   Control wrapper. Exists so a prefix/suffix (currency, unit, reveal toggle)
   can sit inside the visual border of the input.
   --------------------------------------------------------------------------- */
.field__control {
    display: flex;
    align-items: stretch;
    position: relative;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    transition:
        border-color var(--duration-fast) var(--ease-out),
        box-shadow var(--duration-fast) var(--ease-out),
        background-color var(--duration-fast) var(--ease-out);
}

.field__control:hover {
    border-color: var(--border-strong);
}

/* The ring is drawn on the wrapper, not the input, so it surrounds the affix
   too and reads as one control. :has() lets CSS react to the inner focus. */
.field__control:focus-within {
    border-color: var(--accent);
    box-shadow: var(--shadow-focus);
    background: var(--canvas-alt);
}

/* ---------------------------------------------------------------------------
   Inputs
   --------------------------------------------------------------------------- */
.input,
.select,
.textarea {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
    padding-block: var(--pad-control-y);
    padding-inline: var(--pad-control-x);
    min-height: var(--touch-target);
    background: transparent;
    border: 0;
    color: var(--text);
    font-size: var(--text-base);
    line-height: 1.4;
}

.input:focus,
.select:focus,
.textarea:focus {
    /* The wrapper already shows the ring. */
    outline: none;
}

/* Unless there is no wrapper. A control placed straight into a table cell —
   the price-correction fields in admin history are these — has nothing above it
   to carry the ring, so the rule above left it with no focus indicator at all.
   It draws its own, inset so a scrolling cell cannot clip it. */
.input:focus-visible:not(.field__control *),
.select:focus-visible:not(.field__control *),
.textarea:focus-visible:not(.field__control *) {
    outline: var(--ring-width) solid var(--accent);
    outline-offset: -1px;
}

.input:disabled,
.select:disabled,
.textarea:disabled {
    color: var(--text-faint);
    -webkit-text-fill-color: var(--text-faint);  /* Safari honours this only */
}

.field__control:has(.input:disabled),
.field__control:has(.select:disabled),
.field__control:has(.textarea:disabled) {
    background: var(--surface-sunken);
    border-color: var(--border-subtle);
    opacity: 0.6;
}

/* Read-only shows real content, so it must not look disabled — only inert. */
.field__control:has(.input[readonly]) {
    background: var(--surface-sunken);
    border-style: dashed;
}

.textarea {
    min-height: calc(var(--touch-target) * 2.5);
    line-height: var(--leading-normal);
    resize: vertical;
}

/* Amount inputs get the mono/tabular treatment from base.css via .num, plus
   a larger size: these are the numbers users double-check before submitting. */
.input--amount {
    font-size: var(--text-lg);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-tight);
}

/* A wallet address or tx hash: long, Latin, must not wrap mid-string. */
.input--address {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    direction: ltr;
    text-align: start;
}

/* ---------------------------------------------------------------------------
   Select. Native element kept (accessible, works on mobile) with the arrow
   drawn via background-image so no wrapper markup is needed.
   --------------------------------------------------------------------------- */
.select {
    appearance: none;
    -webkit-appearance: none;
    padding-inline-end: var(--space-10);
    cursor: pointer;
    /* Inline SVG chevron. currentColor is not available in a data URI, so the
       muted token value is inlined; it is theme-independent enough to read on
       both surfaces. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238e99b3' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 16px;
    background-position: right var(--space-4) center;
}

[dir="rtl"] .select {
    background-position: left var(--space-4) center;
}

.select option {
    /* Native dropdown lists are OS-rendered; set an explicit background so
       dark themes do not produce white-on-white on Windows. */
    background: var(--surface-overlay);
    color: var(--text);
}

/* ---------------------------------------------------------------------------
   Affixes — unit labels and inline actions inside the control border.
   --------------------------------------------------------------------------- */
.field__affix {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding-inline: var(--space-3);
    background: var(--surface-raised);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    white-space: nowrap;
    /* Logical border so the divider lands on the correct side in RTL. */
    border-inline-start: 1px solid var(--border-subtle);
}

.field__affix--start {
    border-inline-start: 0;
    border-inline-end: 1px solid var(--border-subtle);
}

/* An interactive affix (password reveal, "MAX", copy) — still inside the ring. */
.field__action {
    display: inline-flex;
    align-items: center;
    padding-inline: var(--space-3);
    background: none;
    border: 0;
    border-inline-start: 1px solid var(--border-subtle);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out);
}

.field__action:hover {
    color: var(--accent-text);
}

/* ---------------------------------------------------------------------------
   Hints and errors
   --------------------------------------------------------------------------- */
.field__hint {
    max-width: none;
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
    color: var(--text-muted);
}

/* The error line is ALWAYS in the layout — it is revealed, never inserted.
   ---------------------------------------------------------------------------
   It used to be display:none until needed. Showing or hiding it moved
   everything below by a line, and that shift caused a real, reproducible lost
   click: with a server error visible under a field, pressing a button below it
   fired blur first, blur cleared the message, the message's line collapsed,
   the button moved up between mousedown and mouseup, and no click event was
   generated at all. The button looked dead.

   Reserving the space costs ~18px under each field and makes every form
   layout stable while validation state changes. `visibility` rather than
   `display` keeps it out of the accessibility tree when empty. */
.field__error {
    max-width: none;
    display: flex;
    visibility: hidden;
    min-height: calc(var(--text-xs) * var(--leading-snug));
    align-items: flex-start;
    gap: var(--space-2);
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
    font-weight: var(--weight-medium);
    color: var(--danger);
}

/* ---------------------------------------------------------------------------
   States. Driven by data-state so JS owns exactly one attribute per field.

   Errors are announced by colour AND an icon AND text (WCAG 1.4.1) — never
   colour alone, which is what the old pages relied on.
   --------------------------------------------------------------------------- */
.field[data-state="error"] .field__control {
    border-color: var(--danger);
    background: var(--danger-dim);
}

.field[data-state="error"] .field__control:focus-within {
    box-shadow: 0 0 0 var(--ring-width) var(--down-glow);
}

.field[data-state="error"] .field__error {
    visibility: visible;
}

.field[data-state="error"] .field__error::before {
    content: "⚠";
    flex-shrink: 0;
    font-size: var(--text-sm);
    line-height: 1.3;
}

/* The hint STAYS visible when an error appears.
   An earlier version hid it, which reintroduced exactly the layout shift the
   reserved error line exists to prevent — removing the hint's line moved
   everything below up by as much as showing the error moved it down.

   Two lines under one control is a small cost; they are visually distinct
   (the error is red, carries a ⚠ and is announced via role="alert") and the
   hint usually explains the rule the error is about, which is worth keeping
   in view while the user fixes it. */
.field[data-state="error"] .field__hint {
    color: var(--text-faint);
}

.field[data-state="success"] .field__control {
    border-color: var(--success);
}

.field[data-state="warning"] .field__control {
    border-color: var(--warning);
}

/* ---------------------------------------------------------------------------
   Checkbox and radio. Custom-drawn because the native controls cannot be
   themed on Windows, but built on the real input so keyboard and screen
   reader behaviour is untouched.
   --------------------------------------------------------------------------- */
.check {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    cursor: pointer;
    /* Generous hit area without changing visual size. */
    padding-block: var(--space-1);
}

.check__input {
    flex-shrink: 0;
    appearance: none;
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    margin: 0;
    margin-block-start: 1px;
    background: var(--surface-sunken);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-xs);
    cursor: pointer;
    display: grid;
    place-content: center;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
}

.check__input[type="radio"] {
    border-radius: 50%;
}

.check__input::before {
    content: "";
    width: 11px;
    height: 11px;
    transform: scale(0);
    transition: transform var(--duration-fast) var(--ease-out);
    background: var(--text-on-accent);
    /* Checkmark drawn with a clip-path so no icon font or SVG is needed. */
    clip-path: polygon(14% 44%, 0 65%, 40% 100%, 100% 16%, 82% 0%, 37% 62%);
}

.check__input[type="radio"]::before {
    clip-path: none;
    border-radius: 50%;
    width: 8px;
    height: 8px;
}

.check__input:checked {
    background: var(--accent);
    border-color: var(--accent);
}

.check__input:checked::before {
    transform: scale(1);
}

.check__input:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.check__label {
    font-size: var(--text-sm);
    line-height: var(--leading-snug);
    color: var(--text-secondary);
    max-width: 72ch;
}

.check__label strong {
    color: var(--text);
    font-weight: var(--weight-semibold);
}

/* Risk/terms acknowledgement — deliberately heavier than a normal checkbox
   so it cannot be skimmed past. */
.check--ack {
    padding: var(--pad-card-sm);
    background: var(--warning-dim);
    border: 1px solid var(--warning);
    border-radius: var(--radius-md);
}

.check--ack .check__label {
    color: var(--text);
}

/* ---------------------------------------------------------------------------
   Switch — for settings that apply immediately (2FA on/off, notifications).
   Not for form fields that need a submit; a checkbox is correct there.
   --------------------------------------------------------------------------- */
.switch {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    cursor: pointer;
}

.switch__input {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex-shrink: 0;
    width: 44px;
    height: 24px;
    margin: 0;
    background: var(--surface-sunken);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background-color var(--duration-base) var(--ease-out),
                border-color var(--duration-base) var(--ease-out);
}

.switch__input::after {
    content: "";
    position: absolute;
    inset-block-start: 3px;
    inset-inline-start: 3px;
    width: 16px;
    height: 16px;
    background: var(--text-muted);
    border-radius: 50%;
    transition: transform var(--duration-base) var(--ease-out),
                background-color var(--duration-base) var(--ease-out);
}

.switch__input:checked {
    background: var(--accent);
    border-color: var(--accent);
}

.switch__input:checked::after {
    background: var(--text-on-accent);
    /* translate, not inset-inline-start, so the thumb slides the correct way
       in RTL without a direction-specific rule. */
    transform: translateX(20px);
}

[dir="rtl"] .switch__input:checked::after {
    transform: translateX(-20px);
}

/* ---------------------------------------------------------------------------
   Layout helpers for forms
   --------------------------------------------------------------------------- */
.form-stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

/* Two fields on one row that collapse to one column on phones. */
.form-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: var(--space-4);
}

.form-divider {
    height: 1px;
    background: var(--border-subtle);
    border: 0;
    margin-block: var(--space-2);
}

/* A grouped set of controls with its own heading (fieldset semantics). */
.form-group {
    border: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.form-group__legend {
    padding: 0;
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    color: var(--text);
}

/* ---------------------------------------------------------------------------
   Password strength meter. Four segments matching the server's policy in
   src/auth.php (length >= 10, 3 of 4 character classes, not blocklisted),
   so the client never claims a password is acceptable when the API will
   reject it.
   --------------------------------------------------------------------------- */
.strength {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.strength__track {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-1);
}

.strength__seg {
    height: 4px;
    background: var(--border-subtle);
    border-radius: var(--radius-pill);
    transition: background-color var(--duration-base) var(--ease-out);
}

.strength[data-score="1"] .strength__seg:nth-child(-n+1),
.strength[data-score="2"] .strength__seg:nth-child(-n+2),
.strength[data-score="3"] .strength__seg:nth-child(-n+3),
.strength[data-score="4"] .strength__seg:nth-child(-n+4) {
    background: var(--danger);
}

.strength[data-score="2"] .strength__seg:nth-child(-n+2) { background: var(--warning); }
.strength[data-score="3"] .strength__seg:nth-child(-n+3) { background: var(--accent); }
.strength[data-score="4"] .strength__seg { background: var(--success); }

.strength__text {
    font-size: var(--text-xs);
    color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
   Compact input — an editable cell inside a data table.

   A full-height control makes every row in the table taller than the rows
   around it, so a table with one editable column loses its rhythm entirely.
   --------------------------------------------------------------------------- */
.input--sm {
    min-height: 30px;
    padding-block: var(--space-1);
    padding-inline: var(--space-2);
    font-size: var(--text-xs);
    /* Sized to eight decimals plus a five-digit price — "86492.41000000" is
       exactly fourteen characters — and no wider, because a wider column
       pushes the action button off a tablet.

       The padding and borders have to be added on: box-sizing is border-box
       globally, so a bare 14ch left about eleven characters of room and clipped
       the rest of the price. A price editor that hides the end of the price is
       worse than no editor. */
    inline-size: calc(14ch + (var(--space-2) * 2) + 2px);
    min-inline-size: 0;
}

/* A checkbox whose label carries its own explanation. ui_check() takes label
   HTML, so the hint lives inside the <label> and must break onto its own
   line rather than running on after the label text. */
.check__hint {
    display: block;
    margin-block-start: 2px;
    font-size: var(--text-2xs);
    font-weight: var(--weight-regular);
    color: var(--text-muted);
}
