/* Dark-only app (ERA palette, w3-theme.css) — reinforces the
 * <meta name="color-scheme"> tag so native UA widgets (date picker, select
 * list, scrollbars, autofill) render dark instead of light-default. */
:root { color-scheme: dark; }

/*
 * Modal panel. w3pro-4.13.css hardcodes .w3-modal-content{background:#fff} —
 * the one surface it never routes through a theme token — so on this dark
 * theme it painted a white box that inherited body's color:var(--white).
 * That made the title bar white-on-white (invisible) and turned every
 * floating label's var(--surface) backplate into a dark smear on white.
 * Re-point it at the same tokens every other card already uses; page.css
 * loads after the vendor sheets, so equal specificity wins without
 * !important. The scrim also goes darker: w3pro's rgba(0,0,0,.4) barely
 * separates a modal from an already-near-black page.
 */
.w3-modal-content {
  background-color: var(--surface);
  color: var(--white);
  border: 1px solid var(--border-color);
}
.w3-modal { background-color: rgba(0, 0, 0, .7); }

/*
 * Opt a subtree out of text selection, for UI where a press means "click"
 * or "drag" and never "select this text": the event hub's tab bar (every
 * word in it is a link) and its drag-sortable station roster, where a
 * press that started a selection would paint blue across the table
 * instead of picking up the row.
 *
 * Safari still wants the -webkit- prefix here.
 */
.no-select { -webkit-user-select: none; user-select: none; }

/*
 * Tab bar (event hub). Each tab is a real link carrying ?tab=, so this is
 * pure styling — no JS, no state. The active tab is marked by the accent
 * underline sitting on top of the bar's own bottom border, which is why it
 * pulls itself down by 1px.
 *
 * The bar holds two things: the tabs, and the active tab's own action
 * button pinned right (see partials/event/tabs.blade.php). Its children stretch
 * rather than centre, so the tab anchors keep reaching the bottom border
 * they overlap while the action re-centres its button in its full-height
 * slot. Everything tab-shaped is scoped to .tab-nav-items so none of it
 * lands on that button, which is a plain w3-button.
 */
.tab-nav { display: flex; border-bottom: 1px solid var(--border-color); }
.tab-nav-items { display: flex; flex-wrap: wrap; flex: 1; min-width: 0; }
/* gap: a tab may now carry a download alongside its primary action (see
 * partials/event/tabs.blade.php), and two buttons must not touch. */
.tab-nav-action { display: flex; align-items: center; gap: 8px; padding: 0 16px; margin-left: auto; }
.tab-nav-items a {
  display: flex; align-items: center; gap: 8px;
  padding: 14px 18px; white-space: nowrap;
  color: var(--gray); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color .15s, border-color .15s;
}
.tab-nav-items a:hover { color: var(--white); }
.tab-nav-items a.is-active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 500; }
.tab-nav-items .tab-count {
  font-size: 12px; line-height: 1; padding: 3px 7px; border-radius: 999px;
  background: var(--surface-alt); color: var(--gray);
}
.tab-nav-items a.is-active .tab-count { background: var(--primary-light); color: var(--primary); }
@media (max-width: 600px) {
  .tab-nav-items a { flex: 1; justify-content: center; padding: 12px 10px; }
  .tab-nav-items a span:not(.tab-count) { display: none; }
  .tab-nav-action { padding: 0 8px; }
}

/*
 * Filter panel (event hub), and the checkbox that opens it.
 *
 * CSS-only, like the sidebar toggle in admin-styles.css: the toggle is a
 * hidden checkbox that both the tab bar's Filter label and the panel are
 * siblings of, so `~` can reach forward from one to the other. No JS, which
 * also means the panel is already in the DOM when the page loads — it can
 * therefore be rendered open (checkbox `checked` server-side) whenever a
 * filter is actually applied, so a narrowed tab never hides the thing
 * narrowing it.
 *
 * Closed by default: on a tab of eight rows the controls would be taller
 * than the table they filter.
 */
.tab-filter { display: none; padding: 14px 16px; border-bottom: 1px solid var(--border-color); background: var(--surface-alt); }
#tab-filter-toggle:checked ~ .tab-filter { display: block; }

/* The label reads as pressed while the panel is open — it is a toggle, and a
 * button that looks identical either way leaves "did that do anything?" as
 * the only feedback.
 *
 * `~ *` rather than a named sibling: the button lives in the hub's .tab-nav on
 * one page and in a plain card <header> on the events list, and the rule is
 * about the toggle's state, not about which box the label happens to sit in. */
#tab-filter-toggle:checked ~ * .tab-filter-button { background: var(--primary-light); color: var(--primary); }

/* A dot on the button when the tab is narrowed, so a filter left on is
 * visible from the tab bar with the panel shut. */
.tab-filter-button .filter-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--primary); margin-left: 2px; vertical-align: middle;
}

/*
 * Clickable table rows — the events list (opens the hub), the stations
 * list and an event's roster (both open a detail modal). A chevron-only
 * hover didn't read as "this row opens something"; a left accent bar plus
 * a real background highlight does. The highlight needs !important to beat
 * .w3-striped's own !important on even rows (w3-theme.css), which would
 * otherwise win by source order and leave hover invisible on half the rows.
 *
 * The accent is neutral unless the row declares a status, so tables
 * without one (stations) still get the bar without inventing a colour.
 */
tr.row-link { cursor: pointer; }
tr.row-link td:first-child { border-left: 3px solid var(--border-color); }
tr.row-link[data-status="upcoming"] td:first-child { border-left-color: var(--success); }
tr.row-link[data-status="completed"] td:first-child { border-left-color: var(--info); }
tr.row-link[data-status="cancelled"] td:first-child { border-left-color: var(--danger); }
tr.row-link[data-status="draft"] td:first-child { border-left-color: var(--gray); }
tr.row-link:hover td { background-color: var(--primary-light) !important; }
tr.row-link:hover td:first-child { border-left-color: var(--primary); }
tr.row-link:hover .fa-angle-right { color: var(--primary); }
tr.row-link a { text-decoration: none; }

/* Drag-to-reorder rows (the event hub's Stations tab — see
 * public/js/pages/event-detail.js). `is-reordering` lives on the <tbody>
 * only while a drag is actually in progress, so an ordinary click-through
 * row keeps its pointer cursor. Selection is already off for the whole
 * table via .no-select, so this only has the cursor left to change.
 */
tbody.is-reordering tr.row-link { cursor: grabbing; }

/* The row being dragged is lifted off the table — tinted, shadowed and
 * scaled up — so the drag state is unmistakable. The transform itself is
 * set inline by the drag handler, which is also what tracks the pointer;
 * only the presentation lives here.
 *
 * pointer-events:none is load-bearing, not cosmetic: it lets the handler's
 * elementFromPoint() see the row *underneath* the floating one, which is
 * how the drop target is found.
 *
 * The tint has to out-specify tr.row-link:hover's own !important
 * background, hence matching on both classes.
 */
tr.is-dragging {
  position: relative;
  z-index: 20;
  pointer-events: none;
  will-change: transform;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .55);
}
tr.row-link.is-dragging td { background-color: var(--primary-light) !important; }
tr.row-link.is-dragging td:first-child { border-left-color: var(--primary); }

/* Every panel table whose rows carry a 3-dot menu or a drag handle — the
 * event hub's tabs, and the accounts, athletes and stations lists.
 * Deliberately NOT .w3-responsive, whose overflow-x:auto makes the wrapper a
 * clipping (and scrolling) container — three separate things break the
 * moment it is:
 *
 *   - a row's 3-dot menu is an absolutely-positioned dropdown, and an
 *     ancestor that scrolls traps it: the menu appears *inside* the table's
 *     own scroll box, so opening one on the last row scrolls the table
 *     rather than overlaying the page. z-index cannot escape a clipping
 *     ancestor;
 *   - the Stations tab's dragged row loses its lift — overflow-x:auto's
 *     CSS-spec companion is that overflow-y also computes to auto (never
 *     visible), which clipped the shadow/scale at the wrapper's edges;
 *   - a sideways drag scrolled the table instead of reordering it.
 *
 * The columns fit at every width these tables are used at, and the page
 * itself scrolls if they ever don't — so nothing here needs a scrollbar of
 * its own. `visible` on both axes is stated explicitly because leaving
 * either to `auto` re-introduces the clipping.
 */
.panel-table { overflow: visible; }

/* Read-only detail card, used by the athlete and ticket modals on the
 * event hub. A contact-card shape rather than the label/value grid the
 * station modal uses: these are about a *person*, so the portrait and name
 * lead and the facts read as a quiet list underneath.
 *
 * W3.CSS has no portrait/among-facts primitives, hence the handful of rules
 * here; everything with a w3-* equivalent (buttons, tags, text colours)
 * still uses it.
 */
.detail-card-portrait {
  width: 132px; height: 132px; margin-bottom: 14px;
  border-radius: 12px; overflow: hidden;
  background: var(--light);
  display: flex; align-items: center; justify-content: center;
}
.detail-card-portrait img { width: 100%; height: 100%; object-fit: cover; }

/* Inline QR plate (App\View\Components\QrCode). The white background is
 * load-bearing rather than decorative: this panel is dark-only, and the
 * format needs a light quiet zone and a light-to-dark module contrast to be
 * readable at all. Rendering it on the theme surface would produce a QR that
 * looks right and scans at nothing. W3.CSS has no such primitive, hence the
 * rules; the size comes from the component so one plate can serve a modal
 * and a full page at different footprints. */
.qr-code {
  background: #fff; border-radius: 12px; padding: 6px;
  margin-bottom: 14px; box-sizing: content-box;
}
.qr-code svg { display: block; width: 100%; height: 100%; }

/* Drawn from the name, so an absent photo never looks like a real one.
 * `photo_url` has no requirement written yet — see the athlete modal. */
.detail-card-initials {
  font-size: 2.6rem; font-weight: 500; color: var(--gray); letter-spacing: 1px;
}

.detail-card-name { margin: 0; font-size: 1.35rem; font-weight: 500; }
.detail-card-subtitle { margin: 2px 0 16px; color: var(--gray); }

/* The ticket code doubles as the QR payload, so it is set monospaced and
 * spaced out — it gets read aloud and typed by hand at the gate.
 *
 * The copy button lives INSIDE the dashed plate, on the same line as the code
 * it copies: the plate is what the eye lands on, and a button outside it read
 * as belonging to the card rather than to the code. Centred as a pair, so the
 * code keeps the optical centre it had before the button existed rather than
 * being pushed off to one side by it.
 */
.detail-card-code {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.05rem; letter-spacing: 1px; text-align: center;
  padding: 10px; margin-bottom: 16px;
  border: 1px dashed var(--border-color); border-radius: 8px;
}
/* The button is a control, not part of the code — it keeps the panel's own
 * type rather than inheriting the monospace and the letter-spacing, which
 * would space its icon away from nothing. */
.detail-card-code .copy-button { font-family: inherit; letter-spacing: normal; flex: none; }

/* Copy buttons (components/copy-button.blade.php). Quiet by default — a code
 * is the thing being read, and a button competing with it for attention on
 * every row would win. It comes forward on hover and on focus, so it is
 * findable by pointer and reachable by keyboard without ever being loud. */
.copy-button { color: var(--gray); padding: 2px 8px; }
.copy-button:hover, .copy-button:focus-visible { color: var(--primary); background: var(--primary-light) !important; }

/*
 * A w3-row-padding whose outer edges line up with a full-width card above or
 * below it — the stat-card rows on the events list and the event hub, which
 * sit directly over a panel that spans the container.
 *
 * w3-row-padding puts 8px on the row AND 8px on every column (w3pro-4.13.css),
 * so the first card's left edge lands 16px inside the container and the last
 * card's right edge 16px inside it — while the panel underneath spans the lot.
 * The two read as different widths because they are. Pulling the row out by
 * exactly that 16px cancels the gutter at the outer edges only, leaving the
 * gaps BETWEEN the cards untouched, which is the whole point of the gutter.
 *
 * Safe against the page's own 32px side padding (layouts/admin.blade.php), so
 * the pull never reaches the viewport edge.
 */
.stat-row { margin-left: -16px; margin-right: -16px; }

/* The second line of a modal header (components/modal.blade.php), under the
 * title and above the header's own rule: the registration detail's status and
 * who reviewed it.
 *
 * In the header rather than at the top of the body so the rule falls beneath
 * BOTH lines and binds them into one heading. Below the rule it read as the
 * body's first row and was boxed off from the title it qualifies.
 *
 * :empty collapses it entirely, so every other modal — which leaves the slot
 * blank — keeps exactly the header it had. */
.modal-subtitle {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 6px;
}
.modal-subtitle:empty { display: none; }

/* One entrant on a registration detail. A doubles entry renders two of these
 * side by side, which is the fastest way to see what kind of entry you are
 * looking at — before reading a word of it. Equal height so the pair reads as
 * a pair rather than as a card and an afterthought. */
.entrant-card { background: var(--surface-alt); height: 100%; }

.detail-card-facts { border-top: 1px solid var(--border-color); }
.detail-card-fact {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 2px; border-bottom: 1px solid var(--border-color);
}
.detail-card-fact > i { color: var(--gray); }
.detail-card-row { align-items: flex-start; }
.detail-card-section {
  margin: 18px 0 0; font-size: 0.85rem; font-weight: 500; color: var(--gray);
}

/* The second modal layer sits above the first. W3.CSS gives .w3-modal a
 * z-index of 3 (w3pro-4.13.css); this only has to clear that, and the pair
 * of backdrops is deliberate — the form underneath stays visible but
 * plainly out of reach while a pick is in progress. */
.modal-layer-2 { z-index: 5; }

/* Searchable person picker (the second modal layer). A row per candidate
 * rather than a <select> option, because a display name alone does not
 * identify anybody at a busy desk — each row carries the identifiers and the
 * date of birth underneath the name, which an option cannot show. Scrolls
 * rather than growing, so a long result list never pushes the search box off
 * the top of the panel. */
.picker-list {
  max-height: 320px; overflow-y: auto;
  border: 1px solid var(--border-color); border-radius: 4px;
}
/* Buttons, not radios: the click is the decision *and* the confirmation, so
 * these need no Save. The W3.CSS button reset is overridden back to a
 * two-line block because a picker row is a paragraph, not a label. */
.picker-option {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 9px 10px; cursor: pointer; text-align: left;
  border-bottom: 1px solid var(--border-color);
  white-space: normal; line-height: 1.35;
}
.picker-option:last-child { border-bottom: none; }
.picker-option:hover { background-color: var(--primary-light); }
.picker-option-body { display: block; min-width: 0; }
.picker-option-name { display: block; font-weight: 500; }
.picker-option-meta {
  display: block; font-size: 0.8rem; color: var(--gray);
  overflow-wrap: anywhere;
}

/* One chosen person on the issue-ticket form — the readable face of a hidden
 * id. Laid out as a row so the name and its Add/Change button read as one
 * control rather than a label that happens to sit above a button. */
.picked-person {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; min-height: 52px;
}
.picked-person-body { flex: 1; min-width: 0; }
.picked-person-name { display: block; font-weight: 500; }
.picked-person-actions { flex: none; white-space: nowrap; }

/* The pager under every admin list (components/pagination.blade.php).
 * Centred and wrapping, because the page window plus both arrows is wider
 * than a phone: it folds onto a second line rather than scrolling the table
 * sideways. The gap does the spacing, so the buttons need no margins of
 * their own. */
.pagination {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 4px;
}
/* A disabled arrow keeps its place at the end of the row rather than
 * disappearing — a control that vanishes shifts every number beside it. */
.pagination [aria-disabled="true"] { cursor: default; }

.result-pre { white-space: pre-wrap; word-break: break-word; }
.spinner {
  display: inline-block; width: 0.8rem; height: 0.8rem; margin-left: 0.5rem;
  border: 2px solid #fff; border-top-color: transparent; border-radius: 50%;
  animation: spin 0.6s linear infinite; vertical-align: middle;
}
.spinner[hidden] { display: none; }
@keyframes spin { to { transform: rotate(360deg); } }

/*
 * Skeleton loading placeholders (profile page, and anywhere content is
 * fetched async). Shimmer via animated background-position rather than
 * opacity pulsing so it reads as "loading" not "disabled".
 */
.skeleton { background: linear-gradient(90deg, var(--surface) 25%, var(--surface-alt) 37%, var(--surface) 63%); background-size: 400% 100%; animation: skeleton-shimmer 1.4s ease infinite; border-radius: 4px; }
.skeleton-text { height: 14px; margin: 10px 0; }
.skeleton[hidden] { display: none; }
@keyframes skeleton-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
/*
 * Nav icons are hardcoded inline <svg> in the blade markup so they paint with
 * the HTML — no separate file request, no webfont, so no load delay. This class
 * just sizes them (1em) and tints them with the current text color (fill:
 * currentColor), so hover / active / w3-text-* still color the icon.
 */
.nav-icon { width: 1em; height: 1em; fill: currentColor; vertical-align: -0.125em; margin-right: 2px; }

/*
 * Floating-label input (login, register, forgot-password pages). Markup
 * order matters: the <input> must come immediately BEFORE its sibling
 * <label> so :focus ~ label / :not(:placeholder-shown) ~ label can float
 * it — the reverse of the label-before-input order used in forms.blade.php.
 * Every input needs placeholder=" " (a single space) so :placeholder-shown
 * engages consistently, including for non-required fields (e.g. register's
 * optional email) where :valid alone would float the label even when empty.
 * These inputs drop w3-border/w3-round: this block owns the border, radius
 * and height itself.
 */
.input-field { position: relative; }
.input-field input {
  width: 100%;
  height: 52px;
  border-radius: 6px;
  font-size: 16px;
  padding: 0 14px;
  border: 2px solid var(--border-color);
  background: transparent;
  outline: none;
  box-sizing: border-box;
}
.input-field label {
  position: absolute;
  top: 50%;
  left: 14px;
  transform: translateY(-50%);
  font-size: 15px;
  color: var(--secondary);
  pointer-events: none;
  transition: 0.15s ease-out;
  background: var(--surface);
  padding: 0;
}
/*
 * A <textarea> in an .input-field used to fall through every rule here:
 * it kept .w3-input's own look, its label stayed pinned to the vertical
 * centre (so it sat on top of the text), and the float-up rule below only
 * matched `input`, so the label never lifted out of the way at all. It
 * gets the same treatment as an input, except the resting label sits on
 * the first line rather than the box's centre.
 */
.input-field textarea {
  width: 100%;
  min-height: 96px;
  border-radius: 6px;
  font-size: 16px;
  padding: 14px;
  border: 2px solid var(--border-color);
  background: transparent;
  outline: none;
  box-sizing: border-box;
  resize: vertical;
  display: block;
}
.input-field textarea ~ label { top: 26px; }

.input-field input:focus,
.input-field textarea:focus { border-color: var(--primary); }
.input-field input:focus ~ label,
.input-field input:not(:placeholder-shown) ~ label,
.input-field textarea:focus ~ label,
.input-field textarea:not(:placeholder-shown) ~ label {
  top: 0;
  font-size: 12px;
  padding: 0 4px;
  color: var(--primary);
}

/*
 * Row actions menu (accounts table): a native <details>/<summary> disclosure
 * needs no JS, but its content flows inline by default — position it as an
 * absolute dropdown instead so it overlays the table rather than pushing them
 * down. summary::marker is hidden since the FA ellipsis icon is the trigger.
 */
.action-menu { position: relative; display: inline-block; }
/* A square hit target rather than whatever w3-button's padding leaves around
 * a single narrow glyph. The ellipsis is ~4px wide, so the default button
 * was a sliver to aim at — and it is the only way into edit/delete/check-in
 * on every row of every table. Sized to stay comfortably clickable without
 * a mouse being precise, and the row grows to fit it. */
.action-menu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  font-size: 15px;
  line-height: 1;
}
.action-menu > summary::-webkit-details-marker { display: none; }
.action-menu-content {
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 10;
  min-width: 170px;
  white-space: nowrap;
}
.action-menu-content form button { width: 100%; text-align: left; }

/*
 * Dismissible flash notice (layouts/partials/notice.blade.php). Pure CSS
 * dismiss via a hidden checkbox + label — same mechanism as the
 * #sidebar-control toggle, so no JS is needed to hide one banner.
 */
.notice { position: relative; padding-right: 40px; }
.notice-close {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  color: inherit;
}
/* One dismiss checkbox per notice kind, because a success and a refusal can
 * be on screen together and dismissing one must not take the other with it. */
#notice-dismiss-status:checked ~ .notice-status,
#notice-dismiss-error:checked ~ .notice-error { display: none; }

/* The red notice is the panel's ONLY report of a refused action — the forms
 * carry no summary of their own (see partials/ticket/form-fields.blade.php).
 * A refusal is very often a modal submit, and the redirect back reopens
 * that modal *over* this banner: .w3-modal is a fixed, full-viewport,
 * 40%-black overlay at z-index 3 (.modal-layer-2 is 5), which would leave
 * the one sentence explaining the failure sitting dimmed underneath it.
 * Lifting it clear of both layers is what keeps it legible while the form
 * that caused it is still open. */
.notice-error { position: relative; z-index: 6; }

/* ---------------------------------------------------------------------
 * The desk's register-a-walk-in form
 * (pages/admin/partials/registration/form-fields.blade.php).
 *
 * A stepped form, because a category plus up to two people — each with a
 * profile, an account and a competition card — is four screens of fields,
 * and a wall of fields at a busy desk gets abandoned. All of this is
 * layout for that: the trail across the top, the panel showing one step,
 * and the confirm list at the end.
 * ------------------------------------------------------------------ */

/* The trail is a progress read-out, not a set of links: steps are reached
 * in order through Next, because a later one can ask different questions
 * depending on an earlier answer. Hidden in the markup until the step
 * engine claims it — with JS off there are no steps to trail. */
.step-trail {
  display: flex; flex-wrap: wrap; gap: 6px;
  list-style: none; margin: 0 0 20px; padding: 0;
}
.step-trail li {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 4px; border-radius: 999px;
  font-size: 0.8rem; color: var(--gray);
}
.step-trail-no {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--surface-alt); color: var(--gray); font-weight: 500;
}
.step-trail li.is-active { color: var(--primary); font-weight: 500; }
.step-trail li.is-active .step-trail-no { background: var(--primary); color: var(--white); }
/* A finished step keeps its number rather than turning into a tick: the
 * number is how the trail is counted, and swapping it out mid-form makes
 * "step 3 of 4" stop matching what is on screen. */
.step-trail li.is-done .step-trail-no { background: var(--primary-light); color: var(--primary); }
@media (max-width: 600px) {
  .step-trail-label { display: none; }
}

/* Each step is a <fieldset> so the partner one can be disabled outright on
 * a singles category, which removes its fields from the submission. The
 * browser default border/padding is in the way of that. */
.step-panel { border: 0; margin: 0; padding: 0; min-width: 0; }
.step-lead { margin: 0 0 16px; color: var(--gray); font-size: 0.9rem; }

/* Back on the left, Next on the right, the count between them — the count
 * sits in the middle because it is a read-out rather than a control, and
 * putting it beside either button reads as a label for it. */
.step-nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: 8px;
}

/* The heading over each block of a person's fields. Not a <legend>: those
 * belong to the step's own fieldset, and a second one inside it would claim
 * to name the whole step. */
.entrant-section {
  margin: 20px 0 10px; padding-bottom: 4px;
  border-bottom: 1px solid var(--border-color);
  font-weight: 500; font-size: 0.85rem;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--gray);
}
.entrant-section:first-child { margin-top: 0; }
/* The lookup's answer — "already has an account" or "nobody has that
 * address". Sits directly under the email field it is about. */
.entrant-found { margin: 0 0 12px !important; }
/* A block waiting on its lookup dims rather than emptying: the fields under
 * it are still readable while the answer is on its way. */
[data-entrant-fields][aria-busy="true"] { opacity: 0.5; }

/* The confirm step's summary, built client-side from the fields above. A
 * definition list in all but name — term on the left, what is about to
 * happen on the right — laid out as a list so it wraps sanely on a phone. */
.review-list { list-style: none; margin: 0 0 16px; padding: 0; }
.review-list li {
  display: flex; flex-wrap: wrap; gap: 4px 12px;
  padding: 10px 0; border-bottom: 1px solid var(--border-color);
}
.review-list li:last-child { border-bottom: none; }
.review-term { flex: 0 0 90px; color: var(--gray); font-size: 0.8rem; text-transform: uppercase; }
.review-detail { flex: 1; min-width: 0; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------
 * /download — the tester install page.
 * --------------------------------------------------------------- */

/* Centres the card in what is left of the viewport under the 54px topbar.
 * This page holds one short card and nothing else, so left-aligning it at
 * the top of a full-height column would strand it against the sidebar. */
/* Centred, but biased upward. Dead-centre left too much empty space above
 * the card on a tall screen; the bottom padding shrinks the box the card
 * is centred in (border-box is global), lifting it by half that amount
 * without giving up the centring. */
.download-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-bottom: 96px;
  min-height: calc(100vh - 190px);
}
.download-card { max-width: 420px; width: 100%; }

/* W3.CSS has no button that pairs an icon with a two-line label, which is
 * the whole shape of a store badge — hence the flex row and the two spans. */
.store-button { display: inline-flex; align-items: center; gap: 12px; text-align: left; }
.store-button img { width: 30px; height: 30px; flex-shrink: 0; }
.store-button-eyebrow { display: block; font-size: 10px; line-height: 1.3; color: var(--gray); }
.store-button-name { display: block; font-size: 15px; line-height: 1.3; font-weight: 500; }
