/* ==========================================================================
   REPULSE UK — COMPONENTS
   The card system is the point here: five distinct weights (plain, bordered,
   dark, violet, media) so a grid can have rhythm instead of fourteen
   identical white boxes.
   ========================================================================== */

/* --------------------------------------------------------------------------
   BUTTONS
   -------------------------------------------------------------------------- */
.btn {
  --bg: transparent; --fg: var(--t-strong); --bd: transparent;
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  min-height: 50px;
  padding: 0 var(--sp-6);
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--bd); border-radius: var(--r-ctl);
  font-size: var(--fs-sm); font-weight: 600; line-height: 1;
  letter-spacing: -0.005em; white-space: nowrap;
  cursor: pointer; text-align: center; touch-action: manipulation;
  transition: background var(--d-fast) var(--e-both),
              border-color var(--d-fast) var(--e-both),
              color var(--d-fast) var(--e-both),
              transform var(--d-fast) var(--e-both),
              box-shadow var(--d-base) var(--e-both);
}
button.btn { color: var(--fg); }
button.btn:hover,
button.btn:focus {
  background: var(--bg);
  border-color: var(--bd);
  color: var(--fg);
}

/* The same guarantee for a button built as a link.
 *
 * The rule above was only ever scoped to <button>, which is why an anchor
 * styled as a button lost its text colour on hover and a real button did not
 * -- the inconsistency that made this look random rather than systematic.
 *
 * Reading --fg rather than a literal is what makes one rule enough: every
 * variant hover (.btn--ghost:hover and the rest) works by changing that
 * variable, so they all keep composing correctly through this. */
.btn:hover,
.btn:focus { color: var(--fg); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .btn:hover { transform: translateY(-3px); }
}
.btn:active { transform: translateY(0) scale(.98); }

.btn--primary { --bg: var(--violet); --fg: #fff; --bd: var(--violet); box-shadow: var(--sh-1); }
.btn--primary:hover { --bg: #A216E8; --bd: #A216E8; box-shadow: var(--sh-2); }

.btn--dark { --bg: var(--ink); --fg: #fff; --bd: var(--ink); }
.btn--dark:hover { --bg: #232330; --bd: #232330; }

.btn--ghost { --bd: var(--line-2); --fg: var(--t-strong); }
.btn--ghost:hover { --bd: var(--violet); --fg: var(--violet); }

/* On dark bands */
.on-dark .btn--ghost, .section--night .btn--ghost { --bd: rgba(255,255,255,.28); --fg: #fff; }
.on-dark .btn--ghost:hover, .section--night .btn--ghost:hover { --bd: #fff; --bg: rgba(255,255,255,.08); }

.btn--light { --bg: #fff; --fg: var(--ink); --bd: #fff; }
.btn--light:hover { --bg: var(--paper); --bd: var(--paper); }

.btn--block { width: 100%; }
.btn--lg { min-height: 56px; font-size: var(--fs-base); padding-inline: var(--sp-8); }
.btn--sm { min-height: 42px; font-size: var(--fs-xs); padding-inline: var(--sp-4); }

.btn svg { width: 16px; height: 16px; }
.btn__arrow { transition: transform var(--d-fast) var(--e-out); }
.btn:hover .btn__arrow { transform: translateX(3px); }

.btn[disabled], .btn[aria-disabled='true'] { opacity: .45; cursor: not-allowed; pointer-events: none; }

.btn.is-loading { color: transparent; pointer-events: none; }
.btn.is-loading::after {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 18px; height: 18px;
  border: 2px solid rgba(255,255,255,.35); border-top-color: #fff;
  border-radius: 50%; animation: spin 700ms linear infinite;
}
.btn--ghost.is-loading::after { border-color: rgba(17,17,28,.2); border-top-color: var(--violet); }
@keyframes spin { to { transform: rotate(360deg); } }

/* Inline chevron link */
.link {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px;              /* standalone links are tap targets too */
  color: var(--violet); font-size: var(--fs-sm); font-weight: 600;
}
.link svg { width: 15px; height: 15px; transition: transform var(--d-fast) var(--e-out); }
.link:hover svg { transform: translateX(3px); }
.on-dark .link, .section--night .link { color: var(--violet-bright); }

/* Restated for hover, or the a:hover rule in tokens.css hands this back to
   inherit and the violet is lost exactly when the pointer is on it. */
.link:hover,
.link:focus { color: var(--violet); }
.on-dark .link:hover, .on-dark .link:focus,
.section--night .link:hover, .section--night .link:focus { color: var(--violet-bright); }

/* --------------------------------------------------------------------------
   TAGS
   -------------------------------------------------------------------------- */
.tag {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 6px var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--wash); color: var(--violet-deep);
  font-size: var(--fs-xs); font-weight: 600;
  white-space: nowrap;
}
.tag svg { width: 14px; height: 14px; color: var(--violet); }
.tag--outline { background: transparent; border: 1px solid var(--line); color: var(--t-muted); }
.tag--dark { background: rgba(255,255,255,.08); color: #fff; border: 1px solid rgba(255,255,255,.14); }
.tag--dark svg { color: var(--violet-bright); }

.pulse-dot { position: relative; width: 7px; height: 7px; border-radius: 50%; background: var(--signal); flex: 0 0 auto; }
.tag--dark .pulse-dot, .on-dark .pulse-dot { background: var(--signal-on-dark); }
.pulse-dot::after {
  content: ''; position: absolute; inset: -4px;
  border-radius: 50%; border: 1px solid currentColor; color: inherit;
  opacity: 0; animation: pulse-ring 2.6s var(--e-out) infinite;
}
@keyframes pulse-ring { 0% { transform: scale(.6); opacity: .7; } 70%,100% { transform: scale(1.9); opacity: 0; } }

/* --------------------------------------------------------------------------
   CARDS — five weights so a grid can breathe
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  display: flex; flex-direction: column;
  padding: var(--sp-6);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
  transition: border-color var(--d-base) var(--e-both),
              box-shadow var(--d-base) var(--e-both),
              transform var(--d-base) var(--e-out);
}
@media (min-width: 720px) { .card { padding: var(--sp-8); } }

.card__icon { display: block; margin-bottom: var(--sp-5); color: var(--violet); }
.card__icon svg { width: 26px; height: 26px; stroke-width: 1.6; }
/* An accreditation card leads with the scheme's own artwork. On a dark card the
   marks are printed for light backgrounds, so they sit on a white chip rather
   than being knocked out — a scheme's logo is not ours to recolour. */
.card__mark {
  display: inline-flex; align-items: center;
  height: 62px; margin-bottom: var(--sp-5);
  padding: var(--sp-2) var(--sp-3);
  background: #fff; border-radius: var(--r-ctl);
}
.card__mark img { height: 100%; width: auto; display: block; }

.card__title { font-size: var(--fs-h4); margin-bottom: var(--sp-3); }
.card__text  { color: var(--t-muted); font-size: var(--fs-sm); line-height: 1.6; flex: 1; }
.card__foot  { margin-top: var(--sp-6); }

/* Interactive */
.card--link:hover { border-color: var(--line-2); box-shadow: var(--sh-2); transform: translateY(-3px); }
.card--link:hover .link svg { transform: translateX(3px); }

/* --- DARK card -------------------------------------------------------- */
.card--dark {
  background: var(--grad-night);
  border-color: transparent;
  color: var(--t-on-dark-body);
}
.card--dark .card__title, .card--dark h2, .card--dark h3, .card--dark h4 { color: #fff; }
.card--dark .card__text { color: var(--t-on-dark-body); }
.card--dark .card__icon { color: var(--violet-bright); }
.card--dark.card--link:hover { box-shadow: var(--sh-3); }

/* --- VIOLET card ------------------------------------------------------ */
.card--violet {
  background: var(--grad-violet);
  border-color: transparent;
  color: rgba(255,255,255,.88);
}
.card--violet .card__title, .card--violet h2, .card--violet h3, .card--violet h4 { color: #fff; }
.card--violet .card__text { color: rgba(255,255,255,.86); }
.card--violet .card__icon { color: #fff; }
.card--violet .link { color: #fff; }

/* --- WASH card (light violet) ----------------------------------------- */
.card--wash { background: var(--grad-wash); border-color: var(--line); }

/* --- MEDIA card — photography inside the card ------------------------- */
.card--media { padding: 0; }
.card--media .card__body { padding: var(--sp-6); display: flex; flex-direction: column; flex: 1; }
@media (min-width: 720px) { .card--media .card__body { padding: var(--sp-6); } }

.card__media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--paper-2);
}
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--d-slow) var(--e-out); }

/* A band rather than a 16:9 plate. Used where the picture is there to give the
   card a face, not to be the card — the copy still has to lead. */
.card__media--band { aspect-ratio: 16 / 6; }
@media (min-width: 700px) and (max-width: 1039px) { .card__media--band { aspect-ratio: 16 / 5; } }
.card--link:hover .card__media img { transform: scale(1.04); }

/* Media card that puts copy OVER the image */
.card--overlay { padding: 0; min-height: 340px; justify-content: flex-end; }
.card--overlay .card__media { position: absolute; inset: 0; aspect-ratio: auto; }
.card--overlay .card__body {
  position: relative; z-index: 2;
  padding: var(--sp-6);
  color: #fff;
}
@media (min-width: 720px) { .card--overlay .card__body { padding: var(--sp-8); } }
.card--overlay .card__title { color: #fff; }
.card--overlay .card__text { color: rgba(255,255,255,.84); }
.card--overlay::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(13,13,20,.15) 0%, rgba(13,13,20,.72) 62%, rgba(13,13,20,.92) 100%);
}

/* A hairline violet edge-light along the top of feature cards */
.card--edge::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--grad-edge);
}

/* --------------------------------------------------------------------------
   BENTO GRID — cards of differing span, the thing that creates rhythm
   -------------------------------------------------------------------------- */
.bento { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 700px)  { .bento { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); } }
@media (min-width: 1040px) { .bento { grid-template-columns: repeat(6, 1fr); } }

/* Column spans at desktop only — everything stacks cleanly below */
@media (min-width: 1040px) {
  .bento > .span-2 { grid-column: span 2; }
  .bento > .span-3 { grid-column: span 3; }
  .bento > .span-4 { grid-column: span 4; }
  .bento > .span-6 { grid-column: span 6; }
  .bento > .row-2  { grid-row: span 2; }
}

/* --------------------------------------------------------------------------
   STAT — big numeral, used on dark bands and inside cards
   -------------------------------------------------------------------------- */
.stat__value {
  font-size: var(--fs-stat);
  font-weight: 700; line-height: 1;
  letter-spacing: var(--tr-display);
  color: var(--t-strong);
  margin-bottom: var(--sp-3);
}
.section--night .stat__value, .card--dark .stat__value, .card--violet .stat__value { color: #fff; }
.stat__value .suffix { color: var(--violet); }
.section--night .stat__value .suffix, .card--dark .stat__value .suffix { color: var(--violet-bright); }
.card--violet .stat__value .suffix { color: rgba(255,255,255,.7); }

.stat__label { font-size: var(--fs-base); font-weight: 600; color: var(--t-strong); margin-bottom: var(--sp-1); }
.section--night .stat__label, .card--dark .stat__label, .card--violet .stat__label { color: #fff; }
.stat__sub { font-size: var(--fs-sm); color: var(--t-muted); }
.section--night .stat__sub, .card--dark .stat__sub { color: var(--t-on-dark-muted); }
.card--violet .stat__sub { color: rgba(255,255,255,.72); }

/* --------------------------------------------------------------------------
   FORMS
   -------------------------------------------------------------------------- */
.field { display: block; margin-bottom: var(--sp-5); }
/* Label colour travels as an inherited custom property, not as a selector.
   The quote card is a WHITE panel that sits inside .hero.on-dark, so any rule
   written as `.on-dark .field__label { color: #fff }` cascades straight into
   it and paints the labels white on white — which is exactly the bug that
   left only the violet asterisk visible. Chasing it with ever-more-specific
   reset selectors is a fight you have to re-win every time the markup nests
   one level deeper. A custom property is resolved by the NEAREST ancestor
   that sets it, so a light island inside a dark section simply wins, at any
   depth, with no specificity involved. */
.field__label { display: block; margin-bottom: var(--sp-2); font-size: var(--fs-sm); font-weight: 600; color: var(--label-fg, var(--t-strong)); }
.field__label .req { color: var(--label-req, var(--violet)); margin-left: 2px; }

/* Dark surfaces. */
.on-dark, .section--night, .card--dark, .card--violet {
  --label-fg: #fff;
  --label-req: var(--violet-bright);
}
/* Light islands that can be nested inside any of the above. */
.quote-card, .modal__panel, .wizard__panel {
  --label-fg: var(--t-strong);
  --label-req: var(--violet);
}
.on-dark .quote-card .link,
.section--night .quote-card .link { color: var(--violet); }
.on-dark .quote-card :focus-visible,
.section--night .quote-card :focus-visible { outline-color: var(--violet); }
.on-dark .quote-card .btn--ghost,
.section--night .quote-card .btn--ghost { --bd: var(--line-2); --fg: var(--t-strong); }

.input, .textarea, .select {
  width: 100%; min-height: 50px;
  padding: var(--sp-3) var(--sp-4);
  background: #fff;
  border: 1px solid var(--line-2);
  border-radius: var(--r-ctl);
  color: var(--t-strong);
  font-size: var(--fs-base);
  line-height: 1.4;
  transition: border-color var(--d-fast) var(--e-both), box-shadow var(--d-fast) var(--e-both);
}
.textarea { min-height: 108px; resize: vertical; }
.input::placeholder, .textarea::placeholder { color: var(--t-faint); }
.input:hover, .textarea:hover, .select:hover { border-color: var(--violet-bright); }
.input:focus, .textarea:focus, .select:focus {
  outline: none; border-color: var(--violet);
  box-shadow: 0 0 0 3px rgba(147, 0, 211, .14);
}

.select {
  appearance: none; cursor: pointer; padding-right: var(--sp-10);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236E6780' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right var(--sp-4) center;
}

.field.is-invalid .input, .field.is-invalid .textarea, .field.is-invalid .select { border-color: var(--danger); }
.field__error {
  display: none; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-2); font-size: var(--fs-sm); font-weight: 500; color: var(--danger);
}
.field.is-invalid .field__error { display: flex; }
.field__error svg { width: 14px; height: 14px; }

.hp-field { position: absolute !important; left: -9999px !important; opacity: 0; pointer-events: none; }

/* --------------------------------------------------------------------------
   CHOICE TILES (wizard)
   -------------------------------------------------------------------------- */
.choices { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.choices--wide { grid-template-columns: 1fr; }

.choice {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 60px; padding: var(--sp-3) var(--sp-4);
  background: #fff;
  border: 1px solid var(--line-2);
  border-radius: var(--r-ctl);
  cursor: pointer; text-align: left;
  font-size: var(--fs-sm); font-weight: 500; color: var(--t-strong);
  transition: border-color var(--d-fast) var(--e-both), background var(--d-fast) var(--e-both), transform var(--d-fast) var(--e-both);
  touch-action: manipulation;
}
.choice:hover,
.choice:focus {
  border-color: var(--violet-bright);
  background: var(--wash);
  color: var(--t-strong);
}
.choice:active { transform: scale(.99); }

.choice__icon { display: grid; place-items: center; width: 22px; height: 22px; flex: 0 0 auto; color: var(--violet); }
.choice__icon svg { width: 20px; height: 20px; stroke-width: 1.6; }

/* Own the wrapping explicitly: min-width:0 lets the label shrink inside the
   flex row instead of forcing the tile wider, and the balance keeps a two-line
   label from leaving one orphaned word on the second line. */
.choice__label { flex: 1 1 auto; min-width: 0; line-height: 1.35; text-wrap: balance; hyphens: none; }

.choice__check {
  margin-left: var(--sp-2); width: 20px; height: 20px; flex: 0 0 auto;
  border: 1.5px solid var(--line-2); border-radius: 50%;
  display: grid; place-items: center; color: transparent;
  transition: background var(--d-fast) var(--e-both), border-color var(--d-fast) var(--e-both), color var(--d-fast) var(--e-both);
}
.choice__check svg { width: 12px; height: 12px; }

.choice.is-selected { border-color: var(--violet); background: var(--wash); color: var(--t-strong); }
.choice.is-selected .choice__check {
  background: var(--violet); border-color: var(--violet); color: #fff;
  animation: tick-pop var(--d-base) var(--e-out);
}
@keyframes tick-pop { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.choice input { position: absolute; opacity: 0; pointer-events: none; }

/* --------------------------------------------------------------------------
   TABS — sector switcher, replaces an endless list
   -------------------------------------------------------------------------- */
.tabs { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-8); }
.tab {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-5);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  color: var(--t-muted);
  font-size: var(--fs-sm); font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: background var(--d-fast) var(--e-both), color var(--d-fast) var(--e-both), border-color var(--d-fast) var(--e-both);
  touch-action: manipulation;
}
.tab:hover { border-color: var(--violet-bright); color: var(--t-strong); }
.tab[aria-selected='true'] { background: var(--ink); border-color: var(--ink); color: #fff; }

.tabpanel { display: none; }
.tabpanel.is-active { display: block; animation: panel-in var(--d-slow) var(--e-out); }
@keyframes panel-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* --------------------------------------------------------------------------
   SCROLL REVEAL — directional, so cards enter from the side they sit on
   -------------------------------------------------------------------------- */
/* Content is visible by default and JS opts IN to animating it.

   The compiled build had this the other way round: .reveal started at opacity 0
   and only motion.js made it visible. That means any failure of that one script
   -- a WP Rocket delay, a blocked request, an error earlier in the file -- left
   every animated section on the site invisible, with the markup present and
   nothing to see. A visual effect must never be load-bearing for content.

   inc/motion-boot.php adds .has-reveal to <html> before first paint, so the
   animation still runs for everyone whose browser gets that far. */
.reveal { opacity: 1; transform: none; }
html.has-reveal .reveal { opacity: 0; transform: translateY(22px); transition: opacity var(--d-slow) var(--e-out), transform var(--d-slow) var(--e-out); will-change: opacity, transform; }
html.has-reveal .reveal--left  { transform: translateX(-34px); }
html.has-reveal .reveal--right { transform: translateX(34px); }
html.has-reveal .reveal--scale { transform: scale(.97); }
html.has-reveal .reveal.is-visible { opacity: 1; transform: none; will-change: auto; }

@media (prefers-reduced-motion: reduce) { html.has-reveal .reveal { opacity: 1; transform: none; } }
