/* Almere Pickleball — shared styles for the member portal (every page under
   /members/). --gold/--card and the site-wide header/menu styles live in
   site.css (the landing page leads for those tokens); this file only holds
   what goes beyond that for the member portal itself. Popups are
   deliberately opaque, not "liquid glass" — see .popup-card. */
:root { --accent: #e41d23; }
main { max-width: 640px; margin: 18px auto 24px; padding: 0 18px; }
/* border-radius/padding/box-shadow come from site.css's shared .card rule
   (the landing page's values) — margin-bottom here only, for member-portal
   pages that stack several cards directly under each other. */
.card { margin-bottom: 14px; }
.card h2 { font-size: 14px; margin: 0 0 12px; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.status-badge {
  display: inline-block; padding: 4px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 700;
  background: rgba(15,61,138,0.1); color: var(--navy);
}
@media (prefers-color-scheme: dark) { .status-badge { color: #8ab6ec; } }
/* Manual theme choice (assets/theme.js) must win over the system setting
   here too, same as the --paper/--ink/... tokens in site.css — without
   these two, toggling dark mode manually on a light-OS device (or vice
   versa) left this text at the wrong color for the background it landed
   on, hard to read either way. */
:root[data-theme="dark"] .status-badge { color: #8ab6ec; }
:root[data-theme="light"] .status-badge { color: var(--navy); }
.status-badge.status-ended { background: rgba(91,107,125,0.12); color: var(--ink-muted); }
/* ---- Status badge colour variants (admin/trial-lessons/news) — shared
   here instead of a copy in each page's own <style> block, with a proper
   "good" colour for Active. ---- */
.status-badge.role-administrator { background: rgba(249,229,52,0.2); color: var(--gold-deep, #b8860a); }
.status-badge.status-active, .status-badge.status-confirmed, .status-badge.status-published { background: rgba(30,138,76,0.12); color: var(--success, #1e8a4c); }
.status-badge.status-pending, .status-badge.status-hidden { background: rgba(249,229,52,0.2); color: var(--gold-deep, #b8860a); }
.status-badge.status-disabled, .status-badge.status-deleted, .status-badge.status-cancelled { background: rgba(228,29,35,0.1); color: var(--danger, #e41d23); }
.status-badge.linked-account { background: rgba(15,61,138,0.1); color: var(--navy); }
/* Same dark-background-vs-fixed-text-color problem as the base .status-badge
   above, for each color variant — lighten to the tone the rest of the site
   already uses for that same meaning in dark mode (--gold for gold-deep,
   see .accent in landing.css; a lighter red/green for danger/goed, which
   don't have their own dark tokens). */
@media (prefers-color-scheme: dark) {
  .status-badge.role-administrator, .status-badge.status-pending, .status-badge.status-hidden { color: var(--gold, #f4c21b); background: rgba(249,229,52,0.28); }
  .status-badge.status-active, .status-badge.status-confirmed, .status-badge.status-published { color: #4ade80; }
  .status-badge.status-disabled, .status-badge.status-deleted, .status-badge.status-cancelled { color: #ff6b6b; }
}
:root[data-theme="dark"] .status-badge.role-administrator, :root[data-theme="dark"] .status-badge.status-pending, :root[data-theme="dark"] .status-badge.status-hidden { color: var(--gold, #f4c21b); background: rgba(249,229,52,0.28); }
:root[data-theme="light"] .status-badge.role-administrator, :root[data-theme="light"] .status-badge.status-pending, :root[data-theme="light"] .status-badge.status-hidden { color: var(--gold-deep, #b8860a); }
:root[data-theme="dark"] .status-badge.status-active, :root[data-theme="dark"] .status-badge.status-confirmed, :root[data-theme="dark"] .status-badge.status-published { color: #4ade80; }
:root[data-theme="light"] .status-badge.status-active, :root[data-theme="light"] .status-badge.status-confirmed, :root[data-theme="light"] .status-badge.status-published { color: var(--success, #1e8a4c); }
:root[data-theme="dark"] .status-badge.status-disabled, :root[data-theme="dark"] .status-badge.status-deleted, :root[data-theme="dark"] .status-badge.status-cancelled { color: #ff6b6b; }
:root[data-theme="light"] .status-badge.status-disabled, :root[data-theme="light"] .status-badge.status-deleted, :root[data-theme="light"] .status-badge.status-cancelled { color: var(--danger, #e41d23); }
:root[data-theme="dark"] .status-badge.linked-account { color: #8ab6ec; }
:root[data-theme="light"] .status-badge.linked-account { color: var(--navy); }
.button { padding: 8px 14px; border-radius: var(--radius-pill); font-size: 13px; white-space: nowrap; }
.button:disabled { opacity: 0.5; cursor: default; }
/* display:none/.show toggle was a repeated copy in admin/profile/change_password/trial-lessons's own <style> blocks; the rest of the look was already here. */
.message { display: none; font-size: 13px; margin-top: 10px; padding: 8px 10px; border-radius: 8px; }
.message.show { display: block; }
.message.error { background: rgba(228,29,35,0.1); color: var(--accent); }
.message.ok { background: rgba(15,61,138,0.1); color: var(--navy); }
@media (prefers-color-scheme: dark) { .message.ok { color: #8ab6ec; } }
:root[data-theme="dark"] .message.ok { color: #8ab6ec; }
:root[data-theme="light"] .message.ok { color: var(--navy); }
.loading { text-align: center; padding: 30px; }
/* ============================================================================
   The components below used to be duplicated in the <style> blocks of
   several member-portal pages (each page had its own copy). They live here
   once now, since every page that uses them loads this file anyway.
   ============================================================================ */
/* ---- Popup/modal (confirmation dialogs, detail cards) — used on
   admin/home/members/news/profile/booking/tournaments. ---- */
/* overflow-y so a popup taller than the viewport can actually be scrolled to
   instead of its bottom (e.g. the submit button on a long form) landing
   below the fold with no way to reach it. */
.popup-overlay { display: flex; justify-content: center; position: fixed; inset: 0; z-index: 100; background: rgba(11,31,63,0.45); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); overflow-y: auto; padding: 24px 0; }
/* Solid, not translucent: the page behind a see-through (glass) card
   bleeds through the text and makes the popup hard to read. The dimmed,
   blurred overlay above already sets the popup apart from the page. */
.popup-card { width: 100%; background: var(--card); border: 1px solid var(--line); box-shadow: var(--shadow-card-hover); }
/* Themed scrollbar for the internal scroll above (a long form's default
   browser scrollbar is a solid light-gray bar with arrow buttons, clashing
   hard with the dark card) — thin, no visible track, and a soft
   thumb using the same muted tone as the rest of the card's text.
   Deliberately webkit-only (Chrome/Edge/Brave/Safari): this build of
   Chromium falls back to the classic arrow-button scrollbar the moment the
   standard scrollbar-width/scrollbar-color properties are set at all
   (regardless of their value) alongside ::-webkit-scrollbar-*, so Firefox
   is left with its own default scrollbar rather than risk that. */
.popup-card::-webkit-scrollbar { width: 8px; }
.popup-card::-webkit-scrollbar-track { background: transparent; }
.popup-card::-webkit-scrollbar-thumb { background: var(--ink-muted); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
.popup-card::-webkit-scrollbar-thumb:hover { background: var(--ink); background-clip: padding-box; }
.popup-header { align-items: center; display: flex; justify-content: space-between; }
.popup-header h3 { margin: 0; }
/* Without background/font-size/padding reset here, this fell back to the
   browser's native button chrome (a light-gray box) instead of a plain
   icon — barely visible against the dark popup, and inconsistent
   with every other icon button on the site (e.g. .close-button, site.css). */
.popup-close {
  border: none; background: none; color: var(--ink-muted); cursor: pointer;
  width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; padding: 0; font-size: 18px; line-height: 1; font-family: inherit;
}
.popup-close:hover { background: var(--paper); color: var(--ink); }
.popup-body { padding: 18px 20px; }
/* ---- Confirm dialog (assets/confirm-dialog.js) — replaces window.confirm();
   built on the popup-* classes above. ---- */
.confirm-dialog-message { margin: 0 0 18px; color: var(--ink); font-size: 14.5px; line-height: 1.5; }
/* A short yes/no question, so centered vertically rather than top-aligned
   like the longer form popups; the body's own side padding is dropped so
   the message lines up with the title (the card already pads both). */
.popup-card.confirm-dialog-card { align-self: center; }
.confirm-dialog-card .popup-body { padding: 14px 0 0; }
.confirm-dialog-actions { display: flex; justify-content: flex-end; align-items: center; gap: 10px; }
/* margin/width reset: page-level button.primary rules (members.css's
   margin-top, and the full-width submit button on the login/register/
   set-password pages) otherwise leak into the dialog's OK button and push
   it out of line with Cancel. This selector's two classes outrank those. */
.confirm-dialog-actions .button { margin: 0; width: auto; padding: 10px 20px; border-radius: var(--radius-pill); font-size: 14px; line-height: 1.2; }
/* Same height as .button.secondary next to it, which has a 1.5px border. */
.confirm-dialog-actions .button.primary { border: 1.5px solid transparent; }
.button.secondary { background: none; border: 1.5px solid var(--line); color: var(--ink); }
/* ---- Invitation card (dashboard.html) — used as the
   dashboard's role-based action tiles, one per row inside a .card. ---- */
.action-tile { align-items: center; background: none; border: none; border-radius: 14px; cursor: pointer; display: flex; font-family: inherit; gap: 14px; padding: 10px; text-align: left; text-decoration: none; transition: background 0.15s ease; width: 100%; }
.action-tile:hover { background: var(--paper); }
/* Its own display:flex above has the same specificity as the native
   [hidden] UA rule, and (being an author rule) wins regardless of order —
   so an admin-only tile marked hidden for non-administrators would
   otherwise still show. Force it, same pattern as .menu-panel [hidden] in
   site.css. */
.action-tile[hidden] { display: none !important; }
.action-tile-icon { align-items: center; background: rgba(15,61,138,0.1); border-radius: 50%; color: var(--navy); display: flex; flex-shrink: 0; height: 44px; justify-content: center; width: 44px; }
.action-tile-icon svg { height: 22px; width: 22px; }
.action-tile-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.action-tile-title { color: var(--ink); font-size: 14.5px; font-weight: 600; }
.action-tile-sub { color: var(--ink-muted); font-size: 12.5px; }
.dashboard-tiles { display: flex; flex-direction: column; gap: 4px; }
/* ---- Member list row (admin/members) ---- */
/* One row per item in an admin list (users, subscription plans, members'
   subscriptions): text and badges on the left, action buttons on the right. */
.member-row { align-items: center; display: flex; justify-content: space-between; gap: 12px; padding: 12px 0; border-top: 1px solid var(--line); flex-wrap: wrap; }
.member-row:first-of-type { border-top: none; padding-top: 0; }
.member-row .name { font-weight: 700; font-size: 14.5px; }
.member-row .email, .member-row .details { color: var(--ink-muted); font-size: 12.5px; }
.member-row .details { margin-top: 2px; }
.member-row .badges { display: flex; gap: 6px; margin-top: 4px; flex-wrap: wrap; }
.member-row .plan-details { margin-top: 8px; }
/* A payment row (assets/payments.js, paymentRowHtml): the text takes the
   room on the left, the status badge sits top right with the buttons under
   it, also on a narrow screen. */
.member-row.payment-row { align-items: flex-start; flex-wrap: nowrap; }
.payment-row-main { flex: 1; min-width: 0; }
.payment-row-side { align-items: flex-end; display: flex; flex-direction: column; flex-shrink: 0; gap: 8px; }
.payment-row-side .actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
/* ---- Admin list pages (admin.html/trial-lessons.html) — was a near-literal
   copy in both page's own <style> blocks (the old user-list- and trial-list-
   prefixed classes were the same rules under different names); now one
   shared admin-list- prefix. ---- */
main.admin { max-width: 900px; }
.card h2 { font-size: 15px; margin: 0 0 16px; }
button.primary { margin-top: 18px; padding: 11px 22px; border-radius: var(--radius-pill); font-size: 14px; }
button.primary:disabled { opacity: 0.5; cursor: not-allowed; }
/* margin-top dropped (was 60px) now that .popup-overlay already pads the
   top itself — this only needed align-self: flex-start so a short popup
   sits near the top instead of vertically centered/stretched; max-height +
   overflow-y so a long one (many form fields) scrolls internally instead of
   its bottom running off-screen with no way to reach it. */
.popup-card { max-width: 420px; width: calc(100% - 40px); align-self: flex-start; border-radius: 20px; padding: 22px; max-height: calc(100vh - 48px); overflow-y: auto; }
.actions { display: flex; gap: 6px; flex-wrap: wrap; }
.actions button { padding: 6px 10px; border-radius: var(--radius-pill); border: 1.5px solid var(--line); background: none; color: var(--ink); font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
.admin-list-toolbar { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 20px; }
.admin-list-toolbar .toolbar-field { flex: 0 0 150px; margin-top: 0; }
.admin-list-toolbar .toolbar-search { flex: 1 1 220px; margin-bottom: 10px; }
.admin-list-pagination { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 24px; font-size: 12.5px; color: var(--ink-muted); flex-wrap: wrap; }
.admin-list-pagination-buttons { display: flex; align-items: center; gap: 10px; }
.admin-list-pagination button { padding: 6px 12px; border-radius: var(--radius-pill); border: 1.5px solid var(--line); background: none; color: var(--ink); font-size: 12.5px; font-weight: 600; cursor: pointer; font-family: inherit; }
.admin-list-pagination button:disabled { opacity: 0.4; cursor: not-allowed; }
/* ---- Form fields in a two-column row (admin/profile) ---- */
.field-row label { color: var(--ink-muted); display: block; font-weight: 600; margin-bottom: 4px; }
.field-row input, .field-row select, .field-row textarea { background: var(--paper); border: 1.5px solid var(--line); color: var(--ink); font-family: inherit; width: 100%; }
/* ---- Small centered-card pages (login, register, set-password,
   confirm-email) — each page used to carry its own copy of these rules.
   Add class="auth-page" to <body>; .card.wide for the longer register form.
   The full-width submit button is scoped to the page's own form, so it
   can't leak into the shared confirm dialog's buttons. ---- */
body.auth-page { min-height: 100vh; display: flex; align-items: flex-start; justify-content: center; padding: 98px 24px 60px; }
.auth-page .card { width: 100%; max-width: 420px; border-radius: 20px; padding: 28px 26px; box-shadow: 0 4px 24px rgba(0,0,0,0.06); margin-top: 24px; }
.auth-page .card.wide { max-width: 460px; }
.auth-page .brand-block { text-align: center; }
.auth-page .brand-block img { display: block; margin: 0 auto 8px; }
.auth-page h1 { font-family: var(--font-display); font-size: 21px; margin: 8px 0 20px; text-align: center; }
.auth-page p.description { text-align: center; font-size: 13.5px; margin: -12px 0 18px; }
.auth-page form button.primary { width: 100%; margin-top: 22px; padding: 13px; border-radius: var(--radius-pill); font-size: 15px; }
.auth-page .back-link { display: block; text-align: center; margin-top: 20px; font-size: 13px; color: var(--ink-muted); text-decoration: none; }
.auth-page [hidden] { display: none; }
/* "+ New …" collapsible create form at the top of an admin list page
   (admin.html, news.html) — was an identical per-page copy on each. */
details.admin-new-item { background: none; border: none; box-shadow: none; padding: 0; }
details.admin-new-item summary { padding: 0; font-size: 15px; font-weight: 700; color: var(--ink); }
details.admin-new-item[open] summary { margin-bottom: 16px; }
/* ---- Subscriptions (subscription.html, subscription-plans.html) ---- */
.plan-card { padding: 14px 0; border-top: 1px solid var(--line); }
.plan-card:first-of-type { border-top: none; padding-top: 0; }
.plan-card-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.plan-card-header h3 { margin: 0; font-size: 15px; }
.plan-description { color: var(--ink-muted); font-size: 13px; margin: 6px 0 0; }
.plan-details { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 10px 0 0; font-size: 13px; }
.plan-details dt { color: var(--ink-muted); }
.plan-details dd { margin: 0; font-weight: 600; }
.plan-quote { font-size: 13px; margin: 10px 0 0; }
.subscription-summary .name { font-weight: 700; font-size: 15px; }
.subscription-summary .details { color: var(--ink-muted); font-size: 13px; margin-top: 3px; }
.subscription-summary + .subscription-summary { border-top: 1px solid var(--line); margin-top: 12px; padding-top: 12px; }
.subscription-subheading { font-size: 13px; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.04em; margin: 18px 0 8px; }
/* A plain element rule like site.css's `label { display: block }` beats the
   browser's own [hidden] rule (same specificity, author styles win), so a
   hidden form field would still show — same fix as .menu-panel [hidden] in
   site.css and .auth-page [hidden] above. */
main [hidden] { display: none !important; }
/* ---- Payments (subscription.html, single-play.html, payments.html,
   admin-payments.html) ---- */
.payment-message { margin: 0 0 12px; }
.subscription-summary .actions { margin-top: 10px; }
.subscription-summary .actions .button.primary { margin-top: 0; }
/* The fields of one kind of plan (subscription-plans.html): a fieldset only
   to disable them as a group, so no border or padding of its own. */
/* One language version of bilingual content an administrator writes (a news
   story, a subscription plan): a framed group with the language as legend. */
.language-version { border: 1px solid var(--line); border-radius: 14px; padding: 4px 16px 16px; margin: 16px 0 0; min-width: 0; }
.language-version legend { padding: 0 6px; font-weight: 700; font-size: 13.5px; color: var(--ink); }
.plan-type-fields { border: 0; margin: 0; padding: 0; min-width: 0; }
.plan-type-fields[hidden] { display: none; }
/* ---- Family members (family.html and the administrators' family popup
   in admin.html, assets/family.js) ---- */
.family-form-buttons { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
.family-documents-check .hint { margin: 16px 0 8px; }
.family-form-buttons .button { margin: 0; }
#family-popup .family-form-heading { font-size: 14px; margin: 20px 0 0; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.04em; }
/* ---- Club documents per person (agreement.html and the
   administrators' documents popup in admin.html, assets/club-documents.js) ---- */
.agreement-read-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.agreement-read-link { text-decoration: none; }
/* The required "I agree" checkboxes (documentsCheckboxHtml()), on the
   member pages and the registration form. */
.documents-check { display: flex; flex-direction: column; gap: 8px; }
/* --accent-text switches with the theme, so the links stay readable in dark mode. */
.documents-check a { color: var(--accent-text); font-weight: 600; text-underline-offset: 2px; }
.documents-check-for { margin: 0; font-size: 12.5px; font-weight: 600; color: var(--ink); }
.agreement-person > div { flex: 1; min-width: 0; }
.agreement-accept { margin-top: 10px; }
.agreement-accept button.primary { margin-top: 10px; }

/* ---- Polls (assets/poll.js): the form on the dashboard, and the results
   and editor on polls.html ---- */
.poll-intro { margin: 0 0 4px; color: var(--ink-muted); font-size: 14px; }
.poll-question { border: none; padding: 0; margin: 18px 0 0; min-width: 0; }
.poll-question legend { padding: 0; color: var(--ink); font-size: 14.5px; font-weight: 700; }
.poll-question .hint { margin: 2px 0 6px; }
.poll-option { padding: 6px 0; font-size: 14px; }
#poll-actions { margin-top: 18px; }
.poll-own-answers { margin: 6px 0 0; padding-left: 20px; color: var(--ink); font-size: 14px; }
/* The editor: one box per language version and per question. */
.poll-editor-box { border: 1px solid var(--line); border-radius: 14px; padding: 4px 16px 16px; margin: 16px 0 0; min-width: 0; }
.poll-editor-box legend { padding: 0 6px; color: var(--ink); font-size: 13.5px; font-weight: 700; }
.poll-editor-multiple { margin-top: 12px; }
.poll-editor-options { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.poll-editor-option { display: grid; grid-template-columns: 1fr 1fr 32px; gap: 8px; align-items: center; }
.poll-editor-option input { margin: 0; }
.poll-editor-remove { width: 32px; height: 32px; border: none; border-radius: var(--radius-pill); background: color-mix(in srgb, var(--ink) 7%, transparent); color: var(--ink); cursor: pointer; font-family: inherit; }
.poll-editor-remove:disabled { opacity: 0.35; cursor: default; }
.poll-editor-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.poll-editor-buttons .button { padding: 8px 16px; border-radius: var(--radius-pill); font-size: 13px; }
@media (max-width: 420px) { .poll-editor-option { grid-template-columns: 1fr 32px; } .poll-editor-option input[lang="en"] { grid-column: 1; } }
/* The results: a bar per option, then who answered what. */
.poll-results-title { margin: 0; font-weight: 700; font-size: 15px; }
.poll-result-question { margin-top: 18px; }
.poll-result-question h4 { margin: 0 0 8px; font-size: 14px; }
.poll-result-option { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; margin-bottom: 10px; font-size: 13.5px; }
.poll-result-count { color: var(--ink-muted); white-space: nowrap; }
.poll-result-bar { grid-column: 1 / -1; height: 8px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 8%, transparent); overflow: hidden; }
.poll-result-bar span { display: block; height: 100%; border-radius: 999px; background: var(--gold); }
.poll-results-members-heading { margin: 24px 0 4px; font-size: 14px; }
.poll-response { padding: 10px 0; border-top: 1px solid var(--line); font-size: 13.5px; }
.poll-response-name { font-weight: 600; }
.poll-response-answers { margin: 4px 0 0; padding-left: 20px; color: var(--ink-muted); }
/* ---- Attendance (attendance.html, assets/attendance.js): a row is one
   big tap target, since it's filled in on a phone during the evening. ---- */
.attendance-row .checkbox-row { align-items: center; flex: 1; font-size: 14.5px; min-width: 0; padding: 4px 0; }
.attendance-row .checkbox-row input[type=checkbox] { height: 22px; margin-top: 0; width: 22px; }
.attendance-row .badges { margin-top: 0; }
.attendance-totals { font-weight: 700; margin: 12px 0 4px; }
/* A member's own attendance (my-attendance.html): one section per person. */
.own-attendance + .own-attendance { margin-top: 24px; }
.own-attendance h3 { font-family: var(--font-display); font-size: 1.05rem; margin: 0 0 4px; }
.own-attendance .hint { margin: 0 0 8px; }
.walk-in-results { margin-top: 16px; }
.walk-in-results .member-row .actions .button { margin-top: 0; }
/* The play evenings of a subscription (subscription-plans.html): a group of
   checkboxes, labelled like the other fields. */
.plan-weekdays { border: 0; margin: 16px 0 0; min-width: 0; padding: 0; }
.plan-weekdays legend { color: var(--ink); font-size: 13px; font-weight: 600; padding: 0; }
.plan-weekdays .checkbox-row { margin-top: 8px; }
