/*
 * The booking flow: field validation states, numbered steps, and the bits of
 * the register/checkout path the static design had no equivalent for.
 *
 * Every value is a design token from assets/css/style.css. Nothing here
 * introduces a colour, a size or a radius the design system did not already
 * define — this is interaction state, not a repaint.
 *
 * ## What this file overrides in style.css
 *
 * Nine selectors are declared in both files. None of them is a duplicate —
 * every pair sets different properties — but a rule in two places is a
 * contradiction waiting to happen, and style.css is the design's own file and
 * is replaced wholesale when _static is refreshed, so the note has to live
 * here (task 08):
 *
 *   .brand  .nav__l  .hdr__u .dl      raised to 44px targets (QC-047)
 *   .acc__b  .acc__p a                the same, in the account
 *   .summary__l  .cartrow .amt        alignment for the controls task 06
 *   .cartrow__x                       put in the summary and the cart row
 *   .ffile b                          the file field's filename slot
 *
 * If one of those stops behaving as the design draws it, this file is the
 * second place to look.
 */

/* ---- field error state ---------------------------------------------------
   Three signals, never colour alone: a thicker maroon left border, an icon,
   and a sentence naming the actual problem. */

.fld2__err {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  margin-top: var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  line-height: var(--lh-snug);
  color: var(--mar);
  font-style: normal;
}
.fld2__err i { margin-top: .1em; flex: 0 0 auto; }
.fld2__err[hidden] { display: none; }

.fld2.is-err > span { color: var(--mar); }

.fld2.is-err input,
.fld2.is-err select,
.fld2.is-err textarea {
  border-color: var(--mar);
  border-left-width: var(--bw-accent);
  background: var(--mar-tint);
}

.fld2.is-err input:focus,
.fld2.is-err select:focus,
.fld2.is-err textarea:focus {
  box-shadow: 0 0 0 3px rgba(var(--rgb-mar), .18);
}

/* A whole fieldset can carry the state — the category group and the consent
   checkbox have no single input to mark. */
.fset.is-err { border-color: var(--mar); }
.fset.is-err > legend { color: var(--mar); }

/* ---- numbered steps inside a fieldset legend ----------------------------- */

.fset > legend {
  display: flex;
  gap: var(--sp-4);
  align-items: center;
  font-family: var(--fd);
  font-size: var(--fs-3xl);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-h3);
  color: var(--ink);
  margin-bottom: var(--sp-3);
  padding: 0;
}

.fset__n {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  background: var(--mar);
  color: var(--paper);
  font-family: var(--fd);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-none);
}

/* A sub-heading inside a step, above a group of options. */
.fset__h2 {
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--soft);
  margin: var(--sp-6) 0 var(--sp-4);
}

/* A reassurance line at the foot of a step. */
.fset__foot {
  display: flex;
  gap: var(--sp-4);
  align-items: flex-start;
  margin: var(--sp-6) 0 0;
  padding-top: var(--sp-5);
  border-top: var(--bw) solid var(--line);
  font-size: var(--fs-sm);
  color: var(--soft);
  line-height: var(--lh-base);
}
.fset__foot i { margin-top: .15em; flex: 0 0 auto; color: var(--soft); }

/* ---- conditional reveal --------------------------------------------------
   The LASA membership ID only exists when the LASA rate is chosen. Height
   animation rather than display:none so it does not jump. */

.reveal {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows var(--t), opacity var(--t);
}
/* `overflow: hidden` is what makes the 0fr -> 1fr collapse work, so it cannot
   simply be removed. But it also clips the focus ring of whatever is inside:
   the conditional email and LASA-ID fields on /register/ sit flush against
   the clip on both sides, so a keyboard user sees the ring cut off on the
   left and right (task 24, all three widths).

   The padding gives the ring its 2px plus 2px of offset inside the clip; the
   matching negative margin means nothing moves. */
.reveal > * {
	overflow: hidden;
	padding-inline: 4px;
	margin-inline: -4px;
}
.reveal.is-open { grid-template-rows: 1fr; opacity: 1; }

/* Without JS every option is visible, which is the safe direction to fail. */
html:not(.js) .reveal { grid-template-rows: 1fr; opacity: 1; }

/* ---- read-only delegate summary at the checkout -------------------------- */

.whois {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-6) var(--sp-7);
  background: var(--cream);
  border: var(--bw) solid var(--line);
  border-radius: var(--r);
  margin-bottom: var(--sp-6);
}
.whois dl { display: grid; gap: var(--sp-3); margin: 0; }
.whois dl > div { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); justify-content: space-between; }
.whois dt {
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--soft);
}
.whois dd { margin: 0; font-size: var(--fs-lg); color: var(--ink); text-align: right; }
.whois__edit { align-self: start; font-size: var(--fs-sm); font-weight: var(--fw-semi); }

@media (max-width: 30rem) {
  .whois dl > div { flex-direction: column; gap: var(--sp-1, .25rem); }
  .whois dd { text-align: left; }
}

/* ---- the test payment step ----------------------------------------------
   Deliberately unmistakable. This must never be taken for the real thing. */

.paytest {
  border: var(--bw-2) dashed var(--warn);
  border-radius: var(--r);
  background: var(--gold-tint);
  padding: var(--sp-7);
  margin-bottom: var(--gap);
}
.paytest__h {
  display: flex;
  gap: var(--sp-4);
  align-items: center;
  font-family: var(--fd);
  font-size: var(--fs-2xl);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-h3);
  color: var(--gold-ink);
  margin: 0 0 var(--sp-3);
}
.paytest__d { font-size: var(--fs-md); color: var(--gold-ink); line-height: var(--lh-base); margin: 0 0 var(--sp-6); }

.paytest__grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

.paytest__btn {
  display: flex;
  gap: var(--sp-5);
  align-items: center;
  width: 100%;
  padding: var(--sp-6) var(--sp-7);
  background: var(--paper);
  border: var(--bw-2) solid var(--line);
  border-radius: var(--r);
  font-family: inherit;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t), box-shadow var(--t), background-color var(--t);
}
.paytest__btn:hover { border-color: var(--mar); box-shadow: var(--sh-1); }
.paytest__btn:focus-visible { outline: 2px solid var(--mar); outline-offset: 2px; }
.paytest__btn i { font-size: var(--fs-3xl); color: var(--mar); flex: 0 0 auto; }
.paytest__btn > span { min-width: 0; }
.paytest__btn small { display: block; font-size: var(--fs-sm); font-weight: var(--fw-normal); color: var(--soft); margin-top: .15rem; }

/* The band that says so, wherever a payment can happen. */
.paytest__band { margin-bottom: var(--gap); }

.paytest__btn--fail { border-style: dashed; }
.paytest__btn--fail i { color: var(--warn); }
.paytest__btn--fail:hover { border-color: var(--warn); }

/* ---- My Account ---------------------------------------------------------- */

.acct__empty {
  padding: var(--sp-8);
  text-align: center;
  border: var(--bw-2) dashed var(--line-2);
  border-radius: var(--r);
  background: var(--cream);
  color: var(--mid);
}

.statline {
  display: inline-flex;
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-2) var(--sp-5);
  border-radius: var(--r-pill);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: .08em;
  text-transform: uppercase;
}
.statline--ok { background: var(--ok-tint); color: var(--ok); }
.statline--wait { background: var(--gold-tint); color: var(--gold-ink); }
.statline--no { background: var(--mar-tint); color: var(--mar); }

/* A visually hidden helper: the design had none, and "(required)" needs to
   reach a screen reader without appearing twice on screen. */
.u-sr {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* ---- carried billing values ---------------------------------------------
   Name, email and phone were answered on the register form. They are posted
   as hidden values so WooCommerce still has them; the row WooCommerce wraps
   them in has nothing to show. */

.form-row.lasacon-carried { display: none; }

/* ---- the GST invoice block ----------------------------------------------
   Hidden by a class on each row, never by nesting: WooCommerce re-parents
   every billing row on each country change, so a wrapper element around a
   subset of them does not survive first paint. */

/* !important, deliberately. WooCommerce's address-i18n.js calls jQuery
   .show() on the address rows every time the country changes, which writes an
   inline display:block that no class selector can outrank. This is the one
   case the keyword exists for: overriding a third party's inline style. */
.woocommerce-billing-fields:not(.is-gst) .form-row.lasacon-gst { display: none !important; }
.woocommerce-billing-fields.is-gst .form-row.lasacon-gst { display: block; }

/* No JavaScript, no disclosure — show everything rather than hide a field
   behind a control that will never work. */
html:not(.js) .woocommerce-billing-fields .form-row.lasacon-gst { display: block !important; }
html:not(.js) .gsttoggle { display: none; }

.gsttoggle > label {
  display: flex;
  gap: var(--sp-5);
  align-items: flex-start;
  padding: var(--sp-6) var(--sp-7);
  background: var(--cream);
  border: var(--bw) solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  transition: background-color var(--t), border-color var(--t);
}
.gsttoggle > label:hover { background: var(--sand); }
.gsttoggle input { flex: 0 0 auto; margin-top: .2em; width: auto; }
.gsttoggle b { display: block; font-size: var(--fs-lg); font-weight: var(--fw-semi); color: var(--ink); }
.gsttoggle small { display: block; font-size: var(--fs-sm); color: var(--soft); margin-top: .15rem; line-height: var(--lh-snug); }
.woocommerce-billing-fields.is-gst .gsttoggle > label { border-color: var(--mar); background: var(--mar-tint); }

/* ---- the abstract form's word count -------------------------------------
   The 250-word limit is the commonest reason a submission is refused, so the
   count is live and goes maroon the moment it is over. */

.fhint.is-over { color: var(--mar); font-weight: var(--fw-bold); }

/* The design's upload control hides the real file input, so without this
   nothing on screen changes when a file is chosen. */
.ffile b { overflow-wrap: anywhere; }

/* A checkbox row can carry the error state too. */
.fcheck.is-err > span { color: var(--mar); }

/* ---- a field you cannot change ------------------------------------------
   The badge name and the institution lock once the badge has been paid for.
   The hint underneath says so, but a field that looks editable and is not is
   a small lie, so it is drawn as the read-only thing it is. */

.fld2 input[readonly] {
  background: var(--sand);
  color: var(--mid);
  cursor: default;
}
.fld2 input[readonly]:focus {
  border-color: var(--line-2);
  box-shadow: none;
}

/* A price must not break between the rupee sign and the figure. At 390px the
   cart row's amount column is narrow enough that it did. */
.cartrow .amt { white-space: nowrap; }
/* WooCommerce wraps the ₹ in its own <span>, and the design's
   `.cartrow span { display: block }` (meant for the line's detail text) broke
   the amount into "₹" over "3,000.00". Inside an amount, a span is inline. */
.cartrow .amt span { display: inline; margin-top: 0; font-size: inherit; color: inherit; }

/* ---- discount codes (inc/coupons.php) ------------------------------------
   The code field sits in the summary, next to the total it changes; the
   discount is its own line, before GST, so nobody is surprised at the total. */

.coupon {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-4);
  padding: var(--sp-5) 0;
  border-bottom: var(--bw) solid var(--line);
}
.coupon__f { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.coupon__f input { background: var(--paper); text-transform: uppercase; }
.coupon .btn { flex: 0 0 auto; margin-top: 0; }

.summary__l--disc b { color: var(--ok); }
.summary__x {
  display: inline-block;
  margin-left: var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--mar);
  text-decoration: underline;
}

/* The same line on an order that has been placed. */
.cartrow--disc .amt { color: var(--ok); }

/* .summary__code dressed the checkout's pointer back to the review page's
   discount field. Task 06 put the field on the checkout itself, so the
   pointer and its markup are gone and this styled nothing (task 08). */


/* --------------------------------------------------------------------------
 * Heading order (QC-044). The footer's column titles and the form pages'
 * summary titles were h4 and h3 straight after an h1 or h2. They are h2 now;
 * these repeat style.css's .ft h4 and .summary h3 so nothing moves.
 * ------------------------------------------------------------------------ */
.ft h2{font-size:var(--fs-xs);font-weight:var(--fw-bold);letter-spacing:.13em;text-transform:uppercase;color:var(--gold-lt);margin-bottom:1rem}
.summary h2{font-size:var(--fs-3xl);font-weight:var(--fw-bold);letter-spacing:var(--ls-h3);margin-bottom:var(--sp-6)}

/* One submit on a phone (QC-019). Below 960px the register summary moves above
 * the form (style.css), where its button would submit a form not yet filled
 * in; step 3's own button is the one that follows the fields. */
@media (max-width:960px){#reg-summary .btn{display:none}}

/* An update's date is its own line, not crowded under the standfirst (QC-038). */
.ph2 .ph2__date{margin-top:var(--sp-5)}

/* The GST opt-in reads as a sentence, not a field label, and its box is the
 * target rather than the 16px native checkbox (QC-052). */
.gsttoggle > label{font-size:var(--fs-md);font-weight:var(--fw-normal);letter-spacing:normal;text-transform:none;color:var(--ink);min-height:44px}
.gsttoggle input{width:20px;height:20px;accent-color:var(--mar)}




/* --------------------------------------------------------------------------
 * Pointer targets in the header (QC-047, second pass).
 *
 * v2.5 raised .more, .crumb a, .orgs a and .burger to 44px. Three header
 * controls were not in that list and are still short: the primary nav's
 * links (41px) and its dropdown buttons (36px), and the two organiser logo
 * links in the top bar (34px — .orgs is the strip under the key dates, a
 * different element).
 *
 * They grow to 44px without moving anything: the header row is 76px and the
 * top bar has the slack, so the page is pixel-identical to _static either
 * way — verified with the diff, not assumed.
 * ------------------------------------------------------------------------ */
.nav__l{min-height:44px}
.orgbar a{display:inline-flex;align-items:center;min-height:44px}
.hdr__u .dl{min-height:44px}
.brand{min-height:44px}

/* --------------------------------------------------------------------------
 * Sponsorship booking (inc/sponsor-booking.php).
 *
 * "First come, first served" is in the brochure on nearly every page, so what
 * is left has to be on screen beside each tier, and a tier that has gone has
 * to look gone rather than simply refuse when pressed.
 * ------------------------------------------------------------------------ */
.optcard .tag,
.fcheck .tag{display:inline-block;margin-top:var(--sp-2);font-size:var(--fs-2xs);font-weight:var(--fw-bold);
  letter-spacing:.08em;text-transform:uppercase;color:var(--ok);font-style:normal}
.optcard .tag--gone,
.fcheck .tag--gone{color:var(--mar)}
.optcard.is-gone,
.fcheck.is-gone{opacity:.55;cursor:not-allowed}
.optcard.is-gone .price{text-decoration:line-through}

/* --------------------------------------------------------------------------
 * The last controls under 44px (QC-047, third pass).
 *
 * Found by the probe on pages the earlier sampling had not reached: the
 * drawer's own links and the account tabs at 41px, the checkout's inputs and
 * WooCommerce's coupon button a few pixels short, "Change these details" at
 * 22px, and the cart's remove control, which the design draws at 32px.
 *
 * The remove control keeps the size it was drawn at and gains the hit area
 * around it, so nothing moves.
 * ------------------------------------------------------------------------ */
.mnav__s > a,
.acc__p a,
.acc__b{min-height:44px}
.acc__p a{display:flex;align-items:center}
.whois__edit{display:inline-flex;align-items:center;min-height:44px}
.woocommerce-cart-form .button,
button[name="apply_coupon"],
button[name="update_cart"]{min-height:44px}
.cartrow__x{position:relative}
.cartrow__x::after{content:"";position:absolute;top:-6px;right:-9px;bottom:-6px;left:-9px;inset:-6px -9px;border-radius:inherit}
/* A phone number a sponsor taps, and the inbox beside it, are targets. The
   hit area is extended around them rather than the row being made taller,
   so the summary keeps the rhythm it was drawn with. */
.summary__l a{position:relative;display:inline-block}
.summary__l a::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
/* The checkout's pointer back to the discount code field is a control. */
a[data-lasacon-code-link]{display:inline-flex;align-items:center;min-height:44px}

/* --------------------------------------------------------------------------
 * Quantities on the booking form (task 05).
 *
 * The brochure's Availability column is "Single" for the cover positions and
 * "Any number" for the inside pages, so those take a quantity. The number
 * field sits beside the checkbox rather than inside its label: a field inside
 * a label toggles the checkbox every time it is clicked.
 * ------------------------------------------------------------------------ */
.fmulti{display:flex;gap:var(--sp-4);align-items:center}
.fmulti .fcheck{flex:1 1 auto;margin-bottom:0}
.fqty{flex:0 0 auto}
.fqty input{width:4.5rem;min-height:44px;padding:var(--sp-2) var(--sp-3);text-align:center;
  font:inherit;color:var(--ink);background:var(--paper);border:var(--bw) solid var(--line);border-radius:var(--r-sm)}
.fqty input:focus-visible{outline:2px solid var(--mar);outline-offset:2px}

/* The two-payment split, filled in by assets/js/sponsor-booking.js as the
   selection changes. Without JavaScript it stays hidden and the hint under
   the button says the same thing in prose.

   The [hidden] rule is not belt and braces: .alert sets display:flex, which
   beats the user agent's [hidden]{display:none}, so without this the notice
   is on screen from the first paint — warning about a split nobody has
   chosen yet. The same trap v2.5 hit with .mnav[hidden]. */
.lasacon-split[hidden]{display:none}
.lasacon-split [data-lasacon-split-line]{display:block;font-weight:var(--fw-semi);margin-bottom:var(--sp-2)}
.optlist + .fhint{margin-bottom:var(--sp-6)}

/* --------------------------------------------------------------------------
 * The summary carries the editing (task 06).
 *
 * The review step is gone, so every line in the sticky summary has a control
 * on it — Change for the registration itself, Remove for what was added to
 * it. Two things have to be true of those controls and both are measured by
 * check-review-collapse.js rather than looked at:
 *
 *   1. they are 44px targets, and
 *   2. at 390px, where the summary moves above the form, each one is the
 *      topmost element at its own centre.
 *
 * The 44px comes from the control's own box, not from the extended hit area
 * .summary__l a::after gives the phone and email links. Two of those areas on
 * consecutive rows would overlap — a 44px band on a 33px row reaches into its
 * neighbour — and the lower row's would cover the upper row's control. That
 * is the same class of fault as S24-3, one element quietly on top of another.
 * ------------------------------------------------------------------------ */
.summary__l a.summary__x::after{content:none}
.summary__x{display:inline-flex;align-items:center;min-height:44px}
.summary__l{align-items:center}

/* The early-bird warning, inside the summary and above the payment. */
.summary__warn{margin:var(--sp-6) 0 0;padding:var(--sp-5);font-size:var(--fs-sm)}
.summary__warn b{font-size:var(--fs-md)}
.summary__warn i{font-size:var(--fs-lg)}

/* --------------------------------------------------------------------------
 * Recognising a returning delegate, in place (task 07).
 *
 * The panel opens between the question and the fields, on the same page,
 * with everything typed still in the form behind it. It is hidden with the
 * [hidden] attribute, and .alert sets display:flex, so the rule below is what
 * actually keeps it shut — the same trap as .mnav[hidden] and the
 * sponsorship split notice.
 * ------------------------------------------------------------------------ */
.recog[hidden],
.recog__done[hidden]{display:none}
.recog{margin:0 0 var(--sp-6)}
.recog__row{display:flex;gap:var(--sp-4);align-items:flex-end;margin-top:var(--sp-5)}
.recog__row .fld2{flex:1 1 auto;min-width:0;margin-bottom:0}
.recog__row .btn{flex:0 0 auto}
.recog__f input{background:var(--paper);letter-spacing:.3em;font-weight:var(--fw-bold);text-align:center}
.recog__help{margin:var(--sp-4) 0 0;font-size:var(--fs-sm);color:var(--mid)}
.recog__done{margin:0 0 var(--sp-6)}

/* A button that reads as a link: "Send the code again" and "Use a different
   email address" are submits, because without JavaScript that is the only
   thing that can act. 44px, like every other control on the site. */
.lasacon-link{display:inline-flex;align-items:center;min-height:44px;padding:0;
  background:none;border:0;font:inherit;font-size:var(--fs-sm);color:var(--mar);
  text-decoration:underline;cursor:pointer}
.lasacon-link:focus-visible{outline:2px solid var(--mar);outline-offset:2px}

/* --------------------------------------------------------------------------
 * The sponsor's proof-of-transfer form (QC-104).
 *
 * The booking card is a .paycard, and style.css has
 *
 *     .paycard input{accent-color:var(--mar);width:18px;height:18px;flex:0 0 auto}
 *
 * which is written for the payment-method radio on the checkout and matches
 * every input inside a paycard — including the UTR text field, which rendered
 * 29px wide. A sponsor could not type a transaction reference into the field
 * the bank statement is matched against.
 *
 * The rule cannot be narrowed where it lives: style.css is the design's own
 * file and is replaced wholesale when _static is refreshed. So it is undone
 * here, for the fields that are fields.
 * ------------------------------------------------------------------------ */
.paycard .fld2 input[type="text"],
.paycard .fld2 input[type="email"],
.paycard .fld2 input[type="tel"],
.paycard .fld2 input[type="number"],
.paycard .fld2 select,
.paycard .fld2 textarea{width:100%;height:auto;min-height:44px;flex:1 1 auto}

/* The association's mark on its own page (task 12). */
.about__logo{max-width:240px;height:auto;margin-inline:auto;display:block}

/* Proof-of-status, revealed under the category list when the reduced rate is
   chosen (task 13). A `.fhint` on its own rather than under a field, so it
   needs the icon spacing an inline hint never has. */
.fhint--block{display:flex;gap:var(--sp-3);align-items:flex-start;margin-top:var(--sp-4)}
.fhint--block i{color:var(--gold);margin-top:.15em;flex:0 0 auto}

/* An add-on with no rate for the chosen category. Disabled rather than
   hidden: a card that vanishes as the category changes moves everything
   under it, and the delegate cannot tell whether they mis-saw it (task 13). */
.optcard.is-off{opacity:.55}
.optcard.is-off .price{color:var(--soft)}

/* An advertising card's Book control (task 15).

   The card is a GET form so the quantity travels with the item it belongs
   to, which means the number field and the button share a row inside a
   `.tier`. `.fqty` already sizes the input; this only lays the two out and
   keeps the button filling what is left. */
/* `position:relative` is load-bearing, not decoration. The quantity input's
   label is a `.u-sr`, which is `position:absolute` with `white-space:nowrap`
   — so "How many of Standee banner inside the conference hall" lays out at
   444px against whatever its nearest positioned ancestor is. With none, that
   was the page, and /advertisement/ scrolled sideways at 390 (441px against a
   390px viewport). Positioning the form clips it here. */
.advbook{position:relative;display:flex;flex-wrap:wrap;gap:var(--sp-3);align-items:stretch;margin-top:var(--sp-3)}
/* `min-width:0` is the whole fix.
   A flex item defaults to `min-width:auto`, which refuses to shrink below its
   own content width — so "Book and pay online" held the button at its full
   179px inside a 179px card while the quantity box sat beside it, and the row
   ran 104px past the edge of the card it lives in. Measured at 1440: form
   179px, button 179px, quantity 104px. Adding the visible "Qty" label made it
   32px worse, which is how it was noticed; it was already overflowing
   without it (task 23). With `min-width:0` the button shrinks, and with
   `flex-wrap` it drops to its own line when shrinking would leave it
   unreadable. */
.advbook .btn{flex:1 1 8rem;min-width:0}
.advbook .fqty{flex:0 0 auto}
.advbook .fqty input{height:100%}

/* A `.note` must not widen the page.
   `.note` is a flex row — icon, then the text as one anonymous flex item —
   and that item is sized by its min-content width, which nothing was allowed
   to break. On /advertisement/ at 390 that made the document 441px wide and
   the whole page scrolled sideways (task 15). Measured: with this rule the
   document is 390. */
.note{overflow-wrap:anywhere}

/* ==========================================================================
   Task 18 — the homepage as a front door
   ========================================================================== */

/*
 * The homepage was one scroll carrying nearly every section of the site in
 * full: about 13,000px at 1440, and a visitor got everything without ever
 * clicking through. Each band is now a summary that links to its own page.
 *
 * Eleven short bands at the full `--sect-y` rhythm spend 100px above and
 * below each one — over 2,000px of the page, a quarter of it, on air between
 * paragraphs that are three lines long. `--sect-y-sm` is the design system's
 * own band rhythm (it is what `.u-band` uses), so this is the existing token
 * applied where the section is now a band rather than a chapter.
 *
 * Scoped to the homepage. Every inner page keeps the reviewed rhythm
 * untouched — this is the one page the task deliberately re-baselines.
 */
body.home main > .sect {
	padding-block: var(--sect-y-sm);
}

/*
 * The closing call to action is the exception: it is a full-bleed panel
 * rather than a band of text, and it reads as an afterthought when it is the
 * same height as the contact strip above it.
 */
body.home main > .sect.cta {
	padding-block: var(--sect-y);
}

/*
 * The day cards carry a date chip above the title. `.fcard b` is a block, so
 * without this the chip and the title collide.
 */
.fcard > .tag {
	display: inline-block;
	margin-bottom: var(--sp-3);
}

/*
 * A tier card on the homepage is the name, the amount and what is left —
 * the entitlement list that used to close it is on /sponsorship/. The list
 * carried the dashed rule that separated the price from the detail, so the
 * remaining-count chip takes it over.
 */
.tier > .tag {
	display: inline-block;
	margin-top: var(--sp-2);
	padding-top: var(--sp-5);
	border-top: 1px dashed var(--line);
	width: 100%;
}

/*
 * Two tier cards to a row on a phone, on the homepage only.
 *
 * The cards on /sponsorship/ carry the entitlement list and need the full
 * width. These do not — they are the name, the amount and what is left — so
 * stacking five of them one-up spends 1,670px of a 390px-wide page on five
 * short cards. `.spon` asks for minmax(196px,1fr), which is one column
 * inside a 390px viewport once the gutters are taken off.
 */
@media (max-width: 27.5rem) {
	body.home #partner .spon {
		grid-template-columns: repeat(2, 1fr);
	}

	body.home #partner .tier {
		padding: var(--sp-7) var(--sp-6);
	}
}

/* ==========================================================================
   Task 20 — the policy links in the footer bar
   ========================================================================== */

/*
 * The bottom bar carried two links; it now carries eight, because Razorpay's
 * merchant verification looks for the policy pages to be reachable from the
 * site and not merely to exist. Eight in one line overflows a phone, so the
 * list wraps and centres under the copyright rather than pushing it out.
 */
.ft__legal {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 0 var(--sp-3);
	row-gap: var(--sp-2);
}

@media (max-width: 47.5rem) {
	.ft__legal {
		justify-content: center;
	}
}

/* ==========================================================================
   Task 21 — footer credits
   ========================================================================== */

/*
 * "Jointly organised by" above the two organiser logos. The brand paragraph
 * beside them already says it in a sentence; this is the label for the marks
 * themselves, in the same treatment the header bar uses.
 */
.ft__by {
	display: block;
	margin-bottom: var(--sp-3);
	font-size: var(--fs-xs);
	font-weight: var(--fw-black);
	letter-spacing: .14em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, .5);
}

/*
 * The developer credit. Quiet by instruction: a line under the copyright, not
 * a banner. It reads at the same weight as the copyright beside it and only
 * the name is a link.
 */
.ft__credit {
	display: inline-block;
	margin-top: var(--sp-2);
	color: rgba(255, 255, 255, .45);
}

.ft__credit a {
	color: rgba(255, 255, 255, .7);
}

.ft__credit a:hover,
.ft__credit a:focus-visible {
	color: #fff;
	text-decoration: underline;
}

/* ==========================================================================
   Task 23 — advertising and branding as selectable cards
   ========================================================================== */

/*
 * The ten items were ten checkbox rows in one flat `.checkgrid` — a form
 * control at the foot of the page rather than something a sponsor browses.
 * They are now two groups of `.optcard`s, the same card the tiers above them
 * use, so selection reads the same way in both halves of the form.
 *
 * `auto-fit` at 20rem gives three across a desktop, two on a tablet and one
 * on a phone without a media query at any of them.
 */
.optgrid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
	gap: var(--gap-sm);
	margin: 0 0 var(--sp-5);
}

@media (max-width: 30rem) {
	/* Below a phone's width `minmax(20rem, 1fr)` stops being a minimum and
	   starts being an overflow. */
	.optgrid { grid-template-columns: 1fr; }
}

/*
 * The advertising card is a `div`, not the `label` `.optcard` normally is,
 * because four of these carry a quantity field: a number input nested inside
 * the checkbox's label toggles the checkbox on every click into the number.
 * So the pick has its own label and the quantity sits beside it.
 *
 * The base `.optcard` grid is `auto minmax(0,1fr) auto` for input, text,
 * price. Here the input and text live together in `.optcard__pick`, so the
 * card is two columns.
 */
.optcard--adv {
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: start;
	cursor: default;
}

.optcard--adv .optcard__pick {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: var(--sp-5);
	align-items: start;
	cursor: pointer;
	min-width: 0;
}

/* `.optcard input` is already sized and coloured; this only stops the box
   drifting off the first line of a two-line name. */
.optcard--adv .optcard__pick input { margin-top: .15rem; }

.optcard--adv .optcard__t { display: block; min-width: 0; }

.optcard--adv .optcard__end {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: var(--sp-3);
}

/* The price keeps the tier treatment but steps down a size: these are cards
   in a grid three across, not rows across the full width. */
.optcard--adv .price {
	font-family: var(--fd);
	font-size: var(--fs-2xl);
	font-weight: var(--fw-black);
	letter-spacing: var(--ls-h2);
	color: var(--mar);
	white-space: nowrap;
}

/* A sold-out card cannot be chosen, and says so rather than looking broken. */
.optcard--adv.is-gone {
	opacity: .55;
	cursor: not-allowed;
}
.optcard--adv.is-gone .optcard__pick { cursor: not-allowed; }

/*
 * The quantity control, with a visible label.
 *
 * The audit for task 23 found eight number inputs whose only label was a
 * visually hidden one. They were hidden correctly — measured at 1x1 and
 * clipped on every page and at all three widths — so nothing was leaking on
 * screen; what was missing was anything a sighted person could read. "Qty"
 * is `aria-hidden` so the accessible name stays the full "How many of
 * Compendium — inside full page", which is what tells four identical boxes
 * apart.
 */
.fqty__l {
	font-size: var(--fs-2xs);
	font-weight: var(--fw-bold);
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--soft);
}

.optcard--adv .fqty {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
}

/* 44px is the smallest a control should be on a phone; the steppers sit in a
   stacked card here and are otherwise easy to miss. */
.optcard--adv .fqty input {
	width: 4.5rem;
	min-height: 44px;
	text-align: center;
}

@media (max-width: 30rem) {
	.optcard--adv { grid-template-columns: minmax(0, 1fr); }
	.optcard--adv .optcard__end {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		width: 100%;
		margin-top: var(--sp-4);
	}
}

/* ==========================================================================
   Task 24 — UI pass
   ========================================================================== */

/*
 * The entitlement matrix must stay a table below 760px.
 *
 * `.matrix` is also `.rtab`, and `.rtab` gets the stacked treatment at
 * `max-width: 760px`: `thead {display:none}` and every cell turned into a
 * flex row labelled from its own `data-l`. That is exactly right for the fee
 * tables, where each row is one category and each cell carries its own label.
 *
 * It is wrong for the matrix. Its columns are the six tiers and its `td`s
 * have no `data-l`, so at 390 the tier names disappeared with the `thead` and
 * every cell stacked into an unlabelled column of ticks and dashes — a
 * sponsor could see that something was included, and not what, nor in which
 * tier (task 24, found at 390 on /sponsorship/).
 *
 * The matrix already has the right treatment waiting for it: `min-width:
 * 720px` inside a `.tscroll` with `overflow-x: auto`. Six tiers cannot be
 * stacked into a phone and still be compared, so it scrolls, which is what
 * that pair was built for. This only stops the stacking rules reaching it.
 */
@media (max-width: 47.5rem) {
	.tscroll .matrix,
	.tscroll .matrix tbody,
	.tscroll .matrix tr,
	.tscroll .matrix td {
		display: revert;
		width: auto;
	}

	.tscroll .matrix { display: table; min-width: 45rem; }
	.tscroll .matrix thead { display: table-header-group; }
	.tscroll .matrix tbody { display: table-row-group; }
	.tscroll .matrix tr { display: table-row; padding: 0; border-bottom: 0; }
	.tscroll .matrix td {
		display: table-cell;
		padding: 1.1rem 1.25rem;
		border-bottom: 1px solid var(--line);
	}
	/* The stacked rules label each cell from `data-l`; the matrix has none,
	   so the pseudo-element would only add empty space. */
	.tscroll .matrix td::before { content: none; }
}

/*
 * And a cue that it scrolls.
 *
 * On a touch device the scrollbar only appears *while* scrolling, so a
 * sponsor seeing Premium Platinum and Platinum has no reason to think
 * Diamond, Gold and Silver are there. The hint is real markup in
 * `page-sponsorship.php` rather than CSS `content`, so it can be translated
 * and read aloud.
 */
.tscroll__hint {
	display: none;
	margin: 0 0 var(--sp-3);
	font-size: var(--fs-xs);
	font-weight: var(--fw-bold);
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--soft);
}

@media (max-width: 47.5rem) {
	.tscroll__hint { display: block; }
}

/*
 * Four cards, two columns at tablet — everywhere, not just the homepage.
 *
 * `.fcards` is `repeat(auto-fit, minmax(232px, 1fr))`, which resolves to
 * three columns in the ~767px container at 834. A grid of four then lands
 * 3 + 1 and the fourth sits alone on its own row. Found at 834 on the
 * homepage programme band, both bands on /about-accuprec/, /event-details/
 * and /contact-us/ — 834 had never been looked at before this pass.
 *
 * `:has(> :nth-child(4):last-child)` is "exactly four children", which is
 * the only count that misbehaves here: three fits, five and six fill their
 * rows, and two is already two.
 *
 * Bounded to the tablet range. At 390 they stack one-up and at 1440 the row
 * takes all four, and both of those are already right.
 */
@media (min-width: 40rem) and (max-width: 64rem) {
	.fcards:has(> :nth-child(4):last-child) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/*
 * The account tabs were clipped, not scrollable.
 *
 * `style.css` sets `.acct__nav { display:flex; overflow-x:auto }` inside
 * `@media (max-width: 860px)` at line 1101 — and then, at line 1108,
 * unconditionally sets `.acct__nav { overflow: hidden }`. Same specificity,
 * later in the file, so it wins at every width and the horizontal scroll
 * never happens.
 *
 * The result at 390 and 834: the tabs are a flex row wider than the box,
 * clipped with no way to scroll, so Entry pass, Abstract, My details and
 * Sign out could not be reached at all — measured at 481px to 929px of
 * content inside a 390px viewport. The mask gradient in that same media
 * query fades the right edge, which makes it *look* scrollable, which is
 * worse than looking cut off.
 *
 * `flow.css` loads after `style.css`, so restoring the intended behaviour
 * here needs no edit to the reviewed file (task 24).
 */
@media (max-width: 53.75rem) {
	.acct__nav {
		overflow-x: auto;
		overflow-y: hidden;
	}
}

/*
 * And the focus ring, which the same `overflow:hidden` clips at every width —
 * the links sit flush against the box on all four sides. Drawing the ring
 * inside the link with a negative offset keeps it whole without giving the
 * nav padding it was not designed with.
 */
.acct__nav a:focus-visible {
	outline: 2px solid var(--mar);
	outline-offset: -3px;
}

/*
 * An empty scan log should look empty, not broken.
 *
 * `.checkin__list` reserves `min-height: 13rem` so the list does not jump
 * about as scans arrive. Before the first scan that leaves a 13rem blank
 * above the "Nothing scanned yet." line, which reads as something that
 * failed to load rather than something that has not happened yet.
 */
.checkin__list:empty {
	min-height: 0;
}

/* --------------------------------------------------------------------------
 * Copy review, 27 September 2026.
 *
 * The camera hint used to be pre-filled with "The camera starts when you tap
 * Scan." -- the interface narrating the button beside it. The text is gone and
 * the element stays, because checkin.js writes scan status into it. Empty, it
 * would otherwise hold open the gap the sentence used to fill.
 * ----------------------------------------------------------------------- */
.checkin__hint:empty {
  display: none;
}

/* LASA membership — the Verify button and its verdict on the register form.
   A clean pass is green (--ok); a flagged result (name mismatch, or an ID not
   on the list) is amber (--warn) — accepted, not refused. */
.lasaverify { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: .55rem; }
.lasaverify__status { font-size: .92rem; font-weight: 600; line-height: 1.4; }
.lasaverify__status.is-wait { color: var(--mut); }
.lasaverify__status.is-ok { color: var(--ok); }
.lasaverify__status.is-flag { color: var(--warn); }

/* Contact: the Organizing Secretary's number, called out a little larger
   (correction 30). */
.chan__big { font-size: 1.05em; font-weight: 700; color: var(--ink); white-space: nowrap; }

/* Contact line in the footer (correction 28): the delegate and sponsor lines,
   moved out of the footer menu and onto the bottom line. */
.ft__contact { font-size: .9rem; color: var(--mut); margin-bottom: .4rem; }
.ft__contact a { color: inherit; }
.ft__contact a:hover { color: var(--gold); }
@media (max-width: 560px) { .ft__contact .ft__contact-sep { display: block; height: .2rem; } }

/* Co-author repeater on the abstract form (task 28, item 23). */
.coauthor-row { display: flex; gap: .5rem; align-items: center; margin-bottom: .5rem; }
.coauthor-row input { flex: 1 1 0; min-width: 0; }
.coauthor-row__x { background: none; border: 1px solid var(--line); border-radius: 6px; padding: .45rem .6rem; cursor: pointer; color: var(--mut); line-height: 1; }
.coauthor-row__x:hover { border-color: var(--mar); color: var(--mar); }

/* ------------------------------------------------------------------ *
 * Task 29 A — card action buttons pinned to the bottom of the card.
 * Every .tier card (sponsorship tiers, compendium and branding cards)
 * is a flex column; the action area sits in .tier__foot, which
 * margin-top:auto pushes to the bottom, so every button in a row lines
 * up regardless of how much content the card holds.
 * ------------------------------------------------------------------ */
.tier { display: flex; flex-direction: column; }
.tier__foot { margin-top: auto; padding-top: 1rem; }
.tier__foot .btn { width: 100%; }
.tier__foot .tier__left { margin: 0 0 .55rem; }
.tier__foot .advbook { margin: 0; }

/* ------------------------------------------------------------------ *
 * Task 29 B1 — exhibition floor plan: full image, hover zoom, lightbox.
 * The plan is shown in full (not cropped like a gallery tile); a hover
 * zooms into the point under the cursor, a click opens it full screen.
 * ------------------------------------------------------------------ */
.stallmap { margin: 0 0 1rem; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: #fff; box-shadow: var(--sh-1); }
.stallmap__btn { display: block; width: 100%; padding: 0; border: 0; background: #fff; cursor: pointer; overflow: hidden; line-height: 0; }
.stallmap__btn img { width: 100%; height: auto; display: block; object-fit: contain; transition: transform .18s ease; }
.stallmap__btn--zoomable { cursor: zoom-in; }
.stallmap__btn.is-zoom img { transform: scale(2); }
.stallmap figcaption { padding: .8rem 1rem; font-size: var(--fs-base); color: var(--soft); text-align: center; border-top: 1px solid var(--line); }

/* Lightbox (used by the floor plan) */
body.lbox-open { overflow: hidden; }
.lbox { position: fixed; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: calc(var(--z-header) + 100); display: flex; align-items: center; justify-content: center;
  background: rgba(14,16,22,.86); padding: clamp(1rem, 4vw, 3rem); opacity: 0; transition: opacity .2s ease; }
.lbox.is-open { opacity: 1; }
.lbox__img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--r); box-shadow: 0 20px 60px rgba(0,0,0,.5); cursor: zoom-out; }
.lbox__close { position: absolute; top: 1rem; right: 1.2rem; width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: rgba(255,255,255,.14); color: #fff; font-size: 1.8rem; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.lbox__close:hover { background: rgba(255,255,255,.26); }

/* ------------------------------------------------------------------ *
 * Task 29 C1/C2 — header login / account control.
 * Signed out: a "Sign in" button (styled like the header CTAs).
 * Signed in: the delegate's initials in a circle, with a dropdown.
 * ------------------------------------------------------------------ */
.acctmenu { position: relative; display: inline-flex; }
.acctmenu__btn { width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line); background: var(--mar); color: #fff;
  font-weight: var(--fw-bold); font-size: .85rem; letter-spacing: .02em; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: transform var(--t), box-shadow var(--t); }
.acctmenu__btn:hover { transform: translateY(-1px); box-shadow: var(--sh-1); }
/* Closed by default — only open when the wrapper has .is-open (JS sets it on
   click). The dropdown previously set display:grid unconditionally, which
   overrode the [hidden] attribute's display:none, so it showed permanently. */
.acctmenu__pop { position: absolute; top: calc(100% + .5rem); right: 0; min-width: 210px; background: #fff; border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--sh-2); padding: .4rem; z-index: calc(var(--z-header) + 1); display: none; gap: .1rem; }
.acctmenu.is-open .acctmenu__pop { display: grid; }
.acctmenu__pop[hidden] { display: none; }
.acctmenu__pop a { display: flex; align-items: center; gap: .6rem; padding: .6rem .8rem; border-radius: calc(var(--r) - 4px); font-size: var(--fs-md); color: var(--ink); text-decoration: none; white-space: nowrap; }
.acctmenu__pop a:hover, .acctmenu__pop a:focus { background: var(--cream); color: var(--mar); }
.acctmenu__pop a .fa-solid { width: 1.05rem; text-align: center; color: var(--mar); font-size: .95em; }
.acctmenu__out { border-top: 1px solid var(--line); margin-top: .2rem; padding-top: .6rem; color: var(--mar); }
/* When signed in, the Register-now CTA dims — a signed-in delegate has registered. */
.btn--register-dim { opacity: .5; }

/* "I intend to present" — called out so delegates don't overlook it (correction 55). */
.fcheck--mark {
	border: 2px solid var(--gold);
	background: var(--gold-tint);
	border-radius: var(--r-md);
	padding: .85rem 1rem;
	align-items: flex-start;
}
.fcheck--mark input[type="checkbox"] {
	margin-top: .15rem;
}

/* Entry-pass badge: the three organiser marks across the top (correction 59). */
.pass__logos {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-6);
	padding: var(--sp-6) var(--sp-7);
	background: var(--paper);
	border-bottom: var(--bw) solid var(--line);
}
.pass__logos img {
	height: 38px;
	width: auto;
	max-width: 31%;
	object-fit: contain;
}

/* Entry-pass byline: designation / organisation / location under the name (correction 21). */
.pass__by {
	display: block;
	margin-top: .2rem;
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	color: rgba(255, 255, 255, .78);
}

/* An organiser's own logo, in an .fcard, in place of the usual icon circle (round 3b, point 4). */
.fcard__logo {
	display: block;
	height: 44px;
	width: auto;
	max-width: 140px;
	object-fit: contain;
	margin-bottom: .9rem;
}

/* ---------------------------------------------------------------------------
   Key dates: three cards, not four
   The strip was laid out for four entries. It carries three, so the fourth
   column rendered as an empty cell with the divider lines around it and read
   as a missing card (client feedback, 9 Oct).
   --------------------------------------------------------------------------- */
.kd ol { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .kd ol { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .kd ol { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   Numbered terms inside .prose
   The design only ever needed bullets (.bul). The Industry showcase session
   carries nine numbered terms the client supplied, and a number that is part
   of the sentence cannot be a ::before dot. Built on the same spacing and
   colour tokens as .bul so the two read as one family.
   --------------------------------------------------------------------------- */
.prose ol.num { display: grid; gap: .6rem; margin: 0 0 1.25rem; padding: 0; counter-reset: num; list-style: none; }
.prose ol.num li { display: flex; gap: .7rem; align-items: baseline; color: var(--mid); line-height: 1.6; counter-increment: num; }
.prose ol.num li::before { content: counter(num) "."; flex: 0 0 auto; min-width: 1.35em; color: var(--mar); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
   Sign in stays in the header at every width
   style.css hides `.hdr__m .btn` below 1024px to make room for the burger.
   That rule also took the Sign in control with it, so below 1024px — and on
   every phone — there was no way to reach an account from the header at all
   (client feedback, 9 Oct). Register now still collapses into the mobile menu;
   only the account control is brought back, and it shrinks rather than wraps.
   --------------------------------------------------------------------------- */
@media (max-width: 1024px) {
  .hdr__m .btn.acct-signin { display: inline-flex; margin-left: auto; }
}
@media (max-width: 560px) {
  .hdr__m .btn.acct-signin { padding: .5rem .8rem; font-size: var(--fs-base); }
}
@media (max-width: 380px) {
  .hdr__m .wrap { gap: .5rem; }
  .hdr__m .btn.acct-signin { padding: .45rem .65rem; }
  .brand__l { max-width: 46vw; }
}

/* ---------------------------------------------------------------------------
   The gap between the compact nav and a roomy desktop
   style.css compacts the nav links at <=1180px and hides the burger at
   >1024px, which leaves 1181px-1500px rendering the full-size nav, Register
   now and Sign in on one row that does not fit. The Sign in button was pushed
   past the right edge and `body{overflow-x:hidden}` swallowed it, so it simply
   was not there at 1280 and 1440 (measured: right edge 1369 at 1280, 1453 at
   1440). Same compact treatment, applied across the gap.
   --------------------------------------------------------------------------- */
@media (min-width: 1025px) and (max-width: 1500px) {
  .nav__l { padding-inline: .42rem; font-size: var(--fs-base); }
  .brand__l em { display: none; }
  .hdr .btn { margin-left: .45rem; }
}

/* ---------------------------------------------------------------------------
   The sign-in card at very narrow widths — 9 October 2026
   ---------------------------------------------------------------------------
   /my-account/ took the document to 343px inside a 320px viewport, and
   body{overflow-x:hidden} hid it, which is the third time that rule has
   covered a real overflow on this site.

   The cause is not the card. `.btn` is `white-space:nowrap`, and the longest
   label on it — "Email me a sign-in code" — has a min-content width of 251px.
   With the card's 2.25rem padding either side that puts the card's floor at
   325px, which a 320px viewport cannot hold.

   Scoped to the sign-in card and to the widths that actually break, so the
   pill buttons everywhere else keep their shape: `.btn` is shared by every
   page and must not be changed globally for this.
   --------------------------------------------------------------------------- */
@media (max-width: 359px) {
  .login { padding: var(--sp-8); }
  .login .btn { white-space: normal; padding-inline: var(--sp-6); }
}

/* The card prints the address back in a <strong>, and an email address is one
   unbreakable token. A long one — a 36-character address is not unusual at a
   university — set the card's min-content width on its own and overflowed at
   320px even with the button fixed above. `anywhere` rather than `break-word`
   because only `anywhere` is taken into account when min-content is worked
   out, which is the measurement that was overflowing. Not width-scoped: a long
   enough address overflows a narrow card at any width. */
.login .fset__d strong,
.u-wrap { overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------------
   The LASA verification dialog — 9 October 2026
   ---------------------------------------------------------------------------
   The verdict used to be a single line under the Verify button and was being
   missed, so it is now announced in a SweetAlert2 dialog (client feedback).
   The library is bundled in assets/vendor/, never a CDN.

   Only the shell is styled here. The OK button is given the site's own
   `.btn .btn--p` classes through SweetAlert's customClass, so the maroon
   comes from the existing button rules rather than being restated.
   --------------------------------------------------------------------------- */
.swal2-popup.lasaswal {
  width: 23rem;
  max-width: calc(100vw - 2 * var(--sp-7));
  padding: var(--sp-9) var(--sp-8) var(--sp-8);
  border: var(--bw) solid var(--line);
  border-radius: var(--r-lg);
  background: var(--paper);
  box-shadow: var(--sh-2);
  font-family: var(--fd);
}
.lasaswal .lasaswal__t {
  font-family: var(--fd);
  font-size: var(--fs-xl);
  font-weight: var(--fw-semi);
  color: var(--ink);
  padding: 0;
  margin: 0 0 var(--sp-4);
}
.lasaswal .lasaswal__b {
  font-size: var(--fs-lg);
  line-height: 1.55;
  color: var(--mid);
  margin: 0;
  padding: 0;
  /* a LASA id or a long word must not widen the dialog past the viewport */
  overflow-wrap: anywhere;
}
.lasaswal .lasaswal__b a { color: var(--mar); text-decoration: underline; }
.lasaswal .lasaswal__a { margin: var(--sp-8) 0 0; gap: var(--sp-5); }
.lasaswal .lasaswal__a .btn { min-width: 7rem; }
/* SweetAlert sizes its icon in em of the popup font; keep it modest. */
.lasaswal .swal2-icon { width: 3.4rem; height: 3.4rem; margin: 0 auto var(--sp-6); }
.lasaswal .swal2-icon .swal2-icon-content { font-size: 2rem; }

@media (max-width: 359px) {
  .swal2-popup.lasaswal { padding: var(--sp-8) var(--sp-6) var(--sp-6); }
  .lasaswal .lasaswal__a .btn { width: 100%; white-space: normal; }
}

/* ---------------------------------------------------------------------------
   An exhibition stand in the checkout summary
   ---------------------------------------------------------------------------
   Two Silver stands are two lines with the same product name, so the line has
   to say which stall it is. WooCommerce's own cart item data carries "Stall"
   and "Size"; this puts them under the name rather than beside it, where they
   would push the price off a phone. */
.summary__l .summary__m {
  display: block;
  font-size: var(--fs-sm);
  color: var(--soft);
  line-height: var(--lh-snug);
  margin-top: var(--sp-1);
}

/* A calm line under a field -- information, not a refusal. */
.fhint--info{display:flex;gap:var(--sp-2);align-items:flex-start;font-weight:400;color:var(--soft);line-height:var(--lh-snug)}
.fhint--info i{margin-top:.2em}

/* Country code beside the number it belongs to. */
.phonerow{display:grid;grid-template-columns:minmax(0,9.5rem) minmax(0,1fr);gap:var(--sp-3)}
.phonerow .dialcode{min-width:0}
@media (max-width:620px){.phonerow{grid-template-columns:minmax(0,7.5rem) minmax(0,1fr)}}

/* The booking page's two columns may shrink below their content, so the stand
   table stacks inside the phone viewport instead of pushing the page wider. */
.acct > div{min-width:0}
.summary .rtab td{min-width:0;overflow-wrap:anywhere}
.summary dl.summary__l{flex-direction:column;align-items:stretch;gap:0;padding:0;border-bottom:0;margin:0}
.summary dl.summary__l > div{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-5);min-width:0;padding:var(--sp-4) 0;border-bottom:var(--bw) dashed var(--line);font-size:var(--fs-md)}
.summary dl.summary__l > div.summary__t{border-bottom:0;border-top:var(--bw-2) solid var(--line-2);padding-top:var(--sp-6);margin-top:var(--sp-3)}
.summary dl.summary__l dt{color:var(--mid)}
.summary dl.summary__l dd{margin:0;min-width:0;text-align:right;color:var(--ink);font-weight:var(--fw-semi);white-space:nowrap}
.summary dl.summary__l .summary__t dt{font-size:var(--fs-lg);font-weight:var(--fw-bold);color:var(--ink)}
.summary dl.summary__l .summary__t dd{font-family:var(--fd);font-size:var(--fs-4xl);font-weight:var(--fw-black);color:var(--mar)}
.summary .rtab .btn{margin-top:0}
.summary + .fset{margin-top:var(--sp-9,2rem)}

/* The plan's first block starts below the fixed header. --lsc-clear is
   measured from the real header by assets/js/stalls.js; the fallback is the
   header's own token plus the organisers bar, for the moment before it runs. */
.lsc-booking{padding-top:var(--lsc-clear,calc(var(--hh) + 4.5rem))}
.lsc-booking [id],.lsc-booking{scroll-margin-top:calc(var(--hh) + 1rem)}

/* A text-style button that opens the floor-plan picture. */
.floorlink{appearance:none;background:none;border:0;padding:0;margin:0;font:inherit;color:var(--mar);text-decoration:underline;text-underline-offset:.2em;cursor:pointer;display:inline-flex;gap:.4em;align-items:center;min-height:44px}
.floorlink:hover{color:var(--mar-dp)}
.floorlink:focus-visible{outline:2px solid var(--mar);outline-offset:3px;border-radius:2px}
/* Whole pixels only: a fractional margin here shifts the plan below it by a fraction of a pixel and
   every 1px rule in the floor is then antialiased differently from the reference. */
.lsc-floorlink{text-align:center;margin:0 0 1rem;height:44px;line-height:44px}
.lsc-floorlink .floorlink{vertical-align:middle}
.summary__n .floorlink{min-height:0}

/* Tier cards on the stalls block: the price and what is left. */
.inc--stalls .inc__price{color:var(--mar);font-weight:var(--fw-semi);margin-top:.35rem}
.inc--stalls .inc__price small{display:inline;font-size:var(--fs-xs);color:var(--soft);font-weight:400}
.inc--stalls .inc__left{margin-top:.2rem;color:var(--ink);font-weight:var(--fw-semi)}
.inc--stalls .inc__left.is-out{color:var(--soft)}

/* Five branding cards: five across on a wide screen, then 3 + 2 centred, then
   one column. Same card, same height (grid rows stretch). */
@media (min-width:1100px){.spon--five{grid-template-columns:repeat(5,minmax(0,1fr))}}
@media (min-width:620px) and (max-width:1099px){
  .spon--five{grid-template-columns:repeat(6,minmax(0,1fr))}
  .spon--five > .tier{grid-column:span 2}
  .spon--five > .tier:nth-child(4){grid-column:2 / span 2}
  .spon--five > .tier:nth-child(5){grid-column:4 / span 2}
}
@media (max-width:619px){.spon--five{grid-template-columns:1fr}}

/* ---------------------------------------------------------------------------
   Statue of Unity feature (template-parts/sou-feature.php)
   The picture is a whole brochure page with its words baked in, so it is never
   cropped: complete, capped in height on a desktop so it stays readable beside
   the text, full width on a phone.
   ------------------------------------------------------------------------ */
.sou{display:grid;grid-template-columns:minmax(0,26rem) minmax(0,1fr);gap:var(--gap-lg);align-items:center}
.sou__pic{margin:0;justify-self:center}
.sou__pic img{display:block;width:100%;max-width:calc(41rem * 661 / 935);height:auto;aspect-ratio:661 / 935;border-radius:var(--r);box-shadow:var(--sh-2)}
.sou__body > * + *{margin-top:var(--sp-5)}
.sou__title{font-family:var(--fd);font-size:var(--fs-4xl);font-weight:var(--fw-black);color:var(--ink);letter-spacing:var(--ls-h2);line-height:1.15;margin:0}
.sou__facts{display:grid;gap:0;margin:var(--sp-6) 0 0;padding:0}
.sou__facts > div{display:grid;grid-template-columns:6.5rem minmax(0,1fr);gap:var(--sp-5);padding:var(--sp-4) 0;border-bottom:var(--bw) dashed var(--line)}
.sou__facts dt{color:var(--soft);font-size:var(--fs-sm);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--fw-bold)}
.sou__facts dd{margin:0;color:var(--ink);font-weight:var(--fw-semi)}
.sou--inline{margin-top:var(--sp-9,2.5rem)}
@media (max-width:860px){
  .sou{grid-template-columns:1fr}
  .sou__pic{justify-self:stretch}
  .sou__pic img{max-width:none}
}

/* An icon inside a plain link in running text.
   The arrow after "accuprec.com" on /about-us/ had no size of its own -- the
   rules that size link icons are all scoped to .btn, .more, .hero__meta and
   friends -- so the browser drew it at its default size, a huge arrow in the
   middle of a sentence. One rule for every such link, at zero specificity so
   every existing, more specific icon rule still wins. */
:where(p, li, dd, .prose) a > svg{display:inline-block;width:.8em;height:.8em;margin-left:.3em;vertical-align:-.1em;flex:none}
.spon--five{grid-auto-rows:1fr}

/* The dropdown link for the page you are on. */
.menu a.on strong{color:var(--mar)}
.menu a.on{background:var(--mar-tint)}

/* ---------------------------------------------------------------------------
   /stall-booking/: the details form on the left, a small sticky "Your stalls"
   card on the right. On a phone the card comes first, then the form.
   Everything is the site's own type and tokens (as /register/ uses them): the
   family, the weights and the ink and brand colours -- no new faces.
   ------------------------------------------------------------------------ */
.stallbook{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,22rem);gap:var(--gap-lg);align-items:start}
.stallbook > .stallform{grid-column:1;grid-row:1;margin:0;min-width:0}
.stallbook > .stallcard{grid-column:2;grid-row:1;min-width:0}
.stallcard{position:sticky;top:calc(var(--stick-hdr, var(--stick)) + var(--sp-6));max-height:calc(100vh - var(--stick-hdr, var(--stick)) - var(--sp-9, 2rem));overflow:auto;
  background:var(--cream);border:var(--bw) solid var(--line);border-radius:var(--r);padding:var(--sp-7);font-family:var(--fb);color:var(--ink-2)}
.stallcard__h{font-size:var(--fs-3xl);font-weight:var(--fw-bold);color:var(--ink);letter-spacing:var(--ls-h3);line-height:1.2;margin:0 0 var(--sp-5)}
.stallcard__rows{list-style:none;margin:0;padding:0;display:grid;gap:0}
.stallcard__row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--sp-3) var(--sp-5);align-items:baseline;padding:var(--sp-5) 0;border-top:var(--bw) dashed var(--line)}
.stallcard__row:first-child{border-top:0;padding-top:0}
.stallcard__who{display:flex;flex-wrap:wrap;gap:0 var(--sp-3);align-items:baseline;min-width:0}
.stallcard__who b{font-size:var(--fs-xl);font-weight:var(--fw-bold);color:var(--ink)}
.stallcard__who span{font-size:var(--fs-lg);font-weight:var(--fw-semi);color:var(--ink)}
.stallcard__who small{font-size:var(--fs-md);font-weight:var(--fw-medium);color:var(--mid)}
.stallcard__price{font-size:var(--fs-lg);font-weight:var(--fw-bold);color:var(--ink);white-space:nowrap}
.stallcard__acts{grid-column:1 / -1;display:flex;gap:var(--sp-3);flex-wrap:wrap}
.stallcard__acts .btn{margin-top:0}
.stallcard dl.summary__l{flex-direction:column;align-items:stretch;gap:0;padding:0;border-bottom:0;margin:var(--sp-3) 0 0}
.stallcard dl.summary__l > div{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-5);min-width:0;padding:var(--sp-3) 0;border-top:var(--bw) dashed var(--line);font-size:var(--fs-md)}
.stallcard dl.summary__l dt{color:var(--mid);font-weight:var(--fw-medium)}
.stallcard dl.summary__l dd{margin:0;text-align:right;white-space:nowrap;color:var(--ink);font-weight:var(--fw-semi)}
.stallcard dl.summary__l > div.summary__t{border-top:var(--bw-2) solid var(--line-2);margin-top:var(--sp-3);padding-top:var(--sp-5)}
.stallcard dl.summary__l .summary__t dt{font-size:var(--fs-lg);font-weight:var(--fw-bold);color:var(--ink)}
.stallcard dl.summary__l .summary__t dd{font-family:var(--fd);font-size:var(--fs-4xl);font-weight:var(--fw-black);color:var(--mar)}
.stallcard__n{margin:var(--sp-5) 0 0;font-size:var(--fs-sm);color:var(--soft);line-height:var(--lh-snug);display:flex;flex-direction:column;gap:var(--sp-2)}
.stallcard__n .floorlink{min-height:0;font-size:var(--fs-sm)}
@media (max-width:900px){
  .stallbook{grid-template-columns:1fr}
  .stallbook > .stallcard{grid-column:1;grid-row:1;position:static;max-height:none;overflow:visible}
  .stallbook > .stallform{grid-column:1;grid-row:2}
}

/* .alert is display:flex, which beats the browser's [hidden] rule: without this
   the "your hold has expired" note under the plan showed to everybody. */
.lsc-expired[hidden]{display:none}
.lsc-expired{max-width:60rem;margin:0 auto var(--sp-5)}
