/* The student verification page (/verify/). Page-local styles only: everything
   structural, every colour and every control comes from tokens.css and site.css.
   The one shared class this page borrows outright is .connect-slip, the ruled
   document slip the Shopify install page already uses; the student pass is that
   same slip on the student's side of the deal. */

.vf-main { padding-block: clamp(var(--tud-space-10), 6vw, 80px) clamp(var(--tud-space-16), 9vw, 112px); }

/* ---------- who is signed in ---------- */

/* Sits above every state, because every lane below is about this address.
   The sign-out door is a link, never a button: nobody came here to leave. */
.vf-account {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--tud-space-2) var(--tud-space-5);
  margin-bottom: var(--tud-space-8);
  padding-bottom: var(--tud-space-4);
  border-bottom: var(--tud-border-hairline) solid var(--tud-color-border-default);
}

/* One line or two: the login address always, and the university address as
   well once one has verified this account. */
.vf-account-lines { display: grid; gap: 2px; min-width: 0; }
.vf-account-line { color: var(--tud-color-text-muted); font-size: 14px; overflow-wrap: anywhere; }
.vf-account-line strong { color: var(--tud-color-text-primary); font-family: var(--tud-font-secondary); font-weight: 700; }
.vf-account .link-button { font-size: 13px; }

/* ---------- panels ---------- */

/* Panels sit on the canvas. The only surfaces on this page are the two lanes,
   the sign-in form and the pass, so nothing here is ever a card inside a card. */
.vf-panel--narrow { width: min(100%, 560px); margin-inline: auto; }
.vf-waiting { color: var(--tud-color-text-muted); font-size: 18px; text-align: center; }

.vf-title {
  max-width: 18ch;
  font-size: clamp(30px, 4.4vw, 44px);
  line-height: 1.04;
  letter-spacing: -0.038em;
}
.vf-title:focus-visible { outline: none; }

.vf-body {
  max-width: 52ch;
  margin-top: var(--tud-space-4);
  color: var(--tud-color-text-secondary);
  font-size: 17px;
  line-height: 1.55;
}

.vf-lede {
  max-width: 46ch;
  margin-top: var(--tud-space-3);
  color: var(--tud-color-text-secondary);
  font-size: clamp(17px, 2vw, 19px);
  line-height: 1.5;
}

.vf-fine { margin-top: var(--tud-space-4); }
.vf-links { display: flex; flex-wrap: wrap; gap: var(--tud-space-2) var(--tud-space-5); margin-top: var(--tud-space-2); }
.vf-links--centered { justify-content: center; }

/* The pending, verified and offline panels are read before they are acted on,
   so they centre; the fork and the forms stay left, where they are worked. */
#vf-panel-pending,
#vf-panel-verified,
#vf-panel-offline { text-align: center; }

#vf-panel-pending .vf-title,
#vf-panel-verified .vf-title,
#vf-panel-offline .vf-title { max-width: 15ch; margin-inline: auto; }

#vf-panel-pending .vf-body,
#vf-panel-verified .vf-body,
#vf-panel-offline .vf-body { margin-inline: auto; }

#vf-panel-offline .btn { margin-top: var(--tud-space-6); }

.vf-panel-art { display: block; width: clamp(132px, 22vw, 188px); margin: 0 auto var(--tud-space-5); }
.vf-panel-art img { width: 100%; }

/* ---------- sign in ---------- */

.vf-form-card { padding: clamp(var(--tud-space-6), 5vw, var(--tud-space-10)); }
.vf-form { margin-top: var(--tud-space-6); }
.vf-form-card .vf-links { margin-top: var(--tud-space-4); }

/* ---------- the fork ---------- */

#vf-panel-choose { width: min(100%, 1000px); margin-inline: auto; }
#vf-panel-choose .vf-title { max-width: 20ch; }

.vf-fork {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: start;
  gap: var(--tud-space-6);
  margin-top: var(--tud-space-8);
}

.vf-lane {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: clamp(var(--tud-space-5), 2.4vw, var(--tud-space-8));
  border: var(--tud-border-default) solid var(--tud-color-border-default);
  border-radius: var(--tud-radius-xl);
  background: var(--tud-color-bg-surface);
  box-shadow: var(--tud-elevation-e1);
}

/* How long it takes is the fact that decides the lane, so it leads the lane
   and is set in the label face rather than being buried in the body copy. */
.vf-lane-time {
  margin-bottom: var(--tud-space-3);
  color: var(--site-accent-text);
  font-family: var(--tud-font-secondary);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1;
  text-transform: uppercase;
}

.vf-lane-title { font-size: clamp(19px, 2.1vw, 22px); line-height: 1.2; letter-spacing: -0.02em; }
.vf-lane-body { margin-top: var(--tud-space-3); color: var(--tud-color-text-secondary); font-size: 15px; line-height: 1.6; }

/* The quiet half-step below the body copy: what to expect, or what has to be
   readable. It also gives the fast lane the height its neighbour has, so the
   two buttons meet on one line instead of one lane holding an empty middle. */
.vf-lane-note {
  margin-top: var(--tud-space-4);
  padding-top: var(--tud-space-4);
  border-top: var(--tud-border-hairline) solid var(--tud-color-border-default);
  color: var(--tud-color-text-muted);
  font-size: 14px;
  line-height: 1.55;
}
/* The action always sits at the foot of the lane, whatever height the lane
   grew to, so the two buttons line up across the fork. Where a note is the last
   thing before the button, the pair anchors together and the slack falls above
   them instead: a gap under a paragraph reads as a hole, a gap above a closing
   note reads as spacing. */
.vf-lane .btn-block { margin-top: auto; }
.vf-lane-note:has(+ .btn-block) { margin-top: auto; }
.vf-lane-note:has(+ .btn-block) + .btn-block { margin-top: var(--tud-space-5); }
.vf-lane .vf-send { margin-top: var(--tud-space-4); }

/* The address, split at the @ so the domain, the only part the check looks at,
   is the part that is legible from across the room. */
.vf-domain {
  margin-top: var(--tud-space-5);
  padding: var(--tud-space-3) var(--tud-space-4);
  border: var(--tud-border-hairline) solid var(--tud-color-accent-tint-border);
  border-radius: var(--tud-radius-lg);
  background: var(--tud-color-accent-tint);
  font-family: var(--tud-font-secondary);
  font-size: 15px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}
.vf-domain-user, .vf-domain-at { color: var(--tud-color-text-muted); }
.vf-domain-host { color: var(--tud-color-text-primary); font-weight: 700; }

/* ---------- the fast lane's second door ---------- */

/* A student who signed up on a personal address is still in this lane; they
   just have to name the address the lane is about. The door sits directly
   under the address chip, because that chip is the thing it corrects: reading
   your own gmail.com there and finding the answer in the next line is the
   whole point. Closed by default, since one press is still the shortest way
   through for everyone whose login address already qualifies. */
.vf-alt { margin-top: var(--tud-space-3); }

.vf-alt-toggle {
  align-items: flex-start;
  gap: var(--tud-space-2);
  min-height: 0;
  padding-block: var(--tud-space-1);
  text-align: left;
}

.vf-alt-chevron {
  flex: none;
  margin-top: 3px;
  transition: transform var(--tud-duration-fast) var(--tud-ease-standard);
}

.vf-alt-toggle[aria-expanded="true"] .vf-alt-chevron { transform: rotate(180deg); }

/* Opened, it is a panel inside the lane rather than the next thing in it. The
   lane keeps one primary action at its foot; this form has its own, and the
   sunken inset is what stops the two reading as rivals. */
.vf-alt-body {
  margin-top: var(--tud-space-4);
  padding: var(--tud-space-5);
  border: var(--tud-border-hairline) solid var(--tud-color-border-default);
  border-radius: var(--tud-radius-lg);
  background: var(--tud-color-bg-sunken);
}

/* The lane pins its own primary action to its foot; the two inside this
   disclosure are steps in a form and sit where the form's own rhythm puts
   them. Specificity here has to clear both .vf-lane .btn-block rules. */
.vf-lane .vf-alt-body .btn-block { margin-top: 0; }

.vf-alt-note {
  color: var(--tud-color-text-muted);
  font-size: 14px;
  line-height: 1.55;
}

/* The sentence and the control it describes are one object, so the form's
   20px rhythm closes to 12px wherever the two sit together. */
.vf-alt-form .field + .vf-alt-note,
.vf-alt-form .vf-alt-note + .field { margin-top: calc(var(--tud-space-2) * -1); }

.vf-alt-body .vf-links { margin-top: calc(var(--tud-space-2) * -1); }
.vf-alt-body .vf-links .link-button { font-size: 13px; }
.vf-alt-body .vf-msg:not(:empty) { margin-top: var(--tud-space-5); }

@media (prefers-reduced-motion: reduce) {
  .vf-alt-chevron { transition: none; }
}

/* ---------- the "or" between the lanes ---------- */

/* They are alternatives, not steps, so the divider says so in a word. Drawn
   rather than ruled, because everything else in this world is drawn. */
.vf-or {
  display: grid;
  grid-template-rows: minmax(var(--tud-space-8), 1fr) auto minmax(var(--tud-space-8), 1fr);
  justify-items: center;
  align-self: stretch;
  gap: var(--tud-space-3);
  color: var(--tud-color-ramp-neutral-300);
}

[data-theme="dark"] .vf-or { color: var(--tud-color-border-strong); }

.vf-or-rule { width: 6px; height: 100%; }

.vf-or-word {
  color: var(--tud-color-text-muted);
  font-family: var(--tud-font-secondary);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  line-height: 1;
  text-transform: uppercase;
}

/* ---------- the drop zone ---------- */

.vf-drop {
  display: grid;
  justify-items: center;
  gap: var(--tud-space-1);
  margin-top: var(--tud-space-5);
  padding: var(--tud-space-6) var(--tud-space-4);
  border: var(--tud-border-default) dashed var(--tud-color-border-strong);
  border-radius: var(--tud-radius-lg);
  background: var(--tud-color-bg-sunken);
  text-align: center;
  cursor: pointer;
  transition:
    border-color var(--tud-duration-fast) var(--tud-ease-standard),
    background-color var(--tud-duration-fast) var(--tud-ease-standard);
}

.vf-drop:hover,
.vf-drop.is-over { border-color: var(--tud-color-accent-base); background: var(--tud-color-accent-tint); }
/* The file input is off screen (it is the real control and stays keyboard
   reachable), so the frame wears its focus ring on its behalf. verify.js adds
   the class on the input's own focus and blur. */
.vf-drop.is-focused { border-color: var(--tud-color-border-focus); box-shadow: var(--tud-focus-ring); }

.vf-drop-art { display: block; width: 88px; margin-bottom: var(--tud-space-2); }
.vf-drop-art img { width: 100%; }
.vf-drop-lead { font-size: 15px; font-weight: 800; line-height: 1.3; }
.vf-drop-sub { color: var(--tud-color-text-muted); font-family: var(--tud-font-secondary); font-size: 12px; letter-spacing: 0.02em; }

.vf-drop-actions { display: flex; flex-wrap: wrap; gap: var(--tud-space-2); margin-top: var(--tud-space-3); }
.vf-drop-actions .btn { flex: 1 1 140px; }

/* ---------- the chosen photo ---------- */

.vf-preview {
  display: grid;
  gap: var(--tud-space-3);
  margin-top: var(--tud-space-5);
  padding: var(--tud-space-4);
  border: var(--tud-border-default) solid var(--tud-color-border-strong);
  border-radius: var(--tud-radius-lg);
  background: var(--tud-color-bg-sunken);
}

.vf-preview-frame {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 8 / 5;
  overflow: hidden;
  border-radius: var(--tud-radius-md);
  background: var(--tud-color-bg-surface);
}
.vf-preview-frame img { width: 100%; height: 100%; object-fit: contain; }
.vf-preview-nopreview { max-width: 24ch; padding: var(--tud-space-4); color: var(--tud-color-text-muted); font-size: 13px; line-height: 1.45; text-align: center; }

.vf-preview-meta { display: flex; align-items: baseline; justify-content: space-between; gap: var(--tud-space-4); }
.vf-preview-name { min-width: 0; overflow: hidden; font-size: 14px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; }
.vf-preview-size { flex: none; color: var(--tud-color-text-muted); font-family: var(--tud-font-secondary); font-size: 13px; font-variant-numeric: tabular-nums; }
.vf-preview .link-button { justify-self: start; min-height: 32px; font-size: 13px; }

/* ---------- upload progress ---------- */

.vf-progress { display: flex; align-items: center; gap: var(--tud-space-3); margin-top: var(--tud-space-4); }

.vf-progress-track {
  flex: 1 1 auto;
  height: 10px;
  overflow: hidden;
  border: var(--tud-border-hairline) solid var(--tud-color-border-strong);
  border-radius: var(--tud-radius-pill);
  background: var(--tud-color-bg-sunken);
}

/* Scaled, not widened: a width transition relayouts the track on every progress
   event, and this one fires continuously through the upload. */
.vf-progress-fill {
  width: 100%;
  height: 100%;
  border-radius: var(--tud-radius-pill);
  background: var(--tud-color-accent-base);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--tud-duration-base) var(--tud-ease-decelerate);
}

.vf-progress-value {
  flex: none;
  min-width: 4ch;
  color: var(--tud-color-text-secondary);
  font-family: var(--tud-font-secondary);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* ---------- messages ---------- */

/* .form-msg's twin, for the two places a message has to carry an action as
   well as a sentence: the 422 that sends a student across to the other lane,
   and a pass that is past its date. Same box, same weight, one nested link. */
.vf-msg {
  color: var(--tud-color-status-error-text);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.45;
}

.vf-msg:not(:empty) {
  margin-top: var(--tud-space-3);
  padding: var(--tud-space-3) var(--tud-space-4);
  border-radius: var(--tud-radius-lg);
  background: var(--tud-color-status-error-bg);
}

.vf-msg--ok:not(:empty) { color: var(--tud-color-status-success-text); background: var(--tud-color-status-success-bg); }
.vf-msg--warn:not(:empty) { color: var(--tud-color-status-warning-text); background: var(--tud-color-status-warning-bg); }
.vf-msg .link-button { min-height: 32px; margin-top: var(--tud-space-1); color: inherit; font-size: 14px; }

/* A rejected decision is context for the fork below it, not an error thrown at
   the student, so it reads as a note in the page rather than as a form message. */
.vf-note {
  margin-bottom: var(--tud-space-6);
  padding: var(--tud-space-4) var(--tud-space-5);
  border: var(--tud-border-hairline) solid var(--tud-color-status-warning-text);
  border-radius: var(--tud-radius-lg);
  color: var(--tud-color-status-warning-text);
  background: var(--tud-color-status-warning-bg);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.5;
}

/* ---------- the lapsed strip ---------- */

.vf-lapsed {
  display: flex;
  align-items: center;
  gap: var(--tud-space-4);
  margin-bottom: var(--tud-space-6);
  padding: var(--tud-space-4) var(--tud-space-5);
  border: var(--tud-border-default) solid var(--tud-color-border-strong);
  border-radius: var(--tud-radius-lg);
  background: var(--tud-color-bg-sunken);
}
.vf-lapsed-art { display: block; width: 56px; flex: none; }
.vf-lapsed-art img { width: 100%; }
.vf-lapsed-head { font-size: 16px; font-weight: 800; line-height: 1.25; }
.vf-lapsed-sub { margin-top: 2px; color: var(--tud-color-text-secondary); font-size: 14px; line-height: 1.4; }

/* ---------- what we check ---------- */

.vf-terms { margin-top: clamp(var(--tud-space-8), 4vw, var(--tud-space-12)); }
.vf-terms-title { font-size: 18px; line-height: 1.25; letter-spacing: -0.015em; }
.vf-terms-rows { margin: var(--tud-space-4) 0 0; border-top: var(--tud-border-hairline) solid var(--tud-color-border-default); }
.vf-terms-rows > div {
  display: grid;
  grid-template-columns: minmax(140px, 200px) minmax(0, 1fr);
  gap: var(--tud-space-2) var(--tud-space-6);
  align-items: baseline;
  padding-block: var(--tud-space-4);
  border-bottom: var(--tud-border-hairline) solid var(--tud-color-border-default);
}
.vf-terms-rows dt { color: var(--tud-color-text-primary); font-size: 14px; font-weight: 800; }
.vf-terms-rows dd { max-width: 62ch; margin: 0; color: var(--tud-color-text-secondary); font-size: 15px; line-height: 1.6; }

/* ---------- the pass ---------- */

/* Two drawings of one document. The card is the object the apps hand a verified
   student, ported whole: an orange laminate under a holofoil coat that answers
   to the pointer. The slip under it is the same three facts set as ruled paper,
   and it is what a browser without WebGL keeps. holofoil.js decides which one
   stands, and only ever after it has a context in hand. */
.vf-pass { margin-top: var(--tud-space-8); text-align: left; }

/* The stage never moves. It holds the perspective the card turns inside, and it
   is the box the pointer is measured against, because reading a rotated card's
   own rect back into its rotation is a feedback loop. */
.pass-stage {
  width: min(100%, 460px);
  margin-inline: auto;
  perspective: 1100px;
  /* The card is one printed object, so everything on it is sized against the
     card's own width rather than against the page. The query container is the
     stage rather than the card, because an element cannot query itself and the
     two are the same width by construction.
     Each measure below is written as a plain value first and a container-width
     one second, so a browser without container queries keeps the fixed layout
     and simply does not scale. */
  container-type: inline-size;
}

.pass-card {
  position: relative;
  isolation: isolate;
  /* ISO/IEC 7810 ID-1, the bank and ID card: 85.60mm by 53.98mm. Written as
     the standard's own two figures rather than as a rounded decimal, because
     the whole point of the proportion is that a hand recognises it. The width
     is the only thing that flexes here; the height always follows it, and the
     apps hold the same ratio the same way. */
  aspect-ratio: 8560 / 5398;
  /* 24px on a card the width of the one in the apps, closing as the card gets
     smaller than that. A fixed inset on a card the ratio has made short is the
     one thing that pushes the four identity lines through the bottom edge. */
  padding: var(--tud-space-6);
  padding: clamp(16px, 5.59cqw, 24px);
  overflow: hidden;
  border-radius: var(--tud-radius-xl);
  /* The pass gradient, top leading to bottom trailing, at the apps' values. */
  background: linear-gradient(135deg, #FF713C 0%, #FF6230 100%);
  /* Fixed, not themed: ink on orange is ink on orange in both appearances. */
  color: #141412;
  box-shadow:
    0 calc(10px + var(--pass-lift, 0) * 4px) 18px rgba(0, 0, 0, calc(0.12 + var(--pass-lift, 0) * 0.05)),
    inset 0 0 0 1px rgba(20, 20, 18, 0.1);
  /* A finger drags the card sideways and scrolls the page vertically. The
     browser arbitrates that far better than a gesture classifier can. */
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
}
.pass-card.is-live { will-change: transform; }

:root[data-theme="dark"] .pass-card {
  background: linear-gradient(135deg, #FF581E 0%, #EB501D 100%);
  box-shadow:
    0 calc(12px + var(--pass-lift, 0) * 4px) 26px rgba(0, 0, 0, calc(0.42 + var(--pass-lift, 0) * 0.08)),
    inset 0 0 0 1px rgba(20, 20, 18, 0.16);
}

/* Edge to edge, straight under the type. The foil cannot wash the words out:
   it only lightens the field between them. */
.pass-foil {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Fills the card rather than setting its height: the ratio decides how tall
   the box is, and the content lays itself out inside whatever that comes to.
   Percentage height resolves because the card's own height is definite. */
.pass-face {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.pass-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--tud-space-4);
}

/* The lockup, in the app's on-accent split: "The" steps back, "Uni" carries the
   weight, "Deals" sits between them. It never mirrors and never wraps.
   The container measures below are all tuned to land on the apps' own value at
   the width the apps draw the card, so on a phone-width browser the card is set
   exactly as the app card is, and the ceiling holds it there on a wider one.
   Only a card narrower than a phone's scales down, which is what a card does. */
.pass-wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.09em;
  font-family: var(--tud-font-primary);
  font-size: 18px;
  font-size: clamp(15px, 5.085cqw, 18px);
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.pass-wordmark-the { font-weight: 500; color: rgba(20, 20, 18, 0.62); }
.pass-wordmark-uni { font-weight: 800; }
.pass-wordmark-deals { font-weight: 800; color: rgba(20, 20, 18, 0.76); }

/* Ink disc, white check. Never green and never orange, so it reads the same on
   the pass as it does on a neutral surface. */
.pass-seal {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  width: clamp(30px, 11.3cqw, 40px);
  height: clamp(30px, 11.3cqw, 40px);
  overflow: hidden;
  border-radius: 50%;
  background: linear-gradient(135deg, #2B2B27 0%, #11110F 58%, #070706 100%);
  color: #FFFFFF;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.22), inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
.pass-seal-sheen {
  position: absolute;
  inset: -30%;
  background: radial-gradient(circle at 34% 30%, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.07) 42%, rgba(255, 255, 255, 0) 68%);
  transform: translate(var(--pass-sheen-x, 0px), var(--pass-sheen-y, 0px));
}
/* Kept as a share of the disc, so the check stays the same mark at any size. */
.pass-seal-check {
  position: relative;
  width: 18px;
  height: 18px;
  width: 45%;
  height: 45%;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.38));
}

/* The identity block sits on the bottom edge of the card, whatever the card's
   height turns out to be. The field above it is the whole of the slack, which
   is what gives a wide card its empty middle and a narrow one its fit. */
.pass-identity {
  margin-top: auto;
  padding-top: var(--tud-space-6);
  padding-top: clamp(14px, 4.47cqw, 24px);
}
/* One line per field, the way a card is printed. A fixed ratio fixes the
   height, so a name or a university that wraps is a line the card does not
   have, and a wrapped line here used to disappear under the bottom edge with
   no sign that anything was missing. An ellipsis says so, and the full string
   stays in the document for a screen reader and on the page above. */
.pass-name,
.pass-line,
.pass-until {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.pass-name {
  font-family: var(--tud-font-primary);
  font-size: 22px;
  font-size: clamp(18px, 6.215cqw, 22px);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: -0.02em;
}
.pass-line {
  margin-top: 4px;
  font-size: 14px;
  font-size: clamp(12px, 3.955cqw, 14px);
  font-weight: 500;
  line-height: 1.35;
  color: rgba(20, 20, 18, 0.78);
}
.pass-until {
  margin-top: var(--tud-space-5);
  margin-top: clamp(12px, 5.65cqw, 20px);
  font-size: 13px;
  font-size: clamp(11px, 3.672cqw, 13px);
  font-weight: 500;
  line-height: 1.4;
  color: rgba(20, 20, 18, 0.78);
}
.pass-until-label { font-family: var(--tud-font-primary); }
/* Figures in the label face, the way every date on this site is set. */
.pass-until-date { font-family: var(--tud-font-secondary); font-weight: 500; }

.vf-pass-note {
  margin-top: var(--tud-space-4);
  color: var(--tud-color-text-muted);
  font-size: 13px;
  line-height: 1.45;
}

.vf-pass-mark {
  color: var(--site-accent-text);
  font-family: var(--tud-font-secondary);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.18em;
  line-height: 1;
  text-transform: uppercase;
}

.vf-pass-rows { margin-top: var(--tud-space-4); }
.vf-pass-rows dd { font-family: var(--tud-font-secondary); overflow-wrap: anywhere; }

.vf-pass-foot {
  margin-top: var(--tud-space-4);
  padding-top: var(--tud-space-3);
  border-top: var(--tud-border-hairline) dashed var(--tud-color-border-strong);
  color: var(--tud-color-text-muted);
  font-size: 13px;
  line-height: 1.45;
}

.vf-verified-cta { margin-top: var(--tud-space-6); }
.vf-pending-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--tud-space-3); margin-top: var(--tud-space-6); }
#vf-panel-pending .vf-msg:not(:empty) { text-align: left; }

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

/* One authored moment, borrowed from the site's own card steps: the state that
   arrives is the only thing that moves. The pass lands with the success settle
   the signup card already uses, because it is the same kind of news. */
@media (prefers-reduced-motion: no-preference) {
  .vf-panel:not(.hidden) { animation: vf-rise 300ms var(--tud-ease-decelerate) both; }
  #vf-panel-verified:not(.hidden) .vf-pass { animation: vf-pass-land 420ms var(--tud-ease-standard) 120ms both; }

  @keyframes vf-rise {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
  }
  @keyframes vf-pass-land {
    0% { opacity: 0; transform: translateY(10px) rotate(-1.2deg); }
    64% { opacity: 1; transform: translateY(0) rotate(0.4deg); }
    100% { opacity: 1; transform: none; }
  }
}

/* ---------- responsive ---------- */

@media (max-width: 880px) {
  /* The lanes stop being columns and become a sequence read top to bottom, so
     the divider stays on the vertical axis and simply gets short: the same
     drawn rule, now a connector between one card and the next. (It is not
     rotated flat. A rotate() on a stretched preserveAspectRatio="none" path
     turns the squiggle inside out, which is how this looked before.) */
  .vf-fork { grid-template-columns: 1fr; gap: var(--tud-space-5); }
  .vf-or {
    grid-template-rows: 26px auto 26px;
    align-self: center;
    justify-self: center;
    gap: var(--tud-space-2);
  }
  .vf-lane .btn-block { margin-top: var(--tud-space-5); }
  .vf-terms-rows > div { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .vf-main { padding-block: var(--tud-space-8) var(--tud-space-12); }
  .vf-account { margin-bottom: var(--tud-space-6); }
  .vf-title { font-size: clamp(28px, 8.6vw, 34px); }
  .vf-lane { padding: var(--tud-space-5); }
  .vf-form-card { padding: var(--tud-space-6) var(--tud-space-5); }
  .vf-panel-art { width: 132px; }
  .vf-drop { padding: var(--tud-space-5) var(--tud-space-4); }
  .vf-drop-actions .btn { flex: 1 1 100%; }
  .vf-pending-actions .btn { width: 100%; }
  .vf-lapsed { align-items: flex-start; }
  .vf-preview-frame { aspect-ratio: 4 / 3; }
  /* The pass card needs nothing here. It holds the ID-1 ratio at every width
     and sizes its own inset, type and seal against its own width, so a phone
     gets the same card the desktop does, drawn smaller. */
}
