/* =====================================================================
   The refreshed shopfront treatment.

   Every rule here is scoped to .ui-refresh, which all four layouts now set
   on <body> — the board included. It used to opt out, on the grounds that
   its palette carried meaning (live, win, court, ready) that a prettier
   colour would cost. That reasoning still holds for the *meanings*, which
   is why they are tokens; what it did not justify was the board having its
   own shadows, radii, spacing and button shapes. Those were not signals,
   just drift, and they made the screen players stare at all night look
   like a different product from the one that sold it to them.

   Loaded last, so it wins ties against app.css without needing !important
   or inflated selectors.

   Borrowed from the reference: the rhythm (generous section spacing, a
   centred section head), the type weight (800 with tight tracking), cards
   that float on shadow rather than sitting inside a border, and an accent
   that is unmistakably the thing you press. Not borrowed: its white-on-
   orange buttons, which measure 2.85:1 and are not readable.
   ===================================================================== */

/* ---------- shell ------------------------------------------------------ */
/* Width lives in --wrap now, so there is one number rather than a base
   value and a treatment that quietly disagrees with it by 40px. */

/* ---------- type ------------------------------------------------------- */
/* No heading rule here on purpose. app.css already sets 800 weight and
   -.02em tracking on h1-h4 — tighter than the reference — and .hero h1 tunes
   it further to -.035em. A blanket rule in this file would have the same
   specificity and load later, so it would quietly loosen a headline that was
   already deliberately set. The type was not the thing that needed fixing.

   The eyebrow was a faint grey monospace label — legible, but it asked to be
   ignored. In the reference it is the accent doing the pointing, so it is
   the first thing that says which colour means "act". */
/* A kicker above a heading is a label, not an accent.
   It was --action-ink, the lime-as-text. That measures 7.55:1 on white so
   it was never a contrast failure on a light page — but it is a
   desaturated yellow-green, which is the hue red-green colour blindness
   collapses toward brown, and at 11.5px uppercase on .14em tracking there
   is very little of it to judge. It also measures 2.04:1 on the brand
   navy, which is why two other rules already override it by hand wherever
   an eyebrow lands on a dark panel.
   A neutral slate is legible for everyone, carries no hue to misread, and
   is what the unprefixed .eyebrow was reaching for with --text-faint. */
.ui-refresh .eyebrow {
  font-family: var(--body);
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---------- the action colour ------------------------------------------ */
/* Orange fill, dark label. The edge is not decoration: a solid fill alone
   sits at 2.85:1 against a white card, which is not enough to delineate the
   control, and the edge takes that to 3.73:1. */
/* The exclusions are load-bearing. .btn-danger and .btn-dark carry their own
   meaning and are only one class deep, so an unqualified ".ui-refresh .btn"
   outranks them and paints "Delete session" as a cheerful primary action. */
.ui-refresh .btn:not(.btn-ghost):not(.btn-danger):not(.btn-dark) {
  background: var(--action);
  color: var(--on-action);
  border: 1.5px solid var(--action-dark);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-action);
  transition: background-color .15s ease, border-color .15s ease,
              box-shadow .15s ease, transform .08s ease;
}
.ui-refresh .btn:not(.btn-ghost):not(.btn-danger):not(.btn-dark):disabled {
  box-shadow: none;
}
.ui-refresh .btn:not(.btn-ghost):not(.btn-danger):not(.btn-dark):hover {
  background: var(--action-dark);
  border-color: var(--action-dark);
}
.ui-refresh .btn:active { transform: translateY(1px); }

/* The hero's Join button is a pill inside a pill.
   home.css asks for it, but the rule above is five classes deep and sets
   --r-md, so a two-class ".hero-join .btn" never reached it — and
   refresh.css loads last in any case. The override lives here, beside the
   rule it is answering, matching its shape so the two stay in step. */
.ui-refresh .hero-join .btn:not(.btn-ghost):not(.btn-danger):not(.btn-dark) {
  border-radius: var(--r-full);
}

/* Ghost and danger keep their own meaning; only their metrics are shared. */
.ui-refresh .btn-ghost {
  background: transparent;
  color: var(--text);
  border: 1.5px solid var(--border-strong);
}
.ui-refresh .btn-ghost:hover {
  background: var(--action-soft);
  border-color: var(--action-dark);
  color: var(--action-ink);
}

/* The reference runs its large button taller than this app did. .btn-sm and
   .btn-lg already exist, so this adjusts the one that changes rather than
   inventing a parallel set of names. */
.ui-refresh .btn-lg { min-height: 54px; padding: 0 28px; font-size: 16px; }

/* Focus belongs to the action colour too, and must clear the fill it sits on. */
.ui-refresh :focus-visible { outline: 3px solid var(--action-dark); outline-offset: 2px; }

/* ---------- surfaces --------------------------------------------------- */
/* A border and a shadow are two ways of saying the same thing. The reference
   picks one: the card floats, and the edge is implied. */
.ui-refresh .card {
  border: none;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}

/* The home page builds its "how it works" cards and features out of bare
   divs rather than .card, so they need naming explicitly or the page ends
   up half bordered and half floating — which reads as a mistake rather
   than a style.

   .step here is the homepage card, NOT the session form's fieldset: that
   one is .form-step precisely because this shadow was landing on it. */
.ui-refresh .steps .step,
.ui-refresh .feature {
  border: none;
  box-shadow: var(--shadow);
}

/* A card you can click should say so before you click it. */
.ui-refresh a.card,
.ui-refresh .tile {
  transition: transform .16s ease, box-shadow .16s ease;
}
.ui-refresh a.card:hover,
.ui-refresh .tile:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lift);
}

/* Nothing should leap about for someone who has asked it not to. */
@media (prefers-reduced-motion: reduce) {
  .ui-refresh a.card,
  .ui-refresh .tile,
  .ui-refresh .btn { transition: none; }
  .ui-refresh a.card:hover,
  .ui-refresh .tile:hover { transform: none; }
}

/* ---------- section rhythm --------------------------------------------- */
/* The reference gives a section head room to breathe and centres it. That
   single change does most of the work of making a page feel composed. */
.ui-refresh .section { padding: 78px 0; }
.ui-refresh .section-head {
  max-width: 660px;
  margin: 0 auto 46px;
  text-align: center;
}
.ui-refresh .section-head h2 { font-size: clamp(26px, 4vw, 38px); margin-bottom: 10px; }
.ui-refresh .section-head p { color: var(--text-muted); font-size: 17px; margin: 0; }

/* ---------- small surfaces --------------------------------------------- */
.ui-refresh .chip-link,
.ui-refresh .panel-badge { border-radius: var(--r-full); }

.ui-refresh .chip-link.is-on {
  background: var(--action-soft);
  border-color: var(--action-dark);
  color: var(--action-ink);
}

/* The active page in the panel nav: the accent marks where you are. */
.ui-refresh .panel-link.is-active {
  color: var(--action-ink);
  background: var(--action-soft);
}
.ui-refresh .panel-link.is-active svg { color: var(--action-ink); }

/* ---------- fields ----------------------------------------------------- */
.ui-refresh .input:focus {
  border-color: var(--action-dark);
  outline: none;
  box-shadow: 0 0 0 3px var(--action-soft);
}

/* ---------- links ------------------------------------------------------ */
/* Body links take the readable orange, never the fill orange — #FF6B18 as
   text on the page ground is 2.55:1. */
.ui-refresh .panel-main a:not(.btn):not(.card):not(.chip-link):not(.panel-link) {
  color: var(--action-ink);
}


/* ---------- dashboard surfaces ----------------------------------------- */
/* .tile and .stat predate .card and carry their own border, so removing it
   from .card alone would leave the dashboard bordered and the rest floating. */
.ui-refresh .tile,
.ui-refresh .stat {
  border: none;
  box-shadow: var(--shadow);
}

/* Four figures across where there is room. Two columns made the row as tall
   as the session list beneath it, which is backwards for a summary. */
.ui-refresh .stat-row {
  grid-template-columns: repeat(auto-fit, minmax(136px, 1fr));
}
/* A summary should not be the tallest thing above the list it summarises. */
.ui-refresh .stat { padding: 14px 18px; }
.ui-refresh .stat .n { font-size: 28px; }
.ui-refresh .stat .k {
  margin-top: 5px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .09em;
  text-transform: uppercase;
  /* --text-faint measures 3.81:1 on a white card, and this is 10.5px.
     Small text needs 4.5:1; --text-muted gives 7.25:1 and still reads as
     the quiet half of the pair. */
  color: var(--text-muted);
}

/* The session tiles borrow the homepage card language so a session looks
   like the same object in both places. */
.ui-refresh .tile-meta {
  gap: 22px;
  margin-top: 15px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.ui-refresh .tile-meta .code {
  font-family: var(--mono);
  letter-spacing: .16em;
  color: var(--action-ink);
  font-weight: 500;
}
/* auto-fill, not a media query: these sit in a 224px-narrower column than
   the viewport suggests, and a breakpoint cannot know that. */
.ui-refresh .tile-grid {
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
}

/* The page heading block, given the same room the homepage sections get. */
.ui-refresh .panel-title { margin-bottom: 26px; }

/* ---------- site header ------------------------------------------------- */
/* The header was a pale translucent bar. With a dark hero directly beneath
   it that reads as a seam across the top of the page, so the two become one
   block instead — which is also what the reference does. The board has its
   own header and never loads this file. */
.ui-refresh .site-head {
  background: var(--brand);
  border-bottom: none;
  backdrop-filter: none;
}
/* Scoped to the site header. The dashboard has its own white header and
   reuses .brand, so an unscoped rule here painted that wordmark near-white
   on white — 1.16:1, which is not a colour choice, it is a disappearance. */
.ui-refresh .site-head .brand { color: var(--on-brand); }

/* Everything in the bar has to borrow the bar's ink rather than the page's. */
.ui-refresh .site-head .themebtn {
  color: var(--on-brand);
  background: rgba(255,255,255,.10);
  border-color: rgba(255,255,255,.20);
}
.ui-refresh .site-head .themebtn:hover { background: rgba(255,255,255,.18); }

.ui-refresh .site-head .btn-ghost {
  color: var(--on-brand);
  border-color: rgba(255,255,255,.32);
}
.ui-refresh .site-head .btn-ghost:hover {
  background: rgba(255,255,255,.12);
  border-color: var(--on-brand);
  color: var(--on-brand);
}


/* ---------- the stepped form -------------------------------------------- */
/* A fieldset carries browser defaults — a border, odd margins, a legend that
   sits in the border — none of which suit a form that already lives in a
   card. Stripped rather than styled: the grouping is semantic, not visual. */
.ui-refresh .form-step {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;              /* a fieldset will not otherwise shrink in flex */
}
.ui-refresh .form-step > legend {
  padding: 0;
  margin-bottom: 16px;
  font-family: var(--display);
  font-weight: 800;
  font-size: 20px;
  letter-spacing: -.02em;
}

/* The rail. Without script every fieldset is on screen at once and there is
   no "current" step, so this is built by stepform.js and never rendered
   server-side — a progress bar that cannot progress is a lie. */
.ui-refresh .formrail {
  display: flex;
  gap: 6px;
  list-style: none;
  margin: 0 0 22px;
  padding: 0 0 18px;
  border-bottom: 1px solid var(--border);
}
.ui-refresh .formrail li { flex: 1 1 0; min-width: 0; }

.ui-refresh .formrail-dot {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 4px 0;
  background: none;
  border: 0;
  border-top: 3px solid var(--border);
  color: var(--text-faint);
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.ui-refresh .formrail-no {
  flex: none;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: var(--r-full);
  background: var(--bg-alt);
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 500;
}
/* The label is the first thing to go when there is no room: the number and
   the coloured rule still say where you are. */
.ui-refresh .formrail-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 560px) { .ui-refresh .formrail-label { display: none; } }

.ui-refresh .formrail-dot.is-done { color: var(--text-muted); border-top-color: var(--action-dark); }
.ui-refresh .formrail-dot.is-done .formrail-no { background: var(--action-soft); color: var(--action-ink); }

.ui-refresh .formrail-dot.is-at { color: var(--text); border-top-color: var(--action); }
.ui-refresh .formrail-dot.is-at .formrail-no { background: var(--action); color: var(--on-action); }

/* ---------- navigation --------------------------------------------------- */
.ui-refresh .step-nav {
  display: flex;
  gap: 10px;
  margin-top: 22px;
}
/* The button that moves you on -- Continue, or the one that finishes --
   takes the room. */
.ui-refresh .step-nav .btn { flex: 1; }

/* Back is the way out, not the way on. Sized to its label so it cannot
   read as the thing to press, and it keeps that role on the last step
   where it sits beside the button that creates the session. */
.ui-refresh .step-nav .btn-ghost { flex: 0 1 auto; min-width: 108px; }

/* btn-block is width:100%, which is right when this button is alone at
   the foot of a form with no JavaScript, and wrong once it has been moved
   into the row. */
.ui-refresh .step-nav .btn-block { width: auto; }

/* The numbered steps are the way back and forward; they need to look
   clickable without looking like the thing to press next. */
.ui-refresh .formrail-dot:hover .formrail-label { color: var(--text); }

/* ---------- the price quote --------------------------------------------- */
/* Tinted rather than bordered: this is the form answering back, not another
   thing to fill in, and it should not read as a fieldset. */
.ui-refresh .quote {
  padding: 16px 18px;
  border-radius: var(--r-md);
  background: var(--action-soft);
}
.ui-refresh .quote-row {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 5px 0;
  font-size: 14px;
  color: var(--text-muted);
}
.ui-refresh .quote-row strong {
  font-family: var(--mono);
  font-weight: 500;
  color: var(--text);
}

/* A suggestion, not a decision. Filled orange here put a second primary
   button on the step, competing with Continue for the same glance —
   so it is outlined, and the filled style is left to mean one thing. */
.ui-refresh .quote-take {
  width: 100%;
  min-height: 40px;
  margin-top: 12px;
  border: 1.5px solid var(--action-dark);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--action-ink);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
.ui-refresh .quote-take:hover { background: var(--paper, #fff); }

.ui-refresh .quote-note {
  margin: 10px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted);
}

/* ---------- a choice between a few things ------------------------------- */
/* Bigger than a radio in a row: each option carries a consequence worth
   reading, so the whole card is the target rather than a 16px circle. */
.ui-refresh .choices { display: grid; gap: 10px; }

.ui-refresh .choice {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border: 1.5px solid var(--border);
  border-radius: var(--r-md);
  cursor: pointer;
}
.ui-refresh .choice:hover { border-color: var(--border-strong); }
.ui-refresh .choice input { margin-top: 3px; flex: none; }
.ui-refresh .choice strong { display: block; margin-bottom: 3px; font-size: 15px; }
.ui-refresh .choice .hint { display: block; }

/* :has, so the whole card reacts to its own radio rather than needing a
   script to keep a class in step with the input. */
.ui-refresh .choice:has(input:checked) {
  border-color: var(--action-dark);
  background: var(--action-soft);
}
.ui-refresh .choice:has(input:focus-visible) {
  outline: 3px solid var(--action-dark);
  outline-offset: 2px;
}

/* An option that exists but cannot be taken yet. Shown rather than hidden:
   knowing it is coming is worth more than a shorter list. */
.ui-refresh .choice.is-off { cursor: default; opacity: .62; }
.ui-refresh .choice.is-off:hover { border-color: var(--border); }
.ui-refresh .choice-soon {
  display: inline-block;
  margin-top: 7px;
  padding: 2px 9px;
  border-radius: var(--r-full);
  background: var(--bg-alt);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* ---------- what a session costs, where players see it ------------------ */
.ui-refresh .price-tag {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--r-full);
  background: var(--action-soft);
  color: var(--action-ink);
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: .04em;
}

/* ---------- the price helper, folded away -------------------------------- */
/* Useful when an organiser does not know what to charge, clutter when they
   do — and most already do. So it is closed by default and reads as an offer
   rather than as three more fields to fill in. */
.ui-refresh .calc {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 14px 16px;
  background: var(--bg-alt);
}
.ui-refresh .calc > summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 700;
  color: var(--action-ink);
  list-style: none;
}
/* The disclosure triangle differs between browsers; a chevron we draw does
   not, and it can point where the state actually is. */
.ui-refresh .calc > summary::-webkit-details-marker { display: none; }
.ui-refresh .calc > summary::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 10px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg) translate(-2px, -2px);
  transition: transform .15s ease;
}
.ui-refresh .calc[open] > summary::before {
  transform: rotate(45deg) translate(0, -3px);
}
@media (prefers-reduced-motion: reduce) {
  .ui-refresh .calc > summary::before { transition: none; }
}
  /* A flash between the header and the hero.
     Both are var(--brand) and are meant to read as one block; a message in
     its own strip put a band of page background straight through it. The
     dock carries the same ground, so the block stays whole and the flash
     sits inside it as a card rather than as a seam. */
  .ui-refresh .flashdock {
    background: var(--brand);
    padding-bottom: 16px;
  }

/* The phone menu panel belongs to the dark bar, not to the page. Its links and
   ghost buttons are already coloured for a dark header above; on the light
   page background they were white on near-white, so the menu opened blank. */
@media (max-width: 720px) {
  /* .has-navtoggle is on <html>, .ui-refresh on <body>, so the html
     selector comes first -- the other way round matches nothing. */
  html.has-navtoggle .ui-refresh .site-nav {
    background: var(--brand);
    border-bottom: 1px solid rgba(255,255,255,.14);
  }
  .ui-refresh .site-nav .site-link {
    border-bottom: 1px solid rgba(255,255,255,.14);
  }
  .ui-refresh .navtoggle {
    color: var(--on-brand);
    background: rgba(255,255,255,.10);
    border-color: rgba(255,255,255,.22);
  }
  .ui-refresh .navtoggle:hover {
    background: rgba(255,255,255,.18);
    border-color: var(--on-brand);
    color: var(--on-brand);
  }
}
