/* ==========================================================================
   Personalisation — quizzes and configurators
   --------------------------------------------------------------------------
   WHY THIS IS HERE

   Every demo promised personalisation and none of them delivered it. Halo had
   a link reading "Not sure what to buy? Describe your skin" that went to a
   contact form. Northbound sold subscriptions with no way to work out which
   one. Tidewalk sold technical outerwear and never asked what you would use it
   for.

   For a studio selling at these prices, a working configurator is one of the
   strongest things a demo can show, because it is the part a client cannot
   picture themselves building. So it is a shared component here rather than
   five separate attempts.

   HOW A QUIZ IS DECLARED

     <div class="qz" data-quiz="halo">
       <section class="qz-step" data-step="1">
         <p class="qz-count">Question 1 of 4</p>
         <h2>How does your skin feel an hour after washing?</h2>
         <div class="qz-options">
           <button class="qz-opt" data-value="dry">Tight and dry</button>
           ...
         </div>
       </section>
       ...
       <section class="qz-result" data-result>
         <p class="qz-count">Your routine</p>
         <h2 data-result-title></h2>
         <div data-result-body></div>
       </section>
     </div>

   assets/quiz.js reads the buttons, records the answers, moves between steps and
   scores the results. A demo supplies only the questions and the result
   mapping — see the data-results block in any demo's quiz page.

   MOTION
   Steps slide and fade, 240ms, transform and opacity only. No height
   animation, which would force layout on every frame.
   ========================================================================== */

.qz {
  width: min(660px, 100% - 44px);
  margin-inline: auto;
  position: relative;
}

/* the progress rail across the top */
.qz-rail {
  display: flex;
  gap: 6px;
  margin-bottom: 30px;
}

.qz-rail i {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: var(--d-line);
  position: relative;
  overflow: hidden;
}

.qz-rail i::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--d-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s cubic-bezier(0.16, 0.84, 0.28, 1);
}

.qz-rail i.done::after { transform: scaleX(1); }

/* ---------------------------------------------------------------- steps */
.qz-step,
.qz-result {
  display: none;
}

.qz-step.on,
.qz-result.on {
  display: block;
  animation: qz-in 0.34s cubic-bezier(0.16, 0.84, 0.28, 1) both;
}

/* a step that has just been left animates out to the opposite side */
.qz-step.leaving,
.qz-result.leaving {
  display: block;
  animation: qz-out 0.2s ease-in both;
  position: absolute;
  inset: 0;
  pointer-events: none;
}

@keyframes qz-in {
  from { opacity: 0; transform: translate3d(18px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes qz-out {
  from { opacity: 1; transform: translate3d(0, 0, 0); }
  to   { opacity: 0; transform: translate3d(-14px, 0, 0); }
}

/* going backwards reverses the direction, which reads as "undo" */
.qz.back .qz-step.on,
.qz.back .qz-result.on {
  animation-name: qz-in-back;
}

@keyframes qz-in-back {
  from { opacity: 0; transform: translate3d(-18px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

.qz-count {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--d-accent);
  margin: 0 0 12px;
}

.qz h2,
.qz h1 {
  font-size: clamp(1.4rem, 3.2vw, 2.05rem);
  line-height: 1.18;
  letter-spacing: -0.028em;
  margin: 0 0 10px;
}

.qz-sub {
  color: var(--d-muted);
  font-size: 0.96rem;
  margin: 0 0 26px;
  max-width: 46ch;
}

/* -------------------------------------------------------------- options */
.qz-options {
  display: grid;
  gap: 10px;
}

.qz-opt {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 16px 18px;
  text-align: left;
  font: inherit;
  font-size: 0.98rem;
  color: inherit;
  background: var(--d-surface);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  cursor: pointer;
  transition: border-color 0.18s ease, transform 0.18s cubic-bezier(0.16, 0.84, 0.28, 1),
              background-color 0.18s ease;
}

.qz-opt:hover {
  border-color: var(--d-ink);
  transform: translate3d(3px, 0, 0);
}

.qz-opt:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
}

/* the small square that fills when chosen */
.qz-opt::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--d-line);
  border-radius: 5px;
  transition: background-color 0.16s ease, border-color 0.16s ease;
}

.qz-opt[aria-pressed="true"] {
  border-color: var(--d-accent);
  background: color-mix(in srgb, var(--d-accent) 7%, var(--d-surface));
}

.qz-opt[aria-pressed="true"]::before {
  background: var(--d-accent);
  border-color: var(--d-accent);
}

/* options that carry a description under the label */
/* The description under the label.
   `.qz-opt` is a flex row, so a bare text node plus a <span> would sit side by
   side. The label and its description belong in one child; any demo that puts
   them straight into the button gets them stacked by these rules instead. */
.qz-opt > span:last-child,
.qz-opt .qz-opt-text { display: block; min-width: 0; }

.qz-opt span {
  display: block;
  font-size: 0.84rem;
  color: var(--d-muted);
  margin-top: 3px;
}

.qz-opt b { font-weight: 600; }

/* A heading that has been focused by the engine is not a control, so it must
   not be painted like one. The focus move is still there for screen readers. */
.qz h1:focus,
.qz h2:focus,
.qz h1:focus-visible,
.qz h2:focus-visible { outline: none; }

/* multi-select uses a round marker so the two behave differently */
.qz-multi .qz-opt::before { border-radius: 50%; }

/* ------------------------------------------------------------- controls */
.qz-nav {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 26px;
  flex-wrap: wrap;
}

.qz-nav .qz-back {
  background: none;
  border: 0;
  padding: 10px 4px;
  font: inherit;
  font-size: 0.9rem;
  color: var(--d-muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.qz-nav .qz-back:hover { color: var(--d-ink); }
.qz-nav .qz-back[hidden] { display: none; }

.qz-hint {
  font-size: 0.8rem;
  color: var(--d-muted);
  margin-left: auto;
}

/* ---------------------------------------------------------------- result */
.qz-result-card {
  border: 1px solid var(--d-line);
  border-radius: calc(var(--d-radius) + 4px);
  background: var(--d-surface);
  padding: 30px 28px;
  animation: qz-in 0.42s 0.06s cubic-bezier(0.16, 0.84, 0.28, 1) both;
}

.qz-result-badge {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--d-accent);
  background: color-mix(in srgb, var(--d-accent) 12%, transparent);
  border-radius: 999px;
  padding: 5px 12px;
  margin-bottom: 14px;
}

.qz-result h2 { margin-bottom: 8px; }

.qz-result .qz-why {
  color: var(--d-muted);
  font-size: 0.95rem;
  line-height: 1.6;
  margin: 0 0 22px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--d-line);
}

/* the recommended products, listed as rows rather than cards so a result
   page does not look like a shop page */
.qz-picks {
  display: grid;
  gap: 0;
}

.qz-pick {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 15px 0;
  border-bottom: 1px solid var(--d-line);
  text-decoration: none;
  transition: padding-left 0.22s cubic-bezier(0.16, 0.84, 0.28, 1);
}

.qz-pick:hover { padding-left: 8px; }

.qz-pick-img {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 36% 32%,
      color-mix(in srgb, var(--d-accent) 26%, var(--d-surface)),
      var(--d-surface) 72%);
}

.qz-pick b { display: block; font-weight: 600; font-size: 0.97rem; }
.qz-pick span { font-size: 0.82rem; color: var(--d-muted); }

.qz-pick .qz-pick-price {
  font-family: var(--d-font);
  font-size: 1.05rem;
  white-space: nowrap;
}

.qz-result-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 24px;
}

.qz-restart {
  background: none;
  border: 0;
  padding: 12px 4px;
  font: inherit;
  font-size: 0.88rem;
  color: var(--d-muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.qz-restart:hover { color: var(--d-ink); }

/* the running summary of what has been answered, shown on later steps */
.qz-chosen {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-bottom: 22px;
}

.qz-chosen span {
  font-size: 0.76rem;
  padding: 4px 11px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--d-ink) 6%, transparent);
  color: var(--d-muted);
}

@media (prefers-reduced-motion: reduce) {
  .qz-step.on,
  .qz-result.on,
  .qz-step.leaving,
  .qz-result.leaving,
  .qz-result-card {
    animation: none !important;
  }
  .qz-opt:hover { transform: none; }
  .qz-rail i::after { transition: none; }
}

@media print {
  .qz-nav, .qz-restart, .qz-rail { display: none !important; }
  .qz-step, .qz-result { display: block !important; }
}
