﻿/* Campus Forms — what the Campus portal adds on top of the handoff.
   Load order: bootstrap.css → campus-forms-tokens.css → campus-forms-bootstrap.css
               → campus-forms-components.css → THIS

   Two jobs:

   1. The SHARED form engine (Content/page/AdmissionShared/form-renderer) draws a
      section as a Bootstrap .card and a question as .col-md-6.mb-3 with a
      .form-label. That markup is Admissions2's as much as ours and cannot change,
      so it is mapped onto the CfSection / CfField contract here, under .cf-engine,
      rather than in the engine.

   2. The check screen, the done screen, and the event picker's rows that the
      design system has no class for (a tick row inside a choice, a band heading).

   Every value is a token. The two !important-free workarounds for Bootstrap
   utilities (.mb-3, .small) are noted where they happen. */

/* ---------- 1. the engine's markup, mapped ---------- */

/* A section: the engine's .card becomes a run of content, separated from the
   previous one by a rule, exactly as .cf-section + .cf-section is. */
.cf-engine .card {
  --bs-card-spacer-y: 0;
  --bs-card-spacer-x: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  margin: 0;
}
.cf-engine .card + .card {
  margin-top: var(--space-10);
  padding-top: var(--space-10);
  border-top: 1px solid var(--line);
}
.cf-engine .card-title {
  font-family: var(--font-display);
  font-size: 19px;
  line-height: 25px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--ink);
  margin: 0 0 var(--space-2);
}
/* .small is 0.875em in Bootstrap; a two-class selector outranks it without !important. */
.cf-engine .card-body > p.small {
  color: var(--ink-muted);
  font-size: 15px;
  line-height: 23px;
  margin: 0 0 var(--space-6);
  max-width: 58ch;
}
.cf-engine .card-title:last-child,
.cf-engine .card-title + .row { margin-top: var(--space-4); }
.cf-engine .card-body > .row { margin-top: var(--space-2); }

/* A question. .mb-3 is 16px with !important; the extra 4px of padding takes the
   gap to space-5 (20px) without fighting it. */
.cf-engine .row > [class*="col-"] { padding-bottom: var(--space-1); }
.cf-engine .form-check-label { font-size: 15px; line-height: 23px; color: var(--ink); }
.cf-engine .form-check-inline { margin-right: var(--space-5); min-height: 44px; display: inline-flex; align-items: center; gap: var(--space-2); }
.cf-engine .form-check-inline .form-check-input { margin-left: 0; float: none; }

/* An invalid answer: the 2px danger border, and its message set like
   .invalid-feedback. The engine emits adm-has-error as a hook, not a look. */
.cf-engine .adm-has-error .form-control,
.cf-engine .adm-has-error .form-select {
  border-width: 2px;
  border-color: var(--danger);
  padding: calc(var(--space-3) - 1px) calc(var(--space-4) - 1px);
}
.cf-engine .adm-has-error > .small.mt-1 {
  font-size: 13px;
  line-height: 19px;
  font-weight: 600;
  margin-top: var(--space-2);
}
.cf-engine .adm-has-error .form-check-input { border-color: var(--danger); border-width: 2px; }

/* The engine's "heading" question is an instruction block, drawn on the sunken surface. */
.cf-engine .alert-light {
  --bs-alert-bg: var(--surface-sunken);
  --bs-alert-color: var(--ink);
  --bs-alert-border-color: var(--line);
  border-radius: var(--radius-md);
  font-size: 15px;
  line-height: 23px;
}
.cf-engine .alert-light .small { font-size: 13px; line-height: 19px; color: var(--ink-muted); }

/* A repeating section's rows and its add link. */
.cf-engine .border.rounded { border-radius: var(--radius-md); }
.cf-engine .btn-outline-info {
  --bs-btn-bg: var(--surface-card);
  --bs-btn-border-color: var(--control-border);
  --bs-btn-color: var(--ink);
  --bs-btn-hover-bg: var(--surface-hover);
  --bs-btn-hover-border-color: var(--control-border);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-active-bg: var(--surface-hover);
  --bs-btn-active-border-color: var(--control-border);
  --bs-btn-active-color: var(--ink);
}

/* A file that has been chosen. */
.cf-engine .adm-file-thumb img { max-height: 120px; border-radius: var(--radius-sm); border: 1px solid var(--line); margin-bottom: var(--space-2); }

/* Date picker input group. */
.cf-engine .input-group .input-group-text { border-radius: 0 var(--radius-md) var(--radius-md) 0; }

/* The event picker's own total strip. The public page carries the total in the
   rail, so it is hidden there; the editor's preview has no rail and keeps it. */
.cf-engine .adm-total {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
.cf-portal .adm-total { display: none; }

/* ---------- 2. the event picker's rows ---------- */

/* A category that is ticked rather than counted (an event entered once). Same
   shape as a quantity row, whole row is the target. */
.cf-check-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  margin: 0;
  padding: var(--space-1) 0;
  cursor: pointer;
}
.cf-check-row .form-check-input { flex: none; }
.cf-check-row > span { min-width: 0; }

/* A category that is entered through its divisions: the name once, then a row
   per division, indented. */
.cf-band {
  margin-top: var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--line);
}
.cf-band:first-child { margin-top: 0; }
.cf-band-name { display: block; font-size: 13px; line-height: 18px; font-weight: 600; color: var(--ink); }
.cf-band ~ .is-in-band { padding-left: var(--space-4); }

/* The count is typed OR stepped. The handoff's − / + stay; the value between
   them is an input, because "I want 5 participants" should not take four presses. */
.cf-qty input.cf-qty-value {
  width: 52px;
  height: 40px;
  min-width: 0;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
  -moz-appearance: textfield;
}
.cf-qty input.cf-qty-value::-webkit-outer-spin-button,
.cf-qty input.cf-qty-value::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.cf-qty input.cf-qty-value:hover { border-color: var(--line-strong); }
.cf-qty input.cf-qty-value:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

/* ---------- 3. the summary rail actually follows the page ---------- */

/*  ⚠ `.cf-rail` already asks for `position: sticky`, and it did nothing.
    `.cf-shell-inner` sets `align-items: start`, so the rail's grid item shrinks to
    exactly the card's height - and a sticky element can only travel inside its own
    containing block. Zero spare height, zero travel, so it scrolled away with the page
    and somebody who had finished filling the form had to scroll back up to find the
    button.

    Stretching the COLUMN (not the card) gives the card the full height of the row to
    move within. The card keeps its own height; only the invisible column grows. */
.cf-shell-inner > .cf-rail-col { align-self: stretch; }

/*  With a long event list the rail can outgrow the window, and then the total and the
    button - the two things it exists for - sit below the fold with no way to reach them.
    So the card is capped to the viewport and the LINE LIST is what gives way: it scrolls
    inside the card while the heading, the total and the button stay put. */
.cf-rail {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - (var(--space-6) * 2));
}
.cf-rail-head,
.cf-rail-total,
.cf-rail-foot { flex: none; }
/*  `min-height: 0` is what lets a flex child shrink below its content and scroll at all -
    without it the list keeps its full height and pushes the button out of the card. */
.cf-rail-lines { overflow-y: auto; min-height: 0; }

@media (max-width: 860px) {
  /*  Below the grid breakpoint the rail is static and sits under the form, where a cap
      and an inner scrollbar would be nothing but an obstacle. */
  .cf-rail { max-height: none; display: block; }
  .cf-rail-lines { overflow-y: visible; }
}

/* ---------- the two rich-text fields, and line breaks everywhere else ----------

   ⚠ `cf-lines` is the cheap 80%. Typed paragraph breaks in the declaration and the
   closed message used to collapse into one run of text, which is not a formatting
   nicety - it is the difference between two readable sentences and a wall. No markup,
   no parsing, no security surface. */
.cf-lines { white-space: pre-line; }

/*  What sanitised HTML is allowed to look like. The tag set is small on purpose, so
    this is short on purpose. */
.cf-rich p { margin: 0 0 var(--space-3); }
.cf-rich p:last-child { margin-bottom: 0; }
.cf-rich ul,
.cf-rich ol { margin: 0 0 var(--space-3); padding-left: var(--space-6); }
.cf-rich li { margin-bottom: var(--space-1); }
.cf-rich a { color: var(--brand-ink); text-decoration: underline; }
.cf-rich b, .cf-rich strong { font-weight: 600; color: var(--ink); }

/* ---------- 4. the check screen ---------- */

.cf-section-head.is-split { display: flex; align-items: flex-start; gap: var(--space-3); }
.cf-section-head.is-split > div { min-width: 0; flex: 1 1 auto; }
.cf-section-head.is-split .btn { flex: none; margin-left: auto; }

.cf-review { display: grid; }
.cf-review-row {
  display: grid;
  grid-template-columns: minmax(0, 38%) minmax(0, 1fr);
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
  font-size: 15px;
  line-height: 23px;
}
.cf-review-row:first-child { border-top: 0; padding-top: 0; }
.cf-review-k { color: var(--ink-muted); }
.cf-review-v { color: var(--ink); overflow-wrap: anywhere; }

/* The declaration: one choice row, the whole of it the target. */
.cf-choice.is-invalid { border-color: var(--danger); border-width: 2px; }
.cf-choice.is-invalid .cf-choice-main { padding: calc(var(--space-4) - 1px); }
.cf-choice-main .form-check-input { flex: none; }

/* A form with nothing to price has no rail; the one button sits under the card. */
.cf-actions {
  margin-top: var(--space-10);
  padding-top: var(--space-8);
  border-top: 1px solid var(--line);
  display: grid;
  gap: var(--space-3);
}

/* The error summary lists the fields as links to them. */
.cf-callout ul { margin: var(--space-2) 0 0; padding-left: var(--space-5); }
.cf-callout li + li { margin-top: var(--space-1); }
.cf-callout .cf-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--danger-ink);
  text-decoration: underline;
  cursor: pointer;
}
.cf-callout-info .cf-link { color: var(--brand-ink); }

/* ---------- 5. the done screen and the receipt ---------- */

.cf-facts { display: grid; margin-top: var(--space-6); }
.cf-fact {
  display: grid;
  grid-template-columns: minmax(0, 38%) minmax(0, 1fr);
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
  font-size: 15px;
  line-height: 23px;
}
.cf-fact-k { color: var(--ink-muted); }
.cf-fact-v { color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }
.cf-fact-v.is-ref {
  font-family: var(--font-display);
  font-size: 26px;
  line-height: 31px;
  font-variant-numeric: tabular-nums;
  color: var(--brand-ink);
}

.cf-receipt-lines { display: grid; gap: var(--space-3); }
.cf-receipt-total {
  margin-top: var(--space-4);
  background: var(--surface-sunken);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.cf-receipt-total .cf-rail-total-value { margin-left: auto; }
.cf-receipt-total.is-paid .cf-rail-total-value { color: var(--success-ink); }

.cf-amount-nowrap { white-space: nowrap; }

/* ---------- narrow ---------- */

@media (max-width: 575.98px) {
  .cf-review-row,
  .cf-fact { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .cf-section-head.is-split { flex-wrap: wrap; }
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .cf-choice,
  .form-control,
  .form-select,
  .cf-qty input.cf-qty-value { transition: none; }
}
