/* ==========================================================================
   components.css — reusable pieces shared across pages
   Buttons · header/nav · brand · footer · cards · empty states
   ========================================================================== */

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;                 /* touch target floor */
  padding: var(--space-3) var(--space-5);
  border: 2px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--text-base);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  /* transform/box-shadow carry the physical feedback; colour carries the state.
     Nothing here triggers layout. */
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

/* Lift only where a pointer can actually hover, so touch users never get a
   sticky :hover state left behind after a tap. */
@media (hover: hover) {
  .btn:hover {
    transform: translate3d(0, -2px, 0);
    box-shadow: var(--shadow-md);
  }
}

/* Press returns it below the resting position — the whole point is that the
   button acknowledges the click before the page has responded. */
.btn:active {
  transform: translate3d(0, 1px, 0);
  box-shadow: none;
  transition-duration: 60ms;
}

.btn--primary {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-invert);
}
.btn--primary:hover {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: var(--color-text-invert);
}

.btn--accent {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-primary-deep);
}
.btn--accent:hover {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
  color: var(--color-primary-deep);
}

.btn--ghost {
  background: transparent;
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.btn--ghost:hover {
  background: var(--color-primary);
  color: var(--color-text-invert);
}

.btn--ghost-light {
  background: transparent;
  border-color: var(--color-text-invert);
  color: var(--color-text-invert);
}
.btn--ghost-light:hover {
  background: var(--color-text-invert);
  color: var(--color-primary-strong);
}

.btn--lg {
  font-size: var(--text-md);
  padding: var(--space-4) var(--space-6);
}

.btn--sm {
  font-size: var(--text-sm);
  padding: var(--space-2) var(--space-4);
}

/* --------------------------------------------------------------------------
   Brand mark
   -------------------------------------------------------------------------- */

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  color: var(--color-text-invert);
}

/* The global `a:hover` (0,1,1) outranks `.brand` (0,1,0), which was tinting the
   company name the link blue on hover — unreadable on the blue header and it
   read as a rendering bug. Pin every interaction state to the same white. */
.brand:hover,
.brand:focus,
.brand:active,
.brand:visited {
  color: var(--color-text-invert);
}

/* The logo's own ring is the brand blue, which would disappear against the blue
   header — so it sits on a white disc, echoing the mark's circular form. */
.brand__logo {
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  padding: 3px;
  background: var(--white);
  border-radius: var(--radius-pill);
  /* box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.25); */
}

.brand__logo--footer {
  width: 52px;
  height: 52px;
  flex-basis: 52px;
  margin-bottom: var(--space-4);
}

.brand__text { display: flex; flex-direction: column; }

.brand__name {
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.brand__tagline {
  font-size: var(--text-xs);
  color: var(--yellow-500);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.4;
}

/* --------------------------------------------------------------------------
   Site header + primary nav
   -------------------------------------------------------------------------- */

.site-header {
  /* Exact logo blue, so the bar reads as the mark it sits next to. */
  background: var(--color-surface-header);
  /* Sticky rather than relative: a shrink-on-scroll state is pointless on a
     header that has already scrolled away, and on the rate board keeping the
     nav reachable is worth more than the 60px. */
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  transition: box-shadow var(--dur-mid) var(--ease-out),
              background-color var(--dur-mid) var(--ease-out);
}

/* Set by motion.js once the page has scrolled past the header's own height. */
.site-header.is-scrolled {
  background: var(--blue-700);
  box-shadow: 0 1px 0 rgb(255 255 255 / 0.08),
              0 6px 24px rgb(10 8 40 / 0.28);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  padding-block: var(--space-3);
  transition: padding-block var(--dur-mid) var(--ease-out);
}

/* The shrink. Padding is a layout property, but it is confined to the header
   subtree and runs only twice per scroll direction, so it never lands in a
   scroll-linked frame budget the way animating a full-page property would. */
.site-header.is-scrolled .site-header__inner { padding-block: var(--space-2); }

.brand__logo,
.brand__tagline {
  transition: transform var(--dur-mid) var(--ease-out),
              opacity var(--dur-mid) var(--ease-out);
}

.site-header.is-scrolled .brand__logo { transform: scale(0.88); }

/* Anchors must clear the sticky bar. */
:target { scroll-margin-top: 6rem; }

.site-header__utils {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* --------------------------------------------------------------------------
   Language switcher
   -------------------------------------------------------------------------- */

.lang-switch {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.lang-switch__label {
  display: none;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.75);
}

.lang-switch__group {
  display: flex;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.lang-switch__btn {
  min-width: 44px;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  color: var(--color-text-invert);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  transition: background-color 150ms ease-out, color 150ms ease-out;
}

.lang-switch__btn:hover { background: rgba(255, 255, 255, 0.15); }

.lang-switch__btn.is-active {
  background: var(--color-accent);
  color: var(--color-primary-deep);
}

/* Outline would be clipped by the group's overflow:hidden. */
.lang-switch__btn:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 3px var(--color-focus);
}

@media (min-width: 1100px) {
  .lang-switch__label { display: inline; }
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-radius: var(--radius-md);
  color: var(--color-text-invert);
  font-size: var(--text-sm);
  font-weight: 600;
}

.nav-toggle:hover { border-color: var(--color-accent); }

.nav-toggle__bars {
  position: relative;
  width: 18px;
  height: 2px;
  background: currentColor;
  display: block;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 18px;
  height: 2px;
  background: currentColor;
}

.nav-toggle__bars::before { top: -6px; }
.nav-toggle__bars::after  { top: 6px; }

/* No-JS fallback: the toggle is useless without JS, so hide it and leave the
   nav permanently expanded. .js is set by nav.js before first paint. */
.nav-toggle { display: none; }
.js .nav-toggle { display: inline-flex; }

.primary-nav {
  flex-basis: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-block: var(--space-3) var(--space-4);
}

.js .primary-nav[hidden] { display: none; }

.primary-nav__list {
  display: flex;
  flex-direction: column;
}

.primary-nav__list a {
  display: block;
  position: relative;
  padding: var(--space-3) var(--space-2);
  color: var(--color-text-invert);
  text-decoration: none;
  font-weight: 600;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  transition: color var(--dur-fast) var(--ease-out);
}

.primary-nav__list a:hover { color: var(--yellow-500); }

.primary-nav__list a[aria-current="page"] {
  color: var(--yellow-500);
  border-bottom-color: var(--color-accent);
}

.nav-toggle {
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.nav-toggle[aria-expanded="true"] {
  border-color: var(--color-accent);
  background: rgb(255 255 255 / 0.08);
}

.lang-switch__btn {
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.primary-nav__cta { align-self: flex-start; }

/* --- phone header ---------------------------------------------------------
   At 360–400px the brand block plus the switcher plus the toggle overran the
   bar and wrapped onto a second row, which on a sticky header costs the top of
   every page. Each part gives up a little so the whole thing stays one row;
   below ~340px it still wraps, and `margin-left:auto` keeps the utilities
   right-aligned when it does. */
@media (max-width: 559px) {
  .site-header__inner { gap: var(--space-2); }

  .site-header__utils { margin-left: auto; }

  .brand { gap: var(--space-2); }

  .brand__logo {
    width: 38px;
    height: 38px;
    flex-basis: 38px;
  }

  .brand__name { font-size: var(--text-base); }

  .brand__tagline {
    font-size: 0.625rem;
    letter-spacing: 0.04em;
  }

  .lang-switch__btn {
    min-width: 40px;
    padding-inline: var(--space-2);
  }

  /* The bars are the affordance at this size; the word stays for screen
     readers so the button keeps its accessible name. */
  .nav-toggle__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (min-width: 900px) {
  .site-header__inner { flex-wrap: nowrap; padding-block: var(--space-4); }

  /* DOM order is brand → utils → nav so the switcher stays reachable next to
     the menu button on mobile; on desktop the nav moves back into the middle. */
  .brand { order: 1; }
  .primary-nav { order: 2; }
  .site-header__utils { order: 3; }

  .nav-toggle,
  .js .nav-toggle { display: none; }

  .primary-nav,
  .js .primary-nav[hidden] {
    display: flex;
    flex-basis: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--space-5);
    padding-block: 0;
    margin-left: auto;
  }

  .primary-nav__list {
    flex-direction: row;
    gap: var(--space-1);
  }

  .primary-nav__list a {
    padding: var(--space-2) var(--space-3);
    border-bottom: 0;
  }

  /* Underline is a scaled pseudo-element rather than an animated border or
     width, so it wipes in on the compositor without reflowing the nav. */
  .primary-nav__list a::after {
    content: "";
    position: absolute;
    left: var(--space-3);
    right: var(--space-3);
    bottom: 0;
    height: 2px;
    background: var(--color-accent);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--dur-mid) var(--ease-out);
  }

  .primary-nav__list a:hover::after,
  .primary-nav__list a:focus-visible::after,
  .primary-nav__list a[aria-current="page"]::after {
    transform: scaleX(1);
  }

  /* The current page's underline is a state, not a response to the pointer,
     so it must not appear to wipe in when the page loads. */
  .primary-nav__list a[aria-current="page"]::after { transition: none; }
}

/* --------------------------------------------------------------------------
   Payment-safety ticker

   Sits directly under the sticky header. Brand yellow on deep blue is the
   loudest pair in the palette (12.72:1) and is otherwise reserved for CTAs,
   which is exactly why it earns its place here: this is the one line the site
   cannot afford a customer to skim past.

   The loop is two identical tracks laid side by side, both translated from
   -100% to 0. When the animation restarts, track 2 has arrived precisely where
   track 1 started, so there is no seam and no jump.
   -------------------------------------------------------------------------- */

.pay-ticker {
  /* Deliberately not sticky. The header already occupies top: 0 and its height
     changes on scroll, so a second sticky band would have to chase it; the
     ticker only needs to be the first thing under the header on arrival. */
  background: var(--color-primary-deep);
  color: var(--color-accent);
  border-bottom: 1px solid rgb(249 220 6 / 0.25);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
}

.pay-ticker__viewport {
  display: flex;
  overflow: hidden;
  padding-block: var(--space-2);
  /* Both edges fade out, so words dissolve rather than being sliced by the
     viewport. Progressive: without mask support the ticker just has hard
     edges, which is the pre-existing behaviour, not a broken one. */
  mask-image: linear-gradient(to right,
                transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(to right,
                transparent, #000 6%, #000 94%, transparent);
}

.pay-ticker__track {
  display: flex;
  flex: 0 0 auto;
  min-width: 100%;
  justify-content: space-around;
  gap: var(--space-7);
  padding-inline: calc(var(--space-7) / 2);
  white-space: nowrap;
  will-change: transform;
  animation: pay-ticker-slide 34s linear infinite;
}

/* Pause on hover so anyone who wants to read the account name properly can. */
.pay-ticker:hover .pay-ticker__track { animation-play-state: paused; }

@keyframes pay-ticker-slide {
  from { transform: translate3d(-100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

.pay-ticker__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}

.pay-ticker__item strong {
  color: var(--white);
  font-weight: 700;
}

.pay-ticker__dot {
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: var(--radius-pill);
  background: currentColor;
}

@media (min-width: 768px) {
  .pay-ticker { font-size: var(--text-base); }
}

/* --------------------------------------------------------------------------
   Payment policy block (footer)
   -------------------------------------------------------------------------- */

/* This is a warning, not a paragraph of footer copy, so it is pulled off the
   footer's own surface rather than tinted a few percent above it: a yellow-cast
   panel, a full accent border with a heavier spine, and a shadow that lifts the
   whole block. White text sits at 10.7:1 on the resulting background. */
.pay-policy {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  background: rgb(249 220 6 / 0.10);
  border: 1px solid rgb(249 220 6 / 0.55);
  border-left: 6px solid var(--color-accent);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  margin-bottom: var(--space-6);
  box-shadow: 0 8px 24px rgb(10 8 40 / 0.35);
}

.pay-policy__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-primary-deep);
}

.pay-policy__title {
  font-size: var(--text-md);
  color: var(--color-accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: var(--space-2);
}

.pay-policy__lead {
  color: var(--color-text-invert);
  font-size: var(--text-md);
  font-weight: 600;
  margin-bottom: var(--space-3);
}

/* The account name is the single fact this whole block exists to deliver, so
   it is the only thing here allowed to break the footer's type rhythm. */
.pay-policy__name { color: var(--color-accent); }

/* Keeping the name on one line is worth a lot for recognition, but only once
   there is room: at 320px it is wider than the column and would overflow. */
@media (min-width: 480px) {
  .pay-policy__name { white-space: nowrap; }
}

/* Was 0.78 white, which sat at the same weight as the footer's ordinary body
   copy and let the caveat read as boilerplate. */
.pay-policy__note {
  color: rgba(255, 255, 255, 0.93);
  font-size: var(--text-sm);
  line-height: 1.6;
  max-width: 68ch;
}

/* On a phone the icon and the heading belong on one line; the body text then
   runs the full width of the panel rather than a ~40px-narrower column. */
@media (max-width: 559px) {
  .pay-policy {
    display: block;
    padding: var(--space-4);
  }

  .pay-policy__mark {
    flex: none;
    width: 32px;
    height: 32px;
    margin-bottom: var(--space-3);
  }

  .pay-policy__mark svg { width: 18px; height: 18px; }
}

/* --------------------------------------------------------------------------
   Site footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--color-surface-footer);
  color: rgba(255, 255, 255, 0.88);
  margin-top: var(--space-9);
  padding-top: var(--space-7);
  font-size: var(--text-sm);
}

@media (max-width: 559px) {
  .site-footer {
    margin-top: var(--space-7);
    padding-top: var(--space-6);
  }
}

.site-footer a {
  color: var(--yellow-500);
  text-decoration: none;
}
.site-footer a:hover {
  color: var(--yellow-500);
  text-decoration: underline;
}

.site-footer__grid {
  display: grid;
  gap: var(--space-6);
  padding-bottom: var(--space-7);
}

.site-footer__brand .brand__mark--footer { margin-bottom: var(--space-4); }

.site-footer__blurb { max-width: 40ch; }

/* --------------------------------------------------------------------------
   Footer licence plate
   --------------------------------------------------------------------------
   Same three facts as the licence card on the About page, compressed to a
   plate that fits under the footer blurb, and linked to the full block rather
   than repeating it. The number carries the accent colour because that is what
   someone is scanning the footer for; the label and issuer stay quiet.
   -------------------------------------------------------------------------- */

.footer-licence {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: rgb(255 255 255 / 0.05);
  border: 1px solid rgb(255 255 255 / 0.20);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-md);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

/* `.site-footer a:hover` would otherwise underline all three lines at once,
   which on a bordered plate reads as damage. Only the number underlines. */
.site-footer a.footer-licence,
.site-footer a.footer-licence:hover { text-decoration: none; }

.footer-licence:hover {
  background: rgb(255 255 255 / 0.10);
  border-color: rgb(249 220 6 / 0.45);
  border-left-color: var(--color-accent);
}

.footer-licence:hover .footer-licence__number {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer-licence__label {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.72);
}

/* Out-specifies `.site-footer a` so the plate does not inherit the yellow link
   colour wholesale — only the number is meant to be yellow. */
.site-footer .footer-licence__number {
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--color-accent);
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.footer-licence__issuer {
  font-size: var(--text-xs);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.72);
}

.site-footer__heading {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-invert);
  margin-bottom: var(--space-4);
}

.site-footer__nav li { margin-bottom: var(--space-2); }

.site-footer__contact p + p { margin-top: var(--space-3); }

.site-footer__note {
  color: rgba(255, 255, 255, 0.72);
  font-size: var(--text-xs);
  max-width: 42ch;
}

.site-footer__legal {
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  padding-block: var(--space-4);
  font-size: var(--text-xs);
  color: rgba(255, 255, 255, 0.72);
}

@media (min-width: 768px) {
  .site-footer__grid {
    grid-template-columns: 2fr 1fr 1.5fr;
    gap: var(--space-7);
  }
}

/* --------------------------------------------------------------------------
   Empty state
   -------------------------------------------------------------------------- */

.empty-state {
  text-align: center;
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-7) var(--space-5);
  margin-block: var(--space-6);
}

.empty-state__title { margin-bottom: var(--space-3); }

.empty-state p {
  color: var(--color-text-muted);
  max-width: 48ch;
  margin-inline: auto;
  margin-bottom: var(--space-5);
}

/* --------------------------------------------------------------------------
   Side card (used on content pages)
   -------------------------------------------------------------------------- */

.side-card {
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-accent);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}

.side-card + .side-card { margin-top: var(--space-4); }

.side-card__title {
  font-size: var(--text-md);
  margin-bottom: var(--space-2);
}

.side-card__body {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  margin-bottom: var(--space-4);
}

/* --------------------------------------------------------------------------
   Interaction polish (Phase 3)
   -------------------------------------------------------------------------- */

.site-footer a,
.rate-card__link,
.prose a,
.side-card a:not(.btn) {
  transition: color var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}

/* Footer links get the underline on hover rather than permanently, which keeps
   the columns quiet while still signalling they are links on approach. */
.site-footer__nav a,
.site-footer__contact a {
  text-decoration-color: transparent;
  text-decoration-line: underline;
  text-underline-offset: 3px;
  transition: text-decoration-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.site-footer__nav a:hover,
.site-footer__contact a:hover { text-decoration-color: currentColor; }

/* Shared card lift. Applied to the surfaces that behave like cards across
   pages; the shadow does the depth, the transform does the movement, and
   neither touches layout. */
.feature,
.service,
.outlet-card,
.side-card {
  transition: transform var(--dur-mid) var(--ease-out),
              box-shadow var(--dur-mid) var(--ease-out),
              border-color var(--dur-mid) var(--ease-out);
}

@media (hover: hover) {
  .feature:hover,
  .service:hover,
  .outlet-card:hover,
  .side-card:hover {
    transform: translate3d(0, -3px, 0);
    box-shadow: var(--shadow-md);
  }
}
