/* Public site styles — concatenated from the original React CSS modules. */

/* ============ Navbar ============ */
.navbar {
  background-color: var(--blue-dark);
  padding: 8px 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: sticky;
  top: 0;
  z-index: 100;
  transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

/* Transparent-until-scroll. Opt-in per page via {% block body_class %}, because
   it only works over a dark hero — the nav text is light. Pages with a light
   background (FAQs, Contact, ...) keep the solid navbar above.
   `.is-scrolled` is added by public_nav.js once the hero starts leaving. */
.has-transparent-nav .navbar {
  background-color: transparent;
  box-shadow: none;
}

/* `position: sticky` stays in normal flow and would reserve a ~81px strip
   above the hero — transparency there just reveals the page background, not
   the hero image. Fixed lifts the bar out of flow so it truly overlays, and
   the hero's 10rem top padding already clears the logo. */
.has-transparent-nav .navbar {
  position: fixed;
  left: 0;
  right: 0;
}

.has-transparent-nav .navbar.is-scrolled {
  background-color: var(--blue-dark);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Over the hero image the links need a shadow to stay readable; once the navy
   bar is back it would just look muddy, so it's dropped again. */
.has-transparent-nav .navbar:not(.is-scrolled) .nav-link,
.has-transparent-nav .navbar:not(.is-scrolled) .nav-logo-img {
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}

/* The CTA swaps colour with the bar so the two states read as clearly
   different: brand blue while transparent over the hero, then a white pill
   once the navy bar is behind it (where white has the most contrast). */
.has-transparent-nav .navbar:not(.is-scrolled) .nav-cta {
  background-color: var(--blue-medium);
  color: #ffffff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
}

.has-transparent-nav .navbar:not(.is-scrolled) .nav-cta:hover {
  background-color: var(--blue-hover);
  color: #ffffff;
}

.has-transparent-nav .navbar.is-scrolled .nav-cta {
  background-color: #ffffff;
  color: var(--blue-dark);
  box-shadow: none;
}

.has-transparent-nav .navbar.is-scrolled .nav-cta:hover {
  background-color: var(--bg-panel);
  color: var(--blue-dark);
}

/* ---- Light-background pages (FAQs, Contact, Login) ----
   Same transparent-until-scroll behaviour, but these pages have a near-white
   background, so while transparent the nav has to invert to dark-blue text.
   Once scrolled the navy bar returns and everything goes back to light. */
.is-light-nav .navbar:not(.is-scrolled) .nav-link {
  color: var(--blue-dark);
  /* The dark-on-light state needs no shadow; it would just look smudged. */
  text-shadow: none;
}

.is-light-nav .navbar:not(.is-scrolled) .nav-link:hover {
  color: var(--blue-medium);
}

.is-light-nav .navbar:not(.is-scrolled) .nav-link::after {
  background-color: var(--blue-medium);
}

/* The logo is a white-inverted PNG, so undo that filter while the bar is
   transparent over a light page. */
.is-light-nav .navbar:not(.is-scrolled) .nav-logo-img {
  filter: none;
  text-shadow: none;
}

/* Hamburger bars follow the link colour. */
.is-light-nav .navbar:not(.is-scrolled) .hamburger .bar {
  background-color: var(--blue-dark);
}

/* Fixed positioning takes the bar out of flow, so these pages need their own
   top spacing — their content starts near the top and would otherwise sit
   underneath it. The home hero doesn't need this: its padding already clears.
   Targeted per-wrapper rather than by position, so adding a page means adding
   its wrapper here deliberately instead of inheriting a surprise.

   The bar is taller on mobile (the logo wraps), hence the variable rather than
   a single hardcoded height. */
.is-light-nav {
  --nav-h: 81px;
}

.is-light-nav .faq-page,
.is-light-nav .contact-section,
.is-light-nav .login-page {
  margin-top: var(--nav-h);
}

/* .login-page sizes itself against the viewport; the added margin has to come
   out of that height or the page grows a scrollbar it didn't have before. */
.is-light-nav .login-page {
  min-height: calc(100vh - 340px - var(--nav-h));
}

@media (max-width: 768px) {
  .is-light-nav {
    --nav-h: 145px;
  }
}

/* No-JS fallback: without .is-scrolled ever being set, a permanently
   transparent bar would be unreadable past the hero. */
@media (scripting: none) {
  .has-transparent-nav .navbar {
    background-color: var(--blue-dark);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
}

.navbar-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Left navigation links */
.nav-tabs.nav-left {
  display: flex;
  align-items: center;
  gap: 20px;
}

.nav-logo {
  display: flex;
  align-items: center;
  cursor: pointer;
}

.nav-logo-img {
  height: 65px;
  /* Required now that the tag declares width/height attributes: without this
     the attribute's 342px wins for width and the logo renders stretched. */
  width: auto;
  margin-right: 24px;
  filter: brightness(0) invert(1);
}

.nav-logo:hover .nav-logo-img {
  opacity: 0.8;
  transform: scale(1.03);
}

/* Right side (login + hamburger) */
.nav-tabs.nav-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Common nav link style */
.nav-link {
  background: none;
  border: none;
  padding: 0.5rem 0.75rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--blue-navbar-text);
  text-decoration: none;
  cursor: pointer;
  position: relative;
  transition: color 0.2s ease;
}

.nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 2px;
  background-color: #ffffff;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}

.nav-link:hover {
  color: #ffffff;
}

.nav-link:hover::after {
  transform: scaleX(1);
}

/* "Join for Free" CTA pill. Brand blue on the dark navy navbar. */
.nav-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem 1.4rem;
  border: none;
  border-radius: 999px;
  background-color: var(--blue-medium);
  color: #ffffff;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.3s ease, color 0.3s ease, transform 0.2s ease,
              box-shadow 0.3s ease;
}

.nav-cta:hover {
  background-color: var(--blue-hover);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
}

.nav-cta:active {
  transform: translateY(0);
  box-shadow: none;
}

.nav-cta:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 2px;
}

/* The dropdown copy of the CTA is only for <=768px. */
.nav-cta-mobile {
  display: none;
}

/* Hamburger Menu */
.hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 4px;
  padding: 6px;
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 0 4px rgba(0,0,0,0.15);
  cursor: pointer;
  background: none;
}

.hamburger .bar {
  width: 24px;
  height: 3px;
  background-color: var(--blue-navbar-text);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.2s ease;
}

/* Open state: bars fold into an X. */
.hamburger.open .bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.hamburger.open .bar:nth-child(2) {
  opacity: 0;
}
.hamburger.open .bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* Hidden on desktop; the [hidden] attribute is what the JS toggles. */
.nav-dropdown {
  display: none;
}

/* Mobile View */
@media (max-width: 768px) {
  .nav-tabs.nav-left {
    display: none; /* hide desktop nav links */
  }

  .hamburger {
    display: flex !important;
  }

  /* [hidden] must still win over this display:flex when the menu is closed. */
  .nav-dropdown {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 100%;
    right: 10px;
    min-width: 220px;
    background-color: var(--blue-dark);
    padding: 10px;
    border-radius: 8px;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
    z-index: 1000;
  }

  .nav-dropdown[hidden] {
    display: none;
  }

  .nav-dropdown .nav-link {
    padding: 0.75rem 1rem;
    text-align: left;
    white-space: nowrap;
  }

  /* Keep "Sign In" in the bar (it's compact), move the pill into the dropdown
     so the logo + CTA + hamburger don't overflow on narrow screens. */
  .nav-right .nav-cta {
    display: none;
  }

  .nav-cta-mobile {
    display: inline-flex;
    margin: 8px 1rem 4px;
  }

  /* The dropdown has its own navy panel, so it stays opaque even while the
     bar behind it is transparent. */
  .has-transparent-nav .nav-dropdown {
    background-color: var(--blue-dark);
  }
}

.mobile-only {
  display: none;
}

@media (max-width: 768px) {

  .mobile-only {
    display: flex !important;
    justify-content: center;
    padding: 10px 0;
  }
}

@media (max-width: 768px) {

  .mobile-only {
    display: block !important;
    margin: 20px 0;
  }

}

.producer-form {
  max-width: 620px;
  margin: 1rem auto 2.5rem auto;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 2rem 2.25rem;
  background-color: #ffffff;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(15, 96, 155, 0.08), 0 2px 8px rgba(0, 0, 0, 0.05);
}

.producer-form label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: #444;
}

.producer-form input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.85rem;
  font-size: 0.95rem;
  border: 1px solid #d5dde3;
  border-radius: 8px;
  background-color: var(--bg-page);
  transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
}

.producer-form input:focus {
  outline: none;
  border-color: var(--blue-medium);
  background-color: #ffffff;
  box-shadow: 0 0 0 3px rgba(15, 96, 155, 0.15);
}

.producer-form input::placeholder {
  color: #9aa5ad;
}

.producer-form button {
  background-color: var(--blue-medium);
  color: white;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0.85rem 2.75rem;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(15, 96, 155, 0.25);
  transition: background-color 0.2s, transform 0.1s, box-shadow 0.2s;
  display: block;
  margin: 0.75rem auto 0 auto;
  font-size: 0.95rem;
}

.producer-form button:hover {
  background-color: var(--blue-hover);
  box-shadow: 0 6px 16px rgba(15, 96, 155, 0.3);
}

.producer-form button:active {
  background-color: var(--blue-hover);
  transform: translateY(1px);
  box-shadow: 0 2px 6px rgba(15, 96, 155, 0.25);
}

@media (max-width: 768px) {

  .producer-form {
    margin: 1rem;
    padding: 1.5rem 1.25rem;
  }

}

/* ===== pages/FAQPage.css ===== */
/* ---- FAQ page ----
   Title stacked above the questions (was a two-column flex with the heading
   beside the list). Items are cards rather than hairline-separated rows. */
.faq-page {
  max-width: 860px;
  margin: 0 auto;
  padding: 40px 20px 80px;
}

.faq-header {
  text-align: center;
  margin-bottom: 3rem;
}

.faq-title {
  font-size: 2.75rem;
  line-height: 1.15;
  font-weight: 800;
  margin: 0 0 1rem;
  color: var(--blue-dark);
}

/* Short accent rule under the heading, matching .section-title on the home page. */
.faq-title::after {
  content: '';
  display: block;
  width: 60px;
  height: 3px;
  margin: 1rem auto 0;
  border-radius: 2px;
  background: var(--blue-medium);
}

.faq-subtitle {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.6;
  color: #5b666f;
}

.faq-subtitle a {
  color: var(--blue-medium);
  font-weight: 600;
}

.faq-container {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

/* Card per question. The border tightens and the card lifts when open. */
.faq-item {
  background: #ffffff;
  border: 1px solid #e1e9ef;
  border-radius: 14px;
  overflow: hidden;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}

.faq-item:hover {
  border-color: #c3d6e3;
}

.faq-item.is-open {
  border-color: var(--blue-medium);
  box-shadow: 0 8px 24px rgba(8, 47, 77, 0.09);
}

/* The <h2> is purely for document outline; the button carries all the styling. */
.faq-item-heading {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
}

.faq-question {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.25rem 1.5rem;
  background: none;
  border: none;
  font-family: inherit;
  font-size: 1.06rem;
  font-weight: 650;
  line-height: 1.45;
  text-align: left;
  color: var(--blue-dark);
  cursor: pointer;
  transition: color 0.2s ease;
}

.faq-question:hover {
  /* The old rule underlined on hover, which fought the card styling. */
  color: var(--blue-medium);
}

.faq-question:focus-visible {
  outline: 2px solid var(--blue-medium);
  outline-offset: -3px;
  border-radius: 14px;
}

.faq-item.is-open .faq-question {
  color: var(--blue-medium);
}

/* Circular chevron badge; rotates to point up when the panel opens. */
.faq-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg-panel);
  color: var(--blue-medium);
  transition: transform 0.28s ease, background-color 0.25s ease,
              color 0.25s ease;
}

.faq-icon svg {
  width: 17px;
  height: 17px;
}

.faq-item.is-open .faq-icon {
  transform: rotate(180deg);
  background: var(--blue-medium);
  color: #ffffff;
}

/* Answer panel. `hidden` is what the JS toggles, so it must win over any
   display set here. */
.faq-answer {
  color: #46525c;
  line-height: 1.7;
}

.faq-answer[hidden] {
  display: none;
}

/* Padding lives on the inner wrapper so the panel can animate its height
   later without the padding fighting a 0-height container. */
.faq-answer-inner {
  padding: 0 1.5rem 1.4rem;
  /* Indent aligns the answer with the question text above it. */
  border-top: 1px solid #eef3f7;
  padding-top: 1.15rem;
  margin-top: -1px;
  animation: faq-open 0.25s ease both;
}

@keyframes faq-open {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.faq-answer p {
  margin: 0 0 0.85rem;
}

.faq-answer p:last-child {
  margin-bottom: 0;
}

@media (prefers-reduced-motion: reduce) {
  .faq-icon,
  .faq-item {
    transition: none;
  }
  .faq-answer-inner {
    animation: none;
  }
}

@media (max-width: 640px) {
  .faq-page {
    padding: 24px 16px 56px;
  }
  .faq-title {
    font-size: 2rem;
  }
  .faq-header {
    margin-bottom: 2rem;
  }
  .faq-question {
    padding: 1.05rem 1.15rem;
    font-size: 1rem;
    gap: 0.85rem;
  }
  .faq-answer-inner {
    padding: 1.05rem 1.15rem 1.2rem;
  }
}

/* ===== pages/ContactPage.css ===== */
/* ContactPage.css */

.contact-section {
  max-width: 720px;
  margin: 3rem auto;
  padding: 2.5rem 2.75rem;
  font-family: sans-serif;
  background-color: #ffffff;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(15, 96, 155, 0.08), 0 2px 8px rgba(0, 0, 0, 0.05);
}

/* Matches .faq-title: dark blue, mixed case, with the short accent rule
   underneath. The old style was uppercase medium-blue with wide tracking,
   which didn't match any other page heading. */
.contact-title {
  font-size: 2.75rem;
  line-height: 1.15;
  font-weight: 800;
  color: var(--blue-dark);
  text-align: center;
  margin: 0 0 1rem;
}

.contact-title::after {
  content: '';
  display: block;
  width: 60px;
  height: 3px;
  margin: 1rem auto 0;
  border-radius: 2px;
  background: var(--blue-medium);
}

.contact-description {
  text-align: center;
  max-width: 600px;
  margin: 0 auto;
  font-size: 1.05rem;
  color: #5b666f;
  line-height: 1.6;
}

/* .contact-divider is gone — the accent rule lives on .contact-title now, and
   this margin carries the gap the divider used to provide. */
.contact-description {
  margin-bottom: 2.5rem;
}

.contact-form {
  display: grid;
  gap: 1.5rem;
}

.contact-inputs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1rem;
}

.contact-input-wrapper {
  position: relative;
}

.contact-input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.85rem 1rem;
  border: 1px solid #d5dde3;
  border-radius: 8px;
  font-size: 1rem;
  background-color: var(--bg-page);
  transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
}

.contact-input:focus,
.contact-textarea:focus {
  outline: none;
  border-color: var(--blue-medium);
  background-color: #ffffff;
  box-shadow: 0 0 0 3px rgba(15, 96, 155, 0.15);
}

.contact-input::placeholder,
.contact-textarea::placeholder {
  color: #9aa5ad;
}

.full-width {
  grid-column: span 2;
}

.contact-textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 1rem;
  border: 1px solid #d5dde3;
  border-radius: 8px;
  resize: vertical;
  font-size: 1rem;
  color: #333;
  font-family: inherit;
  background-color: var(--bg-page);
  transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
}

.contact-submit {
  text-align: center;
}

.contact-submit-button {
  background-color: var(--blue-medium);
  color: white;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0.85rem 2.75rem;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(15, 96, 155, 0.25);
  transition: background-color 0.2s, transform 0.1s, box-shadow 0.2s;
}

.contact-submit-button:hover {
  background-color: var(--blue-hover);
  box-shadow: 0 6px 16px rgba(15, 96, 155, 0.3);
}

.contact-submit-button:active {
  background-color: var(--blue-hover);
  transform: translateY(1px);
  box-shadow: 0 2px 6px rgba(15, 96, 155, 0.25);
}

@media (max-width: 768px) {

  .contact-input,
.contact-textarea {
    width: 100%;
    box-sizing: border-box;
    padding-left: 1rem;
    padding-right: 1rem;
    margin: 0;
  }

  .contact-section {
    margin: 1.5rem 1rem;
    padding: 1.75rem 1.25rem;
  }

  .contact-title {
    font-size: 1.8rem;
  }

  .contact-description {
    font-size: 1rem;
    margin-bottom: 1.5rem;
  }

  .contact-inputs {
    grid-template-columns: 1fr;
  }

  .full-width {
    grid-column: span 1; 
  }

  .contact-submit-button {
    width: 100%; 
  }
}

/* ===== pages/private/privateApp.css ===== */
/* General */
body, html {
  margin: 0;
  font-family: sans-serif;
  background-color: var(--bg-page);
  color: #333;
}

.rank {
  width: 0rem;
  text-align: right;
  font-size: 1.5rem;
}

.name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 1.3rem;
}

.points {
  font-weight: bold;
  font-size: 1.3rem;
}

.bonus {
  color: var(--blue-medium);
  font-weight: bold;
  font-size: 20px;
  min-width: 60px; 
  text-align: left;
}

/* ===== Site footer (templates/_footer.html) ===== */
.site-footer {
  margin-top: 40px;
  /* The footer keeps its own carbon blue rather than --blue-dark, so it reads
     as the end of the page instead of another navy band. */
  background-color: #1a2b33;
  color: #d7e0e6;
  font-size: 0.875rem;
  line-height: 1.45;
}

.site-footer__grid {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem 2rem 1.5rem;
  display: grid;
  /* Contact is the widest column so its email and phone fit on one line; the
     two link columns are narrow. Collapses via the media queries below. */
  grid-template-columns: 1.4fr 0.8fr 0.9fr 1.6fr;
  gap: 1.75rem 2rem;
}

/* ---- brand ---- */
.site-footer__logo {
  height: 42px;
  width: auto;
  /* Same trick the navbar uses: the source PNG is dark, so flatten and invert
     it to sit on the dark footer. Replacing the asset with a white SVG would
     let both this and the navbar rule go away. */
  filter: brightness(0) invert(1);
}

.site-footer__blurb {
  margin: 0.65rem 0 0;
  max-width: 40ch;
  color: #a8b6c0;
}

/* ---- link columns ---- */
.site-footer__heading {
  margin: 0 0 0.6rem;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #ffffff;
}

.site-footer__list,
.site-footer__contacts {
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__list li + li {
  margin-top: 0.4rem;
}

/* ---- contact column ---- */
.site-footer__contact + .site-footer__contact {
  margin-top: 0.55rem;
}

.site-footer__contact-label {
  display: block;
  font-weight: 700;
  color: #ffffff;
}

/* Email + phone on one row. `gap` rather than a "·" separator character, so a
   wrap at a narrow width doesn't leave a dangling middot at the end of a line. */
.site-footer__contact-lines {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.85rem;
}

/* ---- links ----
   The old footer had no hover or focus state at all, so links were
   indistinguishable from the text around them. */
.site-footer a {
  color: #d7e0e6;
  text-decoration: none;
  transition: color 0.2s ease;
}

.site-footer a:hover {
  color: #ffffff;
  text-decoration: underline;
}

.site-footer a:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 2px;
  border-radius: 2px;
}

/* ---- bottom bar ---- */
.site-footer__bar {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0.9rem 2rem 1.25rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.35rem 1.5rem;
  font-size: 0.8rem;
  color: #8a99a4;
}

.site-footer__copyright,
.site-footer__address {
  margin: 0;
}

/* Below the 4-column layout: brand across the top, the two short link lists
   side by side, then contact across the full width.
   Pairing Panel with Legal saves a whole stacked block, and giving contact the
   full width keeps each email and phone on one line instead of wrapping — both
   of which are what made the narrow footer disproportionately tall. */
@media (max-width: 900px) {
  .site-footer__grid {
    grid-template-columns: 1fr 1fr;
  }
  .site-footer__brand,
  .site-footer__col--contact {
    grid-column: 1 / -1;
  }
}

/* Tablet only: park contact in the second column, alongside the two link lists
   stacked in the first, instead of on its own row underneath. Without this the
   right half of the row sits empty and the footer is ~130px taller than it
   needs to be.
   Deliberately not applied below 601px: a half-width column there is narrower
   than a single email address. */
@media (min-width: 601px) and (max-width: 900px) {
  .site-footer__col--panel {
    grid-column: 1;
    grid-row: 2;
  }
  .site-footer__col--legal {
    grid-column: 1;
    grid-row: 3;
  }
  .site-footer__col--contact {
    grid-column: 2;
    grid-row: 2 / span 2;
  }
}

@media (max-width: 600px) {
  .site-footer__grid {
    gap: 1.35rem 1.5rem;
    padding: 1.75rem 1.5rem 1.25rem;
  }
  .site-footer__blurb {
    max-width: none;
  }
  .site-footer__bar {
    padding: 0.9rem 1.5rem 1.5rem;
  }
}


/* ===== components/PointsChart.css ===== */
.chart-wrapper {
  position: relative;
  width: 140px;
  height: 140px;
}

.chart-center-text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  line-height: 1.2;
}

.chart-center-text .label {
  font-size: 0.875rem; /* ~14px */
  color: #4b5563;       /* Tailwind's gray-600 */
  margin: 0;
}

.chart-center-text .value {
  font-size: 1.25rem;   /* ~20px */
  font-weight: bold;
  color: black;
  margin: 0;
}

.chart-center-text .total {
  font-size: 0.875rem;  /* ~14px */
  color: #6b7280;       /* Tailwind's gray-500 */
}

/* ============================================================
   ===== Updated public design (ported from feature/base-frontend React) =====
   ============================================================ */

:root {
  /* ---- Blue palette (consolidated) ----
     Only 3 brand blues + 2 backgrounds. Footer keeps its own carbon blue. */
  --blue-dark: #082f4d;      /* navbar, headings, strong text */
  --blue-medium: #0f609b;    /* buttons, links, focus, accents */
  --blue-hover: #0c4f85;     /* :hover / :active states */
  --bg-page: #f8fdff;        /* page/body background, near-white */
  --bg-panel: #eaf9fe;       /* cards / panels, soft light blue */
  --blue-navbar-text: #eaf1f7; /* light text/bars on the dark navbar */

  /* Warm accent, used only for money/reward figures. The palette is otherwise
     all blues, so the gift-card amount had nothing to distinguish it from any
     other heading; this is the one place a non-brand hue earns its place. */
  --accent-reward: #f5b942;

  /* Legacy aliases mapped onto the new palette so the "new system"
     styles below keep working without duplicate tones. */
  --color-primary: var(--blue-dark);
  --color-secondary: var(--blue-medium);
  --color-background: var(--bg-panel);
  --color-light: #eaf9fe86;
  --color-font: #333;
  --color-font-button: #fff;
  --color-background-button: var(--color-primary);
  --color-hover-button: var(--blue-hover);
}

/* ---- Shared typography (home + sections) ---- */
.section-title {
  font-size: 2rem;
  color: var(--color-primary);
  margin-bottom: 2rem;
  position: relative;
  text-align: center;
}
.section-title::after {
  content: '';
  width: 60px;
  height: 3px;
  background-color: var(--color-secondary);
  display: block;
  margin: 0.5rem auto 0;
  border-radius: 3px;
}

/* ---- Home: Section 1 hero ---- */
.home-hero {
  /* Full-viewport hero: the photo always fills exactly one screen, whatever the
     window height, so there's no fixed pixel height to re-tune.
     `dvh` (dynamic viewport height) accounts for mobile browser chrome that
     shows/hides on scroll; the `vh` line above it is the fallback for browsers
     without dvh support. */
  min-height: 100vh;
  min-height: 100dvh;
  /* Required: this sheet has no global border-box reset, so without it the
     vertical padding is ADDED to 100vh and the hero overflows the screen by
     exactly that much. */
  box-sizing: border-box;
  position: relative;
  color: white;
  display: flex;
  justify-content: center;
  /* Centred vertically rather than pushed down by a large top padding — on a
     tall screen a fixed top padding would leave the text sitting high. */
  align-items: center;
  text-align: center;
  /* Padding is now just breathing room + navbar clearance. The top value
     exceeds the 81px overlaid navbar so centred content never rides under it;
     it's symmetric so the block stays optically centred. */
  padding: 6rem 0;
  background-image: url('../img/background.png');
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
}
.home-hero .content {
  z-index: 1;
  padding: 0 8rem;
}
.content h1 {
  font-size: 3rem;
  margin-bottom: 1rem;
}
.content p {
  font-size: 1.2rem;
  margin-bottom: 2rem;
}
/* ---- Hero CTA: one semi-transparent capsule ----
   Sits over the hero photo, so the capsule is a white wash rather than a
   solid fill — the image stays visible through it. */
.hero-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem;
  border-radius: 999px;
  background-color: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.25);
  /* Frosts the photo behind the capsule; harmless where unsupported. */
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  /* Slow breathing halo draws the eye without demanding attention. */
  animation: hero-cta-pulse 3.2s ease-in-out infinite;
  transition: background-color 0.25s ease, border-color 0.25s ease,
              transform 0.25s ease;
}

@keyframes hero-cta-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.28); }
  50%      { box-shadow: 0 0 0 12px rgba(255, 255, 255, 0); }
}

.hero-cta:hover {
  background-color: rgba(255, 255, 255, 0.28);
  border-color: rgba(255, 255, 255, 0.5);
  transform: translateY(-2px) scale(1.03);
  /* Pause the halo on hover so it doesn't fight the hover state. */
  animation-play-state: paused;
}

.hero-cta:active {
  transform: translateY(0) scale(0.99);
}

/* Bare text action + arrow inside the capsule. It's the only action in there,
   so the padding is symmetric. */
.hero-cta-secondary {
  position: relative;
  overflow: hidden;              /* clips the shine sweep to the pill */
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.75rem 1.75rem;
  border-radius: 999px;
  color: #ffffff;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  letter-spacing: 0.01em;
  transition: letter-spacing 0.25s ease;
}

/* Diagonal shine that sweeps across on hover. */
.hero-cta-secondary::before {
  content: '';
  position: absolute;
  top: 0;
  left: -60%;
  width: 45%;
  height: 100%;
  background: linear-gradient(
    100deg,
    transparent,
    rgba(255, 255, 255, 0.45),
    transparent
  );
  transform: skewX(-18deg);
  pointer-events: none;
}

.hero-cta:hover .hero-cta-secondary::before {
  animation: hero-cta-shine 0.75s ease;
}

@keyframes hero-cta-shine {
  from { left: -60%; }
  to   { left: 130%; }
}

.hero-cta:hover .hero-cta-secondary {
  letter-spacing: 0.03em;
}

.hero-cta-arrow {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  /* Gentle nudge at rest, so the button reads as clickable before hover. */
  animation: hero-cta-nudge 2.4s ease-in-out infinite;
  transition: transform 0.25s ease;
}

@keyframes hero-cta-nudge {
  0%, 70%, 100% { transform: translateX(0); }
  85%           { transform: translateX(4px); }
}

.hero-cta:hover .hero-cta-arrow {
  transform: translateX(6px);
  animation-play-state: paused;
}

.hero-cta-secondary:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 3px;
}

@media (max-width: 520px) {
  .hero-cta-secondary {
    padding: 0.7rem 1.35rem;
    font-size: 1.05rem;
  }
}

/* Motion is decorative here — drop all of it when reduced motion is asked for. */
@media (prefers-reduced-motion: reduce) {
  .hero-cta,
  .hero-cta-arrow {
    animation: none;
  }
  .hero-cta:hover .hero-cta-secondary::before {
    animation: none;
  }
  .hero-cta:hover {
    transform: none;
  }
}

/* rotating word */
.rotating-word-container {
  display: inline-block;
  height: 1.2em;
  overflow: hidden;
  position: relative;
  vertical-align: middle;
}
.rotating-word-wrapper {
  display: flex;
  flex-direction: column;
  transition: transform 0.5s ease-in-out;
}
.rotating-word {
  height: 1.2em;
  line-height: 1.2em;
  white-space: nowrap;
  text-align: center;
  transform: translateY(-0.1em);
}

/* ---- Home: Section 2+ ---- */
.home-next {
  padding: 6rem 2rem;
  background: linear-gradient(to bottom right, #f8fbfd, #edf3f7);
  text-align: center;
}

.card {
  background-color: white;
  padding: 2rem;
  border-radius: 12px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  flex: 1 1 300px;
  max-width: 350px;
  min-width: 280px;
}
.card:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}

.card h3 {
  margin-top: 1rem;
  margin-bottom: 0.5rem;
  color: var(--color-primary);
  font-size: 1.3rem;
}
.card p {
  font-size: 0.95rem;
  color: var(--color-font);
}
.card button {
  margin-top: 1rem;
  padding: 0.5rem 1.5rem;
  background-color: var(--color-background-button);
  color: var(--color-font-button);
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}
.card button:hover {
  background-color: var(--color-hover-button);
}

/* ---- Home: Section 3 steps ---- */
.steps {
  margin-top: 80px;
  display: flex;
  justify-content: center;
  gap: 70px;
  flex-wrap: wrap;
  /* Anchors the connector line that runs behind the icon circles. */
  position: relative;
}

/* ---- Scroll-linked reveal ----
   home.js writes a 0-1 progress value into --reveal on each step (and
   --reveal-line on the row) from the scroll position, so the reveal tracks the
   wheel directly: scroll slowly and it creeps in, scroll back up and it
   reverses. Nothing is time-based, hence no `transition` on these properties —
   a transition would lag behind the scroll and fight it.

   This is deliberately SEPARATE from :hover — the hover lift/fill still works
   exactly as before, on top of a revealed step. #1 reason for the inner
   .step-reveal wrapper: it owns this transform so .step's stays free for hover. */
.step-reveal {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 34px;
  width: 100%;
}

.steps [data-step-reveal] {
  --reveal: 0;
  opacity: var(--reveal);
  /* Slides up into place as it fades in; 26px at 0, 0px at 1. */
  transform: translateY(calc((1 - var(--reveal)) * 26px));
}

.steps::before {
  --reveal-line: 0;
  opacity: var(--reveal-line);
}

/* Never leave the section invisible if the script is blocked. This used to be
   scoped to `.no-js`, but nothing ever added that class to <html>, so the
   fallback never applied and the whole section stayed at opacity:0 without JS.
   `scripting: none` needs no JS to set it up, and matches how the transparent
   navbar already guards itself higher up in this file. */
@media (scripting: none) {
  .steps [data-step-reveal],
  .steps::before {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .steps [data-step-reveal] {
    opacity: 1;
    transform: none;
  }
  .steps::before {
    opacity: 1;
  }
}

/* Connector line threading the five circles together. Sits behind them and
   stops short of the row edges so it reads as joining the steps, not as a
   rule across the section. Hidden once the row wraps (see media query). */
.steps::before {
  content: '';
  position: absolute;
  top: 75px;                /* vertical centre of a 150px circle */
  left: 10%;
  right: 10%;
  height: 2px;
  background: repeating-linear-gradient(
    to right,
    #cfe0ec 0 8px,
    transparent 8px 16px
  );
  z-index: 0;
}

.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 210px;
  /* Circle → number keeps the original airy gap; the number then sits close
     to the caption it labels (see .step-num margin below). */
  gap: 34px;
  position: relative;
  z-index: 1;               /* above the connector line */
  cursor: default;
  transition: transform 0.28s ease;
}

/* Hover/focus lifts the whole step. :focus-within covers the tabindex on the
   step so keyboard users get the same reveal. */
.step:hover,
.step:focus,
.step:focus-within {
  transform: translateY(-10px);
  outline: none;
}

.step-icon {
  background-color: white;
  border-radius: 50%;
  width: 150px;
  height: 150px;
  display: flex;
  justify-content: center;
  align-items: center;
  box-shadow: 0 0 10px rgba(0,0,0,0.1);
  /* Anchor for the number badge + clip the fill sweep to the circle. */
  position: relative;
  overflow: hidden;
  transition: box-shadow 0.28s ease, transform 0.28s ease;
}

/* Brand-blue disc that grows from the centre to fill the circle on hover. */
.step-icon::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--blue-medium);
  transform: scale(0);
  transition: transform 0.32s ease;
  z-index: 0;
}

.step:hover .step-icon,
.step:focus .step-icon,
.step:focus-within .step-icon {
  box-shadow: 0 12px 28px rgba(8, 47, 77, 0.28);
}

.step:hover .step-icon::after,
.step:focus .step-icon::after,
.step:focus-within .step-icon::after {
  transform: scale(1);
}

.step-icon img {
  max-width: 80px;
  height: auto;
  position: relative;
  z-index: 1;               /* above the fill disc */
  transition: transform 0.28s ease, filter 0.28s ease;
}

/* The icons are dark artwork, so once the disc is blue they invert to white. */
.step:hover .step-icon img,
.step:focus .step-icon img,
.step:focus-within .step-icon img {
  transform: scale(1.08);
  filter: brightness(0) invert(1);
}

/* Step number: a small pill sitting between the circle and the caption, so it
   labels the text rather than crowding the icon. */
.step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg-panel);
  color: var(--blue-medium);
  font-size: 0.95rem;
  font-weight: 800;
  line-height: 1;
  /* Pulls the badge down against its caption, out of the flex gap. */
  margin-bottom: -22px;
  transition: background-color 0.28s ease, color 0.28s ease,
              transform 0.28s ease, box-shadow 0.28s ease;
}

.step:hover .step-num,
.step:focus .step-num,
.step:focus-within .step-num {
  background: var(--blue-medium);
  color: #ffffff;
  transform: scale(1.15);
  box-shadow: 0 4px 12px rgba(15, 96, 155, 0.35);
}

.step-text {
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--color-primary);
  text-align: center;
  transition: color 0.28s ease;
}

.step:hover .step-text,
.step:focus .step-text,
.step:focus-within .step-text {
  color: var(--blue-medium);
}

/* Wrapped rows put steps on multiple lines, where a single horizontal
   connector would cut through the text of the row above. */
@media (max-width: 1250px) {
  .steps::before { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .step,
  .step-icon,
  .step-icon::after,
  .step-icon img,
  .step-num,
  .step-text {
    transition: none;
  }
  .step:hover,
  .step:focus,
  .step:focus-within {
    transform: none;
  }
}

/* ---- Home: browser-extension promo ----
   Two columns: copy left, the laptop illustration right. Sits between "How it
   works" and the reviews. */
.extension-section {
  /* .home-next centres its text; this section is left-aligned in its columns. */
  text-align: left;
}

.extension-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 4rem;
}

.extension-copy {
  flex: 1 1 0;
  min-width: 0;
}

/* .section-title is centred with a centred ::after rule; both need resetting
   here because this heading sits in a left-aligned column. */
.extension-title {
  text-align: left;
  font-size: 2.1rem;
  line-height: 1.2;
  margin-bottom: 1.25rem;
}

.extension-title::after {
  margin-left: 0;
  margin-right: 0;
}

.extension-lead {
  font-size: 1.05rem;
  line-height: 1.7;
  color: #46525c;
  margin: 0 0 1.5rem;
}

.extension-perks {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.extension-perks li {
  position: relative;
  padding-left: 2rem;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--blue-dark);
  font-weight: 600;
}

/* Tick marker, drawn in CSS so there's no extra markup per item. */
.extension-perks li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.15em;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background: var(--bg-panel) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f609b' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 0.72rem no-repeat;
}

/* Solid brand-blue button, matching .nav-cta's pill treatment. */
.extension-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.9rem;
  border-radius: 999px;
  background-color: var(--blue-medium);
  color: #ffffff;
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.extension-cta:hover {
  background-color: var(--blue-hover);
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(8, 47, 77, 0.22);
}

.extension-cta:active {
  transform: translateY(0);
  box-shadow: none;
}

.extension-cta:focus-visible {
  outline: 2px solid var(--blue-medium);
  outline-offset: 3px;
}

.extension-cta-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.extension-cta:hover .extension-cta-icon {
  transform: translateY(2px);
}

.extension-visual {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  justify-content: center;
}

/* Anchors the overlay to the image rather than the column, so the bar tracks the
   artwork at any size. Width is capped here (not on the img) so the wrapper and
   image share identical bounds. */
.extension-visual [data-extension-visual],
[data-extension-visual] {
  position: relative;
  width: 100%;
  max-width: 520px;
  /* Establishes the container for the cqw units the overlay label uses, so the
     text scales with the artwork rather than the viewport. */
  container-type: inline-size;
}

.extension-visual img {
  display: block;
  width: 100%;
  height: auto;
}

/* Sits over the empty white card in the PNG. All offsets are percentages of the
   618x404 artwork, taken from the card's measured pixel bounds
   (x 189-451, y 149-261), so the overlay stays registered as the image scales.

   Layout: the SBKC logo is already drawn in the art, left-aligned at x 198-264
   and vertically centred (y 193-225). The label and bar form a column to its
   RIGHT — label on top, bar under it — vertically centred on the logo, which is
   how the finished design reads. Earlier versions stacked them above/below the
   logo instead, which left both cramped against the card edges. */
.extension-overlay {
  position: absolute;
  left: 30.58%;
  right: 27.02%;
  top: 36.88%;
  bottom: 35.40%;
  pointer-events: none;
}

/* The right-hand column. Starts clear of the logo and keeps the same 3.4% inset
   from the card's right edge that the logo has on the left. Centred vertically
   so the label/bar pair aligns with the logo beside it. */
.extension-overlay-stack {
  position: absolute;
  left: 34%;
  right: 3.4%;
  top: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12%;
}

.extension-overlay-label {
  margin: 0;
  text-align: center;
  /* Scales with the artwork (cqw resolves against the image wrapper) so it never
     outgrows the little browser card; the low floor keeps it inside the card on
     a narrow phone, where the card is only ~140px wide. */
  font-size: clamp(0.34rem, 1.5vw, 0.78rem);
  font-size: clamp(0.34rem, 5.2cqw, 0.78rem);
  font-weight: 700;
  line-height: 1.2;
  color: var(--blue-dark);
  white-space: nowrap;
}

.extension-progress {
  width: 100%;
  height: 22%;
  min-height: 5px;
  max-height: 11px;
  border-radius: 999px;
  background: #e6eaef;
  overflow: hidden;
}

.extension-progress-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 999px;
  /* Green, matching the install-progress convention in the original artwork. */
  background: #34a853;
  transition: width 0.15s linear;
}

/* Completed state: home.js swaps the caption to "Installed!" and adds .is-done.
   Turning the text the same green as the bar makes the completion read at a
   glance instead of relying on the wording alone. */
.extension-overlay-label.is-done {
  color: #1e8e3e;
}

@media (prefers-reduced-motion: reduce) {
  .extension-progress-fill {
    transition: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .extension-cta,
  .extension-cta-icon {
    transition: none;
  }
  .extension-cta:hover {
    transform: none;
  }
  .extension-cta:hover .extension-cta-icon {
    transform: none;
  }
}

/* Stack below the two-column breakpoint: image first, then the copy centred. */
@media (max-width: 900px) {
  .extension-inner {
    flex-direction: column;
    gap: 2.5rem;
    text-align: center;
  }
  /* Image above the text — it explains what the section is about. */
  .extension-visual {
    order: -1;
  }
  /* Cap the WRAPPER, not the img: the overlay is positioned against the
     wrapper, so capping only the image leaves the two different widths and the
     overlay no longer lines up with the card. */
  [data-extension-visual] {
    max-width: 420px;
  }
  .extension-title,
  .extension-title::after {
    text-align: center;
    margin-left: auto;
    margin-right: auto;
  }
  .extension-lead {
    text-align: center;
  }
  /* Ticks stay left of their text, but the list is centred as a block. */
  .extension-perks {
    display: inline-flex;
    text-align: left;
    margin-left: auto;
    margin-right: auto;
  }
}

@media (max-width: 560px) {
  .extension-title { font-size: 1.7rem; }
  [data-extension-visual] { max-width: 100%; }
}

/* ---- Home: Panelist reviews ----
   Sticky stack: every card pins at the same offset, so scrolling makes each new
   card slide up and cover the one before it.

   Two constraints drive this layout:

   1. All cards are DIRECT children of .reviews-stack. A sticky element cannot
      escape its parent, so wrapping each card in its own div would end that
      card's pin the moment the wrapper scrolled past.
   2. The scroll distance between cards comes from `padding-top` on each card
      (not margin, and not a wrapper). Padding on a sticky box shifts the next
      card down while keeping every card inside the one shared container.

   Also: no `overflow: hidden` / `contain` on ANY ancestor of .review-slide —
   a clipping ancestor silently disables position:sticky. */
/* The heading sticks just under the navbar so it stays on screen for the whole
   stack — the cards pin below it (top: 200px) and slide underneath.
   z-index keeps it above the cards, which carry z-index 1..5. */
.reviews-title {
  position: sticky;
  top: 104px;
  z-index: 10;
  padding: 1.25rem 0 1.5rem;
  margin-bottom: 1rem;
}

/* Opaque backing band. The cards slide underneath the heading, so without this
   the photos show through the text.
   It's a full-bleed ::before rather than a background on the heading itself
   because (a) the heading is inset by the section's 2rem padding, so a plain
   background leaves gaps at each side where the photo peeks past, and (b) an
   earlier gradient version faded to transparent at the bottom, which let the
   image bleed through the lower half. Fully opaque, edge to edge. */
.reviews-title::before {
  content: '';
  position: absolute;
  /* Cancels .home-next's 2rem side padding to reach the viewport edges. */
  left: -2rem;
  right: -2rem;
  /* Extends UP past the title to meet the navbar. The title sticks at 104px but
     the navbar ends at 81px, and cards travel up through that strip on their
     way to pinning at 200px — without this overhang they flash in the gap. */
  top: -40px;
  bottom: 0;
  z-index: -1;
  /* Same gradient as .home-next, so the band is invisible against the section
     instead of reading as a lighter stripe. */
  background: linear-gradient(to bottom right, #f8fbfd, #edf3f7);
}

.reviews-stack {
  max-width: 1100px;
  margin: 0 auto;
  /* Room for the last card to sit pinned before the section ends. */
  padding-bottom: 18vh;
}

.review-slide {
  position: sticky;
  /* Identical offset on every card — this is what makes them stack instead of
     scrolling past one another.
     Pinned low enough to leave the navbar (81px) AND the "Panelist reviews"
     heading visible above the stack, so the section title stays on screen the
     whole way through. The 480px card still ends well inside the viewport. */
  top: 200px;
  transform-origin: center top;
  transition: transform 0.45s ease, opacity 0.45s ease;
  will-change: transform;
  /* Upward shadow separates a covering card from the one beneath it. */
  box-shadow: 0 -10px 34px rgba(8, 47, 77, 0.16);
}

/* The gap that gives each card its scroll distance, and the single value that
   controls how soon the next card starts covering the current one. Much less
   than the 480px card height, so the next card's top edge appears while the
   previous is still pinned rather than only after it has scrolled clear.
   The first card needs none — it's already at the top of the stack. */
.review-slide + .review-slide {
  margin-top: 150px;
}

/* Later cards paint over earlier ones. Must be on the sticky card itself —
   z-index is ignored on statically-positioned elements. */
.review-slide:nth-child(1) { z-index: 1; }
.review-slide:nth-child(2) { z-index: 2; }
.review-slide:nth-child(3) { z-index: 3; }
.review-slide:nth-child(4) { z-index: 4; }
.review-slide:nth-child(5) { z-index: 5; }

/* A covered card shrinks and dims so the stack reads as depth rather than the
   top card simply clipping the one behind. .is-covered is set by home.js. */
.review-slide.is-covered {
  transform: scale(0.95) translateY(-10px);
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  .review-slide {
    transition: none;
  }
  .review-slide.is-covered {
    transform: none;
    opacity: 1;
  }
}

/* Sticky stacking needs a tall viewport and real scroll distance; on short or
   narrow screens fall back to a plain vertical list. */
@media (max-width: 900px), (max-height: 620px) {
  /* With the cards in a plain list there's nothing to stack beneath the title,
     so a sticky heading would just trail the user down the page. */
  .reviews-title {
    position: static;
    padding: 0;
  }
  /* No cards pass behind it here, so the backing band isn't needed — and its
     negative side bleed would push the page wider than the viewport. */
  .reviews-title::before {
    display: none;
  }
  .review-slide {
    position: static;
    box-shadow: none;
  }
  .review-slide + .review-slide {
    margin-top: 2rem;
  }
  .review-slide.is-covered {
    transform: none;
    opacity: 1;
  }
  .reviews-stack {
    padding-bottom: 0;
  }
}

/* Card surface. `position` is deliberately NOT set here — the sticky-stack
   rule above owns it; re-declaring `relative` here would silently override it
   (this exact clash broke the stack once already). */
.review-slide {
  border-radius: 16px;
  overflow: hidden;
  min-height: 480px;
  display: flex;
  align-items: stretch;
  justify-content: flex-end;
  background-color: #d7e7ef;
}
.review-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.review-quote {
  position: relative;
  z-index: 1;
  width: min(48%, 500px);
  align-self: stretch;
  margin: 2.5rem;
  padding: 2.75rem;
  border-radius: 14px;
  background-color: var(--color-primary);
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.75rem;
  overflow: hidden;
  /* .home-next centers its text; the quote panel reads left-aligned. */
  text-align: left;
}
/* Serif glyph sits high in its em box, so pull it down to keep the whole
   mark inside the panel instead of clipped by the top edge. */
.review-quote-mark {
  position: absolute;
  top: 0;
  right: 1.5rem;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 11rem;
  line-height: 0.85;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.12);
  pointer-events: none;
}
.review-text {
  position: relative;
  margin: 0;
  font-size: clamp(1.05rem, 1.6vw, 1.5rem);
  line-height: 1.55;
  color: #fff;
}
/* No margin-top:auto here — the whole block is centred as a unit, so the
   attribution stays close to the quote it belongs to. */
.review-role {
  margin: 0 0 0.25rem;
  font-weight: 700;
  color: #2fb6a4;
}
.review-meta {
  margin: 0;
  color: rgba(255, 255, 255, 0.85);
}

@media (max-width: 900px) {
  .review-slide {
    min-height: 0;
    display: block;
  }
  /* Stack: photo on top, quote panel below — no text over a cropped face. */
  .review-photo {
    position: relative;
    height: 260px;
  }
  .review-quote {
    width: auto;
    margin: 0;
    border-radius: 0;
    gap: 1.75rem;
  }
  .review-quote-mark { font-size: 7rem; }
}

@media (max-width: 768px) {
  .content h1 { font-size: 2rem; }
  .home-hero .content { padding: 0 1.5rem; }
  /* Still a full screen on mobile; only the padding changes. The mobile navbar
     is TALLER than the desktop one (145px — the logo wraps to two lines), so
     the top padding has to exceed that or the centred heading rides under it.
     Asymmetric on purpose: the extra top offsets the taller bar and keeps the
     text optically centred in the space below it. */
  .home-hero {
    padding: 10rem 1rem 4rem;
  }
  .review-text { font-size: 1rem; }
  .review-quote { padding: 1.75rem; }
}

/* --- Login chooser page --- */
.login-page {
  height: calc(100vh - 81px);
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(180deg, #f4f8fb 0%, #e8eef3 100%);
  padding: 20px;
  box-sizing: border-box;
}

.login-card {
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 4px 6px rgba(0,0,0,0.04), 0 12px 32px rgba(13,59,102,0.10);
  padding: 48px 44px 40px;
  width: 100%;
  max-width: 440px;
  text-align: center;
  border: 1px solid rgba(13,59,102,0.06);
}

.login-card__logo {
  margin: 0 auto 20px;
}

.login-card__eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #6b8299;
  margin: 0 0 10px;
}

.login-card__heading {
  font-size: 15px;
  font-weight: 600;
  color: var(--blue-dark);
  margin: 0 0 28px;
}

.login-card__form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  text-align: left;
}

.login-card__field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.login-card__field label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #6b8299;
}

.login-card__field input {
  padding: 10px 14px;
  border: 1.5px solid #e1e8ee;
  border-radius: 8px;
  font-size: 14px;
  color: var(--blue-dark);
  background: #fafcfd;
  outline: none;
  transition: border-color 0.15s ease;
}

.login-card__field input:focus {
  border-color: #0d3b66;
  background: #ffffff;
}

.login-card__submit {
  margin-top: 4px;
  padding: 11px 0;
  background: #0d3b66;
  color: #ffffff;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease;
}

.login-card__submit:hover {
  background: #0a2e52;
}

.login-card__error {
  font-size: 13px;
  color: #c0392b;
  background: #fdf3f2;
  border: 1px solid #f5c6c2;
  border-radius: 6px;
  padding: 9px 12px;
  margin-bottom: 4px;
  text-align: left;
}

.login-card__hint {
  font-size: 13px;
  color: #6b8299;
  margin: -16px 0 20px;
  line-height: 1.5;
}

.login-card__success {
  font-size: 13px;
  color: #1c2b3a;
  background: #f0f7f0;
  border: 1px solid #c3dfc3;
  border-radius: 6px;
  padding: 9px 12px;
  margin-bottom: 4px;
  text-align: left;
}

.login-card__forgot {
  margin-top: 16px;
  font-size: 13px;
  text-align: center;
}

.login-card__forgot a {
  color: #0d3b66;
  text-decoration: none;
  font-weight: 500;
}

.login-card__forgot a:hover {
  text-decoration: underline;
}

/* ===== Portal: sidebar navigation ===== */

.portal-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.portal-topbar {
  flex-shrink: 0;
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  height: 56px;
  background-color: var(--blue-dark);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.portal-topbar__logo {
  height: 40px;
  /* See .nav-logo-img: the width attribute would otherwise stretch it. */
  width: auto;
  filter: brightness(0) invert(1);
}

.portal-body {
  display: flex;
  flex: 1;
}

.portal-sidebar {
  width: 220px;
  flex-shrink: 0;
  position: sticky;
  top: 56px;
  height: calc(100vh - 56px);
  align-self: flex-start;
  background-color: var(--blue-dark);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: 16px 0;
}

.sidebar-section-label {
  padding: 20px 20px 6px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.4);
}

.sidebar-link {
  display: block;
  padding: 9px 20px;
  font-size: 0.9rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.75);
  text-decoration: none;
  border-left: 3px solid transparent;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.sidebar-link:hover {
  background-color: rgba(255, 255, 255, 0.07);
  color: #ffffff;
}

.sidebar-link.active {
  border-left-color: var(--blue-medium);
  background-color: rgba(255, 255, 255, 0.10);
  color: #ffffff;
  font-weight: 600;
}

.portal-main {
  flex: 1;
  min-width: 0;
  overflow-x: hidden;
  background-color: var(--bg-page);
}

/* ===== Portal: mobile sidebar ===== */
.portal-hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px;
  flex-shrink: 0;
}
.portal-hamburger span {
  display: block;
  width: 22px;
  height: 2px;
  background: #ffffff;
  border-radius: 2px;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.45);
  z-index: 49;
}
.sidebar-backdrop.is-visible {
  display: block;
}

@media (max-width: 767px) {
  .portal-hamburger {
    display: flex;
  }
  .portal-sidebar {
    position: fixed;
    top: 56px;
    left: 0;
    height: calc(100vh - 56px);
    z-index: 50;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
  }
  .portal-sidebar.is-open {
    transform: translateX(0);
  }
}

/* ===== Portal: modern content card (trial) ===== */
.portal-page-wrap {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  min-height: calc(100vh - 200px);
  background: linear-gradient(180deg, #f4f8fb 0%, #e8eef3 100%);
  padding: 48px 24px;
}

.portal-card {
  box-sizing: border-box;
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.04), 0 12px 32px rgba(13, 59, 102, 0.10);
  border: 1px solid rgba(13, 59, 102, 0.06);
  padding: 40px 48px;
  width: 100%;
  max-width: 900px;
}

.portal-card__heading {
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--blue-dark);
  margin: 0 0 0.75rem;
}

.portal-card__subtext {
  font-size: 0.95rem;
  color: #9aa9b6;
  margin: 0;
}

/* ===== Portal: Dashboard v3 - points hero + earn points grid ===== */

.dash-v3-wrap {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  width: 100%;
  max-width: 1100px;
}

/* Welcome header — plain text, no card */
.dash-welcome {
  padding: 0 4px;
}

.dash-welcome__heading {
  font-size: 2rem;
  font-weight: 700;
  color: var(--blue-dark);
  margin: 0 0 0.375rem;
  line-height: 1.2;
}

.dash-welcome__sub {
  font-size: 1rem;
  color: #5a6a7a;
  margin: 0;
}

.points-hero {
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  border-radius: 20px;
  background: linear-gradient(135deg, var(--blue-dark) 0%, var(--blue-medium) 100%);
  padding: 40px 48px;
  display: flex;
  align-items: center;
  gap: 3rem;
  color: #ffffff;
  box-shadow: 0 8px 32px rgba(13, 59, 102, 0.28);
  width: 100%;
}

.points-hero::before {
  content: "";
  position: absolute;
  top: -80px;
  right: -80px;
  width: 280px;
  height: 280px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.13);
  filter: blur(48px);
  pointer-events: none;
}

.points-hero__ring {
  position: relative;
  flex-shrink: 0;
  z-index: 1;
}

.points-hero .chart-center-text .label {
  color: rgba(255, 255, 255, 0.72);
}

.points-hero .chart-center-text .value {
  color: #ffffff;
}

.points-hero .chart-center-text .total {
  color: rgba(255, 255, 255, 0.55);
}

.points-hero__redeem {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  position: relative;
  z-index: 1;
}

.hero-eyebrow {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.58);
  margin: 0;
}

.hero-pts-count {
  font-size: 2.75rem;
  font-weight: 800;
  color: #ffffff;
  line-height: 1;
  margin: 0;
}

.hero-pts-count span {
  font-size: 1.125rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.58);
}

/* Slim progress bar */
.hero-progress-track {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
  overflow: hidden;
}

.hero-progress-fill {
  height: 100%;
  background: #ffffff;
  border-radius: 3px;
  transition: width 0.4s ease;
}

.hero-progress-fill.eligible {
  background: #7ffcc4;
}

.hero-status-text {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.75);
  margin: 0;
}

.hero-redeem-btn {
  align-self: flex-start;
  margin-top: 0.25rem;
  padding: 0.55rem 1.5rem;
  background: #ffffff;
  color: var(--blue-dark);
  font-weight: 700;
  font-size: 0.875rem;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.hero-redeem-btn:hover:not(:disabled) {
  opacity: 0.9;
  transform: translateY(-1px);
}

.hero-redeem-btn:disabled {
  background: rgba(255, 255, 255, 0.22);
  color: rgba(255, 255, 255, 0.45);
  cursor: not-allowed;
}

@media (max-width: 620px) {
  .points-hero {
    flex-direction: column;
    padding: 32px 24px;
    gap: 1.75rem;
    align-items: center;
  }

  .points-hero__ring {
    align-self: center;
  }

  .hero-pts-count {
    font-size: 2.25rem;
  }

  .hero-redeem-btn {
    align-self: stretch;
    text-align: center;
  }
}

/* Ways to Earn card */
.earn-card {
  max-width: none !important;
}

.earn-card__eyebrow {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blue-medium);
  margin: 0 0 0.375rem;
}

.earn-card__heading {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--blue-dark);
  margin: 0;
}

.earn-card__accent {
  width: 40px;
  height: 3px;
  background-color: var(--blue-medium);
  border-radius: 3px;
  margin: 0.5rem 0 0;
}

.earn-rows {
  display: flex;
  flex-direction: column;
  margin-top: 1.25rem;
}

.earn-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 0.75rem;
  text-decoration: none;
  color: inherit;
  border-radius: 8px;
  margin: 0 -0.75rem;
  transition: background-color 0.15s ease;
}

.earn-row + .earn-row {
  border-top: 1px solid #f0f4f8;
}

.earn-row:hover {
  background-color: var(--bg-panel);
}

.earn-row__text {
  flex: 1;
  min-width: 0;
}

.earn-row__title {
  font-size: 0.975rem;
  font-weight: 700;
  color: var(--blue-dark);
  margin: 0 0 0.2rem;
}

.earn-row__desc {
  font-size: 0.85rem;
  color: #6b7280;
  margin: 0;
  line-height: 1.45;
}

.earn-row__right {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  flex-shrink: 0;
}

.earn-badge {
  padding: 0.275rem 0.7rem;
  background: var(--bg-panel);
  border: 1.5px solid rgba(15, 96, 155, 0.18);
  border-radius: 999px;
  font-size: 0.775rem;
  font-weight: 700;
  color: var(--blue-medium);
  white-space: nowrap;
  transition: transform 0.15s ease;
}

.earn-row:hover .earn-badge {
  transform: scale(1.05);
}

/* ===== Portal: Physical Mail mockup ===== */

.supply-status-badge {
  display: inline-block;
  padding: 0.275rem 0.75rem;
  background: #fef3c7;
  color: #d97706;
  font-size: 0.775rem;
  font-weight: 700;
  border-radius: 999px;
  border: 1px solid rgba(217, 119, 6, 0.25);
  white-space: nowrap;
}

.supply-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.375rem;
  flex-wrap: wrap;
}

.supply-card__title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--blue-dark);
  margin: 0;
}

.supply-scan-date {
  font-size: 0.875rem;
  color: #6b7280;
  margin: 0 0 1.75rem;
}

.supply-stepper {
  margin: 0 0 1.75rem;
  max-width: 440px;
}

.supply-stepper__track {
  display: flex;
  align-items: center;
}

.supply-dot {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border-radius: 50%;
  background: #ffffff;
  border: 2px solid #d5dde3;
}

.supply-dot--done {
  background: var(--blue-medium);
  border-color: var(--blue-medium);
}

.supply-dot--active {
  background: var(--blue-medium);
  border-color: var(--blue-medium);
  box-shadow: 0 0 0 4px rgba(15, 96, 155, 0.15);
}

.supply-line {
  flex: 1;
  height: 2px;
  background: #d5dde3;
}

.supply-line--done {
  background: var(--blue-medium);
}

/* Label row aligned under the dots */
.supply-stepper__labels {
  display: flex;
  justify-content: space-between;
  margin-top: 0.5rem;
}

.supply-step-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: #9aa9b6;
  flex: 1;
  text-align: center;
}

.supply-step-label:first-child { text-align: left; }
.supply-step-label:last-child  { text-align: right; }

.supply-step-label--active {
  color: var(--blue-dark);
}

.supply-points-note {
  font-size: 0.875rem;
  color: #6b7280;
  margin: 0 0 1.5rem;
}

.supply-points-note strong {
  color: var(--blue-medium);
}

.supply-request-btn {
  padding: 0.65rem 1.5rem;
  background: var(--blue-medium);
  color: #ffffff;
  font-weight: 700;
  font-size: 0.9rem;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.1s ease;
}

.supply-request-btn:hover:not(:disabled) {
  background: var(--blue-hover);
  transform: translateY(-1px);
}

.supply-request-btn:disabled {
  background: #d5dde3;
  color: #8a97a3;
  cursor: not-allowed;
}

/* ===== Portal: A/B Showdown mockup ===== */

.ab-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.375rem;
}

.ab-card__eyebrow {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blue-medium);
  margin: 0;
}

.ab-card__counter {
  font-size: 0.78rem;
  font-weight: 700;
  color: #8195a6;
  letter-spacing: 0.05em;
}

.ab-card__accent {
  width: 40px;
  height: 3px;
  background-color: var(--blue-medium);
  border-radius: 3px;
  margin: 0 0 1.5rem;
}

.ab-options {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin-bottom: 1.75rem;
}

.ab-option {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 1rem 1rem 1.25rem;
  border: 2px solid #e1e8ee;
  border-radius: 12px;
  cursor: pointer;
  background: var(--bg-page);
  position: relative;
  text-align: center;
  transition: box-shadow 0.15s ease, border-color 0.15s ease, opacity 0.2s ease;
}

@media (prefers-reduced-motion: no-preference) {
  .ab-option {
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, opacity 0.2s ease;
  }
  .ab-option:hover:not(.dimmed) {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(13, 59, 102, 0.12);
  }
  .ab-option.selected {
    transform: scale(1.03);
  }
}

.ab-option.selected {
  border-color: var(--blue-medium);
  box-shadow: 0 4px 16px rgba(15, 96, 155, 0.18);
}

.ab-option.dimmed {
  opacity: 0.4;
  cursor: default;
}

/* Icon circle wrap */
.ab-icon-wrap {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--bg-panel);
  border: 1.5px solid rgba(15, 96, 155, 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background-color 0.15s ease;
}

.ab-option:hover:not(.dimmed) .ab-icon-wrap,
.ab-option.selected .ab-icon-wrap {
  background: rgba(15, 96, 155, 0.1);
}

.ab-envelope-icon {
  color: var(--blue-medium);
  flex-shrink: 0;
}

.ab-opt-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #8195a6;
}

.ab-opt-text {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--blue-dark);
  margin: 0;
  line-height: 1.4;
  min-height: 2.8em;
}

.ab-vs {
  flex-shrink: 0;
  align-self: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--blue-dark);
  color: #ffffff;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
  margin: 0 -12px;
  z-index: 2;
  position: relative;
}

.ab-check {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--blue-medium);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ab-confirm-msg {
  font-size: 0.9rem;
  font-weight: 600;
  color: #2fb67d;
  margin: 0 0 1.25rem;
}

.ab-next-btn {
  padding: 0.6rem 1.4rem;
  background: var(--bg-panel);
  color: var(--blue-dark);
  font-weight: 600;
  font-size: 0.875rem;
  border: 1.5px solid rgba(13, 59, 102, 0.15);
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.ab-next-btn:hover {
  background: #d8f0fa;
  border-color: var(--blue-medium);
}


@media (max-width: 520px) {
  .ab-options {
    flex-direction: column;
    gap: 1rem;
  }
  .ab-vs {
    align-self: center;
    margin: -12px 0;
  }
}

/* ── Survey nudge inside blue hero box ── */
.hero-survey-nudge {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.2);
  font-size: 12px;
  font-weight: 500;
  color: rgba(255,255,255,0.85);
  text-decoration: none;
  transition: color 0.2s;
}

.hero-survey-nudge:hover { color: #fff; }

.hero-survey-nudge__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #fff;
  flex-shrink: 0;
}

.hero-survey-nudge__arrow {
  margin-left: auto;
  opacity: 0.7;
}

/* ── New survey pill — top right of blue hero card ── */
.ab-new-survey-pill {
  position: absolute;
  top: 14px;
  right: 14px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(255,255,255,0.2);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 20px;
  text-decoration: none;
  letter-spacing: 0.02em;
  white-space: nowrap;
  border: 1px solid rgba(255,255,255,0.35);
  backdrop-filter: blur(4px);
}

.ab-new-survey-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #fff;
}

.ab-new-survey-pill:hover { background: rgba(255,255,255,0.3); }

/* ── A/B survey list cards ── */
.ab-survey-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 24px;
}

.ab-survey-card {
  padding: 20px 24px;
  border-left: 4px solid var(--blue-medium);
}

.ab-survey-card--done {
  border-left-color: #9ca3af;
  opacity: 0.72;
}

.ab-survey-card__body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}

.ab-survey-card__info {
  flex: 1;
  min-width: 0;
}

.ab-survey-card__meta-row {
  margin-bottom: 8px;
}

.ab-survey-card__pts-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  background: #fef3c7;
  color: #92400e;
  padding: 3px 10px;
  border-radius: 20px;
}

.ab-survey-card__pts-badge--earned {
  background: #e6f9f1;
  color: #166534;
}

.ab-survey-card__title {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 4px;
  color: var(--blue-dark, #082f4d);
}

.ab-survey-card__desc {
  font-size: 13px;
  color: #6b7280;
  margin: 0;
}

.ab-survey-card__btn {
  flex-shrink: 0;
  background: var(--blue-medium);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 20px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 0.2s;
  white-space: nowrap;
}

.ab-survey-card__btn:hover { opacity: 0.88; }

.ab-survey-card__completed {
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 600;
  color: #2fb67d;
  background: #e6f9f1;
  padding: 6px 14px;
  border-radius: 20px;
  white-space: nowrap;
}

/* ── Image placeholder (mockup) ── */
.ab-img-wrap {
  width: 100%;
  margin-bottom: 10px;
  border-radius: 10px;
  position: relative;
  z-index: 0;
}

.ab-img {
  width: 100%;
  height: 240px;
  object-fit: cover;
  border-radius: 10px;
  background: #e8edf5;
  display: block;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
  cursor: zoom-in;
  position: relative;
  z-index: 1;
}

.ab-img:hover {
  transform: scale(1.55);
  box-shadow: 0 12px 40px rgba(0,0,0,0.25);
  z-index: 10;
}

/* Zoom expands outward away from the VS divider — A grows left, B grows right */
#ab-opt-a .ab-img { transform-origin: right center; }
#ab-opt-b .ab-img { transform-origin: left center; }

/* Clip PDF scrollbar at rest; allow zoom on hover */
.ab-img-wrap--pdf {
  overflow: hidden;
}
.ab-img-wrap--pdf:hover {
  overflow: visible;
}
.ab-img-wrap--pdf object.ab-img {
  width: calc(100% + 17px);
}



.ab-img-placeholder {
  width: 100%;
  height: 220px;
  background: #e8edf5;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  color: #9ca3af;
  font-weight: 500;
  letter-spacing: 0.03em;
  user-select: none;
}

/* Response view header */
/* center the card within the wider dash-v3-wrap */
#ab-response-view .portal-card {
  margin-left: auto;
  margin-right: auto;
}


.ab-response-header {
  position: relative;
  display: flex;
  align-items: center;
  margin-bottom: 20px;
}

.ab-survey-title-center {
  position: absolute;
  left: 0;
  right: 0;
  text-align: center;
  margin: 0;
  pointer-events: none;
}

.ab-card-desc {
  text-align: center;
  font-size: 14px;
  color: #6b7280;
  margin: 0 0 20px;
}

/* Back button */
.ab-back-btn {
  flex-shrink: 0;
  background: transparent;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  padding: 6px 14px;
  font-size: 13px;
  cursor: pointer;
  color: #374151;
  margin-top: 4px;
}

.ab-back-btn:hover { background: #f3f4f6; }

.ab-back-btn--center {
  margin: 0 auto;
  display: block;
  background: var(--blue-medium);
  color: #fff;
  border-color: var(--blue-medium);
  font-weight: 600;
  padding: 10px 28px;
}

.ab-back-btn--center:hover {
  background: var(--blue-dark);
  border-color: var(--blue-dark);
}

/* Submit row — pts hint + button centered together */
.ab-submit-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid #edf0f3;
}

.ab-pts-hint {
  font-size: 13px;
  color: #6b7280;
  margin: 0;
}

.ab-pts-hint strong {
  color: var(--blue-medium);
}

.ab-submit-btn {
  background: var(--blue-medium);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 32px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 0.2s;
}

.ab-submit-btn:hover { opacity: 0.88; }

/* ── Done / confirmation card ── */
.ab-done-card {
  text-align: center;
  padding: 64px 40px;
}

.ab-done-icon {
  width: 72px;
  height: 72px;
  background: #e6f9f1;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 20px;
  color: #2fb67d;
}

.ab-done-title {
  font-size: 20px;
  font-weight: 700;
  margin: 0 0 16px;
  color: var(--blue-dark, #082f4d);
}

.ab-done-pts-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-bottom: 28px;
}

.ab-done-pts-coin {
  font-size: 22px;
  line-height: 1;
}

.ab-done-pts {
  font-size: 15px;
  font-weight: 600;
  color: #92400e;
  background: #fef3c7;
  padding: 6px 14px;
  border-radius: 20px;
  margin: 0;
}

.supply-confirm-msg {
  margin: 0.875rem 0 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: #2fb67d;
}

@media (prefers-reduced-motion: no-preference) {
  @keyframes earn-badge-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(15, 96, 155, 0.4); }
    70%  { box-shadow: 0 0 0 5px rgba(15, 96, 155, 0); }
    100% { box-shadow: 0 0 0 0 rgba(15, 96, 155, 0); }
  }

  .earn-row:nth-child(1) .earn-badge { animation: earn-badge-pulse 0.65s ease 0.3s 1 both; }
  .earn-row:nth-child(2) .earn-badge { animation: earn-badge-pulse 0.65s ease 0.4s 1 both; }
  .earn-row:nth-child(3) .earn-badge { animation: earn-badge-pulse 0.65s ease 0.5s 1 both; }
}

/* ===== Portal: profile avatar dropdown + edit profile form ===== */

/* Avatar wrapper — positioned so the dropdown anchors to it */
.portal-profile {
  position: relative;
  display: flex;
  align-items: center;
  cursor: pointer;
}

.portal-profile__avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.3);
  display: block;
  object-fit: cover;
  transition: border-color 0.15s ease;
}

.portal-profile__avatar:hover,
.portal-profile[aria-expanded="true"] .portal-profile__avatar {
  border-color: rgba(255, 255, 255, 0.8);
}

/* Dropdown popover */
.portal-profile__dropdown {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 148px;
  background: #ffffff;
  border-radius: 10px;
  border: 1px solid rgba(13, 59, 102, 0.08);
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.06), 0 12px 28px rgba(13, 59, 102, 0.14);
  overflow: hidden;
  z-index: 200;
}

.portal-profile__dropdown[hidden] {
  display: none;
}

.portal-profile__item {
  display: block;
  padding: 0.65rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: #1c2b3a;
  text-decoration: none;
  transition: background-color 0.12s ease;
}

.portal-profile__item:hover {
  background-color: var(--bg-panel);
  color: var(--blue-dark);
}

.portal-profile__item + .portal-profile__item {
  border-top: 1px solid #f0f4f8;
}

/* Edit Profile form */
.cmd-card {
  max-width: 680px;
  margin: 0 auto;
}

.cmd-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.cmd-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  align-items: end;
}

.cmd-form-row--three {
  grid-template-columns: 2fr 1fr 1fr;
}

.cmd-label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: #444;
}

.cmd-input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.85rem;
  font-size: 0.95rem;
  font-family: inherit;
  border: 1px solid #d5dde3;
  border-radius: 8px;
  background-color: var(--bg-page);
  transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
}

.cmd-input:focus {
  outline: none;
  border-color: var(--blue-medium);
  background-color: #ffffff;
  box-shadow: 0 0 0 3px rgba(15, 96, 155, 0.15);
}

.cmd-input::placeholder {
  color: #9aa5ad;
}

.cmd-form-footer {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 0.5rem;
  flex-wrap: wrap;
}

.cmd-save-btn {
  padding: 0.65rem 1.75rem;
  background: var(--blue-medium);
  color: #ffffff;
  font-weight: 700;
  font-size: 0.9rem;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.1s ease;
}

.cmd-save-btn:hover {
  background: var(--blue-hover);
  transform: translateY(-1px);
}

.cmd-confirm-msg {
  font-size: 0.9rem;
  font-weight: 600;
  color: #2fb67d;
  margin: 0;
}

@media (max-width: 600px) {
  .cmd-form-row,
  .cmd-form-row--three {
    grid-template-columns: 1fr;
  }
  .cmd-dob-row,
  .cmd-row {
    flex-direction: column;
  }
  .cmd-field--narrow,
  .cmd-row--address .cmd-field--narrow {
    max-width: 100%;
  }
}

.cmd-req {
  color: #c0392b;
  font-weight: 600;
}

.cmd-label-text {
  display: block;
  font-size: 0.875rem;
  font-weight: 500;
  color: #444;
  margin-bottom: 0.3rem;
}

.cmd-label__text {
  display: block;
}

.cmd-row {
  display: flex;
  gap: 1rem;
}

.cmd-row--address .cmd-field--wide {
  flex: 3;
}

.cmd-row--address {
  align-items: flex-end;
}

.cmd-row--address .cmd-field--narrow {
  flex: 1;
  max-width: 160px;
}

.cmd-field--narrow {
  max-width: 200px;
}

.cmd-dob-row {
  display: flex;
  gap: 0.75rem;
}

.cmd-dob-row .cmd-input {
  flex: 1;
  min-width: 0;
}

/* ============================================================
   ===== Panelist Profile wizard (Duolingo-style step flow) =====
   Markup: templates/public/_join_wizard.html + js/join_wizard.js
   ============================================================ */

/* Full-screen surface. The old .modal-overlay card is replaced by this: at
   this length a centred card scrolls awkwardly, and one-question-per-screen
   reads better edge to edge. */
.wz-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  background: #ffffff;
}

/* [hidden] must beat display:flex, same trap as .modal-overlay. */
.wz-overlay[hidden] {
  display: none;
}

/* Background must not scroll behind the wizard. */
body.wz-open {
  overflow: hidden;
}

.wz-shell {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

/* ---- top bar: close + progress ---- */
.wz-top {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1.25rem 1.5rem 0.5rem;
  flex-shrink: 0;
}

.wz-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: #b7bfc6;
  cursor: pointer;
  transition: color 0.2s ease, background-color 0.2s ease;
}
.wz-close svg { width: 22px; height: 22px; }
.wz-close:hover { color: #7d878f; background: #f1f4f6; }

.wz-progress {
  flex: 1;
  height: 16px;
  border-radius: 999px;
  background: #e8edf1;
  overflow: hidden;
}

.wz-progress-fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--blue-medium);
  transition: width 0.35s ease;
}

/* ---- scrollable question area ---- */
.wz-scroll {
  flex: 1;
  overflow-y: auto;
  display: flex;
  justify-content: center;
  padding: 2.5rem 1.5rem;
}

.wz-form {
  width: 100%;
  max-width: 600px;
}

.wz-q {
  animation: wz-in 0.28s ease both;
}

/* Each screen slides in slightly — the cue that you advanced a step. */
@keyframes wz-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .wz-q { animation: none; }
  .wz-progress-fill { transition: none; }
}

.wz-question {
  font-size: 1.75rem;
  line-height: 1.25;
  color: var(--blue-dark);
  /* Generous gap below the question so the options don't crowd it. When a
     .wz-sub follows, that element's own margin carries the rest of the space. */
  margin: 0 0 1.75rem;
}

.wz-sub {
  font-size: 1rem;
  color: #5b666f;
  margin: 0 0 1.5rem;
  /* Without this the paragraph inherits a tight default line-height and the
     multi-line copy on the Thank You screen reads as a cramped block. */
  line-height: 1.65;
}

/* Used where the sub-label directly introduces a control group below it. */
.wz-sub-tight {
  margin-bottom: 0.75rem;
}

.wz-fineprint {
  font-size: 0.85rem;
  color: #6b7580;
  line-height: 1.5;
}
.wz-fineprint a { color: var(--blue-medium); }

/* ---- intro screen ---- */
.wz-bubble-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.75rem;
}

.wz-mascot {
  height: 76px;
  flex-shrink: 0;
}

/* Speech bubble with a tail pointing back at the logo. */
.wz-bubble {
  position: relative;
  margin: 0;
  padding: 1rem 1.25rem;
  border: 2px solid #e3e9ee;
  border-radius: 14px;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--blue-dark);
}
.wz-bubble::before {
  content: '';
  position: absolute;
  left: -9px;
  top: 50%;
  transform: translateY(-50%) rotate(45deg);
  width: 14px;
  height: 14px;
  background: #fff;
  border-left: 2px solid #e3e9ee;
  border-bottom: 2px solid #e3e9ee;
}

.wz-intro-list {
  margin: 0 0 1.5rem;
  padding-left: 1.2rem;
  color: #46525c;
}
.wz-intro-list li { margin-bottom: 0.5rem; }

/* ---- choice cards ---- */
.wz-choices {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  /* Matches the tile groups' top margin so every question type has the same
     separation from its heading. */
  margin-top: 0.75rem;
}

.wz-choice { cursor: pointer; }

/* The radio itself is hidden but focusable, so keyboard users still get a
   visible ring via :focus-visible below. */
.wz-choice input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.wz-choice-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.05rem 1.25rem;
  border: 2px solid #e3e9ee;
  border-bottom-width: 4px;
  border-radius: 14px;
  font-size: 1.05rem;
  font-weight: 600;
  color: #3c4750;
  transition: background-color 0.15s ease, border-color 0.15s ease,
              transform 0.15s ease;
}

.wz-choice:hover .wz-choice-inner {
  background: #f7fbfd;
  border-color: #cfd9e1;
}

.wz-choice input:checked + .wz-choice-inner {
  background: var(--bg-panel);
  border-color: var(--blue-medium);
  color: var(--blue-dark);
}

.wz-choice input:focus-visible + .wz-choice-inner {
  outline: 3px solid var(--blue-medium);
  outline-offset: 2px;
}

.wz-choice:active .wz-choice-inner {
  transform: translateY(2px);
  border-bottom-width: 2px;
}

/* Two-line choice card: bold label with a lighter hint under it (used by the
   opening "which profile fits you" question). */
.wz-choice-text {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.wz-choice-hint {
  font-size: 0.88rem;
  font-weight: 400;
  color: #6b7580;
}

.wz-choice input:checked + .wz-choice-inner .wz-choice-hint {
  color: var(--blue-medium);
}

/* ---- Square icon tiles, side by side (the opening "which profile" question) --
   .wz-choices is a vertical stack for every other question; this variant lays
   its options out as equal-width square cards in one row. */
.wz-choices-tiles {
  flex-direction: row;
  justify-content: center;
  gap: 1rem;
  /* Break out of the form's 600px measure — three tiles inside it are narrow
     enough that every label wraps mid-phrase. Centred, so it stays aligned
     with the question above. */
  width: min(860px, calc(100vw - 3rem));
  margin-left: 50%;
  transform: translateX(-50%);
  /* Breathing room between the question and the tiles. */
  margin-top: 2.5rem;
}

/* The tiles are centred, so the question above them is too — left-aligned text
   over centred tiles reads as misalignment, most visibly on a short heading like
   "Do you rent or own your home?" that ends well before the tile row.
   Scoped to min-width so it doesn't fight the mobile block below, where tiles
   become left-aligned rows and the heading follows them. */
@media (min-width: 701px) {
  .wz-q:has(.wz-choices-tiles) .wz-question,
  .wz-q:has(.wz-choices-tiles) > .wz-sub {
    text-align: center;
  }
  /* "Preferred method of contact" introduces the tiles below it, so it follows
     them rather than the text input above (whose own .wz-label stays left). */
  [data-wz-reveal]:has(.wz-choices-tiles) .wz-sub {
    text-align: center;
  }
}

/* A tile group nested inside a reveal block (Preferred contact, under the phone
   input) keeps the form column's width instead of breaking out to 860px — the
   wider box would overflow the field above it. It still CENTRES within that
   column, so these tiles read the same as every other tile group. */
[data-wz-reveal] .wz-choices-tiles {
  width: auto;
  margin-left: 0;
  transform: none;
  justify-content: center;
}

/* Equal widths regardless of label length. min-width:0 lets them shrink below
   their content width instead of overflowing the row. `stretch` makes every
   tile match the tallest, so differing label lengths can't leave the row
   ragged. */
.wz-choices-tiles {
  align-items: stretch;
}

/* Capped so a 2-option question doesn't produce two enormous half-width tiles;
   with 3 options the cap isn't reached and they simply divide the row. */
.wz-choices-tiles .wz-choice {
  flex: 1 1 0;
  min-width: 0;
  /* Sized for the longest label in the set; a short pair like Email/Phone looked
     oversized at the previous 276px. */
  max-width: 210px;
  display: flex;
}

.wz-choices-tiles .wz-choice-inner {
  /* Square tiles. `aspect-ratio` alone loses to taller content, so it's paired
     with the flex stretch above: the ratio sets the baseline shape and the row
     equalises any tile whose text needs an extra line.
     border-box is required or the 2px/4px borders would be added on top of the
     ratio and the tile would end up taller than it is wide. */
  box-sizing: border-box;
  width: 100%;
  aspect-ratio: 1 / 1;
  flex-direction: column;
  align-items: center;
  /* Icon + label are centred as a group in the square. Cross-row alignment is
     handled by .wz-choice-text's min-height below (which reserves room for a
     second line whether or not the label needs one) rather than by top-anchoring
     the content — that kept them aligned but left everything hugging the top. */
  justify-content: center;
  gap: 0.85rem;
  padding: 1.25rem 1rem;
  text-align: center;
}

.wz-choices-tiles .wz-choice-text {
  align-items: center;
  gap: 0.3rem;
  justify-content: flex-start;
}

/* Reserve two lines for the LABEL specifically. Without this a one-line label
   makes its whole text block ~20px shorter than a two-line neighbour's, and
   because each tile centres its own content that difference shifts the icon —
   so icons and labels no longer line up across the row. Reserving the second
   line here keeps every text block the same height, which keeps the row aligned
   AND lets the group stay vertically centred. */
.wz-choices-tiles .wz-choice-label {
  min-height: 2.5em;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Icon: dark brand blue, per the rest of the site. */
.wz-tile-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--bg-panel);
  color: var(--blue-dark);
  transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}

.wz-tile-icon svg {
  width: 28px;
  height: 28px;
}

.wz-choice:hover .wz-tile-icon {
  transform: scale(1.06);
}

/* Selected tile inverts the icon badge so the choice is unmistakable. */
.wz-choice input:checked + .wz-choice-inner .wz-tile-icon {
  background: var(--blue-dark);
  color: #ffffff;
}

/* Three square tiles in a row get too narrow to read on small screens, so fall
   back to the stacked rows the rest of the form uses. */
@media (max-width: 700px) {
  .wz-choices-tiles {
    flex-direction: column;
    /* Undo the desktop break-out, or the stacked list sits off-centre. */
    width: auto;
    margin-left: 0;
    transform: none;
  }
  /* The desktop cap would leave the stacked rows narrow and off to one side. */
  .wz-choices-tiles .wz-choice {
    max-width: none;
  }
  /* The reserved second label line exists to align icons ACROSS a row; stacked
     rows don't need it, and it just pads every row ~20px taller. */
  .wz-choices-tiles .wz-choice-label {
    min-height: 0;
    display: block;
  }
  .wz-choices-tiles .wz-choice-inner {
    aspect-ratio: auto;
    flex-direction: row;
    justify-content: flex-start;
    text-align: left;
    padding: 1rem 1.15rem;
    gap: 0.9rem;
  }
  .wz-choices-tiles .wz-choice-text {
    align-items: flex-start;
  }
  .wz-tile-icon {
    width: 44px;
    height: 44px;
  }
  .wz-tile-icon svg {
    width: 22px;
    height: 22px;
  }
}

/* Signal-strength icon for ordered scales (income, credit score). */
.wz-bars {
  display: inline-flex;
  align-items: flex-end;
  gap: 3px;
  height: 22px;
  flex-shrink: 0;
}
.wz-bar {
  width: 5px;
  border-radius: 1px;
  background: #dbe4ea;
}
.wz-bar:nth-child(1) { height: 30%; }
.wz-bar:nth-child(2) { height: 50%; }
.wz-bar:nth-child(3) { height: 75%; }
.wz-bar:nth-child(4) { height: 100%; }
.wz-bar.is-on { background: var(--blue-medium); }

/* ---- text fields ---- */
.wz-fields {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 0.75rem;
}

.wz-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* `display: flex` above (and on .wz-fields) beats the `hidden` attribute, so
   panel-specific blocks need this or they stay visible when JS hides them. */
.wz-field[hidden],
.wz-fields[hidden],
.wz-only-consumer[hidden],
.wz-only-trade[hidden] {
  display: none;
}

.wz-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: #5b666f;
}

.wz-optional {
  font-weight: 400;
  color: #97a1aa;
}

.wz-field input,
.wz-field select {
  width: 100%;
  /* Required: this sheet has no global border-box reset, so without it the
     padding + border push each control ~21px past its flex column and it
     overlaps the next field in a .wz-row (Apt # into City). */
  box-sizing: border-box;
  padding: 0.8rem 0.9rem;
  font-size: 1rem;
  font-family: inherit;
  color: #2f3a43;
  background: #f7fafc;
  border: 2px solid #e3e9ee;
  border-radius: 12px;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.wz-field input:focus,
.wz-field select:focus {
  outline: none;
  background: #fff;
  border-color: var(--blue-medium);
}

.wz-row {
  display: flex;
  gap: 0.75rem;
}
.wz-grow { flex: 1; min-width: 0; }

/* DOB: month takes the slack, day/year stay narrow. */
.wz-dob .wz-field { min-width: 0; }

/* Invalid field / unanswered choice group. */
.has-error input,
.has-error select {
  border-color: #d4574e;
  background: #fdf6f5;
}
.has-error .wz-choice-inner { border-color: #e6a49f; }

.wz-reveal { margin-top: 1rem; }

/* ---- done screen ---- */
.wz-done { text-align: center; padding-top: 1.5rem; }

.wz-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  margin-bottom: 1.5rem;
  border-radius: 50%;
  background: var(--bg-panel);
  color: var(--blue-medium);
}
.wz-check svg { width: 38px; height: 38px; }

/* Slightly wider measure and more space below, so the confirmation copy has
   room to breathe instead of packing into a dense block. */
.wz-done .wz-sub {
  max-width: 520px;
  margin: 0 auto 1.75rem;
  font-size: 1.05rem;
}

.wz-done .wz-fineprint { max-width: 520px; margin: 0 auto; }

/* ---- bottom bar ---- */
.wz-bottom {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-shrink: 0;
  padding: 1.25rem 1.5rem;
  border-top: 2px solid #eef2f5;
  background: #fff;
}

.wz-back {
  padding: 0.85rem 1.6rem;
  border: none;
  border-radius: 12px;
  background: none;
  color: #8b959d;
  font-size: 0.95rem;
  font-weight: 700;
  font-family: inherit;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
}
.wz-back:hover { color: #5b666f; }
.wz-back[hidden] { display: none; }

/* Error text sits between the two buttons and takes the leftover space. */
.wz-error {
  flex: 1;
  margin: 0;
  text-align: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #c9463c;
}
.wz-error[hidden] { display: none; }

/* Pushes Continue to the right when Back and the error are both hidden. */
.wz-bottom .wz-continue { margin-left: auto; }

.wz-continue {
  padding: 0.9rem 2.75rem;
  border: none;
  border-radius: 14px;
  border-bottom: 4px solid rgba(0, 0, 0, 0.18);
  background: var(--blue-medium);
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  font-family: inherit;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.1s ease;
}
.wz-continue:hover { background: var(--blue-hover); }
.wz-continue:active {
  transform: translateY(2px);
  border-bottom-width: 2px;
}

/* ---- small screens ---- */
@media (max-width: 640px) {
  .wz-scroll { padding: 1.75rem 1.15rem; }
  .wz-question { font-size: 1.4rem; }
  .wz-top { padding: 1rem 1.15rem 0.5rem; }
  .wz-bottom { padding: 1rem 1.15rem; }

  .wz-mascot { height: 56px; }
  .wz-bubble { font-size: 1rem; padding: 0.85rem 1rem; }

  /* Address/name rows stack rather than squeezing two inputs side by side. */
  .wz-row { flex-direction: column; }
  /* DOB is the exception — three short selects still fit in a row. */
  .wz-dob { flex-direction: row; }

  .wz-continue { flex: 1; padding: 0.9rem 1.25rem; }
  .wz-back { padding: 0.85rem 1rem; }
}

/* ============================================================
   ===== Home: stats band, payout ladder, closing CTA =====
   ============================================================ */

/* ---- Social-proof band ----
   Sits between the full-bleed hero and the first pale .home-next section, so it
   is navy: it reads as the base of the hero rather than a third background
   colour, and keeps the eye moving down the page. */
.stats-band {
  background-color: var(--blue-dark);
  padding: 2.75rem 2rem;
}

.stats-band__list {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  display: grid;
  /* Three across on desktop, collapsing to one column on a phone without a
     media query. 220px is wide enough for "$5,000,000+" not to wrap. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 2rem 1.5rem;
}

.stats-band__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.4rem;
}

.stats-band__num {
  font-size: clamp(2.1rem, 4vw, 3rem);
  font-weight: 800;
  line-height: 1;
  color: #ffffff;
  /* The digits change width as the counter runs; tabular figures stop the
     number jittering sideways on every frame. */
  font-variant-numeric: tabular-nums;
}

.stats-band__label {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blue-navbar-text);
  opacity: 0.85;
}

/* ---- Payout ladder ---- */
.payout-inner {
  max-width: 1080px;
  margin: 0 auto;
  display: grid;
  /* The figure panel keeps a fixed-ish column and the steps take the rest;
     below ~900px they stack (see the media query at the end of this block). */
  grid-template-columns: minmax(260px, 340px) 1fr;
  gap: 3rem;
  align-items: center;
  text-align: left;
}

/* The headline number. Deliberately the loudest thing in the section — it is
   the single fact that answers "what do I get out of this?". */
.payout-figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 2.25rem 1.75rem;
  border-radius: 18px;
  background-color: var(--blue-dark);
  color: #ffffff;
  text-align: center;
}

.payout-figure__points {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin: 0;
}

.payout-figure__num {
  font-size: clamp(2.4rem, 4.5vw, 3.25rem);
  font-weight: 800;
  line-height: 1;
  /* The counter changes digit widths every frame; tabular figures keep it from
     shuffling sideways as it runs. */
  font-variant-numeric: tabular-nums;
}

.payout-figure__unit {
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  opacity: 0.8;
}

/* ---- the arrow between the two halves ----
   Replaces a "=" glyph at 0.45 opacity, which read as a rendering artefact more
   than a deliberate mark. An arrow also says "becomes", which is the point. */
.payout-figure__arrow {
  display: block;
  width: 26px;
  height: 26px;
  margin: 0.35rem 0;
  color: var(--accent-reward);
  opacity: 0.75;
}

.payout-figure__arrow svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* ---- gift card ---- */
.payout-card {
  position: relative;
  width: 100%;
  max-width: 250px;
  /* This sheet has no global border-box reset, so without this the horizontal
     padding is added to max-width and the card renders ~275px wide, crowding
     the panel's own padding. */
  box-sizing: border-box;
  padding: 1rem 1.15rem 1.05rem;
  border-radius: 14px;
  /* Lighter than the navy panel it sits on, so it lifts off the surface. */
  background: linear-gradient(135deg, #1b4b76 0%, #0d2c49 100%);
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.32);
  text-align: left;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.payout-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 20px 34px rgba(0, 0, 0, 0.4);
}

/* Suggestion of a chip, so the block reads as a card at a glance. */
.payout-card__chip {
  position: absolute;
  top: 1.05rem;
  right: 1.15rem;
  width: 26px;
  height: 19px;
  border-radius: 4px;
  background: linear-gradient(135deg, var(--accent-reward), #c98b1d);
  opacity: 0.9;
}

.payout-card__chip::after {
  content: '';
  position: absolute;
  inset: 5px 4px;
  border-left: 1px solid rgba(0, 0, 0, 0.25);
  border-right: 1px solid rgba(0, 0, 0, 0.25);
}

.payout-card__amount {
  display: block;
  font-size: clamp(2.1rem, 4vw, 2.75rem);
  font-weight: 800;
  line-height: 1.05;
  color: var(--accent-reward);
}

.payout-card__type {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* ---- scroll-in reveal ----
   `is-animatable` is added by home.js, so with no JS nothing is ever hidden and
   the card is simply visible. `is-revealed` then plays the entrance. */
.payout-figure.is-animatable .payout-figure__arrow,
.payout-figure.is-animatable .payout-card {
  opacity: 0;
  transform: translateY(14px);
}

.payout-figure.is-animatable .payout-figure__arrow {
  transition: opacity 0.45s ease 0.35s, transform 0.45s ease 0.35s;
}

.payout-figure.is-animatable .payout-card {
  /* Lands after the arrow, so the eye follows points -> arrow -> card. */
  transition: opacity 0.5s ease 0.55s, transform 0.5s ease 0.55s;
}

.payout-figure.is-animatable.is-revealed .payout-figure__arrow {
  opacity: 0.75;
  transform: none;
}

.payout-figure.is-animatable.is-revealed .payout-card {
  opacity: 1;
  transform: none;
}

/* Once settled, the arrow bobs gently to keep the conversion feeling live —
   same idea as the hero CTA's arrow nudge. */
.payout-figure.is-revealed .payout-figure__arrow svg {
  animation: payout-arrow-bob 2.6s ease-in-out 1.1s infinite;
}

@keyframes payout-arrow-bob {
  0%, 72%, 100% { transform: translateY(0); }
  86%           { transform: translateY(4px); }
}

@media (prefers-reduced-motion: reduce) {
  .payout-figure.is-animatable .payout-figure__arrow,
  .payout-figure.is-animatable .payout-card {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .payout-figure.is-animatable .payout-figure__arrow {
    opacity: 0.75;
  }
  .payout-figure.is-revealed .payout-figure__arrow svg {
    animation: none;
  }
  .payout-card,
  .payout-card:hover {
    transform: none;
    transition: none;
  }
}

.payout-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.payout-step {
  display: flex;
  align-items: flex-start;
  gap: 1.1rem;
}

.payout-step__num {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg-panel);
  color: var(--blue-medium);
  font-size: 0.95rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.payout-step__title {
  margin: 0 0 0.3rem;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--blue-dark);
}

.payout-step__body {
  margin: 0;
  font-size: 0.975rem;
  line-height: 1.6;
  color: var(--color-font);
}

@media (max-width: 900px) {
  .payout-inner {
    grid-template-columns: 1fr;
    gap: 2.25rem;
  }
  /* Stop the navy panel stretching the full width of a tablet — it starts to
     look like another section band rather than a callout. */
  .payout-figure {
    max-width: 340px;
    margin: 0 auto;
  }
}

/* ---- Closing CTA ---- */
.closing-cta {
  padding: 5.5rem 2rem;
  background-color: var(--blue-dark);
  text-align: center;
}

.closing-cta__inner {
  max-width: 640px;
  margin: 0 auto;
}

.closing-cta__heading {
  margin: 0 0 0.75rem;
  font-size: clamp(1.6rem, 3.5vw, 2.35rem);
  font-weight: 800;
  line-height: 1.2;
  color: #ffffff;
}

.closing-cta__lead {
  margin: 0 0 2rem;
  font-size: 1.1rem;
  color: var(--blue-navbar-text);
  opacity: 0.9;
}

/* Solid white pill: the highest-contrast button available on the navy panel,
   and distinct from the frosted-glass treatment the hero CTA uses. */
.closing-cta__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.95rem 2.25rem;
  border-radius: 999px;
  background-color: #ffffff;
  color: var(--blue-dark);
  font-size: 1.05rem;
  font-weight: 700;
  text-decoration: none;
  transition: background-color 0.25s ease, transform 0.2s ease,
              box-shadow 0.25s ease;
}

.closing-cta__btn:hover {
  background-color: var(--bg-panel);
  transform: translateY(-2px);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
}

.closing-cta__btn:active {
  transform: translateY(0);
  box-shadow: none;
}

.closing-cta__btn:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 3px;
}

.closing-cta__arrow {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  transition: transform 0.25s ease;
}

.closing-cta__btn:hover .closing-cta__arrow {
  transform: translateX(5px);
}

.closing-cta__fine {
  margin: 1.5rem 0 0;
  font-size: 0.875rem;
  color: var(--blue-navbar-text);
  opacity: 0.7;
}

/* The footer carries a top margin for the pale sections it normally follows;
   where a page ends on a dark band instead, that margin shows up as a stripe of
   page background between two dark blocks.
   Opted into per page with a body class, the way .has-transparent-nav and
   .is-light-nav already work. An adjacent-sibling selector cannot do this: the
   closing CTA sits inside .scroll-container while the footer is a child of
   .public-root, so the two are never siblings. */
.has-dark-page-end .site-footer {
  margin-top: 0;
}

@media (prefers-reduced-motion: reduce) {
  .closing-cta__btn,
  .closing-cta__btn:hover,
  .closing-cta__arrow,
  .closing-cta__btn:hover .closing-cta__arrow {
    transform: none;
    transition: none;
  }
}
