/* ============================================================
   Southville Run For A Cause 2026 — light + dark, mobile first
   ============================================================ */

/* [hidden] must always win: several classes below set display, and a
   class beats the browser default rule for the hidden attribute. */
[hidden]{display:none !important}

/* ============================================================
   Type
   ============================================================

   Two faces, and each one has a job the other could not do.

   ARCHIVO carries the race. It is a grotesque built for signage and small
   sizes, and the copy here is starting pistols and route markers: distances,
   fees, chest measurements, a reference number somebody reads down a phone
   at a registration desk. Crucially it is variable on WIDTH as well as
   weight, which is what lets one family speak three ways — expanded and
   heavy for the wordmark, normal for everything you fill in, condensed for
   the little uppercase labels, which is how a race bib is set.

   INSTRUMENT SERIF carries the cause. Every heading on the page is set in
   it: one weight, no bold, high contrast. Against Archivo's flat sturdiness
   it reads as printed matter rather than interface, which is the right voice
   for a turtle sanctuary and a library in Bindoy.

   Both are self-hosted. The Content-Security-Policy in vercel.json says
   font-src 'self', so Google's CDN would be blocked outright — and this is
   better anyway: one origin, no third party watching who registers.

   Latin only. Every non-ASCII character the site uses (· ñ – — ' … ) falls
   inside that subset, so there is no second file to fetch and no fallback
   to notice. Adding copy in another script means adding its subset here. */

@font-face{
  font-family:"Archivo";
  font-style:normal;
  font-weight:400 900;
  font-stretch:62% 125%;
  font-display:swap;
  src:url("/fonts/archivo-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,
                U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,
                U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"Instrument Serif";
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url("/fonts/instrument-serif-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,
                U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,
                U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
/* A real italic, not a slanted roman. The tagline is the one line on the site
   written in the event's own voice rather than the organisers', and a
   synthesised oblique would have been the giveaway that nobody set it. */
@font-face{
  font-family:"Instrument Serif";
  font-style:italic;
  font-weight:400;
  font-display:swap;
  src:url("/fonts/instrument-serif-italic-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,
                U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,
                U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

:root{
  /* event palette */
  --aqua-1:#b7f1ee;
  --aqua-2:#8ce3de;
  --aqua-3:#63d3cd;
  --purple:#3a1259;   /* SOUTHVILLE RUN / 2026 */
  --pink:#ffc2dd;     /* FOR A CAUSE */
  --green:#0c7c4a;    /* tagline */

  /* The rest of the page takes one purple out of the wordmark and stays on it.
     There used to be a --brand-1/--brand-2 pair here, ramped purple to pink
     across every button, bar and dialog header on the site; the wordmark is
     where that ramp means something, and running it everywhere else left the
     page with no colour it could use to mean "this one". */
  --accent:#6d2794;
  --accent-ink:#fff;
  --accent-hover:#571d78;
  --accent-soft:rgba(109,39,148,.10);
  --accent-ring:rgba(109,39,148,.28);

  --bg:#f7f5f9;
  --card:#fff;
  --ink:#1b1b1f;
  --ink-2:#54545c;
  --muted:#7a7a84;
  --line:#e3e0dd;
  --line-2:#d3cfcb;

  --ok:#0f7b45;
  --err:#c62f22;
  --err-bg:#fdecea;
  --err-line:#f3bdb6;
  --info-bg:#eef4fd;
  --info-line:#c5d8f2;
  --info-ink:#1c4e8a;
  --warn-bg:#fdf4e3;
  --warn-line:#f0dcb4;
  --warn-ink:#7d5a15;

  /* Panel corner. Kept modest on purpose: at 14px every card on the page
     read as a pill, which is the default look of a page nobody chose a
     radius for. Inputs sit a step tighter again at 8px. */
  --r:10px;
  --shadow:0 1px 2px rgba(16,16,20,.05), 0 8px 24px -12px rgba(16,16,20,.18);
  /* The fallbacks are ordered by width, not by popularity: Archivo is a
     fairly narrow grotesque, so a wide fallback would reflow the page
     visibly when it swaps in. */
  --font:"Archivo","Helvetica Neue",Helvetica,Arial,sans-serif;
  --font-display:"Instrument Serif",Georgia,"Times New Roman",serif;

  /* The three widths the one family is set at. Named, because the numbers
     mean nothing on their own and they are used in a dozen places. */
  --wide:118%;      /* wordmark, big figures — signage */
  --narrow:88%;     /* uppercase micro-labels — bib tape */
}

@media (prefers-color-scheme:dark){
  :root{
    --bg:#131316;
    --card:#1c1c21;
    --ink:#ececf1;
    --ink-2:#b6b6c0;
    --muted:#8d8d99;
    --line:#2e2e36;
    --line-2:#3c3c46;

    /* the hero keeps its aqua identity in dark mode; only the ink shifts */
    --aqua-1:#7ad6d1;
    --aqua-2:#57c4bf;
    --aqua-3:#3aada8;

    --accent:#c48ae8;
    --accent-ink:#25082f;
    --accent-hover:#d3a3f0;
    --accent-soft:rgba(196,138,232,.16);
    --accent-ring:rgba(196,138,232,.34);

    --ok:#5fd39a;
    --err:#ff9c90;
    --err-bg:#331916;
    --err-line:#5c2a24;
    --info-bg:#152130;
    --info-line:#27405c;
    --info-ink:#9dc4f0;
    --warn-bg:#2f2716;
    --warn-line:#4d4023;
    --warn-ink:#f0cd85;
    --shadow:0 1px 2px rgba(0,0,0,.4), 0 8px 24px -12px rgba(0,0,0,.7);
  }
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font:16px/1.55 var(--font);
  -webkit-font-smoothing:antialiased;
}

.skip{
  position:absolute;left:-9999px;top:0;background:var(--accent);color:var(--accent-ink);
  padding:10px 16px;border-radius:0 0 8px 0;z-index:20;font-weight:600;
}
.skip:focus{left:0}

/* ---------- hero (aqua) ---------- */
.hero{
  position:relative;
  background:linear-gradient(160deg,var(--aqua-1) 0%,var(--aqua-2) 60%,var(--aqua-3) 100%);
  padding:40px 20px 58px;overflow:hidden;text-align:center;
}
.hero-inner{max-width:700px;margin:0 auto;position:relative;z-index:1}
/* ---------- partner logos ---------- */
.logo-row{
  --logo-h:clamp(56px,14.5vw,86px);
  display:flex;justify-content:center;align-items:center;
  gap:clamp(16px,5.5vw,36px);margin:0 0 26px;
}
/* No container: the PNGs are transparent, so what separates them from the aqua
   is a drop-shadow tracing each logo's own silhouette rather than a box behind
   it. One shadow, holding still. These are three institutions' marks, and a
   pulsing halo on a school crest reads as decoration applied to a logo by
   someone with no standing to decorate it. */
.logo{
  height:var(--logo-h);width:auto;display:block;object-fit:contain;
  filter:drop-shadow(0 2px 5px rgba(58,18,89,.28));
}
/* Optical sizing: a tall shield reads smaller than a wide wordmark at equal height. */
.logo-sisc{height:calc(var(--logo-h) * 1.12)}
.logo-filinvest{height:calc(var(--logo-h) * .88)}

/* Condensed and tracked, the way the small print on a bib is set. */
.kicker{
  margin:0 0 14px;font-size:11.5px;letter-spacing:.18em;text-transform:uppercase;
  font-weight:800;font-stretch:var(--narrow);color:var(--purple);opacity:.72;
}

/* wordmark: Southville Run (purple) / For A Cause (pink) / 2026 (purple)

   Archivo pushed out to the far end of its width axis and near the top of its
   weight axis. This is the loudest thing on the site and the only place the
   expanded width is used, which is what keeps it feeling like a mark rather
   than a heading that happens to be big. */
.wordmark{
  margin:0;font-weight:800;font-stretch:var(--wide);
  line-height:1.02;letter-spacing:-.004em;
  text-transform:uppercase;font-size:clamp(30px,8.2vw,58px);
  display:flex;flex-direction:column;align-items:center;gap:2px;
}
.wm-purple{color:var(--purple)}
.wm-year{font-size:.82em;letter-spacing:.06em}
.wm-pink{
  color:var(--pink);
  /* Light pink cannot carry enough contrast on aqua by fill alone, so the
     letterforms are outlined in the same dark purple. paint-order keeps the
     stroke behind the fill so the shapes stay crisp. */
  -webkit-text-stroke:.045em var(--purple);
  paint-order:stroke fill;
}
@supports not (-webkit-text-stroke: 1px black){
  .wm-pink{color:#d62a75}
}

/* The one line here in the event's own voice, so it gets the serif italic and
   a size that lets the letterforms show. Set against the wordmark's expanded
   heavy caps directly above it, the contrast is the whole point. */
.tagline{
  margin:12px 0 0;color:var(--green);
  font:italic 400 clamp(19px,4.2vw,27px)/1.25 var(--font-display);
  letter-spacing:.005em;
}

/* When and where, set as one line of signage rather than two lozenges.

   These were white pills, which is the shape every piece of metadata on the
   internet is poured into and which said nothing about a date or a place.
   Condensed caps, tracked, divided by a hairline: the way the standing
   details are printed at the foot of a race poster. The icons stay — they
   are what makes the pair scannable at a glance — they just no longer need
   a capsule drawn round them. */
.event-meta{
  list-style:none;margin:22px 0 0;padding:0;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
  gap:10px 18px;
}
.event-meta li{
  display:inline-flex;align-items:center;gap:8px;
  font-size:12.5px;font-weight:700;font-stretch:var(--narrow);
  letter-spacing:.09em;text-transform:uppercase;
  color:var(--purple);
}
/* The rule between them, drawn by the second item so it never leads or
   trails, and dropped when they stack. */
.event-meta li + li::before{
  content:"";align-self:stretch;width:1px;margin-right:10px;
  background:currentColor;opacity:.32;
}
.event-meta strong{font-weight:800;letter-spacing:.07em}
.meta-icon{display:inline-flex;color:var(--purple);opacity:.75}
@media (max-width:520px){
  .event-meta{flex-direction:column;gap:7px}
  .event-meta li + li::before{display:none}
}

.lede{
  margin:16px auto 0;max-width:52ch;font-size:15px;line-height:1.6;
  color:var(--purple);opacity:.86;
}
.hero-wave{
  position:absolute;left:0;right:0;bottom:-1px;height:34px;background:var(--bg);
  clip-path:ellipse(72% 100% at 50% 100%);
}

/* ---------- compact header (registration view) ---------- */
.hero-compact{padding:20px 20px 30px}
.wordmark-sm{
  margin:0;font-weight:900;text-transform:uppercase;letter-spacing:-.01em;
  font-size:clamp(17px,4.4vw,23px);line-height:1.15;
}
.wordmark-sm .wm-pink{-webkit-text-stroke:.045em var(--purple);paint-order:stroke fill}
.compact-meta{
  margin:7px 0 0;font-size:12.5px;font-weight:600;color:var(--purple);opacity:.78;
}

/* ---------- layout ---------- */
.wrap{max-width:680px;margin:0 auto;padding:0 16px 40px}

/* ---------- proceed (intro -> form) ---------- */
.proceed-card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:20px;text-align:center;
}
.btn-arrow{display:inline-flex;transition:transform .15s}
.btn:hover .btn-arrow{transform:translateX(3px)}

/* ---------- back link + view heading ---------- */
.back-link{
  display:inline-flex;align-items:center;gap:7px;
  background:none;border:0;padding:6px 2px;margin:16px 0 4px;
  color:var(--accent);font:600 14px var(--font);cursor:pointer;
}
.back-link:hover{text-decoration:underline}
.back-link:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring);border-radius:6px}
.view-h{
  margin:4px 0 16px;font:400 32px/1.15 var(--font-display);letter-spacing:0;
}
.view-h:focus{outline:none}
.lede-form{
  margin:0 0 16px;color:var(--ink-2);font-size:14.5px;line-height:1.6;
}

/* ---------- welcome ---------- */
.welcome{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow);padding:24px 24px 22px;margin:-26px 0 16px;
  position:relative;z-index:2;
}
/* Ink, not accent. Colouring a heading purple because purple is available is
   how everything on a page ends up shouting; the accent is worth more spent
   on the things that are actually actionable. */
.welcome-h{
  margin:0 0 12px;font:400 29px/1.15 var(--font-display);letter-spacing:0;color:var(--ink);
}
.welcome p{margin:0 0 11px;color:var(--ink-2);font-size:15px;line-height:1.65}
.welcome p:last-child{margin-bottom:0}
.welcome strong{color:var(--ink);font-weight:650}
/* Where the money goes is the most important sentence on the page, so it is
   set apart — but by a rule and a little more room, the way a pull quote is,
   rather than by being put in a tinted box. A filled panel inside a filled
   card inside a page of filled cards stops registering as emphasis. */
.cause{
  border-left:2px solid var(--accent);padding:2px 0 2px 15px;
  margin-top:16px !important;color:var(--ink) !important;
}
/* Whichever block comes first sits over the hero wave — not both. */
#intro-notice:not([hidden]){margin-top:-26px;position:relative;z-index:2}
#intro-notice:not([hidden]) + .welcome{margin-top:0}

/* ---------- intro buttons ("where does it go?" / "why do we run?") ---------- */
.cause-btns{display:flex;flex-wrap:wrap;gap:10px;margin:16px 0 0}
.cause-btn{
  display:inline-flex;align-items:center;gap:9px;
  padding:11px 16px;
  background:var(--card);color:var(--accent);
  border:1.5px solid var(--accent-ring);border-radius:99px;
  font:600 14px var(--font);cursor:pointer;
  transition:background .18s,border-color .18s,transform .18s;
}
.cause-btn:hover{background:var(--accent-soft);border-color:var(--accent);transform:translateY(-1px)}
.cause-btn:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
.cause-btn-icon{display:inline-flex}
.cause-btn-chev{display:inline-flex;transition:transform .18s}
.cause-btn:hover .cause-btn-chev{transform:translateX(3px)}

/* ---------- modal ---------- */
.modal{
  width:min(760px,calc(100vw - 28px));max-height:min(86vh,900px);
  padding:0;border:1px solid var(--line);border-radius:16px;
  background:var(--card);color:var(--ink);overflow:hidden;
  box-shadow:0 24px 70px -20px rgba(16,16,20,.5);
}
.modal::backdrop{
  background:rgba(28,10,44,.55);
  backdrop-filter:blur(3px);
  animation:fadeIn .2s ease-out;
}
.modal[open]{animation:modalIn .3s cubic-bezier(.2,.9,.3,1.1)}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes modalIn{
  from{opacity:0;transform:translateY(14px) scale(.96)}
  to{opacity:1;transform:none}
}

.modal-head{
  display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  padding:20px 22px 16px;border-bottom:1px solid var(--line);
  /* Flat aqua. The hero earns its gradient — it is the poster, and it is
     600px tall. Repeating it across a 70px dialog strip is the same effect
     at a size too small to read as anything but a smudge. */
  background:var(--aqua-2);
}
.modal-head h2{margin:0;font:400 25px/1.2 var(--font-display);color:var(--purple)}
.modal-sub{margin:4px 0 0;font-size:13px;color:var(--purple);opacity:.78}
.modal-close{
  flex:0 0 auto;width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;cursor:pointer;
  background:rgba(255,255,255,.6);border:1px solid rgba(58,18,89,.15);color:var(--purple);
  transition:background .15s,transform .15s;
}
.modal-close:hover{background:#fff;transform:rotate(90deg)}
.modal-close:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}

.modal-body{padding:20px 22px 22px;overflow-y:auto;max-height:calc(86vh - 92px)}
.cause-group + .cause-group{margin-top:24px}
.cause-name{
  margin:0 0 12px;font:400 21px/1.25 var(--font-display);letter-spacing:0;
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
}
.cause-place{
  font-stretch:var(--narrow);
  font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--accent);background:var(--accent-soft);
  padding:3px 9px;border-radius:99px;
}

.shots{display:grid;grid-template-columns:repeat(3,1fr);gap:11px}
@media (max-width:560px){.shots{grid-template-columns:repeat(2,1fr)}}
.shot{
  margin:0;border-radius:11px;overflow:hidden;background:var(--bg);
  border:1px solid var(--line);
  opacity:0;transform:translateY(12px) scale(.94);
}
/* Staggered pop-in, driven by --i on each figure. */
.modal[open] .shot{
  animation:shotIn .42s cubic-bezier(.2,.9,.3,1.15) forwards;
  animation-delay:calc(140ms + var(--i) * 65ms);
}
@keyframes shotIn{to{opacity:1;transform:none}}
.shot img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;transition:transform .35s}
.shot:hover img{transform:scale(1.06)}
.shot figcaption{
  padding:8px 10px;font-size:11.5px;color:var(--muted);
  border-top:1px solid var(--line);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* Slot with no photo yet: keep the layout, show an honest placeholder. The
   "Full size" href is in the markup, so it has to go too — otherwise the pill
   offers a full-size view of a 404. */
.shot.missing img{display:none}
.shot.missing .shot-zoom{display:none}
.shot.missing{
  border-style:dashed;
  background:
    repeating-linear-gradient(45deg,transparent,transparent 9px,var(--accent-soft) 9px,var(--accent-soft) 18px),
    var(--bg);
}
.shot.missing::before{
  content:"Photo coming soon";
  display:grid;place-items:center;aspect-ratio:4/3;
  font-size:12px;font-weight:600;color:var(--muted);text-align:center;padding:8px;
}
/* One label under the three photos, instead of a caption on each. */
.shots-plain .shot figcaption{display:none}
.shots-label{
  margin:10px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted);
}
.why-placeholder{
  margin:0 0 12px;color:var(--ink-2);font-size:14.5px;line-height:1.65;
}
.why-placeholder:last-of-type{margin-bottom:0}
.modal-foot{
  margin:20px 0 0;padding-top:16px;border-top:1px solid var(--line);
  font-size:13px;color:var(--muted);text-align:center;
}

/* ---------- before you register ---------- */
.prep-lead{margin:14px 0 12px;color:var(--ink-2);font-size:14.5px}
.checklist{
  list-style:none;counter-reset:c;margin:0 0 16px;padding:0;
}
.checklist li{
  counter-increment:c;position:relative;padding:0 0 0 27px;margin:0 0 11px;
  color:var(--ink-2);font-size:14.5px;line-height:1.6;
}
/* Numbered the way a numbered list is normally numbered. The disc these used
   to sit in turned five plain reminders into five badges, which is a lot of
   apparatus for "read this before you register". */
.checklist li::before{
  content:counter(c) ".";position:absolute;left:0;top:0;width:20px;
  text-align:right;
  color:var(--accent);font-size:13.5px;font-weight:800;
  font-variant-numeric:tabular-nums;
}
.checklist strong{color:var(--ink);font-weight:650}
.contact{
  margin:14px 0 4px;font-size:13.5px;color:var(--muted);line-height:1.7;
  word-break:break-word;
}
/* The same note and contacts, repeated directly above the submit button. */
.form-note{margin:26px 0 22px}

/* The way out for someone the form has failed. A link in a sentence was easy
   to read past, so it is drawn as what it is: something to press. Outlined
   rather than filled, so it never competes with the submit button below it. */
.backup{
  margin:14px 0 0;display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;
  font-size:13.5px;color:var(--muted);line-height:1.5;
}
.backup-link{
  display:inline-flex;align-items:center;gap:8px;
  min-height:44px;padding:10px 16px;border-radius:10px;
  border:1.5px solid var(--accent);background:var(--card);color:var(--accent);
  font:600 14px var(--font);text-decoration:none;
  transition:background .15s,color .15s,transform .06s;
}
.backup-link:hover{background:var(--accent);color:var(--accent-ink);text-decoration:none}
.backup-link:active{transform:translateY(1px)}
.backup-link:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
.backup-link svg{flex:none}
/* The only standing notice on the page — it is always true, and it is not a
   problem. The filled panel it used to sit in is the treatment the error and
   warning banners need in order to interrupt; spending it on a permanent
   fixture leaves nothing louder for the messages that actually arrive. */
.notice.info{
  border:0;border-left:2px solid var(--info-ink);border-radius:0;
  background:none;color:var(--ink-2);
  padding:2px 0 2px 15px;margin:0;
}
.notice.info strong{color:var(--ink)}

/* ---------- progress ---------- */
.progress-card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:14px 16px;margin:0 0 16px;
}
.progress-top{
  display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  font-size:13px;color:var(--ink-2);margin-bottom:9px;
}
.progress-pct{font-weight:700;color:var(--accent);font-variant-numeric:tabular-nums}
.track{height:7px;border-radius:99px;background:var(--line);overflow:hidden}
.fill{
  height:100%;width:0;border-radius:99px;background:var(--accent);
  transition:width .35s cubic-bezier(.4,0,.2,1);
}

/* ---------- the intro reads; the form is filled in ----------

   Everything on this site used to be the same white rounded rectangle: four
   on the intro, four more on the form, stacked at even intervals down a grey
   page. That is the shape a page takes when nobody decided what its parts
   are, and no amount of restyling the insides fixes it.

   So the two halves are built differently, on a rule that holds:

     Prose is not boxed. The intro is a welcome, a poster and a checklist —
     things to read. They run straight down the page, parted by hairlines and
     air, the way a printed programme sets them.

     Things you operate are boxed. The form's questions, the waiver link, the
     agreement checkbox, the race poster: all still framed, because a frame
     around something you have to act on says where it starts and stops.

   The result is that the boxes on the intro page are exactly the things a
   reader has to do something about, and the reading matter has no chrome at
   all. */
#view-intro .section{
  background:none;border:0;border-radius:0;overflow:visible;
  border-top:1px solid var(--line);
  margin:0;padding:30px 0 6px;
}
#view-intro .section-head{padding:0;border-bottom:0;margin:0 0 4px}
#view-intro .section-body{padding:0}
/* The CTA is the object here — a panel drawn round it only competes. */
.proceed-card{background:none;border:0;border-radius:0;padding:26px 0 4px}

/* ---------- section cards ----------

   Bordered, not lifted. The shadow used to be on every panel on the page at
   equal strength, which is the same as being on none of them — nothing was
   nearer the reader than anything else, and eight identical floating slabs is
   the look of a page assembled out of a component library. It is kept for the
   two things that genuinely sit above the page: the welcome card, which
   overlaps the hero, and the confirmation card at the end. */
.section{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  margin:0 0 16px;overflow:hidden;
}
.section-head{
  display:flex;align-items:center;gap:12px;
  padding:16px 20px;border-bottom:1px solid var(--line);
}
/* A numeral, not a badge. A digit in a tinted disc is the house style of every
   template on the internet, and it makes the number louder than the heading it
   is numbering. Set as a figure in the accent, it counts the sections without
   competing with them. */
.step{
  flex:0 0 auto;min-width:1.15em;text-align:right;
  color:var(--accent);font:800 13px var(--font);
  font-variant-numeric:tabular-nums;
}
.section-head h2{margin:0;font:400 23px/1.2 var(--font-display);letter-spacing:0}
.section-body{padding:4px 20px 6px}

/* ---------- fields ---------- */
.field{padding:18px 0;border-bottom:1px solid var(--line)}
.field:last-child,.field.last-shown{border-bottom:0}
.q{display:block;font-size:15px;font-weight:600;margin:0 0 3px;color:var(--ink);cursor:pointer}
.req{color:var(--err);margin-left:2px}
.optional{color:var(--muted);font-weight:400;font-size:13px;margin-left:6px}
.help{color:var(--muted);font-size:13px;margin:0 0 10px;line-height:1.5;cursor:pointer}

input[type=text],input[type=email],input[type=tel],textarea,select{
  width:100%;padding:11px 13px;font:inherit;color:var(--ink);
  background:var(--card);border:1px solid var(--line-2);border-radius:8px;
  transition:border-color .15s,box-shadow .15s;
}
textarea{min-height:88px;resize:vertical;line-height:1.5}
select{
  appearance:none;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),
                   linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 19px) 51%,calc(100% - 13px) 51%;
  background-size:6px 6px,6px 6px;background-repeat:no-repeat;padding-right:40px;
}
input::placeholder,textarea::placeholder{color:var(--muted);opacity:.75}
input:focus,textarea:focus,select:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-ring);
}

/* choice chips */
fieldset{border:0;margin:0;padding:0;min-width:0}
legend{padding:0}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:2px}
/* Keep the native radio as the thing that receives the tap. On iOS, an
   absolutely positioned input whose containing block is an inline label can
   end up with a fragile hit box. Make the label a real box and stretch the
   input across the visible chip instead of relying on label retargeting. */
.chip{position:relative;display:inline-block}
.chip input{position:absolute;inset:0;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.chip span{
  display:block;padding:9px 15px;border:1px solid var(--line-2);border-radius:99px;
  font-size:14.5px;font-weight:500;color:var(--ink-2);background:var(--card);
  cursor:pointer;transition:all .15s;user-select:none;
}
.chip input:hover + span{border-color:var(--accent);color:var(--accent)}
.chip input:checked + span{
  background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600;
}
.chip input:focus-visible + span{box-shadow:0 0 0 3px var(--accent-ring)}

/* file upload */
.file-input{position:absolute;width:1px;height:1px;opacity:0;overflow:hidden}
.drop{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:22px 16px;border:1.5px dashed var(--line-2);border-radius:11px;
  background:var(--bg);cursor:pointer;text-align:center;
  transition:border-color .15s,background .15s;
}
.drop:hover,.drop.over{border-color:var(--accent);background:var(--accent-soft)}
.drop:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-ring)}
.drop-icon{
  font-size:19px;line-height:1;color:var(--accent);
  width:34px;height:34px;border-radius:50%;background:var(--accent-soft);
  display:grid;place-items:center;margin-bottom:5px;
}
.drop-main{font-size:14.5px;font-weight:600;color:var(--ink)}
.drop-sub{font-size:12.5px;color:var(--muted)}

.upload{border:1px solid var(--line-2);border-radius:11px;padding:12px 13px;background:var(--card)}
.upload-row{display:flex;align-items:center;gap:12px}
.upload-thumb{
  flex:0 0 auto;width:42px;height:42px;border-radius:8px;border:1px solid var(--line);
  background:var(--bg) center/cover no-repeat;
  display:grid;place-items:center;font-size:10.5px;font-weight:700;color:var(--muted);
}
.upload-meta{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.upload-name{
  font-size:14px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.upload-status{font-size:12.5px;color:var(--muted)}
.upload-status.good{color:var(--ok);font-weight:600}
.upload-status.bad{color:var(--err);font-weight:600}
.upload-track{height:4px;border-radius:99px;background:var(--line);overflow:hidden;margin-top:10px}
.upload-fill{
  height:100%;width:0;border-radius:99px;background:var(--accent);
  transition:width .3s ease;
}

/* validation */
.err-msg{
  display:none;align-items:center;gap:6px;
  color:var(--err);font-size:13px;margin:8px 0 0;font-weight:500;
}
.err-msg::before{
  content:"!";flex:0 0 auto;width:15px;height:15px;border-radius:50%;
  background:var(--err);color:#fff;font-size:10.5px;font-weight:700;
  display:grid;place-items:center;line-height:1;
}
.field.invalid .err-msg{display:flex}
.field.invalid input,.field.invalid textarea,.field.invalid select{
  border-color:var(--err);background:var(--err-bg);
}
.field.invalid .chip span{border-color:var(--err-line)}
.field.done .q::after{
  content:"\2713";color:var(--ok);font-weight:700;margin-left:7px;font-size:13px;
}

/* ---------- submit ---------- */
.submit-row{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:18px 20px;text-align:center;
}
/* One flat brand purple. A two-stop gradient across a button says nothing
   about what the button does — the wordmark is where this event's purple and
   pink actually mean something, and repeating them here only spends the
   effect. Solid also keeps the label legible in both themes, which a fixed
   white-on-gradient did not. */
.btn{
  width:100%;border:0;border-radius:10px;cursor:pointer;
  background:var(--accent);color:var(--accent-ink);
  padding:14px 26px;font:600 16px var(--font);letter-spacing:.01em;
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  transition:background .15s,transform .06s;
}
.btn:hover:not(:disabled){background:var(--accent-hover)}
.btn:active:not(:disabled){transform:translateY(1px)}
.btn:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
.btn:disabled{opacity:.62;cursor:default}
.spinner{
  display:none;width:16px;height:16px;border-radius:50%;
  border:2px solid currentColor;opacity:.45;border-top-color:transparent;
  animation:spin .7s linear infinite;
}
.btn.loading .spinner{display:block}
@keyframes spin{to{transform:rotate(360deg)}}
.fineprint{margin:12px 0 0;font-size:12.5px;color:var(--muted);line-height:1.5}

/* ---------- banners ---------- */
.banner,.notice{
  border-radius:11px;padding:13px 16px;font-size:14px;margin:0 0 16px;line-height:1.55;
  border:1px solid var(--err-line);background:var(--err-bg);color:var(--err);
}
.banner.warn,.notice.warn{
  border-color:var(--warn-line);background:var(--warn-bg);color:var(--warn-ink);
}
.banner ul{margin:7px 0 0;padding-left:19px}
.banner li{margin:2px 0}
.banner code{background:rgba(128,128,128,.18);padding:1px 5px;border-radius:4px;font-size:12.5px}

/* ---------- success ---------- */
.done-card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow);padding:34px 24px 28px;text-align:center;
}
.done-badge{width:46px;height:46px;margin:0 auto 16px}
.done-ring{stroke:var(--ok);opacity:.28}
.done-tick{
  stroke:var(--ok);stroke-dasharray:40;stroke-dashoffset:40;
  animation:draw .45s .1s forwards ease-out;
}
@keyframes draw{to{stroke-dashoffset:0}}
.done-card h2{margin:0 0 8px;font:400 31px/1.15 var(--font-display);letter-spacing:0}
.done-msg{margin:0 0 22px;color:var(--ink-2);font-size:15px}
.ref-block{
  background:var(--accent-soft);border:1px dashed var(--accent-ring);
  border-radius:12px;padding:16px;margin:0 0 18px;
}
.ref-label{
  font-stretch:var(--narrow);
  display:block;font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-2);font-weight:700;margin-bottom:8px;
}
.ref-row{display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap}
.ref-row code{
  font:700 22px ui-monospace,"Cascadia Mono",Consolas,monospace;
  letter-spacing:.09em;color:var(--accent);
}
.btn-ghost{
  border:1px solid var(--line-2);background:var(--card);color:var(--ink-2);
  border-radius:8px;padding:6px 13px;font:500 13px var(--font);cursor:pointer;
  transition:border-color .15s,color .15s;
}
.btn-ghost:hover{border-color:var(--accent);color:var(--accent)}
.btn-ghost:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
.ref-hint{margin:11px 0 0;font-size:12.5px;color:var(--muted)}
.again{margin:4px 0 0}
a{color:var(--accent);font-weight:600;text-decoration:none}
a:hover{text-decoration:underline}

/* ---------- footer ---------- */
.foot{text-align:center;color:var(--muted);font-size:12.5px;padding:0 16px 34px}
.foot p{margin:0}

@media (max-width:520px){
  .hero{padding:34px 18px 50px}
  .section-body{padding:2px 16px 4px}
  .section-head{padding:14px 16px}
  .done-card{padding:28px 18px 24px}
}

@media (prefers-reduced-motion:reduce){
  .spinner{animation:none}
  .fill{transition:none}
  .done-tick{animation:none;stroke-dashoffset:0}
  .modal[open],.modal::backdrop{animation:none}
  .modal[open] .shot{animation:none;opacity:1;transform:none}
  .shot img,.modal-close{transition:none}
  .shot:hover img{transform:none}
  /* The logos have nothing left to sit still: they no longer pulse or lift. */
}

/* ============================================================
   Waiver of Liability + the agreement that gates "Proceed"
   ============================================================ */
.doc-links{display:grid;grid-template-columns:1fr;gap:10px;margin:0 0 14px}
.doc-link{
  display:flex;align-items:center;gap:11px;
  padding:12px 14px;border:1px solid var(--line-2);border-radius:11px;
  background:var(--card);color:var(--ink);text-decoration:none;font-weight:500;
  transition:border-color .15s,background .15s,transform .15s;
}
.doc-link:hover{
  border-color:var(--accent);background:var(--accent-soft);
  transform:translateY(-1px);text-decoration:none;
}
.doc-link:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
/* The icon, not an icon in a tile. A 34px tinted square behind a 17px glyph is
   two shapes doing one glyph's job, and the page had four of them. */
.doc-icon{
  flex:0 0 auto;display:grid;place-items:center;color:var(--accent);
}
.doc-text{display:flex;flex-direction:column;min-width:0}
.doc-name{font-size:14.5px;font-weight:650;color:var(--ink);letter-spacing:-.01em}
.doc-sub{font-size:12px;color:var(--muted);font-weight:400}

/* The waiver agreement. The native box is hidden behind .agree-mark rather
   than removed, so it keeps its keyboard behaviour and its focus ring. */
.agree{
  position:relative;display:flex;align-items:flex-start;gap:11px;
  padding:13px 15px;margin:0 0 16px;cursor:pointer;
  border:1.5px solid var(--line-2);border-radius:11px;background:var(--card);
  transition:border-color .15s,background .15s,box-shadow .15s;
}
.agree:hover{border-color:var(--accent);background:var(--accent-soft)}
/* The checkbox remains native and accessible, but its invisible hit target
   covers the whole agreement card. This avoids relying on Safari to retarget a
   tap from a label to a zero-size input. */
.agree input{position:absolute;inset:0;z-index:2;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.agree-mark{
  flex:0 0 auto;width:20px;height:20px;margin-top:1px;border-radius:6px;
  display:grid;place-items:center;
  border:1.5px solid var(--line-2);background:var(--card);color:transparent;
  transition:background .15s,border-color .15s,color .15s;
}
.agree input:checked + .agree-mark{
  background:var(--accent);border-color:var(--accent);color:var(--accent-ink);
}
.agree input:focus-visible + .agree-mark{
  outline:none;box-shadow:0 0 0 3px var(--accent-ring);
}
.agree-text{font-size:14px;line-height:1.55;color:var(--ink-2)}
.agree-text strong{color:var(--ink);font-weight:650}
.agree:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}

/* Someone reached the form without ticking the box: say where to look. */
.agree.nudge{
  border-color:var(--err);background:var(--err-bg);
  animation:agreeNudge .4s ease-in-out;
}
.proceed-help{display:block;margin-top:10px;font-size:12px;color:var(--muted);line-height:1.5;text-align:center}

/* The two confirmations, one step each: the document, then its box. */
.consent-step{margin:0 0 18px}
.consent-h{display:flex;align-items:center;gap:8px;margin:0 0 8px;font-size:14.5px;font-weight:700;color:var(--ink)}
.consent-n{font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--accent)}
.req-tag{
  margin-left:auto;padding:2px 9px;border-radius:99px;font-size:11px;font-weight:700;
  background:var(--err-bg);color:var(--err);border:1px solid var(--err-line);
}
.consent-step.is-done .req-tag{background:var(--accent-soft);color:var(--accent);border-color:var(--accent-ring)}
/* Ticked: the tag says so instead of "Required". */
.consent-step.is-done .req-tag{font-size:0}
.consent-step.is-done .req-tag::before{content:"\2713  Done";font-size:11px}
.consent-step .doc-link{margin:0 0 10px}
.consent-step .agree{margin:0}
/* An empty box has to read as a box to tick, not as decoration. */
.agree .agree-mark{width:22px;height:22px;border-width:2px;border-color:var(--muted)}

/* Said under a box that was missed, and above Proceed. */
.agree-err{display:flex;gap:7px;margin:8px 2px 0;color:var(--err);font-size:13.5px;font-weight:600;line-height:1.45}
.agree-err[hidden]{display:none}
.proceed-alert{
  margin:0 0 12px;padding:11px 13px;border-radius:10px;
  background:var(--err-bg);border:1px solid var(--err-line);color:var(--ink);
  font-size:14px;font-weight:600;line-height:1.5;
}
.proceed-alert a{color:var(--err);text-decoration:underline}
/* Waiting for both boxes: looks as disabled did, but still answers a tap. */
.btn.is-waiting{opacity:.62}
.btn.is-waiting:hover{background:var(--accent)}
@keyframes agreeNudge{
  0%,100%{transform:translateX(0)}
  25%{transform:translateX(-5px)}
  75%{transform:translateX(5px)}
}

/* ============================================================
   Payment details (top of the Payment section)
   ============================================================ */
.pay-info{
  margin:18px 0 6px;padding:16px;
  border:1px solid var(--line);border-radius:13px;background:var(--bg);
}
.pay-h{
  margin:0 0 12px;font-size:11.5px;letter-spacing:.11em;text-transform:uppercase;
  font-weight:800;color:var(--accent);
}

/* The artwork and the copyable details are the same information in two forms,
   so they sit side by side rather than stacked — and fold to one column when
   there is no room for that. */
.pay-grid{display:grid;grid-template-columns:minmax(0,190px) minmax(0,1fr);gap:13px;align-items:start}
@media (max-width:560px){.pay-grid{grid-template-columns:1fr}}
.pay-shots{grid-template-columns:1fr;gap:11px}
.pay-shots .shot{
  opacity:1;transform:none;animation:none;
  background:var(--card);
  transition:border-color .2s,box-shadow .2s,opacity .2s,transform .2s;
}
/* A QR code or an account card must never be cropped, so these are contained
   in a square rather than covering a 4:3 box the way a photo does. */
.pay-shots .shot{position:relative}
.pay-shots .shot img{aspect-ratio:1/1;object-fit:contain;padding:8px;background:var(--card)}
.pay-shots .shot:hover img{transform:none}
.pay-shots .shot.missing::before{aspect-ratio:1/1;content:"Image coming soon"}

.shot-zoom{
  position:absolute;top:7px;right:7px;
  display:inline-flex;align-items:center;gap:5px;
  padding:5px 9px;border-radius:99px;
  background:var(--card);border:1px solid var(--line-2);
  font-size:11px;font-weight:700;color:var(--ink-2);text-decoration:none;
  opacity:.85;transition:opacity .15s,border-color .15s,color .15s;
}
.shot-zoom:hover{opacity:1;border-color:var(--accent);color:var(--accent);text-decoration:none}
.shot-zoom:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
.sr{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}
/* On a phone the tile is small enough that a worded pill would sit on top of
   the thing it is offering to enlarge, so it drops to its icon. */
@media (max-width:560px){
  .shot-zoom{padding:6px;gap:0;border-radius:50%}
  .shot-zoom-text{display:none}
}
.pay-shots figcaption{
  text-align:center;font-size:11.5px;font-weight:700;color:var(--ink-2);
  letter-spacing:.03em;text-transform:uppercase;
  white-space:normal;overflow:visible;padding:8px 6px;line-height:1.3;
}
.pay-shots .shot.on{
  border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-ring);
  transform:translateY(-2px);
}
.pay-shots .shot.on figcaption{color:var(--accent)}
.pay-shots .shot.off{opacity:.42}

/* Account details read as a card of their own — they are the one thing on
   this screen a runner has to copy exactly. */
.bank-card{
  margin:0;padding:14px 15px;
  border:1px solid var(--line-2);border-radius:11px;background:var(--card);
}
.bank-card-h{
  display:flex;align-items:center;gap:8px;margin:0 0 12px;
  font-size:12px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-2);
}
.bank-mark{
  display:inline-flex;width:26px;height:26px;border-radius:7px;
  align-items:center;justify-content:center;
  background:var(--accent-soft);color:var(--accent);
}
.bank{margin:0;display:grid;gap:10px}
.bank-row{display:grid;grid-template-columns:118px 1fr;gap:12px;align-items:baseline}
@media (max-width:520px){.bank-row{grid-template-columns:1fr;gap:3px}}
.bank dt{
  margin:0;font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  font-weight:700;color:var(--muted);
}
.bank dd{margin:0;font-size:14px;line-height:1.5;color:var(--ink);font-weight:500}
.bank-acct{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.acct{
  font:700 17px ui-monospace,"Cascadia Mono",Consolas,monospace;
  letter-spacing:.06em;color:var(--accent);
}
.acct-copy{display:inline-flex;align-items:center;gap:6px}
.acct-copy-icon{display:inline-flex}
.acct-copy.copied{border-color:var(--ok);color:var(--ok)}
.bank-card{transition:opacity .2s,border-color .2s}
.bank-card.off{opacity:.5}

.pay-note{
  margin:14px 0 0;font-size:13px;color:var(--ink-2);line-height:1.55;
  padding-left:12px;border-left:2px solid var(--accent-ring);
}

/* ============================================================
   SISC salary deduction — card + panel
   ============================================================ */
.sd-summary{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  margin:0 0 18px;padding:14px 16px;
  border:1px solid var(--warn-line);background:var(--warn-bg);border-radius:12px;
}
.sd-summary.ready{border-color:var(--line-2);background:var(--accent-soft)}
.sd-summary-main{flex:1 1 220px;min-width:0}
.sd-badge{
  display:inline-block;margin-bottom:6px;padding:3px 9px;border-radius:99px;
  font-size:11px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  background:var(--warn-ink);color:var(--warn-bg);
}
.sd-summary.ready .sd-badge{background:var(--ok);color:var(--card)}
.sd-summary-text{
  margin:0;font-size:13.5px;line-height:1.5;color:var(--ink-2);
  overflow-wrap:anywhere;
}
.sd-edit{flex:0 0 auto}

.sd-modal{width:min(560px,calc(100vw - 28px))}
.sd-modal .modal-body{max-height:calc(86vh - 168px)}
.sd-lead{margin:0 0 14px;font-size:14.5px;line-height:1.6;color:var(--ink-2)}
.sd-please{margin:0 0 6px;font-size:14px;font-weight:700;color:var(--ink)}
.sd-steps{margin:0 0 4px;padding-left:20px}
.sd-steps li{margin:0 0 7px;font-size:14px;line-height:1.55;color:var(--ink-2)}
.sd-fields{margin-top:6px;border-top:1px solid var(--line)}
.sd-fields .field:last-child{border-bottom:0}
.sd-error:not([hidden]){margin:14px 0 0}

.modal-foot-bar{
  display:flex;justify-content:flex-end;align-items:center;gap:10px;
  padding:14px 22px;border-top:1px solid var(--line);background:var(--card);
}
.btn-sd{width:auto;padding:11px 22px;font-size:15px}

@media (prefers-reduced-motion:reduce){
  .doc-link:hover{transform:none}
  .agree.nudge{animation:none}
}

/* ============================================================
   Progress that follows you, and sections that mark themselves done
   ============================================================ */

/* The form is four sections long, so the count of what is left stays on
   screen instead of scrolling away at the top. */
.progress-card{position:sticky;top:10px;z-index:5;pointer-events:none;}

.section.complete .section-head{border-bottom-color:var(--line)}
/* Done: the number gives way to a tick, in the green that means "settled"
   everywhere else on the page. */
.section.complete .step{
  color:var(--ok);
  font-size:0;                     /* the numeral steps aside for the tick */
}
.section.complete .step::after{
  content:"\2713";font-size:15px;font-weight:700;line-height:1;
}
.section.complete .section-head h2{color:var(--ink-2)}

@media (prefers-reduced-motion:reduce){
  .pay-shots .shot{transition:none}
  .pay-shots .shot.on{transform:none}
}

/* ============================================================
   Race jersey, in 3D (inside the race-category question, and the pop-up)

   Two flat views hung back to back, with the gap between them packed with
   darkened copies of the front silhouette so the shirt has an edge to show
   when it turns. app.js owns the angles; everything here is the box they
   turn inside.
   ============================================================ */

.jersey-card{
  margin:14px 0 2px;padding:13px;
  border:1px solid var(--line);border-radius:12px;background:var(--bg);
}
.jersey-card-head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
}
.jersey-eyebrow{
  margin:0;font-size:10.5px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);
}
.jersey-name{
  margin:3px 0 0;font-size:15px;font-weight:800;letter-spacing:-.01em;color:var(--ink);
}
/* The colourway rides along with the distance rather than under it: two short
   words on one line read as a name, two stacked lines read as a form. */
.jersey-colour{font-weight:600;color:var(--ink-2)}
.jersey-colour::before{content:"· "}
.jersey-open{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;
  font-weight:700;
}
.jersey-hint{
  margin:9px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted);text-align:center;
}

/* ---------- the viewer ---------- */

.jersey{
  --depth:13px;      /* how thick the garment is, front face to back face */
  --j-turn:1;        /* 1 face-on, 0 edge-on — app.js keeps this current */
  --j-tint:140,140,160;
  position:relative;display:grid;place-items:center;
  margin:11px 0 0;border-radius:10px;
  perspective:900px;perspective-origin:50% 44%;
  background:radial-gradient(72% 58% at 50% 46%, rgba(var(--j-tint),.20), transparent 72%);
  transition:background .4s;
}
.jersey-mini{height:196px}
.jersey-big{--depth:20px;height:clamp(200px,40vh,340px);perspective:1150px}

.j-stage{
  position:relative;display:grid;place-items:center;
  width:100%;height:100%;
  transform-style:preserve-3d;
  transition:transform .45s cubic-bezier(.2,.85,.3,1);
  /* Horizontal drags turn the shirt; vertical ones still scroll the page,
     which matters more on a phone than a tilt does. */
  touch-action:pan-y;
  cursor:grab;outline-offset:6px;
}
.j-stage:focus-visible{outline:2px solid var(--accent)}
.jersey.is-turning .j-stage{cursor:grabbing;transition:none}

.j-spin{
  position:relative;height:100%;aspect-ratio:3/4;
  transform-style:preserve-3d;
  transition:transform .55s cubic-bezier(.2,.85,.3,1);
  will-change:transform;
}
/* While a finger is on it, and while app.js is placing it, the shirt tracks
   exactly rather than easing towards where it was asked to be. */
.jersey.is-turning .j-spin,.jersey.is-still .j-spin,
.jersey.is-turning .j-floor,.jersey.is-still .j-floor{transition:none}

.j-face,.j-edge{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;
  user-select:none;-webkit-user-drag:none;pointer-events:none;
}
.j-face{backface-visibility:hidden;-webkit-backface-visibility:hidden}
.j-front,.j-back{z-index:2}
.j-side{
  z-index:3;
  opacity:0;
  transform-origin:center;
  transition:opacity .18s ease,filter .18s ease;
}
.j-front{transform:translateZ(calc(var(--depth) / 2))}
.j-back{transform:rotateY(180deg) translateZ(calc(var(--depth) / 2))}

.j-edges{position:absolute;inset:0;transform-style:preserve-3d;opacity:var(--j-edge-opacity,1);transition:opacity .18s ease}
/* --z runs 0→1 through the stack, so the copies span the full depth. Their
   brightness is baked into the style attribute by app.js. */
.j-edge{transform:translateZ(calc(var(--depth) * (0.5 - var(--z))))}

/* Contact shadow. It narrows as the shirt turns edge-on, which is most of
   what persuades the eye there is an object here at all. */
.j-floor{
  position:absolute;left:50%;bottom:2px;width:56%;height:15px;
  border-radius:50%;pointer-events:none;
  background:radial-gradient(closest-side,rgba(16,16,20,.32),rgba(16,16,20,0) 76%);
  transform:translateX(-50%) scaleX(calc(.55 + .45 * var(--j-turn)));
  transition:transform .55s cubic-bezier(.2,.85,.3,1);
}

/* Nothing picked yet: a quiet outline of what is coming, on a plain card. The
   hint under the card does the asking, so the slot itself stays silent. */
.j-ghost{display:none;width:auto;height:58%;color:var(--line-2);opacity:.75}
.jersey.is-empty{
  height:136px;background:var(--card);border:1px dashed var(--line-2);
}
.jersey.is-empty .j-ghost{display:block}

/* Artwork that was asked for and did not arrive is a different matter, and
   says so exactly as an empty photo tile does. */
.j-note{
  margin:0;padding:0 16px;text-align:center;
  font-size:12.5px;font-weight:600;color:var(--muted);
}
.jersey.is-missing{
  height:136px;
  background:
    repeating-linear-gradient(45deg,transparent,transparent 9px,var(--accent-soft) 9px,var(--accent-soft) 18px),
    var(--card);
  border:1px dashed var(--line-2);
}
.jersey.is-empty .j-stage,.jersey.is-missing .j-stage,
.jersey.is-empty .j-floor,.jersey.is-missing .j-floor{display:none}
.jersey:not(.is-missing) .j-note{display:none}

/* ---------- the pop-up ---------- */

.jersey-modal{width:min(560px,calc(100vw - 28px))}
.jersey-modal-body{text-align:center}
.jersey-tools{
  display:flex;align-items:center;justify-content:center;gap:9px;
  flex-wrap:wrap;margin-top:16px;
}
.jersey-faces{
  display:inline-flex;gap:3px;padding:3px;
  border:1px solid var(--line);border-radius:99px;background:var(--bg);
}
.jersey-facebtn{
  appearance:none;border:0;background:transparent;cursor:pointer;
  padding:6px 17px;border-radius:99px;
  font:700 13px var(--font);color:var(--ink-2);
  transition:background .18s,color .18s;
}
.jersey-facebtn:hover{color:var(--accent)}
.jersey-facebtn.is-on{background:var(--accent);color:var(--accent-ink)}
.jersey-facebtn:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}
.jersey-drag{
  flex:1 1 100%;margin:2px 0 0;
  font-size:12.5px;color:var(--muted);
}
.jersey-drag span{margin-right:5px;font-size:14px}

/* Under the size chart: the way back to the shirt this size is measured for.
   Its own strip at the foot of the guide, so it reads as a way out rather
   than as one more thing in the chart. */
.size-jersey{
  display:flex;align-items:center;justify-content:center;gap:6px;
  width:calc(100% - 26px);margin:0 13px 13px;font-weight:700;
}

@media (prefers-color-scheme:dark){
  .j-floor{background:radial-gradient(closest-side,rgba(0,0,0,.6),rgba(0,0,0,0) 76%)}
}

/* The turn is the whole point, so it is never removed outright — only taken
   down to something that does not swing across the screen. */
@media (prefers-reduced-motion:reduce){
  .j-stage,.j-spin,.j-floor{transition-duration:.001s}
  .jersey{transition:none}
}

/* ============================================================
   Shirt size guide (inside the shirt-size question)
   ============================================================ */

/* Recessed rather than raised: it sits inside a question on a white card, and
   another card on top of that card would read as a second thing to answer. */
.size-guide{
  margin:14px 0 2px;
  border:1px solid var(--line);border-radius:13px;background:var(--bg);
  overflow:hidden;
}

/* ---------- the header: what was chosen, and which cut is on screen ------- */

.sg-top{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;
  padding:12px 13px;border-bottom:1px solid var(--line);background:var(--card);
}
.sg-top-text{min-width:0}
.sg-eyebrow{
  font-stretch:var(--narrow);
  margin:0;font-size:10.5px;font-weight:800;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);
}
/* The answer, kept legible from the top of the question — the highlighted row
   says the same thing, but only while the tab it lives on is the one showing. */
.sg-chosen{margin:2px 0 0;display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.sg-chosen-size{font-size:16px;font-weight:800;color:var(--accent);letter-spacing:-.01em}
.sg-chosen-fit{
  font-stretch:var(--narrow);
  font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--muted);
}
.sg-chosen-none{font-size:14px;color:var(--muted)}

/* The cut tabs. Same segmented pill as the jersey's front/back switch, because
   it is the same gesture — two views of one thing, not two questions. */
.sg-fits{
  display:inline-flex;gap:3px;padding:3px;
  border:1px solid var(--line);border-radius:99px;background:var(--bg);
}
.sg-fit{
  appearance:none;border:0;background:transparent;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;gap:1px;
  padding:5px 15px;border-radius:99px;color:var(--ink-2);
  transition:background .18s,color .18s;
}
.sg-fit-name{font:800 13px var(--font);letter-spacing:.01em}
.sg-fit-sub{
  font-stretch:var(--narrow);font-size:9.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.72}
.sg-fit:hover{color:var(--accent)}
.sg-fit.is-on{background:var(--accent);color:var(--accent-ink)}
.sg-fit.is-on .sg-fit-sub{opacity:.8}
.sg-fit:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-ring)}

/* ---------- the panel ---------- */

.sg-panel{padding:13px 13px 14px}
.sg-panel:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--accent-ring)}
.sg-fit-note{
  margin:0 0 13px;font-size:12.5px;line-height:1.5;color:var(--ink-2);text-align:center;
}

/* Past the breakpoint the drawing and the chart stop queueing: the shirt is a
   fixed 148px either way, so the space a wide screen has spare is exactly the
   space the chart wants. */
@media (min-width:620px){
  /* Capped and centred as a pair rather than spread across whatever width is
     going: a chart floating half a card away from the drawing it explains
     stops looking like one figure. */
  .sg-panel{
    display:grid;grid-template-columns:auto 300px;
    justify-content:center;align-items:start;gap:6px 26px;
  }
  .sg-fit-note{grid-column:1/-1;margin-bottom:6px}
  /* The drawing is a fixed height and the chart is fourteen rows of it, so
     the column would otherwise end in a hole the size of the shirt. Centred,
     the two read as a figure beside a table. */
  .sg-diagram{margin-bottom:0;align-self:center}
  /* The chart's own width override lives with the chart, further down: put
     here it would be overruled by the base rule that comes after it. */
}

/* ---------- the diagram ---------- */

/* The brackets sit in gutters around the shirt rather than on top of it, so
   they never cover the artwork and never have to be aligned to it: the art
   box is a known size, and they are drawn against the box. */
.sg-diagram{
  display:grid;
  grid-template-columns:148px auto;
  grid-template-rows:auto 190px;
  gap:7px 9px;
  justify-content:center;align-items:center;
  margin:0 0 15px;
}
.sg-art{
  grid-column:1;grid-row:2;
  position:relative;width:148px;height:190px;
  display:grid;place-items:center;
}
.sg-art img{max-width:100%;max-height:100%;object-fit:contain;display:block}
/* No distance picked yet: the same outline the jersey card falls back to. */
.sg-ghost{display:none;width:auto;height:78%;color:var(--line-2);opacity:.75}
.sg-art.is-ghost .sg-ghost{display:block}

.sg-width{grid-column:1;grid-row:1;display:flex;flex-direction:column;gap:4px}
.sg-length{
  grid-column:2;grid-row:2;
  display:flex;align-items:center;gap:7px;height:100%;
}
.sg-dim{
  font-stretch:var(--narrow);
  font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap;text-align:center;
}
.sg-dim b{color:var(--ink);font-size:13px;letter-spacing:0}
/* The doubling, shown rather than done in advance. It is the step that gets
   skipped, and a chest measurement is the number people actually know. */
.sg-round{
  display:block;font-style:normal;font-size:10.5px;font-weight:700;
  letter-spacing:.02em;color:var(--accent);text-transform:none;
}
.sg-round:empty{display:none}
/* Nothing is claimed about a size nobody has chosen: the figures show a dash
   and the brackets step back until there is a measurement to point at. */
.size-guide:not(.is-sized) .sg-bar{opacity:.45}

/* The brackets themselves: a rule with a tick at each end. Inset on the
   horizontal one because the chest is measured across the body, not sleeve
   to sleeve. */
.sg-bar{position:relative;display:block;background:var(--line-2)}
.sg-bar-x{height:2px;margin:0 22%}
.sg-bar-y{width:2px;height:100%;margin:2px 0}
.sg-bar::before,.sg-bar::after{content:"";position:absolute;background:var(--line-2)}
.sg-bar-x::before,.sg-bar-x::after{width:2px;height:9px;top:-3.5px}
.sg-bar-x::before{left:0}
.sg-bar-x::after{right:0}
.sg-bar-y::before,.sg-bar-y::after{height:2px;width:9px;left:-3.5px}
.sg-bar-y::before{top:0}
.sg-bar-y::after{bottom:0}

/* ---------- the chart ---------- */

/* Three columns rather than one long ladder of every size the supplier makes:
   the tabs have already halved it, so on a phone "find your size, read across"
   fits without scrolling sideways, and the chosen row is a whole line the eye
   can land on. */
.sg-table-wrap{max-width:360px;margin:0 auto;overflow-x:auto}
/* Beside the drawing, the chart fills its column instead of sitting in the
   middle of it: left to find its own width it comes out around 175px, and a
   narrow table adrift in a wide track reads as two things that failed to line
   up. Auto margins are what make a grid item shrink to fit rather than
   stretch, so the margin has to go too — and this has to come after the rule
   above to beat it, which is why it is here and not up in the layout block. */
@media (min-width:620px){
  .sg-table-wrap{max-width:none;margin:2px 0 0}
}
/* Separated rather than collapsed, with the spacing taken back out: a
   collapsed table discards border-radius on its cells, and the rounded ends
   are what make the highlighted row read as one pill rather than a band
   running off both edges of the chart. */
.sg-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13.5px}
/* Sentence case rather than the small-caps used elsewhere for labels: this
   one is a sentence, and setting it in caps wrapped it onto two lines on a
   phone to say the same thing. */
.sg-table caption{
  caption-side:top;padding:0 0 9px;
  font-size:12px;line-height:1.45;color:var(--muted);text-align:center;
}
.sg-table th,.sg-table td{
  padding:0 10px;height:34px;text-align:center;border-bottom:1px solid var(--line);
}
.sg-table thead th{
  font-stretch:var(--narrow);
  height:auto;padding-bottom:6px;
  font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);border-bottom-color:var(--line-2);
}
.sg-table tbody td{color:var(--ink-2);font-variant-numeric:tabular-nums}
.sg-table tbody tr:last-child th,.sg-table tbody tr:last-child td{border-bottom:0}
/* A measurement the supplier's chart does not give. Set back, so an absent
   figure reads as absent rather than as a number that failed to arrive. */
.sg-none{color:var(--line-2)}

/* Reading the chart and answering the question are one movement: the row is
   the control. The button carries the semantics — a screen reader hears
   "M, button" in the row it belongs to — and stretches over the whole row so
   a thumb has the full width to land on. */
.sg-table tbody tr{position:relative}
.sg-table tbody tr>*{transition:background .13s,color .13s}
.sg-pick{
  appearance:none;border:0;background:transparent;cursor:pointer;
  padding:0;width:100%;height:34px;
  font:800 13.5px var(--font);color:var(--ink);
}
.sg-pick::after{content:"";position:absolute;inset:0;border-radius:7px}
.sg-pick:focus-visible{outline:none}
.sg-pick:focus-visible::after{box-shadow:0 0 0 2px var(--accent-ring)}

/* The tint goes on the cells, not the row: the first and last cell carry the
   rounding, so the highlight reads as one pill across the row rather than a
   band running off both edges of the chart. */
.sg-table tbody tr:hover>*,.sg-table tbody tr.is-on>*{background:var(--accent-soft)}
.sg-table tbody tr:hover>:first-child,.sg-table tbody tr.is-on>:first-child{
  border-radius:7px 0 0 7px;
}
.sg-table tbody tr:hover>:last-child,.sg-table tbody tr.is-on>:last-child{
  border-radius:0 7px 7px 0;
}
.sg-table tbody tr:hover .sg-pick{color:var(--accent)}
.sg-table tbody tr.is-on .sg-pick,.sg-table tbody tr.is-on td{color:var(--accent);font-weight:800}

/* ---------- how to measure ---------- */

/* The supplier's own instructions, folded away. They answer a question most
   people do not have; the ones who do are standing over a shirt on a table
   and will open it. */
.sg-how{border-top:1px solid var(--line);background:var(--card)}
.sg-how summary{
  display:flex;align-items:center;gap:8px;
  padding:11px 13px;cursor:pointer;list-style:none;
  font-size:12.5px;font-weight:700;color:var(--ink-2);
}
.sg-how summary::-webkit-details-marker{display:none}
.sg-how summary::after{
  content:"";margin-left:auto;width:7px;height:7px;
  border:2px solid currentColor;border-width:0 2px 2px 0;
  transform:rotate(45deg) translate(-2px,-2px);opacity:.6;transition:transform .18s;
}
.sg-how[open] summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
.sg-how summary:hover{color:var(--accent)}
.sg-how summary:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--accent-ring)}
.sg-how summary svg{flex:none;opacity:.7}
.sg-how-list{margin:0;padding:0 13px 2px}
.sg-how-row{margin:0 0 10px}
.sg-how-row dt{
  font-stretch:var(--narrow);
  font-size:10.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--accent);margin:0 0 2px;
}
.sg-how-row dd{margin:0;font-size:12.5px;line-height:1.55;color:var(--ink-2)}
.sg-how-note{
  margin:0;padding:0 13px 13px;
  font-size:11.5px;line-height:1.5;color:var(--muted);
}

.size-guide-note{
  margin:0;padding:11px 13px;
  border-top:1px solid var(--line);
  font-size:12.5px;color:var(--muted);line-height:1.55;text-align:center;
}

/* This one question already costs a phone most of a screen, and it is the one
   nobody should skim — so the shirt comes down a little rather than the chart,
   which is the part being read. */
@media (max-width:430px){
  .sg-diagram{grid-template-columns:126px auto;grid-template-rows:auto 162px}
  .sg-art{width:126px;height:162px}
  /* Two cuts side by side, each filling half: at this width the pill would
     otherwise wrap under its own heading and read as a stray control. */
  .sg-fits{display:flex;width:100%}
  .sg-fit{flex:1}
}

/* ============================================================
   Race categories (intro page)
   ============================================================ */
.race-lead{margin:14px 0 13px;color:var(--ink-2);font-size:14.5px;line-height:1.6}

/* The poster carries the distances and the fees, so it is never cropped and
   never scaled past its own size — a fee that cannot be read is no fee at all.
   It sits on a card-coloured mat so artwork with a white background does not
   glow against the dark theme's page. */
.race-shot{
  position:relative;display:block;margin:0;
  border:1px solid var(--line);border-radius:12px;overflow:hidden;
  background:var(--card);opacity:1;transform:none;animation:none;
}
.race-shot img{
  display:block;width:100%;height:auto;max-height:min(70vh,560px);
  object-fit:contain;padding:8px;background:var(--card);transition:none;
}
.race-shot:hover img{transform:none}
.race-shot figcaption{
  font-stretch:var(--narrow);
  text-align:center;font-size:11.5px;font-weight:700;color:var(--ink-2);
  letter-spacing:.03em;text-transform:uppercase;
  white-space:normal;overflow:visible;padding:9px 8px;line-height:1.3;
  border-top:1px solid var(--line);
}
/* No artwork yet: the slot keeps its shape and says so, rather than
   collapsing and leaving the card looking broken. */
.race-shot.missing::before{
  aspect-ratio:4/3;content:"Race category poster coming soon";
  font-size:12.5px;
}

/* The distances on their own — legible before the poster loads, and the
   answer to "which ones are there?" without opening the artwork. */
.race-chips{
  display:flex;flex-wrap:wrap;gap:8px;
  list-style:none;margin:14px 0 0;padding:0;
}
/* These are a legend for the poster above, not four buttons. Outlined rather
   than filled, so they read as labels — and so they stop looking tappable,
   which they never were. */
.race-chip{
  padding:6px 14px;border-radius:99px;
  border:1px solid var(--line-2);color:var(--ink-2);
  font-size:13.5px;font-weight:700;letter-spacing:.03em;
}
/* Left, with the prose it belongs to. Centring these while the
   paragraph above them ranges left was the box speaking, and the box is
   gone. */
.race-note{
  margin:11px 0 4px;font-size:12.5px;color:var(--muted);line-height:1.55;
}

/* ============================================================
   Mobile — most runners register on a phone
   ============================================================ */

/* Long unbroken strings are the usual cause of a page that scrolls sideways:
   the foundation's full name, the account number, an @southville.edu.ph
   address. Break them rather than hiding the overflow — html{overflow-x}
   would kill the sticky progress card. The uploaded file's name is not here:
   .upload-name already truncates with an ellipsis, which is the better answer
   for a name nobody needs to read in full. */
.bank dd,.contact a,.doc-name{overflow-wrap:anywhere}

/* Notched and rounded screens: keep content out from under the corners and
   the home indicator. env() is 0 everywhere else, so nothing else moves. */
.wrap{
  padding-left:max(16px,env(safe-area-inset-left));
  padding-right:max(16px,env(safe-area-inset-right));
  padding-bottom:calc(40px + env(safe-area-inset-bottom));
}
.hero{
  padding-left:max(20px,env(safe-area-inset-left));
  padding-right:max(20px,env(safe-area-inset-right));
}
@media (max-width:520px){
  .hero{
    padding-left:max(18px,env(safe-area-inset-left));
    padding-right:max(18px,env(safe-area-inset-right));
  }
}
.foot{padding-bottom:calc(34px + env(safe-area-inset-bottom))}

/* A phone's viewport height changes as the address bar hides. dvh tracks it;
   vh above stays the fallback for browsers without it. */
@supports (height:100dvh){
  .modal{max-height:min(86dvh,900px)}
  .race-shot img{max-height:min(70dvh,560px)}
}

/* ---------- touch ---------- */

/* A finger is not a cursor: hover effects latch on after a tap and have to
   be sent back, and every target has to be big enough to hit. */
@media (pointer:coarse){
  /* Native controls stay native on touch devices. In particular, iOS Safari's
     own select picker is more reliable than a CSS appearance reset. */
  input[type=text],input[type=email],input[type=tel],textarea,select{
    min-height:48px;
    font-size:16px;
    touch-action:manipulation;
  }
  select{
    -webkit-appearance:auto;
    appearance:auto;
    background-image:none;
    padding-right:13px;
  }
  /* The file picker gets a direct, full-size native hit target through the
     label wrapper; no tiny 1px target is left for an iPhone to find. */
  .drop .file-input{
    position:absolute;inset:0;width:100%;height:100%;
    margin:0;opacity:0;cursor:pointer;overflow:hidden;
  }
  .modal-body{-webkit-overflow-scrolling:touch}
}

@media (hover:none){
  .shot:hover img{transform:none}
  .cause-btn:hover{background:var(--card);border-color:var(--accent-ring);transform:none}
  .cause-btn:hover .cause-btn-chev{transform:none}
  .btn:hover:not(:disabled){background:var(--accent)}
}

@media (pointer:coarse){
  /* Do not animate a native dialog under a finger. iOS has had multiple
     focus/caret issues around top-layer dialogs and transforms; the form is
     more important than the entrance motion here. */
  .modal[open]{animation:none}

  /* The grey flash Android paints over a tapped control fights the styling
     these already have for the same state. */
  a,button,label,summary,.chip span{-webkit-tap-highlight-color:transparent}

  /* ~44px minimum on everything tappable. */
  .chip span{padding:12px 18px;font-size:15px}
  .btn-ghost{padding:12px 16px;font-size:14px}
  .cause-btn{padding:13px 18px}
  .modal-close{width:44px;height:44px}
  .back-link{padding:9px 2px}
  .doc-link{padding:15px 16px}

  /* Collapsed to an icon at this width, so it needs its size back. */
  .shot-zoom{
    min-width:40px;min-height:40px;
    justify-content:center;padding:0;
  }

  /* The distances and fees are printed on the poster, so opening it full
     size is the point of the tile — make the whole thing worth tapping. */
  .race-note{font-size:13px}
}

/* ---------- Scroll FAB & Credit ---------- */
.credit {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-3);
  margin-top: 12px;
}
.credit strong { color: var(--ink-2); }

.scroll-fab {
  position: fixed;
  bottom: 24px;
  right: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.scroll-fab.visible {
  opacity: 1;
  pointer-events: auto;
}
.scroll-fab button {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: var(--surface);
  color: var(--accent);
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s, background 0.2s;
}
.scroll-fab button:hover {
  transform: scale(1.05);
  background: var(--gray-1);
}
.scroll-fab button:active {
  transform: scale(0.95);
}
@media (max-width: 600px) {
  .scroll-fab { bottom: 16px; right: 16px; }
}

/* Pagination */
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 24px;
  padding-bottom: 24px;
}
.pagination button {
  padding: 6px 12px;
  border-radius: 6px;
  border: 1px solid var(--ink-4);
  background: var(--surface);
  color: var(--ink-1);
  font: 500 14px var(--font);
  cursor: pointer;
}
.pagination button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.pagination button:not(:disabled):hover {
  background: var(--gray-1);
}
.kpi-card:hover {
  background: var(--gray-1);
}


/* iOS Safari touch failsafe */
input[type=text], input[type=email], input[type=tel], textarea, select { -webkit-user-select: auto !important; user-select: auto !important; pointer-events: auto !important; touch-action: manipulation; }

#sections { padding-top: 8px; }
