/* BMA UI -- convention component primitives (BMA_UX_CONVENTIONS; enforced by app/conventions_audit.py).
   Builds define the design tokens (--accent, --rule, --paper, --ink-soft, --ink, --ink-faint).
   Look is overridable per build; the structure/behavior here is the convention.

   LOAD ORDER: this sheet loads BEFORE the build's app.css, so the build wins any conflict.

   WHY --accent HAS NO FALLBACK, when the neutrals do. A fallback is safe when being
   wrong is cosmetic and unsafe when being wrong is a SIGNAL. --rule, --paper, --ink,
   --ink-soft and --ink-faint are neutrals: a default grey hairline is merely plain.
   --accent is the colour the conventions spend on "this is required of you", so a
   hardcoded fallback does not degrade, it ASSERTS -- it puts a colour with a meaning
   on the screen that no build ever chose. It carried #8b2c2c until 2026-08-14, and
   because no build has ever defined --accent, that fallback was not a fallback: it was
   the value, in every build, including a dark red helper line under every required
   field of a build whose palette had nothing to do with it. A build could follow its
   own colour rules perfectly, grep its own stylesheet, count zero, and still ship it.

   With no fallback, an undefined --accent makes the declaration invalid at computed-value
   time and the property inherits. A build that defines no accent therefore shows no
   accent, which is a visible absence rather than a confident wrong answer. Do not
   "fix" that by picking a colour here; define --accent in the build. */

/* I.A / I.B -- an inactive action button reads as inactive. */
.btn:disabled, .btn[disabled] { opacity: 0.4; cursor: not-allowed; pointer-events: none; }

/* II -- removable upload: the top-right "x" over a dropzone. */
.dropzone-stack { position: relative; }
.dropzone-remove-form { margin: 0; }
.dropzone-remove {
  position: absolute; top: 14px; right: 14px; width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center; padding: 0;
  border: 1px solid var(--rule, #d8d2c4); border-radius: 50%;
  background: var(--paper, #ffffff); color: var(--ink-soft, #6b6b6b);
  font-size: 20px; line-height: 1; cursor: pointer; z-index: 2;
  transition: color 150ms ease, border-color 150ms ease;
}
.dropzone-remove:hover { color: var(--accent); border-color: var(--accent); }

/* II -- a required-but-empty field prompts in the accent color, hidden once the field is valid. */
.field-required-tag {
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent); margin-left: 8px; vertical-align: middle;
}
.field-hint { display: block; margin-top: 6px; font-size: 12px; color: var(--accent); }
/* Any control counts, not only <input>: the tag and the empty-state hint disappear the moment
   the row's control is valid. The invalid-state hint (.field-hint--invalid) shows only when the
   control has a value AND is invalid (a URL without a scheme, a number out of range); the empty
   state shows only the plain hint. :placeholder-shown tells the two apart for inputs and
   textareas; a select is either empty (value "") or valid, so it never shows the invalid hint. */
.field-row:has(input:valid) .field-required-tag,
.field-row:has(select:valid) .field-required-tag,
.field-row:has(textarea:valid) .field-required-tag,
.field-row:has(input:valid) .field-hint,
.field-row:has(select:valid) .field-hint,
.field-row:has(textarea:valid) .field-hint { display: none; }
.field-hint--invalid { display: none; }
.field-row:has(input:invalid:not(:placeholder-shown)) .field-hint--invalid,
.field-row:has(textarea:invalid:not(:placeholder-shown)) .field-hint--invalid { display: block; }
.field-row:has(input:invalid:not(:placeholder-shown)) .field-hint--empty,
.field-row:has(textarea:invalid:not(:placeholder-shown)) .field-hint--empty { display: none; }
/* The control itself carries the accent while it is invalid, so the eye lands on it. */
.field-row input:invalid, .field-row select:invalid, .field-row textarea:invalid {
  border-color: var(--accent);
}
.field-row input:invalid:focus, .field-row select:invalid:focus, .field-row textarea:invalid:focus {
  box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--accent) 20%, transparent);
}
/* The live "complete these to submit" line under a gated button (data-gating-summary). */
.gating-summary { display: block; margin-top: 8px; font-size: 12px; color: var(--accent); }
.gating-summary:empty { display: none; }

/* Buyer-secret credential rows (credentials_section): a wide input that fills the
   available space, text + password styled alike, and a compact right-sized action button. */
.secret-set-form { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; }
.secret-input {
  flex: 1 1 380px; min-width: 260px;
  font-family: 'JetBrains Mono', monospace; font-size: 13px;
  background: transparent; border: none;
  border-bottom: 1px solid var(--ink-soft, #6b6b6b);
  padding: 6px 0; color: var(--ink, #2b2b2b); outline: none;
}
.secret-input:focus { border-bottom-color: var(--accent); }
.secret-set-form .btn, .secret-remove-form .btn { padding: 9px 18px; font-size: 12px; }
.secret-privacy-note {
  margin: 10px 0 0; font-size: 11px; line-height: 1.5;
  color: var(--ink-faint, #999999);
}

/* III.B -- an out-of-scope ("v2"/Preview) control is visibly inert + badged. */
.is-v2 { opacity: 0.55; pointer-events: none; position: relative; }
.v2-badge {
  display: inline-block; font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--paper, #ffffff); background: var(--ink-faint, #999999);
  padding: 1px 6px; margin-left: 8px; vertical-align: middle;
}
