/* ============================================================
   EduShieldID — components/forms.css
   Shared form primitives: the basic .form-group/.form-control
   pair, the labeled .form-field used across settings pages,
   toggle switches, and small form-layout helpers reused by
   forms that don't have a dedicated page stylesheet.
   ============================================================ */

/* ── Dropdowns ───────────────────────────────────────────────
   Element-level, not class-level, and deliberately so: 34 of the 44
   <select>s in the templates carry no class at all (filter bars,
   term pickers, the scope selector, the onboarding form). Every one
   of them was rendering as a raw OS widget — grey gradient chrome and
   a native arrow — sitting next to inputs that had the full design
   system on them. A class-based rule would have needed 34 template
   edits to fix a problem that is really "selects have no baseline".

   appearance:none strips the native chrome, which also removes the
   native arrow, so we draw our own as a background-image. Two
   consequences follow, and both have bitten this file before:

     * padding-right has to clear the arrow, or the longest option
       text runs underneath it.
     * anything that later sets the `background` SHORTHAND on a select
       resets background-image and the arrow vanishes. Every such rule
       in this codebase now uses background-color instead. Keep it
       that way. */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding: var(--sp-2) var(--sp-3);
  /* Room for the arrow: sp-3 gutter + 10px glyph + sp-2 breathing space. */
  padding-right: calc(var(--sp-3) + 10px + var(--sp-2));
  border: 1px solid var(--clr-border-strong);
  border-radius: var(--radius-md);
  background-color: var(--clr-surface);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%2357606a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  color: var(--clr-text);
  line-height: 1.4;
  cursor: pointer;
  max-width: 100%;
  transition: border-color var(--transition), box-shadow var(--transition);
}
select:hover:not(:disabled) { border-color: var(--clr-text-muted); }
select:focus {
  outline: none;
  border-color: var(--clr-primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .15);
}
select:disabled {
  background-color: var(--clr-surface-alt);
  color: var(--clr-text-muted);
  cursor: not-allowed;
  opacity: 1;   /* Safari greys disabled controls into unreadability. */
}
/* The placeholder row ("Select your school") is not a value — it should not
   look like one until the user has actually chosen. */
select:has(option[value=""]:checked) { color: var(--clr-text-muted); }
/* Firefox/Windows render <option> from the OS palette, which on a dark system
   theme puts near-black text on a near-black list. State both explicitly. */
select option,
select optgroup {
  background-color: var(--clr-surface);
  color: var(--clr-text);
}
select option:disabled { color: var(--clr-text-muted); }
/* A listbox is not a dropdown: no arrow, no arrow gutter, no pointer. */
select[multiple],
select[size]:not([size="0"]):not([size="1"]) {
  background-image: none;
  padding-right: var(--sp-3);
  cursor: default;
}

/* ── Form fields ────────────────────────────────────────────── */
.form-group { display: flex; flex-direction: column; gap: var(--sp-1); margin-bottom: var(--sp-4); }
.form-label { font-size: var(--text-sm); font-weight: var(--weight-medium); }
.form-control {
  padding: var(--sp-2) var(--sp-3);
  /* Stronger than the decorative card border: on an input the border is the
     only thing telling a user where the control is (WCAG 1.4.11, 3:1). */
  border: 1px solid var(--clr-border-strong);
  border-radius: var(--radius-md);
  background: var(--clr-surface);
  font-size: max(16px, var(--text-base));  /* ≥16px stops iOS zoom-on-focus */
  transition: border-color var(--transition), box-shadow var(--transition);
  width: 100%;
}
.form-control:focus {
  outline: none;
  border-color: var(--clr-primary);
  box-shadow: 0 0 0 3px rgba(26,86,219,.15);
}
.form-control::placeholder { color: var(--clr-text-muted); }

/* ── Settings forms ──────────────────────────────────────────── */
.settings-section {
  max-width: 640px;
}
.settings-section h3 { font-size: var(--text-lg); margin-bottom: var(--sp-5); }
/* A settings tab whose content is a table, not a form (Settings, Integrations).
   Two classes so it beats the 640px rule, which portal-records.css repeats. */
.settings-section.settings-section--wide { max-width: 1080px; }
/* Fixed layout so the columns line up from one provider group to the next. */
.integrations-table { table-layout: fixed; width: 100%; }
.integrations-table th:nth-child(1) { width: 44%; }
.integrations-table th:nth-child(2) { width: 16%; }
.integrations-table th:nth-child(3) { width: 16%; }
.integrations-table th:nth-child(4) { width: 13%; }
.integrations-table th:nth-child(5) { width: 11%; }
.integrations-table .badge { white-space: nowrap; }
@media (max-width: 720px) {
  .integrations-table { table-layout: auto; }
  .integrations-table th { width: auto !important; }
}
.integrations-table td:first-child .text-muted { font-size: var(--text-sm); margin-top: var(--sp-1); }
.settings-form { display: flex; flex-direction: column; gap: var(--sp-4); }
.settings-form .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }

/* Baseline for controls dropped straight into a settings form with no
   .form-field / .form-control wrapper around them. Seven of the 22 templates
   that use .settings-form do exactly that (school/settings/general.html,
   security.html, student_id_format.html, eligibility_rules.html,
   student/settings/notifications.html, student/notifications/settings.html,
   student/profile/photo.html), and their inputs were rendering as raw browser
   controls inside an otherwise fully designed card. Same reasoning as the
   element-level `select` rule at the top of this file: give the bare element
   a floor rather than editing every template to add a class. Declarations
   match .form-field below, so it makes no difference which one a wrapped
   field ends up matching. */
.settings-form input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="range"]):not([type="color"]),
.settings-form select,
.settings-form textarea {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--clr-border-strong);
  border-radius: var(--radius-md);
  background-color: var(--clr-surface);
  color: var(--clr-text);
  font-size: var(--text-sm);
}
/* Restore the arrow gutter the padding shorthand above just overwrote. */
.settings-form select { padding-right: calc(var(--sp-4) + 10px + var(--sp-2)); }

/* Labeled field wrapper used across the settings forms
   (personal info, education, contact, photo). */
.form-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.form-field label {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--clr-text-muted);
}
.form-field input,
.form-field select,
.form-field textarea {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--clr-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  /* background-color, not background: the shorthand would reset the arrow
     background-image that the element-level `select` rule above draws. */
  background-color: var(--clr-surface);
  color: var(--clr-text);
}
/* Restore the arrow gutter this rule's own padding shorthand just overwrote. */
.form-field select { padding-right: calc(var(--sp-4) + 10px + var(--sp-2)); }
.form-field input[readonly] {
  color: var(--clr-text-muted);
  background: var(--clr-surface-alt);
  cursor: not-allowed;
}
.field-hint {
  font-size: var(--text-xs);
  color: var(--clr-text-muted);
}

.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--clr-border);
  font-size: var(--text-sm);
}
.toggle-row:last-child { border-bottom: none; }
.toggle-row label { font-weight: var(--weight-medium); }
.toggle-row span  { font-size: var(--text-xs); color: var(--clr-text-muted); display: block; }

/* Toggle switch */
.toggle {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 24px;
  flex-shrink: 0;
}
.toggle input { display: none; }
.toggle-track {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-full);
  background: var(--clr-border);
  transition: background var(--transition);
  cursor: pointer;
}
.toggle input:checked + .toggle-track { background: var(--clr-primary); }
.toggle-track::after {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  top: 3px; left: 3px;
  transition: transform var(--transition);
  box-shadow: var(--shadow-sm);
}
.toggle input:checked + .toggle-track::after { transform: translateX(20px); }

/* ── Simple placeholder-driven form (uploads, quick contact/appeal
   forms that have no visible <label>s — roster/semester-data
   uploads, appeal submit/upload, document upload, help contact) ── */
.simple-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
  max-width: 480px;
}
/* Excludes the types that need their native chrome rather than listing the
   types that don't. The allow-list this replaces named only text and file, so
   every other type fell through to the raw browser control: a bare 2px inset
   border with square corners, sitting inches from a styled sibling. The
   academic-structure form showed both at once — "Name" designed, "Starting
   calendar year" (type=number) untouched. The templates use 17 number, 13
   email, 7 search, 6 tel, 6 date, 2 url and 1 month input, none of which the
   old selector reached. tokens.css already uses this inverted shape for the
   44px min-height rule; matching it means a new input type is styled by
   default instead of silently unstyled. */
.simple-form input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="range"]):not([type="color"]),
.simple-form select,
.simple-form textarea {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--clr-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-family: inherit;
  background-color: var(--clr-surface);
  color: var(--clr-text);
}
.simple-form select { padding-right: calc(var(--sp-4) + 10px + var(--sp-2)); }
.simple-form textarea {
  min-height: 120px;
  resize: vertical;
}

/* ── Password reveal (core/password-reveal.js) ───────────────
   The wrapper is injected around every <input type="password">, so it has to
   disappear into whatever layout it lands in: it is display:block at full
   width because .auth-form, .simple-form and .form-row are all flex columns
   whose children stretch, and the input inside it is display:block so the
   line box under an inline-block input does not push the button a few pixels
   off centre.

   The right-hand gutter that keeps the password from running under the icon
   is set by the script, not here, because these inputs are styled by four
   different rules in four files and the padding shorthand in the winning one
   would overwrite anything this rule declared. */
.pw-field {
  position: relative;
  display: block;
  width: 100%;
}
.pw-field > input { display: block; width: 100%; }
.pw-reveal {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 44px;         /* WCAG 2.5.5 touch target, matching every other control */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--clr-text-muted);
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: color var(--transition);
}
.pw-reveal:hover { color: var(--clr-text); }
/* Inset, not offset: an outward ring on a control sitting flush inside the
   field would be clipped by the field's own border. */
.pw-reveal:focus-visible {
  outline: 2px solid var(--clr-primary);
  outline-offset: -3px;
}
.pw-reveal svg { width: 18px; height: 18px; }

/* ── Checkbox + label row (settings/eligibility_rules.html, terms) ── */
.checkbox-label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-normal);
  cursor: pointer;
}

/* ── Small inline utility text — aliases of the canonical
   .field-hint / .text-muted treatment so every page that reaches
   for the shorter class name gets the same look. ─────────────── */
.hint,
.muted {
  font-size: var(--text-xs);
  color: var(--clr-text-muted);
}

/* ── Single-button action form inside a table cell (remove/revoke) ── */
.inline-form {
  display: inline-block;
}

/* ── Per-row review forms (a textarea + decision buttons) that sit
   inside a table cell — eligibility review, fraud alert resolution ── */
.eligibility-review-form,
.fraud-resolve-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 220px;
  max-width: 320px;
}
.eligibility-review-form textarea,
.fraud-resolve-form textarea {
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--clr-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-family: inherit;
  background: var(--clr-surface);
  color: var(--clr-text);
  resize: vertical;
  min-height: 60px;
}
.eligibility-review-form .btn + .btn {
  margin-left: var(--sp-2);
}

/* ── Responsive ─────────────────────────────────────────────── */
@media (max-width: 768px) {
  .profile-form .row-2 { grid-template-columns: 1fr; }
  .settings-form .form-row { grid-template-columns: 1fr; }
}

/* The Get Started form's own styles (.form-section-heading,
   .onboarding-notice and the rest) live in pages/onboarding.css — that
   page needs to override landing.css, which loads after this file. */

/* A settings form is a flex column, so its children stretch to full width.
   That is right for inputs and wrong for the submit button, which rendered as
   a slab the width of the card — reading as a banner rather than an action. */
.settings-form > button { align-self: flex-start; }
/* .form-row is a fixed two-column grid. A row with three fields (the term
   generator: year / periods / label) needs to fit them without one dropping
   to a half-width orphan on the next line. */
.settings-form .form-row--auto {
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

/* Modifiers that used to be inline style attributes on the branding form. The
   app's CSP has no 'unsafe-inline', so the browser refused every one of them. */
.form-control--swatch { max-width: 5rem; padding: 0.25rem; }
.form-control--subdomain { max-width: 14rem; }
.form-label--plain { font-weight: 400; }
