
  :root {
    /* Only the specific type scale steps this page actually uses
       (2026-09-17 audit: this used to also define --fs-2xs/--fs-xs,
       copied over from generate_dashboard.py's SHARED_STYLE alongside
       the ones genuinely needed here, but never actually referenced
       anywhere in this file -- removed). Duplicated locally rather
       than shared, since this page doesn't import that module (see
       the standalone-<style> note where :focus-visible was added the
       same way). */
    --fs-sm: 12px;
    --fs-base: 13px;
    --fs-md: 14px;
    --fs-lg: 15px;
    --fs-h1: 22px;
    /* Color tokens, same story -- duplicated locally rather than
       shared, matching SHARED_STYLE's own light/dark values exactly
       so this page stays visually identical to the rest of the app
       when the toggle is used, even though it can't import the
       shared definitions. No --surface here distinct from --page-bg
       -- this page is one centered card directly on the page
       background, no separate card surface to distinguish. */
    --ink: #22282f;
    --dim: #5f6471;  /* 2026-09-28: #6b7280 -> #686e7c (gray page) -> #5f6471 (one highlight blue): >= 4.6:1 on white, the gray page, stripes, tinted fills and --accent-tint */
    --border: #e6e9ee;
    --accent: #09539a;
    --link-on-page: #09539a;   /* text links on the page (v2.0) */
    --accent-tint: #d4e6f7;  /* the one highlight blue, as in SHARED_STYLE (2026-09-28) */
    --page-bg: #f1f3f6;  /* matches SHARED_STYLE (2026-09-28): gray page, white cards */
    --surface: #ffffff;  /* card / input fill, as in SHARED_STYLE (2026-09-28) */
    --on-fill: #ffffff;
    --danger: #bc4539;  /* 2026-09-28: was #c4483b -- a hair darker so error text stays >= 4.5:1 on the gray page (4.7:1; 5.2:1 on white) */
    --danger-bg: #fdf2f1;
  }
  [data-theme="dark"] {
    --ink: #e7e9ec;
    --dim: #9aa3ad;
    --border: #33383f;
    --accent: #1e7bd2;
    --link-on-page: #7cb4ea;   /* lighter than --accent so text links read clearly on the dark page (v2.0) */
    --accent-tint: #1a2a38;
    --page-bg: #15181c;
    --surface: #1e2227;
    --danger: #e2685c;
    --danger-bg: #33201f;
  }
  body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--page-bg);
    font-family: 'Inter', sans-serif;
    color: var(--ink);
    padding: 24px;
    box-sizing: border-box;
  }
  .card {
    width: 100%;
    max-width: 340px;
  }
  .brand-row {
    display: flex;
    align-items: center;
    gap: 10px;
    justify-content: center;
    margin-bottom: 6px;
  }
  .logo { height: 32px; }
  h1 {
    font-size: var(--fs-h1);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    margin: 0;
    text-align: center;
  }
  .accent-rule {
    height: 3px;
    background: var(--accent);
    margin: 14px 0 20px;
    border-radius: 2px;
  }
  /* Runner/Coach tab toggle (2026-09-18) -- same filled-pill
     current-indicator language used elsewhere in this app
     (.nav-current, the Vdot Calculator's own tabs), reimplemented
     locally since this page doesn't share SHARED_STYLE with the rest
     of the app. */
  .tab-row {
    display: flex;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
    margin-bottom: 24px;
  }
  .tab-btn {
    flex: 1;
    background: none;
    border: none;
    border-right: 1px solid var(--border);
    padding: 10px 0;
    font-family: 'Inter', sans-serif;
    font-size: var(--fs-base);
    font-weight: 600;
    color: var(--dim);
    cursor: pointer;
  }
  .tab-btn:last-child { border-right: none; }
  .tab-btn.tab-current { background: var(--accent-tint); color: var(--accent); }
  [data-theme="dark"] .tab-btn.tab-current { color: var(--on-fill); }
  label {
    display: block;
    font-size: var(--fs-sm);
    color: var(--dim);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    margin-bottom: 6px;
  }
  input[type=text], input[type=password], input[type=email] {
    width: 100%;
    /* 48px tall -- exactly the Log In / Send email button below (v2.0, coach's request) */
    height: 48px;
    font-family: 'Inter', sans-serif;
    font-size: var(--fs-md);
    padding: 0 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    box-sizing: border-box;
    margin-bottom: 16px;
    /* --surface, not --page-bg (2026-09-28): with the page now gray, a
       page-colored input would blend into it -- and in dark mode it
       already did. Same fill as every other input in the app. */
    background: var(--surface);
    color: var(--ink);
  }
  /* Autofill override (2026-09-15) -- this is the actual reason the
     earlier background/color fix above didn't visibly do anything: a
     field the browser has a saved username/password for gets its
     background forced to the browser's OWN default (white, or a pale
     yellow) by internal autofill styling that normal `background`/
     `color` declarations cannot override, no matter how correct they
     are -- confirmed by testing showing the fix working in an
     automated render (which never simulates stored credentials) while
     the real device, which had a saved login for this field, still
     showed a plain white box. The fix isn't a background override at
     all -- it's a huge inset box-shadow the same color as the
     intended background, which visually paints over the forced
     autofill color since box-shadow isn't subject to the same
     browser override. text-fill-color similarly overrides autofill's
     own forced text color, and the long background-color transition
     stops Chrome/WebKit's brief flash to yellow the instant autofill
     kicks in, before this rule has a chance to apply. Covers both the
     WebKit-prefixed pseudo-class (Chrome/Safari/most Android
     browsers, including IronFox) and the newer unprefixed :autofill
     (Firefox desktop) so this holds regardless of which engine is
     rendering it. */
  input[type=text]:-webkit-autofill,
  input[type=email]:-webkit-autofill,
  input[type=password]:-webkit-autofill,
  input[type=text]:-webkit-autofill:hover,
  input[type=password]:-webkit-autofill:hover,
  input[type=text]:-webkit-autofill:focus,
  input[type=password]:-webkit-autofill:focus {
    -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
    -webkit-text-fill-color: var(--ink);
    caret-color: var(--ink);
    transition: background-color 600000s ease-in-out 0s;
  }
  input[type=text]:autofill,
  input[type=email]:autofill,
  input[type=password]:autofill {
    box-shadow: 0 0 0 1000px var(--surface) inset;
  }
  button[type=submit] {
    width: 100%;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Inter', sans-serif;
    font-size: var(--fs-lg);
    font-weight: 600;
    padding: 0 13px;
    border-radius: 8px;
    border: none;
    background: var(--accent);
    color: var(--on-fill);
    cursor: pointer;
    box-sizing: border-box;
  }
  @media (hover: hover) { button[type=submit]:hover { opacity: 0.92; } }
  /* Keyboard-focus visibility -- this page has its own standalone
     <style> block (doesn't pull in generate_dashboard.py's
     SHARED_STYLE), so it needs its own copy of the same rule rather
     than inheriting one. :focus-visible only, so it doesn't show on
     mouse/touch clicks. */
  a:focus-visible,
  button:focus-visible,
  input:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
  }
  .error {
    background: var(--danger-bg);
    color: var(--danger);
    font-size: var(--fs-base);
    padding: 10px 12px;
    border-radius: 8px;
    margin-bottom: 16px;
  }
  form[hidden] { display: none; }
  /* Forgot password (v2.0): the same 24px-under-the-tabs start, 16px field rhythm and
     48px button as Log In; text links sit 16px under the button (4px + their 12px tap padding). */
  [hidden] { display: none !important; }
  .fp-title { font-size: 18px; font-weight: 700; line-height: 1.3; color: var(--ink); margin: 0 0 6px; }
  .fp-text { font-size: var(--fs-base); line-height: 1.5; color: var(--dim); margin: 0 0 24px; }
  .fp-body { font-size: var(--fs-base); line-height: 1.5; color: var(--ink); margin: 0; }
  button.link-btn { display: block; width: auto; height: auto; margin: 4px auto 0; padding: 12px 8px; background: none; border: none; box-shadow: none;
    font-family: 'Inter', sans-serif; font-size: var(--fs-base); font-weight: 600; line-height: 1.2; color: var(--link-on-page); cursor: pointer; }
  .fp-body + button.link-btn { margin-top: 8px; }
  .fp-error { margin-bottom: 16px; }

  /* Phone touch rules: (1) form fields use 16px text -- iPhones zoom the
     page in when a smaller field is tapped; (2) buttons, dropdowns, text
     fields, tabs, segmented toggles, links styled as buttons, expanders and
     "Back to" links are at least 44px (the recommended touch minimum);
     (3) side-by-side links get room. Phones only; desktop untouched.
     !important only on these sizes, on purpose: some pages set deliberately
     small controls (Debug tabs, repeat days, Export) that must still grow on
     a phone. Checkboxes and plain text links (runner names) aren't touched. */
  @media (max-width: 768px) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
    select, textarea { font-size: 16px !important; }
    /* ...16px text makes a field's natural width larger, and a field in a row
       won't shrink below it on its own -- on narrow phones (360px and under)
       that pushed the Add button out of the Checklist / List / Announcements
       widgets (2026-10-04). Let fields shrink so the button always fits. */
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
    textarea { min-width: 0; }
    /* Dropdowns may shrink too, but never under the 44px touch width (the
       journal's Hour / Minute / AM-PM row went to 39px at 360px). */
    select { min-width: 44px; }
    /* Sortable column headers are tapped to sort: 44px tall (were 37-41px). */
    thead th { height: 44px; }
    /* Calendar day cells (journal month grid, the portal Calendar, the coach
       Calendar): seven across a phone caps their width (36-41px), but they're
       54-60px tall -- what was missing is the 6px dead gap between days. An
       invisible 3px touch extension on every side closes it, so a tap
       between two days still lands on one. */
    .journal-day::after, .cal-day::after { content: ""; position: absolute; inset: -3px; }
    /* The journal's "+ Log additional run" rows (were 37px tall; 51px since v2.0 to
       match the run card -- runner_journal.py's .journal-add-row). */
    .journal-add-row { min-height: 51px; box-sizing: border-box; display: flex; align-items: center; }
    button, select,
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]),
    a.primary, a.outline, a.secondary, a.resv-edit-btn, [role="tab"], summary {
      min-height: 44px !important;
      box-sizing: border-box;
    }
    button, a.primary, a.outline, a.secondary, a.resv-edit-btn, [role="tab"] { min-width: 44px !important; }
    a.primary, a.outline, a.secondary, a.resv-edit-btn,
    [class$="-back-link"], a.manage-link { display: inline-flex; align-items: center; justify-content: center; }
    summary { display: flex; align-items: center; }
    [class$="-back-link"], a.manage-link { min-height: 44px; }
    /* Buttons inside an expanded event card (2026-10-05, coach-reported --
       the first audit only measured pages as they load, so it never saw
       these): View Results, Website and Directions in the Dashboard widget,
       both Calendars and the portal home were 30px tall. */
    .dash-event-results-btn, .cal-event-results-btn,
    .dash-event-link, .cal-event-link, .my-week-event-link { min-height: 44px; box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; }
    a.manage-link + a.manage-link { margin-left: 8px; }
    /* Compact icon buttons that are deliberately drawn as 28px boxes (the red
       remove x's, widget collapse chevrons, the Competition details chevron,
       Training History's icon button): keep the 28px look and give them an
       invisible 44px touch area instead (an ::after reaching 8px past every
       edge) -- growing the box itself changed the design and broke the
       Competition table's fixed chevron column. */
    .dash-widget-remove-btn, .dash-checklist-item-remove, .dash-list-item-remove,
    .dash-widget-collapse-btn, .cp-details-btn, .th-card-chev, .km-row-menu-btn {
      min-width: 0 !important; min-height: 0 !important; position: relative;
    }
    .dash-widget-remove-btn::after, .dash-checklist-item-remove::after, .dash-list-item-remove::after,
    .dash-widget-collapse-btn::after, .cp-details-btn::after, .th-card-chev::after, .km-row-menu-btn::after {
      content: ""; position: absolute; inset: -8px;
    }
    /* Tappable table rows (2026-10-04; the script is in render_header): a row
       with a link and no controls of its own opens that link when tapped
       anywhere -- it shows the pointer and flashes the highlight blue while
       pressed, so the tap visibly registers. */
    tbody tr:has(a[href]):not(:has(button, input, select, textarea)) { cursor: pointer; }
    tbody tr:has(a[href]):not(:has(button, input, select, textarea)):active > td { background: var(--accent-tint); }
    /* ...and at least 44px tall, since the row is now the tap target (Runner
       Vdot and Meet Results rows were 33-34px). td height acts as a minimum. */
    tbody tr:has(a[href]):not(:has(button, input, select, textarea)) > td { height: 44px; }
    /* Edit mode puts collapse and remove side by side: room so their touch
       areas don't overlap (a tap meant to collapse must never remove). */
    .dash-widget-collapse-btn + .dash-widget-remove-btn { margin-left: 10px; }
  }

  /* A school without a logo shows its initials (v1.9 phase 4). */
  .brand-initials { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 8px;
                     background: #d4e6f7; color: #09539a; font-weight: 700; font-size: 16px; }
  [data-theme="dark"] .brand-initials { background: #1a2a38; color: #7cb4ea; }
