/* ==========================================================================
   FAHRSCHULPORTAL: DIE AUSWAHL DER FAHRSCHULE  (fahrschulportal.com/anmelden)
   ==========================================================================

   One page uses it: public/anmelden.html, the step between the landing page
   and the login server. You say which driving school you belong to, the
   portal sets the signed state cookie and sends you on.

   It is loaded AFTER /styles.css and never instead of it: the token block,
   the base rules, the button, the field and the loading rows live there. This
   file is the page, and it declares its own measures with the `--pl-` prefix
   (pl = portal landing, the prefix shared/design-tokens.test.mjs already
   knows). Not one colour value, not one radius.

   ── Why it looks like the login page ─────────────────────────────────────
   Because it is the same moment. A school opens three of our pages in a row:
   this one, the login form, the dashboard. The first two are one gesture and
   have to read as one: black surfaces, a breath of the accent above the card,
   the accent as a hairline across its top edge, the card lifted by a shadow
   rather than by a lighter grey. Every one of those rules is copied from
   login/public/styles.css, deliberately and line for line.

   ── What is new against the page this replaces ───────────────────────────
   The old picker at / did the job with a search field, a list and a button.
   Four things it did not do, and all four cost a school a second every
   morning of the year:

     * the school you picked last time is offered first, by name, as the top
       row. It is kept in this browser and nowhere else (see anmelden.js).
     * the list is reachable from the keyboard: arrow keys walk it, Enter
       takes the highlighted school straight to the login.
     * the search field takes the focus by itself, so typing works the moment
       the page is there.
     * the error state says which of the two things went wrong, and offers
       the one useful action instead of a dead end.
   ========================================================================== */

:root {
  /* The fields and the button on this page. The dashboard's 38px is right for
     a dense form among many; this page IS one question, and on a phone it is
     a thumb target. Same value as --lg-field-h on the login page, and for the
     same reason. */
  --pl-field-h: 44px;

  /* One step of the entrance: five elements at 45ms read as one movement. */
  --pl-step: 45ms;

  /* A row in the list: the logo plate (36) plus padding plus the hairline. */
  --pl-row-h: 54px;
}

/* ── The aura ────────────────────────────────────────────────────────────
   A breath of the accent above the card, fixed so a phone keyboard does not
   drag it up the screen. The page under it is still #0a0a0a: this is light
   added to black, not the black lifted to grey. */
body::before {
  content: '';
  position: fixed;
  inset: 0 0 auto 0;
  height: 70vh;
  background: radial-gradient(52% 100% at 50% -8%, var(--accent-quiet) 0%, transparent 70%);
  opacity: 0;
  pointer-events: none;
  animation: pl-aura 900ms var(--ease-out) 120ms forwards;
}

@keyframes pl-aura {
  to {
    opacity: 0.75;
  }
}

/* .wrap carries a stacking context so the card sits over the aura. */
.wrap {
  position: relative;
  z-index: 1;
}

.panel {
  max-width: 460px;
}

/* ── The entrance ────────────────────────────────────────────────────────
   Each element carries its own step as --pl-i in the markup rather than being
   counted with :nth-child: the card is one element in the DOM and four blocks
   to the eye, and the order a reader sees is the author's decision. `both`
   holds the first frame during the delay, otherwise everything flashes at its
   final position and only then animates. */
@keyframes pl-rise {
  from {
    opacity: 0;
    transform: translateY(9px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.pl-in {
  --pl-i: 0;
  animation: pl-rise var(--d-slow) var(--ease-out) calc(var(--pl-i) * var(--pl-step)) both;
}

/* The global reduce-motion rule in styles.css shortens every duration but
   leaves the delays standing, which would turn the entrance into five things
   blinking in one after another: exactly what the setting asks us not to do. */
@media (prefers-reduced-motion: reduce) {
  .pl-in {
    animation-delay: 0ms !important;
  }
  body::before {
    animation: none;
    opacity: 0.75;
  }
}

/* ── The wordmark, and the way back ──────────────────────────────────── */
.pl-brandline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
}

.pl-back {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  font-size: var(--t-sm);
  color: var(--ink-faint);
  transition: color var(--d-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
  .pl-back:hover {
    color: var(--ink-muted);
  }
}

/* Under the card, for whoever has no school yet: the way to /fahrschulen.
   As quiet as .pl-back, so the card stays the one thing on the page. */
.pl-find {
  margin-top: 18px;
  font-size: var(--t-sm);
  color: var(--ink-faint);
  text-align: center;
}

.pl-find a {
  color: inherit;
  transition: color var(--d-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
  .pl-find a:hover {
    color: var(--ink-muted);
  }
}

/* ── The card ────────────────────────────────────────────────────────────
   `.card` itself stays the card of styles.css; this class is worn next to it.
   What it adds is the lift: a shadow deep enough to separate it from a black
   page, and the accent as a hairline laid across the top edge. */
.pl-card {
  position: relative;
  border-radius: var(--r-lg);
  padding: var(--s-6) var(--s-5) var(--s-5);
  box-shadow: var(--shadow-dialog);
}

.pl-card::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 18%;
  right: 18%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-line), transparent);
}

.pl-card > h1 {
  margin-bottom: var(--s-1);
}

.pl-sub {
  margin-bottom: var(--s-5);
  font-size: var(--t-base);
  color: var(--ink-muted);
}

/* ── The search field ────────────────────────────────────────────────────
   The one control on the page, and on a phone the whole page. --t-md is also
   what keeps iOS from zooming in when it takes the focus. The icon belongs to
   the field, so it lights up with it. */
.pl-search {
  height: var(--pl-field-h);
  font-size: var(--t-md);
}

.input-wrap:focus-within > .icon {
  color: var(--accent-text);
}

.pl-card .input:focus {
  box-shadow: 0 0 0 3px var(--accent-quiet);
}

/* ── The list ────────────────────────────────────────────────────────────
   Its own scroll area, so a school with a long list never pushes the button
   off the screen. */
.pl-results {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin-top: var(--s-3);
  max-height: 320px;
  overflow-y: auto;
  /* The scroll area needs room for the focus ring of its last row. */
  padding: 2px;
  margin-left: -2px;
  margin-right: -2px;
}

/* The loading rows are exactly as tall as the rows that replace them, so the
   list does not jump when the answer arrives. */
.pl-results .skeleton-row {
  height: var(--pl-row-h);
}

/* Empty and error states sit inside the scroll area, so they get the tighter
   padding of a block inside a card rather than the full page one. */
.pl-results .empty {
  padding: var(--s-5) var(--s-4);
}

/* A heading inside the list. There is exactly one: "Zuletzt gewählt". */
.pl-group {
  padding: var(--s-1) 2px;
  font-size: var(--t-xs);
  font-weight: var(--w-medium);
  color: var(--ink-faint);
}

.pl-group + .pl-result {
  margin-bottom: var(--s-1);
}

/* One school. A real <button>: picking a school is reachable with the
   keyboard, and aria-pressed says which one is picked. Same shape as the
   choice() component in the dashboard. */
.pl-result {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: var(--s-2) var(--s-3);
  text-align: left;
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color var(--d-fast) ease, background var(--d-fast) ease;
}

/* The logo slot. Always the same width so the names below it line up, but
   wider than it is tall: a school's logo is usually a wordmark, and a 36px
   square turns one into a sliver. A logo that really is square sits centred. */
.pl-result .mark {
  width: 64px;
  border-radius: var(--r-xs);
}

.pl-result-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1;
  min-width: 0;
}

.pl-result-name {
  font-size: var(--t-base);
  font-weight: var(--w-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pl-result-meta {
  font-size: var(--t-sm);
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pl-result-check {
  display: flex;
  color: transparent;
  transition: color var(--d-fast) ease;
}

.pl-result[aria-pressed='true'] {
  border-color: var(--accent);
  background: var(--accent-quiet);
}

.pl-result[aria-pressed='true'] .pl-result-check {
  color: var(--accent-text);
}

/* Walked to with the arrow keys but not taken yet. A hairline, not a fill:
   the filled row is the one that is picked, and there must never be two rows
   that look picked. */
.pl-result.is-cursor:not([aria-pressed='true']) {
  border-color: var(--line-focus);
}

@media (hover: hover) and (pointer: fine) {
  .pl-result:hover {
    border-color: var(--line-strong);
  }
  .pl-result[aria-pressed='true']:hover {
    border-color: var(--accent-hover);
  }
}

/* ── The way on ──────────────────────────────────────────────────────── */
.pl-submit {
  height: var(--pl-field-h);
  margin-top: var(--s-4);
}

/* The label of the button carries the name of the picked school, which can be
   long. It shortens, the arrow does not move. */
.pl-submit span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The button while it works: between the press and the login server sit a
   redirect and a round trip. The label steps aside for a spinner, and the
   button keeps its size, so nothing on the page moves. */
.pl-spin {
  position: absolute;
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  opacity: 0;
  animation: pl-spin 620ms linear infinite;
}

@keyframes pl-spin {
  to {
    transform: rotate(1turn);
  }
}

.btn.is-busy {
  position: relative;
}

.btn.is-busy > span,
.btn.is-busy > .icon {
  opacity: 0;
}

.btn.is-busy .pl-spin {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .pl-spin {
    animation-duration: 1800ms;
  }
}

/* ── Keys, and the note under the card ───────────────────────────────── */
.pl-keys {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-2);
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--ink-faint);
}

.pl-key {
  display: inline-block;
  min-width: 20px;
  padding: 0 5px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-xs);
  background: var(--surface-sunken);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  text-align: center;
  color: var(--ink-muted);
}

.pl-noscript {
  margin-top: var(--s-3);
}

.pl-note {
  margin-top: var(--s-4);
  font-size: var(--t-sm);
  color: var(--ink-faint);
  text-align: center;
}

.pl-note a {
  color: var(--ink-muted);
  border-bottom: 1px solid var(--line-strong);
}

/* ── Small screens ──────────────────────────────────────────────────────
   The card keeps its padding but loses its shadow: on a phone it fills the
   screen, and a shadow around something that has no page next to it is a
   shadow against nothing. The keyboard hints go, because there is no
   keyboard. */
@media (max-width: 520px) {
  .pl-card {
    padding: var(--s-5) var(--s-4) var(--s-4);
    box-shadow: none;
  }
  .pl-results {
    max-height: 46vh;
  }
}

@media (pointer: coarse) {
  .pl-keys {
    display: none;
  }
}

/* The logo instead of the text wordmark (portal/public/brand/). */
.pl-logo { display: inline-flex; margin: 0; }
.pl-logo img { display: block; width: auto; height: 24px; }

/* ── Already signed in ───────────────────────────────────────────────────
   Filled by public/js/account.js once /me has answered: who is signed in,
   at which school, and the way in — above the picker, which stays for the
   one who wants another school. A card of its own, lifted less than the
   picker's, so the two read as "where you are" and "where else". */
.pl-signed-slot {
  margin-bottom: var(--s-4);
  animation: pl-rise var(--d-slow) var(--ease-out) both;
}

.pl-signed {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
}

.pl-avatar {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--surface-raised);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--ink);
  font-size: var(--t-base);
  font-weight: var(--w-medium);
  letter-spacing: 0.02em;
}

.pl-signed-text {
  display: grid;
  flex: 1;
  min-width: 0;
  gap: 2px;
}

.pl-signed-text strong {
  color: var(--ink);
  font-size: var(--t-md);
  font-weight: var(--w-medium);
}

.pl-signed-text span {
  overflow: hidden;
  color: var(--ink-muted);
  font-size: var(--t-base);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pl-signed-go {
  flex: none;
}

.pl-signed-note {
  margin-top: var(--s-2);
  color: var(--ink-faint);
  font-size: var(--t-sm);
  text-align: center;
}

.pl-signed-note a {
  color: var(--ink-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

@media (max-width: 480px) {
  .pl-signed {
    flex-wrap: wrap;
  }
  .pl-signed-go {
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pl-signed-slot {
    animation: none;
  }
}
