/* ============================================================================
   LFFO - THE SPONSORSHIP PANEL
   ----------------------------------------------------------------------------
   WHAT THIS IS. One dialog, opened from one quiet line of words on the
   Membership page and one on the Partners page. Sponsorship is not a fourth
   membership and must never be laid out like one: single family office, multi
   family office and Partner are what the association offers and they get the
   pages. This is a different relationship and it happens in here, for
   somebody who asked for it.

   WHY THIS FILE WAS REWRITTEN RATHER THAN EXTENDED. It had become six
   correction layers stacked on one base: .spx-fillbar was declared four
   separate times, each block undoing part of the one above it, and the only
   way to know what any control actually looked like was to read all 753 lines
   in order. That is the state a stylesheet reaches when every change is made
   by appending. Everything below is declared once, in the order the eye meets
   it, and the reasoning for each decision sits with the decision.

   THE THREE RULES THE PANEL IS BUILT ON
   ----------------------------------------------------------------------------
   1. NO FIGURE IS PARADED. The association does not put a price on its
      workshops, its papers, its forums or its titles, and it is not going to.
      A sponsor names what their firm wishes to give; what that reaches opens,
      and what it finally costs is agreed with the office and written into a
      contract. So the panel reports what OPENS, never what anything costs,
      and the reader's own figure is shown once, quietly, as a ghost behind
      the field they can type into. Nothing on this panel is a price tag.

   2. ONE AMBIENT LOGIC, APPLIED CONSISTENTLY. A form that shimmers is a form
      nobody trusts, so movement is not decoration here: it is a signal, and
      it means exactly one thing. A surface that is LIVE - the thing the
      person is currently driving, or a choice they have actually made -
      carries a slow drift of the live tone. A surface that is merely present
      is still. That is the whole rule, and it is why the fill bar drifts, why
      a chosen activity breathes and an unchosen one does not, and why the
      panel itself is motionless behind them.

   3. EVERY LOOP IS SEAMLESS BY CONSTRUCTION, NOT BY EASING. A loop that fades
      out and back in is a loop with a visible seam, however gentle. So each
      one either translates a repeating tile by exactly one tile width, or
      travels out and back within a single keyframe so the last frame IS the
      first frame. There is nothing to reset, so there is nothing to see.

   THE PALETTE
   ----------------------------------------------------------------------------
   Three blues and nothing else moves: navy at rest, 2E537D through the
   middle, koningsblauw at the top of the travel. Gold is kept, but only for
   marks that mean THE ASSOCIATION - the seal, the undertaking. Movement is
   blue, identity is gold, and the two never stand in for each other.
   ============================================================================ */

.spx {
  /* Declared on the dialog rather than :root so the panel carries its own
     palette wherever it is opened from, and so nothing here can leak into a
     page that is not showing it. */
  --sx-navy:      #0f2038;
  --sx-navy-deep: #0a1728;
  --sx-mid:       #2e537d;
  --sx-koning:    #3a6bd6;

  --sx-ink:       #14213a;
  --sx-ink-soft:  #55627a;
  --sx-ink-faint: #8493ad;

  --sx-paper:     #ffffff;
  --sx-veil:      rgba(10, 23, 40, .58);
  --sx-line:      rgba(15, 32, 56, .13);
  --sx-line-soft: rgba(15, 32, 56, .07);
  --sx-tint:      rgba(46, 83, 125, .05);

  --sx-gold:      #c9a34e;
  --sx-gold-lit:  #dcb763;

  /* The live tone. The script rewrites --sx-live and --sx-lead on every move
     of the slide, and every animated surface on the panel reads them, which
     is what makes the whole box change temperature together instead of in
     four unrelated places. */
  --sx-live: var(--sx-navy);
  --sx-lead: var(--sx-koning);

  /* Two curves, and only two. Motion that responds to a hand uses the first;
     motion that unfolds on its own uses the second. */
  --sx-quick: cubic-bezier(.32, .72, 0, 1);
  --sx-glide: cubic-bezier(.22, 1, .36, 1);

  --sx-r: 2px;   /* Square, softened by exactly one hair. See note at .spx-in. */
}

/* ============================================================================
   1 - THE SHEET
   ----------------------------------------------------------------------------
   On a desktop this is a panel held in the middle of a darkened, blurred
   page. On a phone it is a sheet that comes up from the bottom edge and
   stops short of the top, because that is where a thumb is and because a
   full-screen takeover of a page somebody was reading is a navigation, not a
   dialog. Same markup, same script, two behaviours, chosen by width alone.

   The scroll lives INSIDE the sheet, not on the sheet, so the head and the
   navigation can stay put while the body moves under them. On a 667px phone
   screen that is the difference between a form you can operate with one hand
   and a form where the Carry on button is always somewhere below the fold.
   ============================================================================ */

dialog.spx {
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--sx-ink);
  max-width: none;
  max-height: none;
  width: 100%;
  height: 100%;
  inset: 0;
  overflow: hidden;
  font-family: var(--sans);
}
dialog.spx::backdrop {
  background: var(--sx-veil);
  -webkit-backdrop-filter: blur(14px) saturate(118%);
  backdrop-filter: blur(14px) saturate(118%);
  opacity: 0;
}
dialog.spx[open]::backdrop { animation: sxVeil .42s var(--sx-quick) forwards; }
@keyframes sxVeil { to { opacity: 1; } }

/* THE DIALOG HAS TO BE A FLEX CONTAINER, NOT A BLOCK.
   The browser's own stylesheet centres a dialog with margin: auto against a
   fit-content box. Overriding width and height to fill the viewport - which
   is what the blurred backdrop and the bottom-hinged phone sheet both need -
   turns it back into an ordinary block, and margin-top: auto in block layout
   computes to zero. The panel silently sat at the top of the screen on the
   desktop and refused to hinge to the bottom edge on a phone, and neither
   looked like a bug in the margins, which is where it actually was. */
dialog.spx[open] {
  display: flex;
  align-items: center;
  justify-content: center;
}

dialog.spx > .spx-in {
  position: relative;
  margin: auto;
  width: min(760px, calc(100vw - 40px));
  max-height: min(92vh, 940px);
  display: flex;
  flex-direction: column;

  /* ONE HAIR OF RADIUS, AND THE REASON FOR IT. The site is square: the type
     system says so and every card, rule and button on the other nine pages
     obeys it. A 2px radius is not a departure from that, it is what stops a
     large white plane on a blurred dark ground from showing the aliased
     staircase a true 0px corner shows at this size. It reads as square. */
  border-radius: var(--sx-r);
  background: var(--sx-paper);

  /* Depth by layered shadow rather than by a border. Three casts: a hairline
     to define the edge, a short one for contact, a long soft one for the
     lift. A single large blur reads as a drop shadow from 2009. */
  box-shadow:
    0 0 0 1px rgba(15, 32, 56, .10),
    0 2px 8px -2px rgba(10, 23, 40, .22),
    0 44px 90px -30px rgba(10, 23, 40, .55);
  overflow: hidden;
}

/* The gold seam along the top edge: the one mark on the panel that means the
   association rather than the interaction. */
dialog.spx > .spx-in::before {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 2px; z-index: 3;
  background: linear-gradient(90deg,
    rgba(201, 163, 78, 0) 0%,
    var(--sx-gold-lit) 26%,
    var(--sx-gold) 52%,
    rgba(201, 163, 78, 0) 100%);
  transform: scaleX(0); transform-origin: left center;
}

.spx-form { display: contents; }

/* -- phone: a sheet, hinged at the bottom ---------------------------------- */
@media (max-width: 680px) {
  /* Hinged at the bottom edge it came from. */
  dialog.spx[open] { align-items: flex-end; }
  dialog.spx > .spx-in {
    margin: 0;
    width: 100%;
    max-height: 92vh;
    max-height: 92dvh;
    border-radius: var(--sx-r) var(--sx-r) 0 0;
    box-shadow:
      0 0 0 1px rgba(15, 32, 56, .10),
      0 -18px 60px -18px rgba(10, 23, 40, .6);
  }
}

/* ============================================================================
   2 - THE OPENING
   ----------------------------------------------------------------------------
   It is one continuous gesture and it is over in two thirds of a second. The
   panel rises a few pixels and resolves; the gold seam draws itself across
   the top; the writing settles in reading order, head, then rail, then body,
   a tenth of a second apart, which is enough for the eye to follow the order
   without anybody waiting for it.

   Nothing scales. A dialog that zooms in is a dialog that draws attention to
   its own arrival rather than to what it is asking.
   ============================================================================ */
@keyframes sxRise {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
@keyframes sxSeam  { to { transform: scaleX(1); } }
@keyframes sxSettle {
  from { opacity: 0; transform: translate3d(0, 7px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

dialog.spx[open] > .spx-in          { animation: sxRise   .5s var(--sx-quick) both; }
dialog.spx[open] > .spx-in::before  { animation: sxSeam   .62s var(--sx-glide) .16s forwards; }
dialog.spx[open] .spx-head          { animation: sxSettle .46s var(--sx-glide) .10s both; }
dialog.spx[open] .spx-rail          { animation: sxSettle .46s var(--sx-glide) .17s both; }
dialog.spx[open] .spx-prog          { animation: sxSettle .46s var(--sx-glide) .22s both; }
dialog.spx[open] .spx-stage         { animation: sxSettle .46s var(--sx-glide) .27s both; }
dialog.spx[open] .spx-x             { animation: sxSettle .34s var(--sx-quick) .34s both; }

@media (max-width: 680px) {
  /* From the edge it came from. */
  @keyframes sxRise {
    from { opacity: 0; transform: translate3d(0, 34px, 0); }
    to   { opacity: 1; transform: translate3d(0, 0, 0); }
  }
}

/* ============================================================================
   3 - HEAD, AND THE WAY OUT
   ----------------------------------------------------------------------------
   The head does not scroll. On a phone it is the only thing telling somebody
   which of three questions they are on, and losing it two swipes in is how a
   form starts to feel like a maze.
   ============================================================================ */
.spx-body {
  display: flex;
  flex-direction: column;
  min-height: 0;          /* required, or the flex child refuses to shrink */
  overflow: hidden;
}

.spx-head {
  position: relative;
  flex: 0 0 auto;
  padding: 30px 34px 0 34px;
  max-width: 68ch;
}
.spx-eyebrow {
  margin: 0 0 9px;
  font-family: var(--sans);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .19em;
  text-transform: uppercase;
  color: var(--sx-gold);
}
.spx-t {
  margin: 0 0 9px;
  font-family: var(--wordmark);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.5rem, 3.2vw, 1.95rem);
  line-height: 1.1;
  letter-spacing: -.005em;
  color: var(--sx-navy);
}
.spx-pass > .spx-lead { display: none; }
.spx-lead {
  margin: 0;
  max-width: 60ch;
  font-family: var(--sans);
  font-size: .855rem;
  font-weight: 400;
  line-height: 1.66;
  letter-spacing: -.004em;
  color: var(--sx-ink-soft);
}

.spx-x {
  position: absolute; top: 16px; right: 16px; z-index: 4;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 0; border-radius: var(--sx-r);
  background: transparent;
  color: var(--sx-ink-faint);
  cursor: pointer;
  transition: color .2s var(--sx-quick), background-color .2s var(--sx-quick);
}
.spx-x i { font-size: 1.05rem; }
.spx-x:hover { color: var(--sx-navy); background: var(--sx-tint); }
.spx-x:focus-visible {
  outline: none;
  color: var(--sx-navy);
  box-shadow: 0 0 0 2px var(--sx-koning);
}

@media (max-width: 680px) {
  .spx-head { padding: 22px 20px 0 20px; }
  /* The standing explanation is six lines on a phone and it was taking a
     third of the sheet before the first question. The script moves it to the
     top of the first pass, where it is read once, in the same order it was
     written, and then scrolls away for good. What stays pinned is the
     eyebrow, the title and the wayfinding: about 130px, which leaves the
     stage the room it needs. */
  .spx-head > .spx-lead { display: none; }
  .spx-pass > .spx-lead {
    display: block;
    margin: 0 0 18px;
    padding: 0 0 16px;
    border-bottom: 1px solid var(--sx-line-soft);
  }
  .spx-x { top: 10px; right: 10px; }
  /* The grab handle. It is the affordance that says this panel came from the
     bottom edge and can go back to it. */
  .spx-head::before {
    content: "";
    position: absolute; top: -12px; left: 50%;
    width: 38px; height: 4px; margin-left: -19px;
    border-radius: 2px;
    background: var(--sx-line);
  }
  dialog.spx > .spx-in { padding-top: 10px; }
}

/* ============================================================================
   4 - THE RAIL, AND THE PROGRESS UNDER IT
   ----------------------------------------------------------------------------
   Three nodes and a line that fills between them. The dot of the step being
   worked on is the one live surface up here, so under rule 2 it is the only
   one that moves: a single ring breathes out from it and back, in the live
   tone, on a keyframe whose last frame is identical to its first.
   ============================================================================ */
.spx-rail {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin: 22px 34px 0;
  padding: 0 0 15px;
  list-style: none;
}
.spx-rail::before,
.spx-fill {
  content: "";
  position: absolute; left: 0; bottom: 0; height: 1px;
}
.spx-rail::before { right: 0; background: var(--sx-line); }
.spx-fill {
  width: 0;
  background: linear-gradient(90deg, var(--sx-navy), var(--sx-mid) 58%, var(--sx-koning));
  transition: width .62s var(--sx-glide);
}

.spx-node {
  position: relative;
  display: flex; align-items: center; gap: 8px;
  font-family: var(--sans);
  font-size: .715rem;
  font-weight: 500;
  letter-spacing: -.002em;
  color: var(--sx-ink-faint);
  opacity: .62;
  transition: color .3s var(--sx-quick), opacity .3s var(--sx-quick);
}
.spx-dot {
  position: relative;
  flex: 0 0 auto;
  width: 8px; height: 8px;
  border-radius: var(--sx-r);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--sx-line);
  transition: background-color .3s var(--sx-quick), box-shadow .3s var(--sx-quick);
}
.spx-node.is-done { opacity: 1; cursor: pointer; color: var(--sx-ink-soft); }
.spx-node.is-done .spx-dot {
  background: var(--sx-mid);
  box-shadow: inset 0 0 0 1px var(--sx-mid);
}
.spx-node.is-now { opacity: 1; color: var(--sx-navy); font-weight: 600; }
.spx-node.is-now .spx-dot {
  background: var(--sx-koning);
  box-shadow: inset 0 0 0 1px var(--sx-koning);
}
/* The breath. Out and back inside one keyframe: 0% and 100% are the same
   frame, so the loop has no seam to hide. */
.spx-node.is-now .spx-dot::after {
  content: "";
  position: absolute; inset: -4px;
  border-radius: var(--sx-r);
  box-shadow: 0 0 0 1px var(--sx-koning);
  animation: sxBreath 3.6s var(--sx-glide) infinite;
}
@keyframes sxBreath {
  0%   { opacity: 0;   transform: scale(.72); }
  46%  { opacity: .42; transform: scale(1.28); }
  100% { opacity: 0;   transform: scale(.72); }
}

@media (max-width: 680px) {
  .spx-rail { margin: 18px 20px 0; gap: 6px; }
  .spx-node { font-size: .64rem; gap: 6px; }
  /* Below this width three labels cannot sit on one line honestly, so only
     the live one keeps its words and the other two keep their dots. The
     information does not go: the sentence under the bar still says where
     the reader is. */
  .spx-node:not(.is-now) span:not(.spx-dot) { display: none; }
}

/* -- the sentence and the bar ---------------------------------------------- */
.spx-prog {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 12px;
  margin: 0 34px;
  font-family: var(--sans);
  font-size: .71rem;
  font-weight: 500;
  letter-spacing: -.002em;
  color: var(--sx-ink-soft);
}
.spx-prog-bar {
  position: relative;
  flex: 0 0 88px;
  height: 3px;
  border-radius: var(--sx-r);
  background: var(--sx-line-soft);
  overflow: hidden;
}
.spx-prog-bar b {
  position: absolute; inset: 0 auto 0 0;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--sx-mid), var(--sx-koning));
  transition: width .62s var(--sx-glide);
}
@media (max-width: 680px) { .spx-prog { margin: 0 20px; } }

/* ============================================================================
   5 - THE STAGE
   ----------------------------------------------------------------------------
   This is the only part of the panel that scrolls, and it is the only part
   that should. A pass leaves to the left and the next arrives from the right,
   which is the direction the rail says the reader is travelling; going back
   reverses it. Both are a clip and an opacity, never a slide of the whole
   surface, so nothing overshoots the panel edge on a narrow screen.
   ============================================================================ */
.spx-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 20px 34px 4px;
  scrollbar-width: thin;
  scrollbar-color: var(--sx-line) transparent;

  /* THE EDGE THAT SAYS THERE IS MORE.
     A pinned head and a pinned navigation give a scrolling middle two hard
     horizontal lines, and content cut off exactly at one of them reads as a
     layout fault rather than as a page continuing. So the stage fades into
     its own edges - but only on the edge that actually has something beyond
     it, which is why the two classes are toggled by the script rather than
     the mask being on all the time. A permanent fade at the top of a form
     that is already scrolled to the top is just a greyed-out first line.

     mask-composite intersects the two gradients so both ends can fade at
     once without one cancelling the other. */
  --sx-mask-top: 0px;
  --sx-mask-bot: 0px;
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0, #000 var(--sx-mask-top)),
    linear-gradient(to top, transparent 0, #000 var(--sx-mask-bot));
  mask-image:
    linear-gradient(to bottom, transparent 0, #000 var(--sx-mask-top)),
    linear-gradient(to top, transparent 0, #000 var(--sx-mask-bot));
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  transition: --sx-mask-top .3s var(--sx-quick), --sx-mask-bot .3s var(--sx-quick);
}
@property --sx-mask-top { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --sx-mask-bot { syntax: '<length>'; inherits: false; initial-value: 0px; }
.spx-stage.has-above { --sx-mask-top: 26px; }
.spx-stage.has-below { --sx-mask-bot: 30px; }
.spx-stage::-webkit-scrollbar { width: 10px; }
.spx-stage::-webkit-scrollbar-track { background: transparent; }
.spx-stage::-webkit-scrollbar-thumb {
  background: var(--sx-line);
  border: 3px solid var(--sx-paper);
  border-radius: 6px;
}
@media (max-width: 680px) { .spx-stage { padding: 16px 20px 4px; } }

.spx-pass { display: none; }
.spx-pass.is-on {
  display: block;
  animation: sxPassIn .46s var(--sx-quick) both;
}
@keyframes sxPassIn {
  from { opacity: 0; transform: translate3d(14px, 0, 0); clip-path: inset(0 0 0 6%); }
  to   { opacity: 1; transform: translate3d(0, 0, 0);    clip-path: inset(0 0 0 0); }
}
.spx-stage.is-back .spx-pass.is-on { animation-name: sxPassBack; }
@keyframes sxPassBack {
  from { opacity: 0; transform: translate3d(-14px, 0, 0); clip-path: inset(0 6% 0 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0);     clip-path: inset(0 0 0 0); }
}

/* ============================================================================
   6 - THE FIGURE
   ----------------------------------------------------------------------------
   THE FIELD STAYS EMPTY WHILE THE SLIDE IS MOVING. This is the centre of the
   whole control and it is worth being exact about. Dragging the handle does
   NOT type into the box: it moves a ghosted number that sits behind the
   caret, so what the reader sees is a suggestion the panel is making, not a
   figure the panel has entered on their behalf. The moment they type, their
   own number is there in solid ink and the ghost is gone. Nobody has to
   delete a value they never chose.

   The ghost is a placeholder rather than a second element, which means it
   disappears on the same frame the first digit lands, with no code and no
   chance of the two being on screen together.

   AND THERE IS NO PRICE HERE. Not on the label, not against any activity,
   not in the sentence under the slide. The figure is the reader's own, shown
   once, quietly.
   ============================================================================ */
.spx-in .bf-amount {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px 30px;
  margin: 0 0 22px;

  /* NAMED GRID AREAS HAVE TO BE CANCELLED, NOT JUST OUT-SPECIFIED.
     lffo-bridge.css lays this block out with grid-template-areas
     'legend legend' / 'field hint' / 'note note' and puts each child on a
     named area. Redeclaring grid-template-COLUMNS here does not remove those
     names: the children keep asking for a line called `field`, the browser
     invents an implicit one, and the field and the hint end up stacked on top
     of each other with the field's white box hiding half the sentence. Which
     is exactly what happened. The template is cleared here and every child is
     put back on auto below, so placement is decided in one file. */
  grid-template-areas: none;
}
.spx-in .bf-amount > * { grid-area: auto; }
.spx-in .bf-legend {
  margin: 0;
  font-family: var(--sans);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: -.004em;
  color: var(--sx-navy);
}
.spx-in .bf-hint {
  margin: 0 0 12px;
  max-width: 52ch;
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: -.004em;
  color: var(--sx-ink-soft);
}

.spx-in .bf-field {
  position: relative;
  display: inline-flex; align-items: baseline; gap: .3em;
  width: 100%;
  max-width: 300px;
  padding: 11px 16px;
  border-radius: var(--sx-r);
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--sx-line);
  transition: box-shadow .26s var(--sx-quick);
}
.spx-in .bf-field:focus-within {
  box-shadow:
    inset 0 0 0 1px var(--sx-mid),
    0 0 0 3px rgba(46, 83, 125, .15);
}
.spx-in .bf-cur {
  font-family: var(--sans);
  font-size: 1.02rem;
  font-weight: 500;
  color: var(--sx-ink-faint);
  transition: color .26s var(--sx-quick);
}
.spx-in .bf-field:focus-within .bf-cur { color: var(--sx-mid); }

#spAmount {
  flex: 1 1 auto;
  min-width: 0;
  border: 0; outline: none; background: none;
  font-family: var(--sans);
  font-size: 1.18rem;
  font-weight: 600;
  letter-spacing: .004em;
  font-variant-numeric: tabular-nums;
  color: var(--sx-navy);
}
/* The spinner is an invitation to nudge a number by one, and this number
   moves in hundreds. It also plants a browser control in the middle of a
   panel that has none anywhere else. */
#spAmount::-webkit-outer-spin-button,
#spAmount::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
#spAmount { -moz-appearance: textfield; appearance: textfield; }

/* One selector per rule. A vendor pseudo-element inside a selector LIST
   invalidates the entire rule in any browser that does not know it, which is
   how the ghost lost its colour the first time. */
#spAmount::placeholder {
  color: #8fa0ba;
  color: color-mix(in srgb, var(--sx-lead) 46%, #ffffff);
  opacity: 1;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: color .3s var(--sx-quick);
}
#spAmount::-webkit-input-placeholder {
  color: #8fa0ba;
  color: color-mix(in srgb, var(--sx-lead) 46%, #ffffff);
  opacity: 1;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: color .3s var(--sx-quick);
}

.spx-in .bf-per {
  font-family: var(--sans);
  font-size: .76rem;
  font-weight: 500;
  color: var(--sx-ink-faint);
  white-space: nowrap;
}
.spx-in .bf-note {
  margin: 8px 0 0;
  min-height: 1.2em;
  font-family: var(--sans);
  font-size: .74rem;
  line-height: 1.5;
  color: var(--sx-ink-soft);
}

/* The panel is 760px wide whatever the window is, so this breakpoint is about
   the panel and not the screen. Below it the block is one column and reads
   straight down; above it the field and the line that comments on it sit
   side by side, which is the only pairing in here that earns two columns. */
@media (min-width: 860px) {
  .spx-in .bf-amount {
    grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
    align-items: start;
  }
  /* Rows are named explicitly, not left to auto-placement. The note asks for
     column 2, and auto-placement will drop it into the first row where
     column 2 happens to be free - which was the hint's row, one line above
     where it belongs. Four fixed rows and there is nothing left to guess. */
  .spx-in .bf-amount > .bf-legend { grid-column: 1 / -1; grid-row: 1; }
  .spx-in .bf-amount > .bf-hint   { grid-column: 1 / -1; grid-row: 2; margin: 0 0 12px; max-width: 62ch; }
  .spx-in .bf-amount > .bf-field  { grid-column: 1; grid-row: 3; justify-self: start; }
  .spx-in .bf-amount > .bf-note   { grid-column: 2; grid-row: 3; align-self: center; margin: 0; }
  .spx-in .bf-amount > .spx-slide { grid-column: 1 / -1; grid-row: 4; }
}

/* ============================================================================
   7 - THE SLIDE
   ----------------------------------------------------------------------------
   THE HANDLE NEVER RUNS OUT OF ROAD, AND IT NEVER STALLS EITHER.

   The track used to spend its first sixty per cent between the floor and
   8,000 and the remaining forty covering everything above it. Two things
   were wrong with that. The reader saw the handle travel more than half the
   bar and the figure stop climbing, which reads as a ceiling at 8,000 - and
   there is no ceiling, the amount is whatever a firm decides. Then, past the
   knee, the same finger movement started adding tens of thousands at a time,
   which reads as broken. A hinge in the middle of a control is felt even
   when it cannot be seen.

   There is no hinge now. The figure is read off a single smooth curve,
   v = floor * (top/floor)^(p^k), with k tuned so the six points where
   something opens spread across the first half of the travel and the climb
   above them stays continuous all the way to the end. Every millimetre of the
   bar does something, the rate never jumps, and no number on it is a limit.

   The notches ARE the unlock points, placed through the same curve the handle
   rides, so they sit exactly under it at every width. They light as they are
   passed. Not one figure is printed against any of them.
   ============================================================================ */
.spx-slide { margin: 18px 0 0; }
.spx-slide-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; row-gap: 3px;
  margin: 0 0 9px;
}
.spx-slide-l {
  flex: 0 0 auto;
  font-family: var(--sans);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--sx-ink-faint);
}
.spx-openct {
  flex: 1 1 auto; min-width: 0;
  text-align: right;
  font-family: var(--sans);
  font-size: .745rem;
  font-weight: 500;
  letter-spacing: -.004em;
  color: var(--sx-mid);
  transition: color .3s var(--sx-quick);
}
@media (max-width: 680px) { .spx-openct { text-align: left; } }

.spx-track { position: relative; height: 30px; touch-action: pan-y; }

.spx-groove {
  position: absolute; left: 0; right: 0; top: 13px; height: 4px;
  border-radius: var(--sx-r);
  background: color-mix(in srgb, var(--sx-navy) 10%, #ffffff);
  box-shadow: inset 0 1px 2px rgba(15, 32, 56, .07);
}

.spx-fillbar {
  position: absolute; left: 0; top: 13px; height: 4px; width: 0;
  border-radius: var(--sx-r);

  /* The colour is a plain background-color because every browser animates
     that natively and smoothly. An earlier version built the gradient from
     two registered custom properties so the stops would interpolate; it
     computed to background-image: none, and a bar that does not paint at all
     is worse than a bar that steps. The script writes the colour; the sheen
     and the drift are laid over it here. */
  background-color: var(--sx-live);
  background-image:
    /* 190px, not 72. At 72 a bar 700px wide carries ten bands and you count
       them: that is stripes travelling, not light drifting. Three across the
       bar, at .09 instead of .16, reads as a lift in the tone rather than a
       mark laid on it. The tile and the translate stay equal, so it is still
       seamless by construction. */
    repeating-linear-gradient(108deg,
      rgba(255,255,255,0)    0px,
      rgba(255,255,255,0)    58px,
      rgba(255,255,255,.09)  95px,
      rgba(255,255,255,0)    132px,
      rgba(255,255,255,0)    190px),
    linear-gradient(90deg, rgba(0,0,0,.26) 0%, rgba(0,0,0,0) 32%),
    linear-gradient(270deg, rgba(255,255,255,.34) 0%, rgba(255,255,255,0) 24%);
  background-repeat: repeat, no-repeat, no-repeat;
  background-size: 190px 100%, 100% 100%, 100% 100%;

  /* THE DRIFT. Rule 2: this is the surface the person is driving, so this is
     the surface that moves. Rule 3: the tile is exactly 72px and the
     animation translates it by exactly 72px, so the frame after the last is
     pixel-identical to the first and there is no reset to see. */
  animation: sxDrift 7s linear infinite;

  transition:
    width .16s var(--sx-quick),
    background-color .3s var(--sx-quick),
    box-shadow .3s var(--sx-quick);
}
@keyframes sxDrift {
  from { background-position: 0 0, 0 0, 100% 0; }
  to   { background-position: 190px 0, 0 0, 100% 0; }
}
/* The leading edge, so the eye has a definite place to read the value from.
   It wears the lighter of the two live tones rather than a colour of its own. */
.spx-fillbar::after {
  content: "";
  position: absolute; right: 0; top: -3px; bottom: -3px; width: 2px;
  border-radius: var(--sx-r);
  background: var(--sx-lead);
  opacity: .92;
}
/* While the handle is actually held, the width stops easing and sits exactly
   under the pointer. Any easing at all here reads as lag rather than as
   smoothness. The colour keeps its glide, because that is the part that
   should feel unhurried. The class is set by the script on pointerdown: the
   range input is the last child of the track and no sibling combinator can
   reach backwards to the bar. */
.spx-track.is-dragging .spx-fillbar { transition-duration: 0s, .3s, .3s; }

.spx-notches { position: absolute; left: 0; right: 0; top: 9px; height: 12px; pointer-events: none; }
.spx-notches i {
  position: absolute; top: 3px;
  width: 1px; height: 6px;
  margin-left: -.5px;
  background: color-mix(in srgb, var(--sx-navy) 26%, #ffffff);
  transition: background-color .34s var(--sx-quick), height .34s var(--sx-glide), top .34s var(--sx-glide);
}
.spx-notches i.is-lit {
  top: 0; height: 12px;
  background: rgba(255, 255, 255, .62);
}

/* -- the handle ------------------------------------------------------------ */
.spx-range {
  position: absolute; inset: 0;
  width: 100%; height: 30px; margin: 0;
  -webkit-appearance: none; appearance: none;
  background: transparent;
  cursor: grab;
}
.spx-range:active { cursor: grabbing; }
.spx-range::-webkit-slider-runnable-track { height: 30px; background: transparent; }
.spx-range::-moz-range-track { height: 30px; background: transparent; }
.spx-range:focus-visible { outline: none; }

.spx-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 14px; height: 26px; margin-top: 2px;
  border: 0; border-radius: var(--sx-r);
  background:
    linear-gradient(180deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,0) 48%),
    var(--sx-navy);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.3),
    0 0 0 2px var(--sx-lead),
    0 8px 20px -8px rgba(15,32,56,.7);
  transition: box-shadow .3s var(--sx-quick), transform .24s cubic-bezier(.34,1.28,.5,1);
}
.spx-range::-moz-range-thumb {
  width: 14px; height: 26px;
  border: 0; border-radius: var(--sx-r);
  background: var(--sx-navy);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.3),
    0 0 0 2px var(--sx-lead),
    0 8px 20px -8px rgba(15,32,56,.7);
  transition: box-shadow .3s var(--sx-quick), transform .24s cubic-bezier(.34,1.28,.5,1);
}
.spx-range:hover::-webkit-slider-thumb  { transform: scaleY(1.08); }
.spx-range:hover::-moz-range-thumb      { transform: scaleY(1.08); }
.spx-range:active::-webkit-slider-thumb {
  transform: scaleY(1.14);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.42),
    0 0 0 2px var(--sx-lead),
    0 0 0 8px color-mix(in srgb, var(--sx-lead) 20%, transparent),
    0 10px 24px -8px rgba(15,32,56,.8);
}
.spx-range:active::-moz-range-thumb { transform: scaleY(1.14); }
.spx-range:focus-visible::-webkit-slider-thumb {
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.42),
    0 0 0 2px var(--sx-lead),
    0 0 0 6px color-mix(in srgb, var(--sx-lead) 26%, transparent);
}

/* A thumb 14px wide is a mouse target. On a touch screen the whole track
   grows so the handle clears the 44px the platform guidelines ask for,
   without the bar itself getting any heavier. */
@media (pointer: coarse) {
  .spx-track { height: 44px; }
  .spx-groove, .spx-fillbar { top: 20px; }
  .spx-notches { top: 16px; }
  .spx-range { height: 44px; }
  .spx-range::-webkit-slider-runnable-track { height: 44px; }
  .spx-range::-moz-range-track { height: 44px; }
  .spx-range::-webkit-slider-thumb { height: 34px; width: 16px; margin-top: 5px; }
  .spx-range::-moz-range-thumb { height: 34px; width: 16px; }
}

/* ============================================================================
   8 - WHAT A SPONSOR WOULD LIKE TO FUND
   ----------------------------------------------------------------------------
   Six activities, no price against any of them. A line opens when the named
   figure reaches it and is shut, with a padlock and a sentence, when it does
   not. The shut state is deliberately legible rather than hidden: knowing
   that something exists further up is the reason to move the slide.

   Rule 2 again: a CHOSEN activity is a live surface, so a chosen one carries
   the drift and the others do not.
   ============================================================================ */
.spx-in .bf-set { margin: 22px 0 20px; border: 0; padding: 0; }
.spx-in .bf-set .bf-legend { display: block; margin: 0 0 4px; }

/* TWO COLUMNS INSIDE THE PANEL, NOT THREE. lffo-bridge.css lays this list out
   three across, which is right on a full-width page section and wrong in a
   760px dialog: the descriptions drop to four and five words a line and the
   follow-up question that opens under a chosen card is squeezed into a third
   of the width. Two columns give the descriptions a readable measure and
   still fit the six lines in three rows. One column below 560px. */
.spx-in .bf-grid {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
}
@media (max-width: 560px) {
  .spx-in .bf-grid { grid-template-columns: 1fr; }
}

.spx-in .bf-item {
  position: relative;
  border-radius: var(--sx-r);
  overflow: hidden;
  transition: opacity .34s var(--sx-quick);
}
.spx-in .bf-opt {
  position: relative;
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  align-items: start;
  gap: 12px;
  padding: 12px 14px;
  cursor: pointer;
  border-radius: var(--sx-r);
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--sx-line);
  transition: box-shadow .28s var(--sx-quick), background-color .28s var(--sx-quick);
}
.spx-in .bf-opt:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sx-mid) 42%, transparent); }
.spx-in .bf-in { position: absolute; opacity: 0; width: 0; height: 0; }

.spx-in .bf-tick,
.spx-in .bf-lock {
  grid-column: 1;
  width: 18px; height: 18px;
  margin-top: 1px;
  display: grid; place-items: center;
  border-radius: var(--sx-r);
}
.spx-in .bf-tick {
  box-shadow: inset 0 0 0 1px var(--sx-line);
  transition: background-color .26s var(--sx-quick), box-shadow .26s var(--sx-quick);
}
.spx-in .bf-tick svg { width: 12px; height: 12px; fill: none; stroke: #fff; stroke-width: 2; stroke-linecap: square; }
.spx-in .bf-tick svg path { stroke-dasharray: 14; stroke-dashoffset: 14; transition: stroke-dashoffset .3s var(--sx-quick); }
.spx-in .bf-tick svg path:last-child { transition-delay: .06s; }

.spx-in .bf-in:checked ~ .bf-tick {
  background: var(--sx-mid);
  box-shadow: inset 0 0 0 1px var(--sx-mid);
}
.spx-in .bf-in:checked ~ .bf-tick svg path { stroke-dashoffset: 0; }
.spx-in .bf-in:focus-visible ~ .bf-tick { box-shadow: inset 0 0 0 1px var(--sx-koning), 0 0 0 3px rgba(58,107,214,.24); }

.spx-in .bf-lock { display: none; color: var(--sx-ink-faint); }
.spx-in .bf-lock svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.4; }

.spx-in .bf-txt { grid-column: 2; min-width: 0; }
.spx-in .bf-txt b {
  display: block;
  font-family: var(--sans);
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: -.006em;
  color: var(--sx-navy);
}
.spx-in .bf-txt i {
  display: block;
  margin-top: 2px;
  font-style: normal;
  font-family: var(--sans);
  font-size: .755rem;
  line-height: 1.5;
  letter-spacing: -.004em;
  color: var(--sx-ink-soft);
}
.spx-in .bf-lockmsg {
  display: none;
  margin-top: 5px;
  font-style: normal;
  font-family: var(--sans);
  font-size: .715rem;
  font-weight: 500;
  letter-spacing: -.002em;
  color: var(--sx-ink-faint);
}

/* -- chosen: the one live state in this list ------------------------------- */
.spx-in .bf-item:has(.bf-in:checked) .bf-opt {
  background: color-mix(in srgb, var(--sx-mid) 4%, #ffffff);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sx-mid) 46%, transparent);
}
/* The drift, on the same 72px tile and the same one-tile translation as the
   fill bar, so the two read as the same material. */
.spx-in .bf-item:has(.bf-in:checked)::before {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  border-radius: var(--sx-r);
  /* Widened with the bar's own drift, for the same reason and to keep the
     two in step: two different band widths crossing the same panel is a
     moire, not a texture. */
  background-image: repeating-linear-gradient(108deg,
    rgba(46,83,125,0)    0px,
    rgba(46,83,125,0)    62px,
    rgba(46,83,125,.05)  95px,
    rgba(46,83,125,0)    128px,
    rgba(46,83,125,0)    190px);
  background-size: 190px 100%;
  animation: sxDriftSoft 11.2s linear infinite;
}
@keyframes sxDriftSoft {
  from { background-position: 0 0; }
  to   { background-position: 190px 0; }
}
/* A hairline in the live tone down the leading edge of a chosen card. */
.spx-in .bf-item:has(.bf-in:checked)::after {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0; width: 2px; z-index: 2;
  background: linear-gradient(180deg, var(--sx-koning), var(--sx-mid));
  transform: scaleY(0); transform-origin: top center;
  animation: sxEdge .42s var(--sx-glide) forwards;
}
@keyframes sxEdge { to { transform: scaleY(1); } }
.spx-in .bf-opt { position: relative; z-index: 1; background-clip: padding-box; }

/* -- shut: present, explained, and not pretending to be available ---------- */
.spx-in .bf-item.is-shut .bf-opt { cursor: default; background: color-mix(in srgb, var(--sx-navy) 2.5%, #ffffff); }
.spx-in .bf-item.is-shut .bf-tick { display: none; }
.spx-in .bf-item.is-shut .bf-lock { display: grid; }
.spx-in .bf-item.is-shut .bf-txt b { color: var(--sx-ink-soft); }
.spx-in .bf-item.is-shut .bf-txt i { opacity: .72; }
.spx-in .bf-item.is-shut .bf-lockmsg { display: block; }
.spx-in .bf-item.is-shut:hover .bf-opt { box-shadow: inset 0 0 0 1px var(--sx-line); }

/* -- the follow-up question a chosen line asks ----------------------------- */
.spx-in .bf-pick[hidden] { display: none; }
.spx-in .bf-pick {
  padding: 11px 14px 13px 44px;
  background: color-mix(in srgb, var(--sx-mid) 3%, #ffffff);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sx-mid) 26%, transparent);
  border-top: 0;
  border-radius: 0 0 var(--sx-r) var(--sx-r);
  margin-top: -1px;
  animation: sxPickIn .36s var(--sx-quick) both;
}
@keyframes sxPickIn {
  from { opacity: 0; transform: translate3d(0, -5px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.spx-in .bf-pick-l {
  margin: 0 0 7px;
  font-family: var(--sans);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--sx-ink-faint);
}
.spx-in .bf-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.spx-in .bf-chip { position: relative; cursor: pointer; }
.spx-in .bf-chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.spx-in .bf-chip span {
  display: inline-block;
  padding: 6px 12px;
  border-radius: var(--sx-r);
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--sx-line);
  font-family: var(--sans);
  font-size: .74rem;
  font-weight: 500;
  letter-spacing: -.004em;
  color: var(--sx-ink-soft);
  transition: color .24s var(--sx-quick), background-color .24s var(--sx-quick), box-shadow .24s var(--sx-quick);
}
.spx-in .bf-chip:hover span { color: var(--sx-navy); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sx-mid) 40%, transparent); }
.spx-in .bf-chip input:checked + span {
  color: #fff;
  background: var(--sx-mid);
  box-shadow: inset 0 0 0 1px var(--sx-mid);
}
.spx-in .bf-chip input:focus-visible + span { box-shadow: inset 0 0 0 1px var(--sx-koning), 0 0 0 3px rgba(58,107,214,.24); }

/* ============================================================================
   9 - WHO WE WILL BE WRITING TO
   ============================================================================ */
.spx-grid {
  display: grid;
  gap: 15px 20px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 14px;
}
.spx-w2 { grid-column: 1 / -1; }
@media (max-width: 680px) {
  .spx-grid { grid-template-columns: 1fr; gap: 13px; }
  .spx-w2 { grid-column: auto; }
}

.spx-field { display: block; position: relative; }
.spx-lab {
  display: block;
  margin: 0 0 5px;
  font-family: var(--sans);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--sx-ink-faint);
}
.spx-lab em {
  font-style: normal;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: none;
  opacity: .8;
}
.spx-field input,
.spx-field textarea {
  width: 100%;
  padding: 10px 0 9px;
  border: 0;
  border-bottom: 1px solid var(--sx-line);
  border-radius: 0;
  background: none;
  font-family: var(--sans);
  /* 16px exactly. Below it, iOS Safari zooms the page on focus and the reader
     is left in a form they then have to pinch their way back out of. */
  font-size: 16px;
  font-weight: 400;
  letter-spacing: -.004em;
  color: var(--sx-navy);
}
@media (min-width: 681px) { .spx-field input, .spx-field textarea { font-size: .92rem; } }
.spx-field textarea { resize: vertical; min-height: 70px; line-height: 1.55; }
.spx-field input:focus, .spx-field textarea:focus { outline: none; }
/* The underline arrives left to right and leaves left to right. The anchor is
   swapped rather than the animation reversed, and transform-origin is kept
   OUT of the transition so it flips in a single frame at zero width, where
   the flip cannot be seen. */
.spx-field::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, var(--sx-mid), var(--sx-koning));
  transform: scaleX(0); transform-origin: right center;
  transition: transform .42s var(--sx-glide);
}
.spx-field:focus-within::after { transform: scaleX(1); transform-origin: left center; }

.ap-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ============================================================================
   10 - READ IT BACK
   ============================================================================ */
.spx-read { margin: 14px 0 20px; border-top: 1px solid var(--sx-line-soft); }
.spx-read-r {
  display: grid;
  grid-template-columns: minmax(0, 150px) minmax(0, 1fr);
  gap: 4px 20px;
  padding: 10px 0;
  border-bottom: 1px solid var(--sx-line-soft);
}
.spx-read-r dt {
  margin: 0;
  font-family: var(--sans);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--sx-ink-faint);
}
.spx-read-r dd {
  margin: 0;
  font-family: var(--sans);
  font-size: .84rem;
  line-height: 1.55;
  letter-spacing: -.004em;
  color: var(--sx-navy);
}
@media (max-width: 600px) { .spx-read-r { grid-template-columns: 1fr; gap: 2px; } }

/* -- the undertaking ------------------------------------------------------- */
.spx-in .bf-settle { margin-top: 18px; }
.spx-in .bf-policy { display: grid; grid-template-columns: 18px minmax(0,1fr); gap: 12px; }
.spx-in .bf-links { display: block; margin-top: 6px; font-size: .72rem; color: var(--sx-ink-faint); }
.spx-in .bf-links a { color: var(--sx-mid); text-decoration: underline; text-underline-offset: 2px; }
.spx-in .bf-links a:hover { color: var(--sx-koning); }

.spx-in .bf-err,
.spx-err {
  margin: 12px 0 0;
  padding: 9px 12px;
  border-radius: var(--sx-r);
  background: rgba(168, 46, 46, .06);
  box-shadow: inset 0 0 0 1px rgba(168, 46, 46, .2);
  font-family: var(--sans);
  font-size: .76rem;
  font-weight: 500;
  letter-spacing: -.004em;
  color: #8f2f2f;
  animation: sxErr .32s var(--sx-quick) both;
}
@keyframes sxErr {
  from { opacity: 0; transform: translate3d(0, -4px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.spx-in .bf-err[hidden], .spx-err[hidden] { display: none !important; }

/* -- the ledger line ------------------------------------------------------- */
/* Not a price tag and not a receipt: one line, in the reader's own figure,
   set as a quiet ledger entry so it can be checked and then forgotten. */
.spx-in .bf-sum { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--sx-line-soft); }
.spx-in .bf-sum-rows { margin: 0; }
.spx-in .bf-sum-row { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.spx-in .bf-sum-row dt {
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: -.004em;
  color: var(--sx-ink-soft);
}
.spx-in .bf-sum-row dd {
  margin: 0;
  font-family: var(--sans);
  font-size: .95rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.006em;
  color: var(--sx-navy);
}
.spx-in .bf-sum-note {
  margin: 8px 0 0;
  font-family: var(--sans);
  font-size: .72rem;
  line-height: 1.55;
  color: var(--sx-ink-faint);
}

/* ============================================================================
   11 - THE NAVIGATION AND THE FOOT
   ----------------------------------------------------------------------------
   The navigation does not scroll away. On a phone it sits above the home
   indicator with the safe-area inset accounted for, so Carry on is always
   exactly where the thumb already is.
   ============================================================================ */
.spx-nav {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px 34px calc(14px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--sx-line-soft);
  background: rgba(255, 255, 255, .88);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.spx-nav [hidden] { display: none !important; }
@media (max-width: 680px) {
  .spx-nav { padding: 12px 20px calc(12px + env(safe-area-inset-bottom, 0px)); gap: 8px; }
  /* On the first pass there is no Back, and a lone button hugging the right
     edge of a phone leaves two thirds of the bar as dead space and puts the
     only target where a right thumb reaches but a left one does not. With
     nothing beside it, Carry on takes the width. With Back beside it they
     share, and Back stays narrow because going back is the rarer act. */
  .spx-back { flex: 0 0 auto; padding: 12px 16px; }
  .spx-next { flex: 1 1 auto; justify-content: center; padding: 13px 20px; }
}

.spx-back, .spx-next {
  display: inline-flex; align-items: center; gap: .5em;
  padding: 11px 20px;
  border: 0; border-radius: var(--sx-r);
  font-family: var(--sans);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: -.004em;
  cursor: pointer;
  transition:
    background-color .26s var(--sx-quick),
    color .26s var(--sx-quick),
    box-shadow .26s var(--sx-quick),
    transform .2s var(--sx-quick);
}
.spx-back {
  background: none;
  color: var(--sx-ink-soft);
  box-shadow: inset 0 0 0 1px var(--sx-line);
}
.spx-back:hover { color: var(--sx-navy); box-shadow: inset 0 0 0 1px var(--sx-mid); }

.spx-next {
  margin-left: auto;
  color: #fff;
  background: var(--sx-navy);
  background-image: linear-gradient(120deg, var(--sx-navy) 0%, var(--sx-mid) 100%);
  box-shadow: 0 6px 18px -8px rgba(15, 32, 56, .7);
}
.spx-next:hover {
  background-image: linear-gradient(120deg, var(--sx-mid) 0%, var(--sx-koning) 100%);
  box-shadow: 0 10px 24px -8px rgba(46, 83, 125, .68);
}
.spx-back:active, .spx-next:active { transform: translateY(1px); }
.spx-back:focus-visible, .spx-next:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--sx-koning);
}
.spx-next i { transition: transform .28s var(--sx-glide); }
.spx-next:hover i { transform: translateX(3px); }

/* While the parcel is in flight the button says so rather than going dead. */
.ap-busy .spx-next { pointer-events: none; opacity: .72; }
.ap-busy .spx-next i { animation: sxWait 1.1s linear infinite; }
@keyframes sxWait {
  0%   { opacity: .3; transform: translateX(0); }
  50%  { opacity: 1;  transform: translateX(4px); }
  100% { opacity: .3; transform: translateX(0); }
}

.spx-foot {
  margin: 16px 0 0;
  padding: 14px 0 2px;
  border-top: 1px solid var(--sx-line-soft);
  font-family: var(--sans);
  font-size: .715rem;
  line-height: 1.6;
  letter-spacing: -.002em;
  color: var(--sx-ink-faint);
}

/* ============================================================================
   12 - THE SEAL
   ----------------------------------------------------------------------------
   Gold, because this is a mark of the association and not a step in a
   process. It draws itself once: ring, then tick.
   ============================================================================ */
.spx-done { text-align: center; padding: 34px 34px 30px; }
.spx-done .spx-t { text-align: center; }
.spx-done .spx-lead { margin: 0 auto 20px; max-width: 46ch; }
.spx-seal { display: block; width: 68px; height: 68px; margin: 0 auto 20px; }
.spx-seal svg { width: 100%; height: 100%; fill: none; }
.spx-ring { stroke: var(--sx-gold); stroke-width: 1.6; stroke-dasharray: 170; stroke-dashoffset: 170; }
.spx-tick { stroke: var(--sx-gold-lit); stroke-width: 2.6; stroke-linecap: square; stroke-dasharray: 40; stroke-dashoffset: 40; }
@keyframes sxRing { to { stroke-dashoffset: 0; } }
@keyframes sxTick { to { stroke-dashoffset: 0; } }
.spx-done.is-in .spx-ring { animation: sxRing .82s var(--sx-glide) both; }
.spx-done.is-in .spx-tick { animation: sxTick .4s var(--sx-glide) .56s both; }
.spx-ref { margin: 0 0 18px; font-family: var(--sans); font-size: .78rem; color: var(--sx-ink-soft); }
.spx-ref b {
  font-family: var(--mono);
  font-size: .82rem;
  font-weight: 500;
  letter-spacing: .06em;
  color: var(--sx-navy);
}
.spx-quiet {
  border: 0; background: none; cursor: pointer;
  padding: .85em 1.4em;
  font-family: var(--sans);
  font-size: .8rem;
  font-weight: 500;
  color: var(--sx-ink-soft);
  transition: color .24s var(--sx-quick);
}
.spx-quiet:hover { color: var(--sx-navy); }
@media (max-width: 680px) { .spx-done { padding: 28px 20px 26px; } }

/* ============================================================================
   13 - THE TRIGGER
   ============================================================================ */
button.link-cta,
button[data-spx-open] {
  border: 0; background: none; cursor: pointer;
  font-family: var(--sans);
  font: inherit;
}

/* ============================================================================
   14 - REDUCED MOTION
   ----------------------------------------------------------------------------
   Everything ambient stops. Nothing that carries meaning is lost with it:
   the live step is still the bold one, a chosen card still has its edge and
   its tint, the fill bar still has its width and its colour. Only the
   movement goes.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
  dialog.spx[open]::backdrop,
  dialog.spx[open] > .spx-in,
  dialog.spx[open] > .spx-in::before,
  dialog.spx[open] .spx-head,
  dialog.spx[open] .spx-rail,
  dialog.spx[open] .spx-prog,
  dialog.spx[open] .spx-stage,
  dialog.spx[open] .spx-x,
  .spx-pass.is-on,
  .spx-node.is-now .spx-dot::after,
  .spx-fillbar,
  .spx-in .bf-item:has(.bf-in:checked)::before,
  .spx-in .bf-item:has(.bf-in:checked)::after,
  .spx-in .bf-pick,
  .spx-in .bf-err, .spx-err,
  .ap-busy .spx-next i,
  .spx-done.is-in .spx-ring,
  .spx-done.is-in .spx-tick { animation: none; }

  dialog.spx[open]::backdrop { opacity: 1; }
  dialog.spx[open] > .spx-in::before { transform: scaleX(1); }
  .spx-in .bf-item:has(.bf-in:checked)::after { transform: scaleY(1); }
  .spx-done .spx-ring, .spx-done .spx-tick { stroke-dashoffset: 0; }

  .spx-fill, .spx-fillbar, .spx-prog-bar b, .spx-field::after,
  .spx-back, .spx-next, .spx-notches i, .spx-in .bf-tick,
  .spx-in .bf-chip span, #spAmount::placeholder { transition: none; }
}

/* ============================================================================
   15 - THE SAME LOGIC, ON THE PAGE BEHIND THE PANEL
   ----------------------------------------------------------------------------
   The three blues and the ambient rule do not stop at the dialog's edge. The
   cards on the Partners and Membership pages that lead INTO this application
   are the ones that get the treatment, and nothing else does, because that is
   what makes the movement mean something rather than decorate everything.

   Rule 2, restated for a page rather than a control: a surface a reader is
   ADDRESSING is live. On these pages that is the card under the pointer or
   the keyboard focus, and the tier the page has been deep-linked to. A card
   sitting in a row of eight is not being addressed and does not move.

   Rule 3 still holds. Each loop below either translates a repeating tile by
   exactly one tile width, or travels out and back inside a single keyframe so
   0% and 100% are the same frame. No fades, no resets, no seams.
   ============================================================================ */

.bfx-grid,
.tiers,
.partner-logos,
.inst-register {
  --sx-navy:   #0f2038;
  --sx-mid:    #2e537d;
  --sx-koning: #3a6bd6;
  --sx-quick:  cubic-bezier(.32, .72, 0, 1);
  --sx-glide:  cubic-bezier(.22, 1, .36, 1);
}

/* ---------------------------------------------------------------------------
   THE THREE PLATES THAT EXPLAIN SPONSORSHIP
   The wash follows the pointer. Two custom properties carry its position, so
   the gradient itself never re-renders from scratch; it is one paint that
   moves. Registered with @property below so the browser interpolates the
   percentages instead of snapping between them.
   --------------------------------------------------------------------------- */
@property --sx-mx { syntax: '<percentage>'; inherits: false; initial-value: 50%; }
@property --sx-my { syntax: '<percentage>'; inherits: false; initial-value: 50%; }

.bfx-plate {
  position: relative;
  isolation: isolate;
  transition: box-shadow .42s var(--sx-quick), transform .42s var(--sx-glide);
}
.bfx-plate > * { position: relative; z-index: 1; }
.bfx-plate::before {
  content: "";
  /* z-index 0, not -1. A negative index would put the wash BEHIND the
     plate's own background and it would never be seen; it has to sit on the
     background and under the writing, which is what the rule above puts the
     writing on layer 1 for. */
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(340px circle at var(--sx-mx) var(--sx-my),
    rgba(58, 107, 214, .10) 0%,
    rgba(46, 83, 125, .05) 42%,
    rgba(46, 83, 125, 0) 72%);
  transition: opacity .5s var(--sx-quick), --sx-mx .28s linear, --sx-my .28s linear;
}
.bfx-plate:hover,
.bfx-plate:focus-within { transform: translateY(-2px); }
.bfx-plate:hover::before,
.bfx-plate:focus-within::before { opacity: 1; }

/* A hairline in koningsblauw down the leading edge, arriving left to right
   the way every rule on this site arrives. */
.bfx-plate::after {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: linear-gradient(180deg, var(--sx-koning), var(--sx-mid));
  transform: scaleY(0); transform-origin: top center;
  transition: transform .46s var(--sx-glide);
}
.bfx-plate:hover::after,
.bfx-plate:focus-within::after { transform: scaleY(1); }

/* ---------------------------------------------------------------------------
   THE TIER CARDS
   The card a reader is addressing lifts and takes the blue edge. The card the
   page was deep-linked to (membership.html#partner, and the two beside it)
   also counts as addressed, for as long as it takes to read it: a single
   pulse that starts and ends at nothing, so there is no state to leave.
   --------------------------------------------------------------------------- */
.tier {
  position: relative;
  transition: box-shadow .42s var(--sx-quick), transform .42s var(--sx-glide);
}
.tier::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: linear-gradient(90deg, var(--sx-mid), var(--sx-koning));
  transform: scaleX(0); transform-origin: right center;
  transition: transform .46s var(--sx-glide);
  pointer-events: none;
}
.tier:hover::after,
.tier:focus-within::after { transform: scaleX(1); transform-origin: left center; }
.tier:hover, .tier:focus-within { transform: translateY(-3px); }

/* :target is the deep link. One pass of light across the card and it is
   finished; the keyframe begins and ends transparent, so nothing lingers and
   nothing has to be cleaned up. */
.tier:target { animation: sxArrive 2.4s var(--sx-glide) 1; }
@keyframes sxArrive {
  0%   { box-shadow: 0 0 0 0 rgba(58, 107, 214, 0); }
  24%  { box-shadow: 0 0 0 3px rgba(58, 107, 214, .22); }
  100% { box-shadow: 0 0 0 0 rgba(58, 107, 214, 0); }
}

/* ---------------------------------------------------------------------------
   THE PARTNER PLATES AND THE INSTITUTIONAL REGISTER
   Quieter still. These are a list of firms and a list of bodies: neither is
   an invitation, so neither gets a wash. They get the edge and nothing else.
   --------------------------------------------------------------------------- */
.partner-logo {
  position: relative;
  transition: color .34s var(--sx-quick), box-shadow .34s var(--sx-quick), transform .34s var(--sx-glide);
}
.partner-logo:hover,
.partner-logo:focus-visible {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sx-mid) 44%, transparent);
}
.partner-logo-add:hover { color: var(--sx-koning); }

.inst-row { transition: background-color .34s var(--sx-quick); }
.inst-row:hover { background-color: rgba(46, 83, 125, .035); }
.inst-row .inst-mark { transition: color .34s var(--sx-quick); }
.inst-row:hover .inst-mark { color: var(--sx-mid); }

/* ---------------------------------------------------------------------------
   THE LINE THAT OPENS THE PANEL
   It is one sentence and a button, deliberately not a plate, because
   sponsorship is not a fourth membership. What it does get is the site's own
   underline, in blue rather than gold, so it reads as the way IN to the
   application rather than as another association mark.
   --------------------------------------------------------------------------- */
.bfx-roll .link-cta,
[data-spx-open] {
  position: relative;
  display: inline-flex; align-items: center; gap: .5em;
  padding: .2em 0 .4em;
  color: var(--sx-navy, #0f2038);
  transition: color .28s var(--sx-quick);
}
.bfx-roll .link-cta::after,
.bfx-roll .link-cta::before { bottom: 0; }
[data-spx-open]:not(.btn)::before,
[data-spx-open]:not(.btn)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
}
[data-spx-open]:not(.btn)::before { background: rgba(46, 83, 125, .3); }
[data-spx-open]:not(.btn)::after {
  background: linear-gradient(90deg, var(--sx-mid, #2e537d), var(--sx-koning, #3a6bd6));
  transform: scaleX(0); transform-origin: right center;
  transition: transform .44s var(--sx-glide, cubic-bezier(.22,1,.36,1));
}
[data-spx-open]:not(.btn):hover::after,
[data-spx-open]:not(.btn):focus-visible::after { transform: scaleX(1); transform-origin: left center; }
[data-spx-open] i { transition: transform .3s var(--sx-glide, cubic-bezier(.22,1,.36,1)); }
[data-spx-open]:hover i { transform: translateX(3px); }

@media (hover: none) {
  /* A hover state on a touch screen is a state that sticks after a tap and
     then has to be tapped away. None of the above applies where there is no
     pointer to hover with. */
  .bfx-plate:hover, .tier:hover, .partner-logo:hover { transform: none; }
  .bfx-plate:hover::before { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bfx-plate, .bfx-plate::before, .bfx-plate::after,
  .tier, .tier::after, .partner-logo, .inst-row,
  [data-spx-open]:not(.btn)::after, [data-spx-open] i { transition: none; }
  .tier:target { animation: none; }
  .bfx-plate:hover, .bfx-plate:focus-within,
  .tier:hover, .tier:focus-within, .partner-logo:hover { transform: none; }
}


/* ============================================================================
   THE SLIDE, REBUILT AS A CONTROL RATHER THAN A GRAPHIC
   ----------------------------------------------------------------------------
   What was here was a 14x26 navy blade with a 2px coloured ring around it,
   growing 8 per cent taller on hover and 14 on press. Every one of those
   decisions is a decoration standing where an affordance should be: the
   slab does not look like something you pick up, the ring restates the fill
   colour a second time two pixels away from where it already is, and a
   control that changes SIZE under the finger moves the thing you are
   holding while you are holding it.

   The reference is the platform slider, because it is the most handled
   control of its kind in the world and every part of it earns its place: a
   thin fully-rounded track, and one round white knob that reads as a
   physical object lying ON the track rather than cut into it. The knob is
   white at every value -- the track carries the colour, the knob carries the
   light. Under the finger it does not grow; the shadow deepens, which is
   what a real object does when you press it.
   ============================================================================ */

.spx-track .spx-groove,
.spx-track .spx-fillbar {
  height: 4px;
  top: 13px;
  border-radius: 999px;
}
.spx-track .spx-groove {
  background: rgba(15, 32, 56, .11);
  box-shadow: none;
}
.spx-track .spx-fillbar { box-shadow: none; }

/* The leading cap the old bar drew is gone: the knob is the leading edge now,
   and two marks for one position is one too many. */
.spx-track .spx-fillbar::after { content: none; }

/* The knob. */
.spx-track .spx-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px;
  margin-top: -9px;
  border: 0; border-radius: 50%;
  background: #ffffff;
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .09),
    0 1px 1px rgba(15, 32, 56, .10),
    0 3px 8px rgba(15, 32, 56, .16);
  transition: box-shadow .22s cubic-bezier(.22,1,.36,1);
}
.spx-track .spx-range::-moz-range-thumb {
  width: 22px; height: 22px;
  border: 0; border-radius: 50%;
  background: #ffffff;
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .09),
    0 1px 1px rgba(15, 32, 56, .10),
    0 3px 8px rgba(15, 32, 56, .16);
  transition: box-shadow .22s cubic-bezier(.22,1,.36,1);
}

/* No scaling, on any state. */
.spx-track .spx-range:hover::-webkit-slider-thumb,
.spx-track .spx-range:active::-webkit-slider-thumb,
.spx-track .spx-range:focus-visible::-webkit-slider-thumb { transform: none; }
.spx-track .spx-range:hover::-moz-range-thumb,
.spx-track .spx-range:active::-moz-range-thumb { transform: none; }

.spx-track .spx-range:hover::-webkit-slider-thumb {
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .11),
    0 1px 1px rgba(15, 32, 56, .12),
    0 4px 12px rgba(15, 32, 56, .2);
}
.spx-track .spx-range:active::-webkit-slider-thumb {
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .14),
    0 1px 1px rgba(15, 32, 56, .16),
    0 2px 5px rgba(15, 32, 56, .26);
}
.spx-track .spx-range:focus-visible::-webkit-slider-thumb {
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .09),
    0 1px 1px rgba(15, 32, 56, .10),
    0 3px 8px rgba(15, 32, 56, .16),
    0 0 0 4px color-mix(in srgb, var(--sx-lead, #3a6bd6) 30%, transparent);
}

/* The notches drop out of the track and sit under it as tick marks. Inside
   the groove they were competing with the fill for the same four pixels, and
   the lit ones were painting white ON the colour that was meant to be doing
   the telling. */
.spx-track .spx-notches { top: 21px; height: 5px; }
.spx-track .spx-notches i {
  top: 0; height: 4px; width: 1px; margin-left: -.5px;
  border-radius: 999px;
  background: rgba(15, 32, 56, .18);
  transition: background-color .34s var(--sx-quick), height .34s var(--sx-glide);
}
.spx-track .spx-notches i.is-lit {
  top: 0; height: 5px;
  background: var(--sx-lead, #3a6bd6);
}

/* Phone: the knob grows to a finger, the track stays thin. */
@media (max-width: 680px) {
  .spx-track { height: 44px; }
  .spx-track .spx-groove,
  .spx-track .spx-fillbar { top: 20px; height: 5px; }
  .spx-track .spx-notches { top: 29px; }
  .spx-track .spx-range::-webkit-slider-thumb { width: 28px; height: 28px; margin-top: -11px; }
  .spx-track .spx-range::-moz-range-thumb { width: 28px; height: 28px; }
}

@media (prefers-reduced-motion: reduce) {
  .spx-track .spx-range::-webkit-slider-thumb,
  .spx-track .spx-range::-moz-range-thumb { transition: none; }
}


/* ============================================================================
   THE STEP RAIL ON A PHONE -- the two dots that looked like broken buttons
   ----------------------------------------------------------------------------
   Below 680px only the live step keeps its words and the other two keep
   their dots, which is the right call. But the rail was still
   justify-content: space-between, so those two bare 8px squares were flung
   to the middle and the far right of a 335px row with nothing attached to
   them. Two lone marks pinned to the edges of a panel do not read as steps;
   they read as controls that have been cut in half by the edge of the
   screen, which is exactly what was reported.

   Grouped instead: the live step takes the row, and the steps still to come
   sit together at the end as a tight pair. That is the same information --
   where you are, how much is left -- said as one object instead of three
   pieces of wreckage.
   ============================================================================ */
@media (max-width: 680px) {
  .spx-rail { justify-content: flex-start; gap: 0; align-items: center; }
  .spx-node.is-now { flex: 1 1 auto; min-width: 0; }
  .spx-node.is-now span:not(.spx-dot) {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .spx-node:not(.is-now) { flex: 0 0 auto; margin-left: 9px; }
  .spx-node:not(.is-now):first-of-type { margin-left: 0; }
  /* A step already behind you is a smaller mark than one still ahead: the
     ones ahead are what the row is counting down. */
  .spx-node.is-done .spx-dot { opacity: .55; }
}


/* ============================================================================
   THREE DEFECTS FROM THE PHONE, MEASURED AND FIXED
   ----------------------------------------------------------------------------
   1. THE KNOB WAS FLOATING ABOVE ITS OWN TRACK. margin-top on a
      ::-webkit-slider-thumb is measured from the top of the RUNNABLE TRACK,
      which is the full 44px control on a phone -- not from the 5px groove
      that is drawn at top:20px inside it. -9px put the knob nine pixels
      above the control's top edge, so it sat over the line instead of on it
      and its left half read as hanging off the panel. The number it wants is
      the groove's centre minus half the knob: 22.5 - 14 = 8.5 on a phone,
      15 - 11 = 4 on a pointer. Stated as arithmetic so it stays true if
      either size changes.

   2. THE ENDS COULD CLIP. A round knob at value 0 puts its leading edge on
      the track's own origin, and the panel's scroll box clips at exactly
      that line. The track is inset by half a knob at each end and the groove
      and fill are pulled back out to the full width, so the bar still spans
      edge to edge while the knob always has its own width to stand in.

   3. THE BODY COLLIDED WITH THE HEAD. The stage scrolls under a fixed rail
      and progress line with nothing between them, so the first paragraph ran
      into "What you would like to give" and both were legible at once in the
      same 20 pixels. The stage now fades out over its top 18px, which is the
      same answer the site header uses over the hero.
   ============================================================================ */

/* CORRECTION to (2) above: the track needed no inset at all. A native range
   input already keeps its thumb inside the track box -- at value 0 the
   thumb's LEFT edge sits on the track's left edge, not its centre -- so the
   ends were never going to clip once the knob was sitting at the right
   height. Insetting the track and pulling the groove back out by the same
   amount put the groove 8px past the right edge of a 375px screen, which is
   a worse fault than the one it was fixing. The track, the groove, the fill
   and the marks all share one box again, and (1) does the work. */
.spx-track { --sx-knob: 22px; }

/* CORRECTION to (1): margin-top on the thumb is fragile, because it is
   measured from a runnable track whose height keeps changing with the
   breakpoint. The RUNNABLE TRACK is given the offset instead -- it becomes a
   knob-tall band sitting exactly over the groove -- and the thumb then
   centres on it with no offset at all. The input keeps its full 44px height,
   so the hit area is unchanged. */
.spx-track .spx-range::-webkit-slider-runnable-track {
  height: var(--sx-knob);
  margin-top: calc(13px + 2px - var(--sx-knob) / 2);
  background: transparent;
}
.spx-track .spx-range::-webkit-slider-thumb {
  width: var(--sx-knob); height: var(--sx-knob);
  margin-top: 0;
}
.spx-track .spx-range::-moz-range-thumb {
  width: var(--sx-knob); height: var(--sx-knob);
}

@media (max-width: 680px) {
  .spx-track { --sx-knob: 28px; }
  .spx-track .spx-range::-webkit-slider-runnable-track {
    margin-top: calc(20px + 2.5px - var(--sx-knob) / 2);
  }
  .spx-track .spx-range::-webkit-slider-thumb { margin-top: 0; }
}

/* The stage's top edge. */
.spx-in .spx-stage {
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 18px);
  mask-image: linear-gradient(180deg, transparent 0, #000 18px);
}


/* ============================================================================
   THE STEP MARKS  --  circles, and no box around the live one
   ----------------------------------------------------------------------------
   The marks were 8px squares carrying the panel's shared corner radius, and
   the live one wore a breathing ring drawn at inset -4px, which is a 16px
   box. On a phone that box sat hard against "What you would like to give"
   and read as a checkbox somebody had drawn a frame around -- two controls
   where there is one state.

   A step mark is a position in a sequence, so it is a dot. The live one is
   filled and keeps a halo, but the halo is a circle at half the offset and a
   third of the weight: present when you look at it, invisible when you are
   reading the words beside it.
   ============================================================================ */
.spx-dot { border-radius: 50%; width: 7px; height: 7px; }
.spx-node.is-now .spx-dot::after {
  inset: -3px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--sx-koning) 42%, transparent);
}
/* Room between the mark and the word it belongs to. */
.spx-node { gap: 9px; }
@media (max-width: 680px) { .spx-node { gap: 8px; } }


/* ============================================================================
   THE DRAWN KNOB
   ----------------------------------------------------------------------------
   See the note in js/apply.js. One custom property carries the position and
   the travel is inset by half a knob at each end, so at 0 the knob's left
   edge is the track's left edge and at 1 its right edge is the track's right
   edge -- it cannot be clipped at either end, at any size, in any browser.
   The native thumb stays for dragging and keyboard, invisible.
   ============================================================================ */
.spx-track { --spx-p: 0; }

.spx-knob {
  position: absolute;
  top: 15px;
  /* left is the plain percentage; the end correction rides in the transform.
     Written the other way round -- calc(half + p * (100% - knob)) -- the
     multiplication has a percentage MINUS a length inside it, which engines
     are entitled to refuse, and Chrome did: the whole expression collapsed
     to the 14px first term and the knob never left the origin. Here the only
     multiplications are number x percentage and number x length, which are
     both unambiguous. At p=0 the shift is +half a knob, at p=1 it is minus
     half, so the knob's edges land exactly on the track's. */
  left: 0;
  width: var(--sx-knob); height: var(--sx-knob);
  margin: 0;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #ffffff;
  pointer-events: none;
  z-index: 3;
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .09),
    0 1px 1px rgba(15, 32, 56, .10),
    0 3px 8px rgba(15, 32, 56, .16);
  transition:
    left .16s cubic-bezier(.22,1,.36,1),
    box-shadow .22s cubic-bezier(.22,1,.36,1);
}
.spx-track.is-dragging .spx-knob { transition: left 0s, box-shadow .22s cubic-bezier(.22,1,.36,1); }

.spx-range:hover ~ .spx-knob {
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .11),
    0 1px 1px rgba(15, 32, 56, .12),
    0 4px 12px rgba(15, 32, 56, .2);
}
.spx-range:active ~ .spx-knob {
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .14),
    0 1px 1px rgba(15, 32, 56, .16),
    0 2px 5px rgba(15, 32, 56, .26);
}
.spx-range:focus-visible ~ .spx-knob {
  box-shadow:
    0 0 0 .5px rgba(15, 32, 56, .09),
    0 1px 1px rgba(15, 32, 56, .10),
    0 3px 8px rgba(15, 32, 56, .16),
    0 0 0 4px color-mix(in srgb, var(--sx-lead, #3a6bd6) 30%, transparent);
}

/* The native thumb: still the control, no longer the picture. */
.spx-track .spx-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: var(--sx-knob); height: var(--sx-knob);
  margin-top: 0;
  background: transparent;
  box-shadow: none;
  border: 0;
}
.spx-track .spx-range::-moz-range-thumb {
  width: var(--sx-knob); height: var(--sx-knob);
  background: transparent; box-shadow: none; border: 0;
}
.spx-track .spx-range::-webkit-slider-runnable-track { margin-top: 0; height: 100%; background: transparent; }

@media (max-width: 680px) {
  .spx-knob { top: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .spx-knob { transition: none; }
}


/* ============================================================================
   SPACING  --  the right amount, measured
   ----------------------------------------------------------------------------
   Measured on the phone: 52px of nothing between the figure field and SLIDE
   TO SEE WHAT OPENS, against 20-24px everywhere else in the same panel. It
   was not rhythm, it was one block carrying both its own bottom margin and
   the next block's top margin. And the stage's bottom padding was 4px under
   a 78px action bar, so the last thing on every pass sat behind Carry on --
   which is why CHOOSE WHAT YOU WOULD LIKE TO FUND was cut in half.

   The rule applied here is one step, not a guess: blocks inside a pass are
   26px apart on a pointer and 22px on a phone, and the stage ends far enough
   above the bar that the last line clears it with one line to spare.
   ============================================================================ */
.spx-in .spx-pass > * + * { margin-top: 26px; }
.spx-in .spx-pass > .bf-amount + * { margin-top: 26px; }

.spx-in .spx-stage {
  padding-bottom: 22px;
  scroll-padding-bottom: 22px;
}

@media (max-width: 680px) {
  .spx-in .spx-pass > * + * { margin-top: 22px; }
  .spx-in .spx-stage { padding-bottom: 18px; }
}

/* The slide's own label and its sentence belong to each other, so they sit
   at the tight interval rather than the block one. */
.spx-slide-head { margin-bottom: 10px; }
.spx-in .bf-note { margin-top: 8px; }


/* ============================================================================
   ONE KNOB, NOT TWO
   ----------------------------------------------------------------------------
   Four generations of thumb rules are stacked in this file. The last one made
   the native thumb transparent at REST, but three earlier ones paint it white
   with a shadow on :hover, :active and :focus-visible, and a pseudo-class
   beats a plain selector -- so the moment the control was touched a second
   white dot appeared beside the drawn one. That is the duplicate.

   Every state is closed here, once, with the weight to end it. The native
   thumb is a hit target and nothing else; .spx-knob is the only thing seen.
   ============================================================================ */
.spx-track .spx-range::-webkit-slider-thumb,
.spx-track .spx-range:hover::-webkit-slider-thumb,
.spx-track .spx-range:active::-webkit-slider-thumb,
.spx-track .spx-range:focus::-webkit-slider-thumb,
.spx-track .spx-range:focus-visible::-webkit-slider-thumb {
  -webkit-appearance: none !important;
  appearance: none !important;
  background: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  border: 0 !important;
  transform: none !important;
  width: var(--sx-knob) !important;
  height: var(--sx-knob) !important;
  margin-top: 0 !important;
}
.spx-track .spx-range::-moz-range-thumb,
.spx-track .spx-range:hover::-moz-range-thumb,
.spx-track .spx-range:active::-moz-range-thumb,
.spx-track .spx-range:focus::-moz-range-thumb {
  background: transparent !important;
  box-shadow: none !important;
  border: 0 !important;
  transform: none !important;
  width: var(--sx-knob) !important;
  height: var(--sx-knob) !important;
}
.spx-track .spx-range::-webkit-slider-runnable-track,
.spx-track .spx-range::-moz-range-track {
  background: transparent !important;
  border: 0 !important;
  height: 100% !important;
  margin: 0 !important;
}

/* And nothing in the row may clip it. The knob's travel is inset by half its
   width in js/apply.js, so at either end it sits exactly inside the track --
   but only if no ancestor between the track and the panel is cutting at that
   line. Stated rather than assumed. */
.spx-track { overflow: visible; }
.spx-in .bf-amount,
.spx-in .spx-pass { overflow: visible; }

/* ============================================================================
   11 - THE SPONSOR APPLICATION, COMPLETED (14 Sep 2026)
   ----------------------------------------------------------------------------
   Acknowledgement sits under the activities in the chips those already use.
   Invoicing is set apart by space, not by a rule or a box. The one select in
   the panel takes the same underline as the fields beside it, with a drawn
   caret instead of the platform's, so it reads as one of them.
   ============================================================================ */
.spx-in .spx-credit { margin-top: 26px; }
.spx-in .spx-credit .bf-chips { margin-top: 9px; }
.spx-in .bf-legend.spx-sub { margin-top: 30px; }
.spx-in .spx-origin { margin: 0 0 24px; }

.spx-field select {
  width: 100%;
  padding: 10px 22px 9px 0;
  border: 0;
  border-bottom: 1px solid var(--sx-line);
  border-radius: 0;
  background-color: transparent;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--sx-ink-faint) 50%),
    linear-gradient(135deg, var(--sx-ink-faint) 50%, transparent 50%);
  background-position: calc(100% - 9px) 52%, calc(100% - 4px) 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  -webkit-appearance: none;
  appearance: none;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: -.004em;
  color: var(--sx-navy);
  cursor: pointer;
}
@media (min-width: 681px) { .spx-field select { font-size: .92rem; } }
.spx-field select:focus { outline: none; }
.spx-field select:focus-visible { box-shadow: 0 1px 0 0 var(--sx-koning); }
