/* ============================================================
   CCD Design System v2 — FORMS
   Ground-up rebuild 2026-07-01, from tokens.css + type.css.
   Internal dense tool: compact fields, accent only on focus,
   error carries meaning by a neg dot (text stays ink — same
   Type-1 doctrine as the table status).
   ============================================================ */

/* Field = label + control + hint, stacked. ------------------- */
.field { display: flex; flex-direction: column; gap: var(--s-2); }

.field__label {
  font-size: var(--fs-body);
  font-weight: var(--fw-semi);   /* labels anchor the scan */
  color: var(--ink);
}
.field__label .req { color: var(--neg-strong); margin-left: 2px; }   /* required mark — TEXT, so the accessible red (dot-tier --neg is 2.99:1, fails AA; tokens.css: bright hues are dot-only) */

.field__hint { font-size: var(--fs-body); color: var(--muted); }

/* Control base — input / textarea / select share this. ------- */
.control {
  width: 100%;
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
  background: var(--ctl-face);
  border: 1px solid var(--rule);
  border-radius: var(--r-base);
  /* Height is the token, not a padding sum — see tokens.css --ctl-h. An <input>
     will not shrink below its font's natural line box whatever line-height says,
     so padding-derived sizing left every field ~8px taller than the button next
     to it. Setting height outright is the only thing that actually holds.
     And it only holds under border-box — see the note in buttons.css for why that
     is declared per component instead of by a global reset. */
  box-sizing: border-box;
  height: var(--ctl-h);
  padding: 0 var(--s-3);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.control::placeholder { color: var(--muted); }   /* muted = 5.51:1, safe as placeholder */

/* :not(:disabled) is load-bearing. Both pseudo-classes can match at once and they
   set different properties, so without the guard a disabled field BRIGHTENED its
   border under the cursor — an inert control advertising that you can use it. The
   :disabled rule below cannot undo it either, because it never restates
   border-color. .btn and .menu-btn already excluded disabled; .control did not
   (Codex audit 2026-07-30). */
.control:hover:not(:disabled) { border-color: var(--muted); }

.control:focus,
.control:focus-visible {
  outline: 2px solid transparent;              /* invisible normally (kills native orange) but Windows High Contrast Mode paints it — box-shadow is stripped there (CCD-110) */
  outline-offset: -2px;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);   /* reads as a crisp 2px brand border, no halo, no layout shift */
}

.control:disabled {
  /* --ctl-track, not --divider. They are the same value on light, but on dark
     --divider is LIGHTER than --card (a hairline has to climb off the surface),
     so a disabled field painted with it read as RAISED — the opposite of inert.
     --ctl-track is the recessing token and sinks correctly in both modes. */
  background: var(--ctl-track);
  color: var(--muted);
  cursor: not-allowed;
}

/* A textarea is prose, not a control on a line — it opts out of --ctl-h and
   keeps real vertical padding and reading leading.
   NO RESIZE GRABBER (owner call 2026-07-29). The handle let every user invent
   their own box size, so no two screenshots of the same form matched, and a
   dragged-tall textarea shoved the rest of the form down the page. Instead the
   box GROWS ITSELF as you type: field-sizing does it natively where supported,
   capped so a long answer scrolls inside instead of swallowing the screen.
   Browsers without field-sizing simply keep the fixed 88px box and scroll —
   same as before, minus the handle. Need a taller default? Set a height on the
   instance; do not hand the decision to the user. */
textarea.control {
  height: auto;
  min-height: 88px;
  max-height: 220px;
  field-sizing: content;
  overflow-y: auto;
  resize: none;
  padding-block: var(--row-y);
  line-height: var(--lh-normal);
}

/* Select — native chevron is inconsistent (Safari clamps height),
   so strip it and paint our own. */
select.control {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--s-6);
  /* Token, not a literal — a colour baked into a data-URI cannot follow a var(),
     so the hardcoded stroke stayed light-grey on a dark field (2.64:1 over a dark
     modal). tokens.css --ctl-chevron carries both modes. */
  background-image: var(--ctl-chevron);
  background-repeat: no-repeat;
  background-position: right var(--s-3) center;
}

/* Checkbox / radio — native, tinted to brand. accent-color is
   one line and respects the OS control; no custom SVG needed. */
.check { display: inline-flex; align-items: center; gap: var(--s-2); font-size: var(--fs-body); color: var(--ink); }
.check input[type="checkbox"],
.check input[type="radio"] {
  width: 16px; height: 16px; margin: 0; flex: 0 0 auto;
  accent-color: var(--accent);
  cursor: pointer;
}
.check input:disabled { cursor: not-allowed; }
.check input:disabled + span { color: var(--muted); }

/* Error state — border turns neg, a neg dot leads the message;
   message text stays ink (bright red would fail AA as text). */
.field--error .control { border-color: var(--neg); }
.field--error .control:focus { box-shadow: inset 0 0 0 1px var(--neg); }   /* 2px neg border, matching the no-halo focus */
.field__error {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-body); color: var(--ink);
}
.field__error::before {
  content: ""; width: 8px; height: 8px; border-radius: var(--r-pill);
  background: var(--neg); flex: 0 0 auto;
}

/* ── Layout — form measure + field grouping. -----------------
   forms.css now covers page assembly, not just the control:
   .form caps + centres the measure; .stack / .row2 group fields.

   NAME RISK, KNOWN AND ACCEPTED. `.stack` and `.row2` are bare single-class
   selectors at specificity (0,1,0), and they are generic enough that an app could
   plausibly define its own. On a tie the CDN <link> loads after a Next CSS module,
   so THE DS WINS and quietly reshapes the consumer's element — the same family as
   the scar in memory `reference_ds_cdn_beats_module_css`.
   Left as-is on purpose: these are the DS's published layout helpers and the v2
   consumers using them are using them deliberately, so a rename is a breaking
   change that buys nothing today. If a real collision ever appears, rename here
   AND in the consumer in one batch — never ship an alias. Same call for .li in
   scale.css, which is the riskier name of the three (CCD-174). */
.form  { max-width: var(--form-measure, 480px); margin-inline: auto; }
.form--wide { --form-measure: 720px; }          /* admin / dense multi-column forms */

.stack { display: flex; flex-direction: column; gap: var(--s-4); }
.row2  { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }

/* ── Mobile — attendee forms (register, rate) are phone-used.
   Two real-device landmines closed here; everything else is
   layout reflow. Admin forms run on laptops — unaffected. ---- */
@media (max-width: 400px) {
  .control { font-size: 16px; min-height: 44px; }   /* 16px = no iOS focus-zoom · 44px = thumb target */
  textarea.control { min-height: 88px; }
  .form { max-width: 100%; }                          /* full-width on phone */
  .row2 { grid-template-columns: 1fr; }              /* field pairs stack */
}
