/*
The course finder: a wizard that asks one question at a time, and its ranked
results. Loaded only on those two pages through `page_styles`, rather than
added to `portal.css`, which every public page already carries.

Colours come from tokens or `color-mix()`. Radii match the marketplace set:
0.875rem for panels and cards, 999rem for pills.
*/

/* The wizard is a reading surface, not a scanning one, so it takes a narrow
   column rather than the wide container the listings use. One decision alone
   on the screen is the whole point of asking one question at a time. */
.finder-column {
  margin-inline: auto;
  max-width: 44rem;
}

.finder-progress {
  display: grid;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}

/* The answers so far (Miller's Law): one row of chips under the bar, each
   opening the step that asked. Wraps on wide screens; one sideways row on
   phones, like the feed's chips, so it never pushes the question down. */
.finder-answers {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: -0.5rem 0 1.25rem;
}

@media (max-width: 575.98px) {
  .finder-answers {
    flex-wrap: nowrap;
    overflow-x: auto;
    /* Holds each chip's visually hidden label, which is absolute: without
       this it escapes the scroller and widens the page (`docs/ux.md`). */
    position: relative;
    scrollbar-width: none;
  }

  .finder-answers li {
    flex: 0 0 auto;
  }
}

/* One segment per question, gapped rather than joined, so the number of
   questions is countable at a glance instead of inferred from a bar's fill. */
.finder-progress__steps {
  display: flex;
  /* 8px between the segments: they are tap targets, not just a bar. */
  gap: 0.5rem;
  margin: 0;
}

.finder-progress__step {
  flex: 1 1 0;
}

/* The link is a full touch target; the bar it paints is a half-rem of it.
   A pseudo-element rather than padding, because a border drawn on the link
   itself would outline the whole target instead of the bar. */
.finder-progress__step a {
  align-items: center;
  block-size: 2.75rem;
  display: flex;
}

.finder-progress__step a::before {
  background: var(--color-background);
  border-radius: var(--radius-pill);
  block-size: 0.5rem;
  content: "";
  inline-size: 100%;
  transition: background var(--motion-base) var(--motion-ease);
}

.finder-progress__step a:hover::before,
.finder-progress__step a:focus-visible::before {
  border-color: var(--color-brand);
}

.finder-progress__step--done a::before,
.finder-progress__step--current a::before {
  background: var(--color-brand);
  border-color: var(--color-brand);
}

/* "Step 2 of 3 · Location": the bar is countable, this is readable, and the
   step's name is what tells a learner what is still to come. */
.finder-progress__label {
  color: var(--color-text);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  margin: 0;
}

.finder-step {
  /* One padding, so the phone action bar below can bleed to the card edge. */
  --finder-pad: clamp(1.25rem, 3vw, 2rem);

  background: var(--color-surface);
  border-radius: var(--radius-card);
  padding: var(--finder-pad);
}

/* While the next question loads ---------------------------------------------
   A tap has to answer within a tenth of a second or it reads as missed
   (`docs/aesthetic.md`). The question dims and stops taking input until the
   next one arrives; `hx-indicator` puts `htmx-request` on the region. No
   transition: a dim that eases in would arrive after the answer on a fast
   connection, which is most of them. */
.finder-step.htmx-request {
  cursor: progress;
}

.finder-step.htmx-request :is(.finder-question, .finder-answers, .finder-tally) {
  opacity: var(--loading-opacity);
  pointer-events: none;
}

.finder-fieldset {
  border: 0;
  margin: 0;
  min-inline-size: 0;
  padding: 0;
}

.finder-legend {
  float: none;
  font-family: var(--font-heading);
  font-size: clamp(1.25rem, 2.5vw, 1.625rem);
  font-variant-numeric: lining-nums;
  font-weight: 700;
  margin-bottom: 1.25rem;
  width: auto;
}

/* Choice cards -------------------------------------------------------------
   The control is a real radio or checkbox, hidden visually and never removed,
   so the card is driven by the input's own state rather than by script. */

.choice-cards {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
}

.choice-card {
  align-items: center;
  background: var(--color-background);
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  cursor: pointer;
  display: grid;
  gap: 0.75rem;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 3.5rem;
  padding: 0.75rem 1rem;
  transition:
    border-color var(--motion-fast) var(--motion-ease),
    background-color var(--motion-fast) var(--motion-ease);
}

/* Tiles, not boxes: the grey fill is the control's shape on the white step,
   and pointing at one tints it; the checked one gets the brand outline. */
.choice-card:hover {
  background: color-mix(in srgb, var(--color-brand-soft) 60%, var(--color-background));
}

/* The ring goes on the card, because the control it belongs to is invisible. */
.choice-card:has(.choice-card__control:focus-visible) {
  outline: var(--focus-outline);
  outline-offset: 3px;
}

/* Both selectors on purpose: the class is server-rendered and survives a
   stylesheet that has not loaded yet, while `:has()` gives the learner an
   answer the instant they click rather than after the next swap. */
.choice-card--checked,
.choice-card:has(.choice-card__control:checked) {
  background: var(--color-brand-soft);
  border-color: var(--color-brand);
}

.choice-card__icon {
  align-items: center;
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  color: var(--color-brand);
  display: inline-flex;
  block-size: 2.25rem;
  inline-size: 2.25rem;
  justify-content: center;
}

.choice-card--checked .choice-card__icon,
.choice-card:has(.choice-card__control:checked) .choice-card__icon {
  background: var(--color-surface);
}

/* The second column is the only one allowed to grow, so a long label wraps
   instead of pushing the tick out of the card. */
.choice-card__label {
  font-weight: 600;
  min-inline-size: 0;
}

.choice-card__mark {
  align-items: center;
  border: 1px solid var(--field-border);
  border-radius: var(--radius-pill);
  color: transparent;
  display: inline-flex;
  block-size: 1.375rem;
  font-size: 0.6875rem;
  inline-size: 1.375rem;
  justify-content: center;
  background: var(--color-surface);
}

.choice-card--checked .choice-card__mark,
.choice-card:has(.choice-card__control:checked) .choice-card__mark {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: var(--color-on-brand);
}

/* A second question on one step --------------------------------------------
   Only the budget step does this, when the catalog prices in more than one
   currency. The rule separates them so the second reads as another question
   rather than as more options for the first. */

.finder-field + .finder-field {
  margin-top: var(--space-5);
}

.finder-field-label {
  color: var(--color-text-muted);
  display: block;
  font-size: var(--text-md);
  margin-bottom: 0.5rem;
}

/* Actions ------------------------------------------------------------------
   Next is the commitment and sits apart from the two ways of leaving the
   question, so Skip is never mistaken for a cancel. */

.finder-actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.finder-actions__next {
  font-weight: 600;
  margin-inline-start: auto;
  padding-inline: 1.5rem;
}

/* Back is a glyph and needs the hit area the glyph alone does not give it;
   Next carries its word and is the step's one filled control. */
.finder-actions__back,
.finder-actions__next {
  min-block-size: 3rem;
  min-inline-size: 3rem;
}

/* The tally ----------------------------------------------------------------
   The number a learner is actually watching: it only ever falls, because every
   answer has to be satisfied rather than merely offering one more way to
   qualify. Below the actions, at reading size, because it is the answer to
   "did that help?" and the header was the wrong place to answer it. */

.finder-tally {
  margin-top: 1.5rem;
  text-align: center;
}

.finder-tally__count {
  color: var(--color-brand);
  font-size: var(--text-lg);
  font-weight: 700;
  margin: 0;
}

.finder-tally--empty .finder-tally__count {
  color: var(--color-text);
}

.finder-tally__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
  margin: 0;
}

.finder-shortcut {
  margin-top: 1rem;
  text-align: center;
}

.finder-shortcut a {
  color: var(--color-text-muted);
  font-size: var(--text-md);
}

/* Results ------------------------------------------------------------------
   An exact match and a near one must not read alike: the near tier is the one
   that has to admit what it missed. */

.card-reasons {
  display: flex;
  margin-bottom: 0.5rem;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.card-reason {
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 600;
  padding: 0.25rem 0.5rem;
}

.card-reason--exact {
  background: var(--color-brand-soft);
  color: var(--color-brand);
}

.card-reason--near,
.card-reason--missed {
  background: var(--color-background);
  color: var(--color-text-muted);
  font-weight: 400;
}

/* A course that did not answer at all, shown because the page had a slot left.
   Same shape as a near match, dimmer, so the twelve read as one list rather
   than as results and consolation prizes. */
.card-reason--missed {
  opacity: 0.85;
}

/* The reveal: the count, how many fit every answer, and the answers
   themselves as chips that reopen their question. A panel rather than the
   listings' toolbar, because this is the moment the wizard was for. */
.finder-recap {
  align-items: start;
  background: var(--color-surface);
  border-radius: var(--radius-card);
  display: grid;
  gap: 0.75rem 1rem;
  grid-template-columns: minmax(0, 1fr) auto;
  padding: var(--card-pad);
}

.finder-recap__count {
  font-size: var(--text-heading);
  margin: 0;
}

.finder-recap__exact {
  align-items: center;
  color: var(--color-brand);
  display: flex;
  font-weight: 600;
  gap: 0.5rem;
  margin: 0.25rem 0 0;
}

.finder-recap__change {
  min-height: 2.75rem;
}

.finder-recap__answers {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  grid-column: 1 / -1;
  margin: 0;
}

.finder-recap__answers .filter-chip {
  gap: 0.5rem;
  min-height: 2.75rem;
}

.finder-recap__answers .fa-pencil {
  color: var(--color-text-muted);
  font-size: 0.75em;
}

@media (max-width: 575.98px) {
  .finder-recap {
    grid-template-columns: minmax(0, 1fr);
  }

  .finder-recap__change {
    justify-self: start;
  }
}

/* "Fits all your answers": shown only when every answered question matched
   exactly (`match_tier`, `portal/views/finder.py`), so it is a fact about the
   course and never a ranking claim. Filled, where the reason chips under it
   are soft, so the one summary reads above the details it sums up; teal
   because the portal's emphasis is teal (`portal.css`, `--highlight-bg`). */
.card-fit {
  align-items: center;
  align-self: start;
  background: var(--color-brand);
  border-radius: var(--radius-pill);
  color: var(--color-on-brand);
  display: inline-flex;
  font-size: var(--text-xs);
  font-weight: 700;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  padding: 0.25rem 0.75rem;
}

@media (max-width: 575.98px) {
  .choice-cards {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Seven subject cards push Next off a phone screen. The row stays in the
     thumb zone above the tab bar instead, the way the request sheet pins
     Send (`conventions.css`, "Fitts's Law"), and bleeds to the card's edge
     so it reads as the card's footer rather than a floating strip. */
  .finder-actions {
    -webkit-backdrop-filter: var(--material-blur);
    backdrop-filter: var(--material-blur);
    background: var(--material-bg-solid);
    bottom: calc(var(--tab-bar-height) + env(safe-area-inset-bottom));
    box-shadow: var(--shadow-raised-bottom);
    flex-wrap: nowrap;
    margin-inline: calc(-1 * var(--finder-pad));
    padding: 0.75rem var(--finder-pad);
    position: sticky;
    z-index: 2;
  }

  .finder-actions__next {
    flex: 1 1 auto;
    margin-inline-start: 0;
  }
}

@media (max-width: 575.98px) and (prefers-reduced-transparency: reduce) {
  .finder-actions {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--color-surface);
  }
}

/* More cities --------------------------------------------------------------
   The location question is the one that does not scale on its own, so the
   long tail folds away. `<details>` because the browser already knows how to
   do this and a disclosure that needs JavaScript is a disclosure that can
   fail closed. */

.choice-cards__more {
  margin-top: 0.75rem;
}

.choice-cards__more summary {
  color: var(--color-brand);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 0.25rem 0;
}

.choice-cards__more[open] summary {
  margin-bottom: 0.75rem;
}

/* Use my location ----------------------------------------------------------
   Offered under the city cards rather than above them: the manual list is the
   answer, and this is a shortcut to it. Deliberately quiet -- a prominent
   button asking for a permission reads as a demand. */

.finder-locate {
  margin-top: 1rem;
}

.finder-locate__status {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  margin: 0.5rem 0 0;
}

.finder-locate__status:empty {
  display: none;
}

.finder-locate__notice {
  background: var(--color-background);
  border-radius: var(--radius-card);
  margin-top: 0.75rem;
  padding: 1rem;
}

.finder-locate__explain {
  font-size: var(--text-sm);
  margin: 0 0 0.75rem;
}

.finder-locate__choices {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
