Open demo

CSS code

HTML
<div><span class="lbl">Accordion steps, completion from :has()</span>
<form class="cw cw-acc" action="#cw-sent" aria-labelledby="cab-title">
  <h2 class="cw-title" id="cab-title">Book Cabin 7 at Pinecrest Lake</h2>
  <p class="cw-sub">Lakeside, sleeps 4 · $148 a night · free cancellation until 7 days before</p>
  <div class="cw-steps">
    <details class="cw-step s1" name="cabin" open>
      <summary><span class="cw-badge" aria-hidden="true"><b>1</b><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="cw-name">Dates <small><span class="todo">Step 1 of 3</span><span class="ok">Step 1 of 3, complete</span></small></span>
        <svg class="cw-chev" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="cw-body" id="cab-dates"><fieldset><legend class="cw-sr">Dates</legend>
        <div class="cw-row">
          <div class="cw-field"><label for="cab-in">Check-in</label><input class="cw-input" id="cab-in" name="checkin" type="date" required value="2026-10-16"></div>
          <div class="cw-field"><label for="cab-nights">Nights</label><input class="cw-input" id="cab-nights" name="nights" type="number" min="2" max="14" required value="3"></div>
        </div></fieldset>
        <div class="cw-links"><a class="cw-btn" href="#cab-guests">Continue to guests</a></div>
      </div>
    </details>
    <details class="cw-step s2" name="cabin">
      <summary><span class="cw-badge" aria-hidden="true"><b>2</b><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="cw-name">Guests <small><span class="todo">Step 2 of 3</span><span class="ok">Step 2 of 3, complete</span></small></span>
        <svg class="cw-chev" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="cw-body" id="cab-guests"><fieldset><legend class="cw-sr">Guests</legend>
        <div class="cw-row">
          <div class="cw-field"><label for="cab-adults">Adults</label><input class="cw-input" id="cab-adults" name="adults" type="number" min="1" max="4" required value="2"></div>
          <div class="cw-field"><label for="cab-kids">Children</label><input class="cw-input" id="cab-kids" name="children" type="number" min="0" max="3" value="1"></div>
        </div>
        <label class="cw-check"><input type="checkbox" name="dog">Bringing a dog ($25 cleaning fee)</label></fieldset>
        <div class="cw-links"><a class="cw-btn ghost" href="#cab-dates">Back</a><a class="cw-btn" href="#cab-contact">Continue to contact</a></div>
      </div>
    </details>
    <details class="cw-step s3" name="cabin">
      <summary><span class="cw-badge" aria-hidden="true"><b>3</b><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="cw-name">Contact <small><span class="todo">Step 3 of 3</span><span class="ok">Step 3 of 3, complete</span></small></span>
        <svg class="cw-chev" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="cw-body" id="cab-contact"><fieldset><legend class="cw-sr">Contact</legend>
        <div class="cw-field"><label for="cab-name">Full name</label><input class="cw-input" id="cab-name" name="name" required autocomplete="name"></div>
        <div class="cw-row">
          <div class="cw-field"><label for="cab-email">Email</label><input class="cw-input" id="cab-email" name="email" type="email" required autocomplete="email"></div>
          <div class="cw-field"><label for="cab-phone">Phone</label><input class="cw-input" id="cab-phone" name="phone" type="tel" autocomplete="tel"></div>
        </div></fieldset>
        <div class="cw-links"><a class="cw-btn ghost" href="#cab-guests">Back</a></div>
      </div>
    </details>
  </div>
  <div class="cw-foot">
    <div class="cw-bar" aria-hidden="true"><i></i></div>
    <p class="cw-count"><span><b></b> of 3 steps complete</span><span class="cw-left">Still to do: <span class="t1">Dates</span><span class="t2">Guests</span><span class="t3">Contact</span></span></p>
    <button class="cw-btn cw-send" type="submit">Request booking</button>
    <p class="cw-sent" id="cw-sent" tabindex="-1">Request sent. Pinecrest Lake Cabins will confirm by email within a day.</p>
  </div>
</form></div>

<div><span class="lbl">Choices that reveal the next step</span>
<form class="cw cw-pick" aria-labelledby="cof-title">
  <h2 class="cw-title" id="cof-title">Build your coffee subscription</h2>
  <p class="cw-sub">Northbound Roasters · roasted to order, ships every Monday</p>
  <ol class="cw-track" aria-label="Progress">
    <li class="c1">Beans<span class="d cw-sr">, done</span></li>
    <li class="c2">Grind<span class="d cw-sr">, done</span></li>
    <li class="c3">Bag size<span class="d cw-sr">, done</span></li>
    <li class="c4">Delivery<span class="d cw-sr">, done</span></li>
  </ol>
  <fieldset class="cw-q q1"><legend><span>Step 1 of 4</span>Choose your beans</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="beans" id="cb-1" value="Ethiopia Guji" required checked style="--price:19"><b>Ethiopia Guji</b><span>Peach, jasmine, black tea</span><em>$19</em></label>
      <label class="cw-opt"><input type="radio" name="beans" id="cb-2" value="Northbound House" style="--price:16"><b>Northbound House</b><span>Cocoa, hazelnut, brown sugar</span><em>$16</em></label>
      <label class="cw-opt"><input type="radio" name="beans" id="cb-3" value="Colombia Huila Decaf" style="--price:17"><b>Huila Decaf</b><span>Red apple, caramel, no caffeine</span><em>$17</em></label>
    </div></fieldset>
  <fieldset class="cw-q q2"><legend><span>Step 2 of 4</span>How do you brew?</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="grind" id="cg-1" value="Whole bean" required><b>Whole bean</b><span>You grind at home</span></label>
      <label class="cw-opt"><input type="radio" name="grind" id="cg-2" value="Espresso"><b>Espresso</b><span>Fine grind</span></label>
      <label class="cw-opt"><input type="radio" name="grind" id="cg-3" value="Filter" checked><b>Filter</b><span>Medium, for pour-over</span></label>
      <label class="cw-opt"><input type="radio" name="grind" id="cg-4" value="French press"><b>French press</b><span>Coarse grind</span></label>
    </div></fieldset>
  <fieldset class="cw-q q3"><legend><span>Step 3 of 4</span>Bag size</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="size" id="cs-1" value="250 g" required><b>250 g</b><span>About 16 cups</span><em>Included</em></label>
      <label class="cw-opt"><input type="radio" name="size" id="cs-2" value="500 g" style="--price:9"><b>500 g</b><span>About 33 cups</span><em>+$9</em></label>
      <label class="cw-opt"><input type="radio" name="size" id="cs-3" value="1 kg" style="--price:24"><b>1 kg</b><span>About 66 cups</span><em>+$24</em></label>
    </div></fieldset>
  <fieldset class="cw-q q4"><legend><span>Step 4 of 4</span>How often?</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="every" id="ce-1" value="Every week" required><b>Every week</b><span>Ships Mondays</span></label>
      <label class="cw-opt"><input type="radio" name="every" id="ce-2" value="Every 2 weeks"><b>Every 2 weeks</b><span>Most popular</span></label>
      <label class="cw-opt"><input type="radio" name="every" id="ce-3" value="Every month"><b>Every month</b><span>First Monday</span></label>
    </div></fieldset>
  <div class="cw-box">
    <h3>Your box</h3>
    <p class="cw-v"><span class="v-b1">Ethiopia Guji</span><span class="v-b2">Northbound House</span><span class="v-b3">Huila Decaf</span>,
      <span class="v-g1">whole bean</span><span class="v-g2">ground for espresso</span><span class="v-g3">ground for filter</span><span class="v-g4">ground for French press</span>,
      <span class="v-s1">250 g</span><span class="v-s2">500 g</span><span class="v-s3">1 kg</span>
      <span class="v-e1">every week</span><span class="v-e2">every 2 weeks</span><span class="v-e3">every month</span>.</p>
    <div class="cw-total"><p><strong></strong> per delivery · free shipping · skip or cancel any time</p><button class="cw-btn" type="submit">Start subscription</button></div>
  </div>
</form></div>
CSS
/* Two wizards with no JavaScript at all.
   1. Accordion steps: exclusive <details name="…"> elements. "Continue" is a link to the next step's content,
      and fragment navigation opens the closed <details> it points into. Each step wraps its fields in a
      <fieldset>, so fieldset:valid / :invalid tells CSS which steps are complete: :has() ticks the badge,
      a counter prints "2 of 3", three custom properties size the bar, and the submit button only appears
      when nothing is left.
   2. Choices that reveal the next step: radio <fieldset>s. :has(:checked) reveals the next step (with an
      @starting-style fade), lights the stepper and fills the summary; a CSS counter adds up the price. */
.cw{--cw-accent:#be123c;--cw-dark:#9f1239;--cw-soft:#ffe4e6;--cw-ink:#23161a;--cw-muted:#6b5a5f;--cw-line:#8e7a80;--cw-ok:#047857;
  background:#fff;border-radius:18px;padding:30px 32px;box-shadow:0 1px 2px rgba(35,22,26,.06),0 12px 32px -14px rgba(136,19,55,.22);color:var(--cw-ink)}
.cw-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.cw-title{margin:0;font-size:1.3rem;font-weight:700;letter-spacing:-.015em}
.cw-sub{margin:4px 0 0;color:var(--cw-muted);font-size:.92rem}
.cw-field{display:grid;gap:6px;min-width:0}
.cw-field label{font-size:.88rem;font-weight:600}
.cw-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px}
.cw-input{width:100%;min-height:44px;font:inherit;font-size:.95rem;color:var(--cw-ink);background:#fff;border:1.5px solid var(--cw-line);border-radius:10px;padding:10px 12px}
.cw-input:focus-visible{outline:none;border-color:var(--cw-accent);box-shadow:0 0 0 4px var(--cw-soft)}
.cw-input:user-invalid{border-color:#b91c1c;background:#fff7f7}
.cw-check{display:flex;align-items:center;gap:10px;font-size:.92rem}
.cw-check input{width:18px;height:18px;margin:0;accent-color:var(--cw-accent)}
.cw-check input:focus-visible{outline:2px solid var(--cw-accent);outline-offset:2px}
.cw-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:0 20px;border-radius:10px;border:1.5px solid var(--cw-accent);background:var(--cw-accent);color:#fff;font:inherit;font-size:.95rem;font-weight:600;text-decoration:none;cursor:pointer;transition:background .2s}
.cw-btn:hover{background:var(--cw-dark)}
.cw-btn:focus-visible{outline:none;box-shadow:0 0 0 3px #fff,0 0 0 5px var(--cw-accent)}
.cw-btn.ghost{background:#fff;color:var(--cw-dark);border-color:var(--cw-line)}
.cw-btn.ghost:hover{background:#fff5f6}
.cw-btn svg,.cw-badge svg,.cw-chev{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}

/* 1 — accordion steps */
.cw-acc{interpolate-size:allow-keywords;counter-reset:cw-done}
.cw-steps{display:grid;gap:10px;margin-top:24px}
.cw-step{border:1.5px solid #e7dcdf;border-radius:14px;background:#fff;transition:border-color .25s,box-shadow .25s}
.cw-step[open]{border-color:var(--cw-accent);box-shadow:0 0 0 4px var(--cw-soft)}
.cw-step summary{display:flex;align-items:center;gap:14px;padding:14px 16px;cursor:pointer;list-style:none;border-radius:12px}
.cw-step summary::-webkit-details-marker{display:none}
.cw-step summary:focus-visible{outline:2px solid var(--cw-accent);outline-offset:2px}
.cw-badge{flex:none;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;border:2px solid var(--cw-line);font-weight:700;font-size:.9rem;color:var(--cw-muted);transition:background .25s,border-color .25s}
.cw-badge svg{display:none}
.cw-step[open] .cw-badge{border-color:var(--cw-accent);color:var(--cw-dark)}
.cw-name{flex:1;display:grid;font-weight:700}
.cw-name small{font-size:.8rem;font-weight:500;color:var(--cw-muted)}
.cw-name .ok{display:none;color:var(--cw-ok)}
.cw-chev{flex:none;color:var(--cw-muted);transition:rotate .25s}
.cw-step[open] .cw-chev{rotate:180deg}
/* a step whose fieldset is valid is complete: tick the badge and say so */
.cw-step:has(fieldset:valid){counter-increment:cw-done}
.cw-step:has(fieldset:valid) .cw-badge{background:var(--cw-ok);border-color:var(--cw-ok);color:#fff}
.cw-step:has(fieldset:valid) .cw-badge b,.cw-step:has(fieldset:valid) .todo{display:none}
.cw-step:has(fieldset:valid) .cw-badge svg{display:block}
.cw-step:has(fieldset:valid) .cw-name .ok{display:inline}
/* smooth open in browsers with ::details-content and interpolate-size; elsewhere it simply opens */
.cw-step::details-content{block-size:0;overflow:hidden;transition:block-size .3s ease,content-visibility .3s allow-discrete}
.cw-step[open]::details-content{block-size:auto}
.cw-body{display:grid;gap:16px;padding:4px 16px 18px;scroll-margin-top:96px}
.cw-body fieldset{border:0;margin:0;padding:0;display:grid;gap:16px;min-width:0}
.cw-links{display:flex;flex-wrap:wrap;gap:10px}
.cw-links .cw-btn:not(.ghost){margin-left:auto}
/* progress, what is left, and the submit button that only shows when every step is valid */
.cw-foot{margin-top:22px;display:grid;gap:12px}
.cw-bar{height:8px;border-radius:99px;background:#efe6e8;box-shadow:inset 0 0 0 1px #8e7a80;overflow:hidden}
.cw-bar i{display:block;height:100%;border-radius:inherit;background:var(--cw-accent);width:calc((var(--cw-d1,0) + var(--cw-d2,0) + var(--cw-d3,0)) / 3 * 100%);transition:width .35s ease}
.cw-acc:has(.s1 fieldset:valid){--cw-d1:1}
.cw-acc:has(.s2 fieldset:valid){--cw-d2:1}
.cw-acc:has(.s3 fieldset:valid){--cw-d3:1}
.cw-count{margin:0;display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px 16px;font-size:.88rem;color:var(--cw-muted)}
.cw-count b::before{content:counter(cw-done)}
.cw-count b{color:var(--cw-ink)}
.cw-left{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.cw-left span{display:none;padding:1px 9px;border-radius:99px;background:#fff0f2;color:var(--cw-dark);font-weight:600;font-size:.8rem}
.cw-acc:has(.s1 fieldset:invalid) .cw-left .t1,.cw-acc:has(.s2 fieldset:invalid) .cw-left .t2,.cw-acc:has(.s3 fieldset:invalid) .cw-left .t3{display:inline}
.cw-acc:has(fieldset:invalid) .cw-send,.cw-acc:not(:has(fieldset:invalid)) .cw-left{display:none}
.cw-send{justify-self:end}
.cw-sent{display:none;margin:0;padding:12px 14px;border-radius:10px;background:#ecfdf5;color:#065f46;font-size:.92rem;font-weight:600}
.cw-sent:target{display:block}

/* 2 — choices that reveal the next step */
.cw-pick{counter-reset:cw-price}
.cw-track{list-style:none;margin:22px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.cw-track li{display:grid;gap:6px;font-size:.8rem;font-weight:600;color:var(--cw-muted)}
.cw-track li::before{content:"";height:6px;border-radius:99px;background:#efe6e8;box-shadow:inset 0 0 0 1px #8e7a80;transition:background .3s}
.cw-track .d{display:none}
.cw-q{border:0;margin:26px 0 0;padding:0;min-width:0;transition:opacity .35s ease,translate .35s ease,display .35s allow-discrete}
@starting-style{.cw-q{opacity:0;translate:0 10px}}
.cw-q legend{padding:0;margin-bottom:12px;font-size:1.05rem;font-weight:700}
.cw-q legend span{display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--cw-dark)}
.cw-opts{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.cw-opt{position:relative;display:grid;gap:2px;padding:13px 14px;border:1.5px solid var(--cw-line);border-radius:12px;cursor:pointer;transition:border-color .2s,background .2s}
.cw-opt input{position:absolute;opacity:0;inset:0;margin:0;width:100%;height:100%;cursor:pointer}
.cw-opt b{font-size:.95rem}
.cw-opt span{font-size:.8rem;color:var(--cw-muted)}
.cw-opt em{font-style:normal;font-size:.8rem;font-weight:700;color:var(--cw-dark)}
.cw-opt:has(:checked){border-color:var(--cw-accent);background:#fff5f6;box-shadow:inset 0 0 0 1px var(--cw-accent)}
.cw-opt:has(:focus-visible){outline:2px solid var(--cw-accent);outline-offset:3px}
.cw-opt input:checked{counter-increment:cw-price var(--price,0)}
/* reveal: each step waits for the one before it */
.cw-pick:not(:has([name="beans"]:checked)) .q2,
.cw-pick:not(:has([name="grind"]:checked)) .q3,
.cw-pick:not(:has([name="size"]:checked)) .q4,
.cw-pick:not(:has([name="every"]:checked)) .cw-box{display:none}
/* stepper: filled when answered, darker for the step being answered now */
.cw-pick:has([name="beans"]:checked) .c1,.cw-pick:has([name="grind"]:checked) .c2,
.cw-pick:has([name="size"]:checked) .c3,.cw-pick:has([name="every"]:checked) .c4{color:var(--cw-ok)}
.cw-pick:has([name="beans"]:checked) .c1::before,.cw-pick:has([name="grind"]:checked) .c2::before,
.cw-pick:has([name="size"]:checked) .c3::before,.cw-pick:has([name="every"]:checked) .c4::before{background:var(--cw-ok);box-shadow:none}
.cw-pick:has([name="beans"]:checked) .c1 .d,.cw-pick:has([name="grind"]:checked) .c2 .d,
.cw-pick:has([name="size"]:checked) .c3 .d,.cw-pick:has([name="every"]:checked) .c4 .d{display:inline}
.cw-pick:not(:has([name="beans"]:checked)) .c1,
.cw-pick:has([name="beans"]:checked):not(:has([name="grind"]:checked)) .c2,
.cw-pick:has([name="grind"]:checked):not(:has([name="size"]:checked)) .c3,
.cw-pick:has([name="size"]:checked):not(:has([name="every"]:checked)) .c4{color:var(--cw-dark)}
.cw-pick:not(:has([name="beans"]:checked)) .c1::before,
.cw-pick:has([name="beans"]:checked):not(:has([name="grind"]:checked)) .c2::before,
.cw-pick:has([name="grind"]:checked):not(:has([name="size"]:checked)) .c3::before,
.cw-pick:has([name="size"]:checked):not(:has([name="every"]:checked)) .c4::before{background:var(--cw-accent);box-shadow:none}
/* summary: one span per option, shown when that option is checked; the price is a CSS counter */
.cw-box{margin-top:26px;padding:18px;border-radius:14px;background:#fff5f6;border:1.5px solid #f4c2cb;display:grid;gap:12px;transition:opacity .35s ease,translate .35s ease,display .35s allow-discrete}
@starting-style{.cw-box{opacity:0;translate:0 10px}}
.cw-box h3{margin:0;font-size:1.05rem}
.cw-box p{margin:0;font-size:.95rem}
.cw-v span{display:none}
.cw-pick:has(#cb-1:checked) .v-b1,.cw-pick:has(#cb-2:checked) .v-b2,.cw-pick:has(#cb-3:checked) .v-b3,
.cw-pick:has(#cg-1:checked) .v-g1,.cw-pick:has(#cg-2:checked) .v-g2,.cw-pick:has(#cg-3:checked) .v-g3,.cw-pick:has(#cg-4:checked) .v-g4,
.cw-pick:has(#cs-1:checked) .v-s1,.cw-pick:has(#cs-2:checked) .v-s2,.cw-pick:has(#cs-3:checked) .v-s3,
.cw-pick:has(#ce-1:checked) .v-e1,.cw-pick:has(#ce-2:checked) .v-e2,.cw-pick:has(#ce-3:checked) .v-e3{display:inline}
.cw-total{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px}
.cw-total p{font-size:.9rem;color:var(--cw-muted)}
.cw-total strong{font-size:1.6rem;color:var(--cw-ink);letter-spacing:-.02em}
.cw-total strong::before{content:"$" counter(cw-price)}
@media (prefers-reduced-motion:reduce){.cw *,.cw *::before,.cw ::details-content{transition:none!important}}
@media (max-width:600px){.cw{padding:24px 18px}.cw-track li{font-size:.72rem}.cw-opts{grid-template-columns:1fr}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Accordion steps, completion from :has()</span>
<form class="cw cw-acc card" action="#cw-sent" aria-labelledby="cab-title">
  <h2 class="cw-title fw-bold" id="cab-title">Book Cabin 7 at Pinecrest Lake</h2>
  <p class="cw-sub">Lakeside, sleeps 4 · $148 a night · free cancellation until 7 days before</p>
  <div class="cw-steps">
    <details class="cw-step s1" name="cabin" open>
      <summary><span class="cw-badge" aria-hidden="true"><b>1</b><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="cw-name">Dates <small><span class="todo">Step 1 of 3</span><span class="ok">Step 1 of 3, complete</span></small></span>
        <svg class="cw-chev" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="cw-body" id="cab-dates"><fieldset><legend class="visually-hidden">Dates</legend>
        <div class="cw-row">
          <div class="cw-field"><label class="form-label mb-0" for="cab-in">Check-in</label><input class="form-control" id="cab-in" name="checkin" type="date" required value="2026-10-16"></div>
          <div class="cw-field"><label class="form-label mb-0" for="cab-nights">Nights</label><input class="form-control" id="cab-nights" name="nights" type="number" min="2" max="14" required value="3"></div>
        </div></fieldset>
        <div class="cw-links"><a class="btn btn-primary" href="#cab-guests">Continue to guests</a></div>
      </div>
    </details>
    <details class="cw-step s2" name="cabin">
      <summary><span class="cw-badge" aria-hidden="true"><b>2</b><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="cw-name">Guests <small><span class="todo">Step 2 of 3</span><span class="ok">Step 2 of 3, complete</span></small></span>
        <svg class="cw-chev" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="cw-body" id="cab-guests"><fieldset><legend class="visually-hidden">Guests</legend>
        <div class="cw-row">
          <div class="cw-field"><label class="form-label mb-0" for="cab-adults">Adults</label><input class="form-control" id="cab-adults" name="adults" type="number" min="1" max="4" required value="2"></div>
          <div class="cw-field"><label class="form-label mb-0" for="cab-kids">Children</label><input class="form-control" id="cab-kids" name="children" type="number" min="0" max="3" value="1"></div>
        </div>
        <div class="form-check"><input class="form-check-input" type="checkbox" name="dog" id="cab-dog"><label class="form-check-label" for="cab-dog">Bringing a dog ($25 cleaning fee)</label></div></fieldset>
        <div class="cw-links"><a class="btn btn-outline-secondary" href="#cab-dates">Back</a><a class="btn btn-primary" href="#cab-contact">Continue to contact</a></div>
      </div>
    </details>
    <details class="cw-step s3" name="cabin">
      <summary><span class="cw-badge" aria-hidden="true"><b>3</b><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="cw-name">Contact <small><span class="todo">Step 3 of 3</span><span class="ok">Step 3 of 3, complete</span></small></span>
        <svg class="cw-chev" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="cw-body" id="cab-contact"><fieldset><legend class="visually-hidden">Contact</legend>
        <div class="cw-field"><label class="form-label mb-0" for="cab-name">Full name</label><input class="form-control" id="cab-name" name="name" required autocomplete="name"></div>
        <div class="cw-row">
          <div class="cw-field"><label class="form-label mb-0" for="cab-email">Email</label><input class="form-control" id="cab-email" name="email" type="email" required autocomplete="email"></div>
          <div class="cw-field"><label class="form-label mb-0" for="cab-phone">Phone</label><input class="form-control" id="cab-phone" name="phone" type="tel" autocomplete="tel"></div>
        </div></fieldset>
        <div class="cw-links"><a class="btn btn-outline-secondary" href="#cab-guests">Back</a></div>
      </div>
    </details>
  </div>
  <div class="cw-foot">
    <div class="progress cw-bar" aria-hidden="true"><div class="progress-bar"></div></div>
    <p class="cw-count"><span><b></b> of 3 steps complete</span><span class="cw-left">Still to do: <span class="t1">Dates</span><span class="t2">Guests</span><span class="t3">Contact</span></span></p>
    <button class="btn btn-primary cw-send" type="submit">Request booking</button>
    <p class="cw-sent alert alert-success" id="cw-sent" tabindex="-1">Request sent. Pinecrest Lake Cabins will confirm by email within a day.</p>
  </div>
</form></div>

<div><span class="lbl">Choices that reveal the next step</span>
<form class="cw cw-pick card" aria-labelledby="cof-title">
  <h2 class="cw-title fw-bold" id="cof-title">Build your coffee subscription</h2>
  <p class="cw-sub">Northbound Roasters · roasted to order, ships every Monday</p>
  <ol class="cw-track" aria-label="Progress">
    <li class="c1">Beans<span class="d visually-hidden">, done</span></li>
    <li class="c2">Grind<span class="d visually-hidden">, done</span></li>
    <li class="c3">Bag size<span class="d visually-hidden">, done</span></li>
    <li class="c4">Delivery<span class="d visually-hidden">, done</span></li>
  </ol>
  <fieldset class="cw-q q1"><legend><span>Step 1 of 4</span>Choose your beans</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="beans" id="cb-1" value="Ethiopia Guji" required checked style="--price:19"><b>Ethiopia Guji</b><span>Peach, jasmine, black tea</span><em>$19</em></label>
      <label class="cw-opt"><input type="radio" name="beans" id="cb-2" value="Northbound House" style="--price:16"><b>Northbound House</b><span>Cocoa, hazelnut, brown sugar</span><em>$16</em></label>
      <label class="cw-opt"><input type="radio" name="beans" id="cb-3" value="Colombia Huila Decaf" style="--price:17"><b>Huila Decaf</b><span>Red apple, caramel, no caffeine</span><em>$17</em></label>
    </div></fieldset>
  <fieldset class="cw-q q2"><legend><span>Step 2 of 4</span>How do you brew?</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="grind" id="cg-1" value="Whole bean" required><b>Whole bean</b><span>You grind at home</span></label>
      <label class="cw-opt"><input type="radio" name="grind" id="cg-2" value="Espresso"><b>Espresso</b><span>Fine grind</span></label>
      <label class="cw-opt"><input type="radio" name="grind" id="cg-3" value="Filter" checked><b>Filter</b><span>Medium, for pour-over</span></label>
      <label class="cw-opt"><input type="radio" name="grind" id="cg-4" value="French press"><b>French press</b><span>Coarse grind</span></label>
    </div></fieldset>
  <fieldset class="cw-q q3"><legend><span>Step 3 of 4</span>Bag size</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="size" id="cs-1" value="250 g" required><b>250 g</b><span>About 16 cups</span><em>Included</em></label>
      <label class="cw-opt"><input type="radio" name="size" id="cs-2" value="500 g" style="--price:9"><b>500 g</b><span>About 33 cups</span><em>+$9</em></label>
      <label class="cw-opt"><input type="radio" name="size" id="cs-3" value="1 kg" style="--price:24"><b>1 kg</b><span>About 66 cups</span><em>+$24</em></label>
    </div></fieldset>
  <fieldset class="cw-q q4"><legend><span>Step 4 of 4</span>How often?</legend>
    <div class="cw-opts">
      <label class="cw-opt"><input type="radio" name="every" id="ce-1" value="Every week" required><b>Every week</b><span>Ships Mondays</span></label>
      <label class="cw-opt"><input type="radio" name="every" id="ce-2" value="Every 2 weeks"><b>Every 2 weeks</b><span>Most popular</span></label>
      <label class="cw-opt"><input type="radio" name="every" id="ce-3" value="Every month"><b>Every month</b><span>First Monday</span></label>
    </div></fieldset>
  <div class="cw-box">
    <h3>Your box</h3>
    <p class="cw-v"><span class="v-b1">Ethiopia Guji</span><span class="v-b2">Northbound House</span><span class="v-b3">Huila Decaf</span>,
      <span class="v-g1">whole bean</span><span class="v-g2">ground for espresso</span><span class="v-g3">ground for filter</span><span class="v-g4">ground for French press</span>,
      <span class="v-s1">250 g</span><span class="v-s2">500 g</span><span class="v-s3">1 kg</span>
      <span class="v-e1">every week</span><span class="v-e2">every 2 weeks</span><span class="v-e3">every month</span>.</p>
    <div class="cw-total"><p><strong></strong> per delivery · free shipping · skip or cancel any time</p><button class="btn btn-primary" type="submit">Start subscription</button></div>
  </div>
</form></div>
CSS
/* Two wizards with no JavaScript at all, on Bootstrap 5: .card, .form-control, .form-check, .btn, .progress and
   .alert, restyled through Bootstrap variables; the step logic is the same CSS as the plain version.
   1. Accordion steps: exclusive <details name="…"> elements. "Continue" is a link to the next step's content,
      and fragment navigation opens the closed <details> it points into. Each step wraps its fields in a
      <fieldset>, so fieldset:valid / :invalid tells CSS which steps are complete: :has() ticks the badge,
      a counter prints "2 of 3", three custom properties size the bar, and the submit button only appears
      when nothing is left.
   2. Choices that reveal the next step: radio <fieldset>s. :has(:checked) reveals the next step (with an
      @starting-style fade), lights the stepper and fills the summary; a CSS counter adds up the price. */
.cw{--bs-border-color:#8e7a80;--bs-body-color:#23161a;--bs-card-border-width:0;--cw-accent:#be123c;--cw-dark:#9f1239;--cw-soft:#ffe4e6;--cw-ink:#23161a;--cw-muted:#6b5a5f;--cw-line:#8e7a80;--cw-ok:#047857;
  background:#fff;border-radius:18px;padding:30px 32px;box-shadow:0 1px 2px rgba(35,22,26,.06),0 12px 32px -14px rgba(136,19,55,.22);color:var(--cw-ink)}
.cw-title{margin:0;font-size:1.3rem;letter-spacing:-.015em}
.cw-sub{margin:4px 0 0;color:var(--cw-muted);font-size:.92rem}
.cw-field{display:grid;gap:6px;min-width:0}
.cw-field label{font-size:.88rem;font-weight:600}
.cw-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px}
.cw .form-control{min-height:44px;border-width:1.5px;padding:10px 12px;font-size:.95rem}
.cw h2,.cw h3{line-height:1.5}
.cw .form-control:focus{border-color:var(--cw-accent);box-shadow:0 0 0 4px var(--cw-soft)}
.cw .form-control:user-invalid{border-color:#b91c1c;background-color:#fff7f7}
.cw .form-check{font-size:.92rem;margin:0}
.cw .form-check-input{border:1.5px solid var(--cw-line)}
.cw .form-check-input:checked{background-color:var(--cw-accent);border-color:var(--cw-accent)}
.cw .form-check-input:focus{border-color:var(--cw-accent);box-shadow:0 0 0 3px var(--cw-soft)}
.cw .form-check-input:focus-visible{outline:2px solid var(--cw-accent);outline-offset:2px}
.cw .btn{--bs-btn-padding-x:20px;--bs-btn-font-size:.95rem;--bs-btn-font-weight:600;--bs-btn-border-width:1.5px;--bs-btn-border-radius:10px;display:inline-flex;align-items:center;justify-content:center;min-height:44px}
.cw .btn-primary{--bs-btn-bg:var(--cw-accent);--bs-btn-border-color:var(--cw-accent);--bs-btn-hover-bg:var(--cw-dark);--bs-btn-hover-border-color:var(--cw-dark);--bs-btn-active-bg:var(--cw-dark);--bs-btn-active-border-color:var(--cw-dark)}
.cw .btn-outline-secondary{--bs-btn-color:var(--cw-dark);--bs-btn-border-color:var(--cw-line);--bs-btn-hover-bg:#fff5f6;--bs-btn-hover-color:var(--cw-dark);--bs-btn-hover-border-color:var(--cw-line);--bs-btn-active-bg:#ffe9ec;--bs-btn-active-color:var(--cw-dark)}
.cw .btn:focus-visible{outline:0;box-shadow:0 0 0 3px #fff,0 0 0 5px var(--cw-accent)}
.cw-badge svg,.cw-chev{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}

/* 1 — accordion steps */
.cw-acc{interpolate-size:allow-keywords;counter-reset:cw-done}
.cw-steps{display:grid;gap:10px;margin-top:24px}
.cw-step{border:1.5px solid #e7dcdf;border-radius:14px;background:#fff;transition:border-color .25s,box-shadow .25s}
.cw-step[open]{border-color:var(--cw-accent);box-shadow:0 0 0 4px var(--cw-soft)}
.cw-step summary{display:flex;align-items:center;gap:14px;padding:14px 16px;cursor:pointer;list-style:none;border-radius:12px}
.cw-step summary::-webkit-details-marker{display:none}
.cw-step summary:focus-visible{outline:2px solid var(--cw-accent);outline-offset:2px}
.cw-badge{flex:none;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;border:2px solid var(--cw-line);font-weight:700;font-size:.9rem;color:var(--cw-muted);transition:background .25s,border-color .25s}
.cw-badge svg{display:none}
.cw-step[open] .cw-badge{border-color:var(--cw-accent);color:var(--cw-dark)}
.cw-name{flex:1;display:grid;font-weight:700}
.cw-name small{font-size:.8rem;font-weight:500;color:var(--cw-muted)}
.cw-name .ok{display:none;color:var(--cw-ok)}
.cw-chev{flex:none;color:var(--cw-muted);transition:rotate .25s}
.cw-step[open] .cw-chev{rotate:180deg}
/* a step whose fieldset is valid is complete: tick the badge and say so */
.cw-step:has(fieldset:valid){counter-increment:cw-done}
.cw-step:has(fieldset:valid) .cw-badge{background:var(--cw-ok);border-color:var(--cw-ok);color:#fff}
.cw-step:has(fieldset:valid) .cw-badge b,.cw-step:has(fieldset:valid) .todo{display:none}
.cw-step:has(fieldset:valid) .cw-badge svg{display:block}
.cw-step:has(fieldset:valid) .cw-name .ok{display:inline}
/* smooth open in browsers with ::details-content and interpolate-size; elsewhere it simply opens */
.cw-step::details-content{block-size:0;overflow:hidden;transition:block-size .3s ease,content-visibility .3s allow-discrete}
.cw-step[open]::details-content{block-size:auto}
.cw-body{display:grid;gap:16px;padding:4px 16px 18px;scroll-margin-top:96px}
.cw-body fieldset{border:0;margin:0;padding:0;display:grid;gap:16px;min-width:0}
.cw-links{display:flex;flex-wrap:wrap;gap:10px}
.cw-links .btn-primary{margin-left:auto}
/* progress, what is left, and the submit button that only shows when every step is valid */
.cw-foot{margin-top:22px;display:grid;gap:12px}
.cw-bar{--bs-progress-height:8px;--bs-progress-border-radius:99px;--bs-progress-bg:#efe6e8;--bs-progress-bar-bg:var(--cw-accent);box-shadow:inset 0 0 0 1px #8e7a80}
.cw-bar .progress-bar{border-radius:inherit;width:calc((var(--cw-d1,0) + var(--cw-d2,0) + var(--cw-d3,0)) / 3 * 100%);transition:width .35s ease}
.cw-acc:has(.s1 fieldset:valid){--cw-d1:1}
.cw-acc:has(.s2 fieldset:valid){--cw-d2:1}
.cw-acc:has(.s3 fieldset:valid){--cw-d3:1}
.cw-count{margin:0;display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px 16px;font-size:.88rem;color:var(--cw-muted)}
.cw-count b::before{content:counter(cw-done)}
.cw-count b{color:var(--cw-ink)}
.cw-left{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.cw-left span{display:none;padding:1px 9px;border-radius:99px;background:#fff0f2;color:var(--cw-dark);font-weight:600;font-size:.8rem}
.cw-acc:has(.s1 fieldset:invalid) .cw-left .t1,.cw-acc:has(.s2 fieldset:invalid) .cw-left .t2,.cw-acc:has(.s3 fieldset:invalid) .cw-left .t3{display:inline}
.cw-acc:has(fieldset:invalid) .cw-send,.cw-acc:not(:has(fieldset:invalid)) .cw-left{display:none}
.cw-send{justify-self:end}
.cw-sent{display:none;margin:0;--bs-alert-padding-y:12px;--bs-alert-bg:#ecfdf5;--bs-alert-color:#065f46;--bs-alert-border-color:#a7f3d0;font-size:.92rem;font-weight:600}
.cw-sent:target{display:block}

/* 2 — choices that reveal the next step */
.cw-pick{counter-reset:cw-price}
.cw-track{list-style:none;margin:22px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.cw-track li{display:grid;gap:6px;font-size:.8rem;font-weight:600;color:var(--cw-muted)}
.cw-track li::before{content:"";height:6px;border-radius:99px;background:#efe6e8;box-shadow:inset 0 0 0 1px #8e7a80;transition:background .3s}
.cw-track .d{display:none}
.cw-q{border:0;margin:26px 0 0;padding:0;min-width:0;transition:opacity .35s ease,translate .35s ease,display .35s allow-discrete}
@starting-style{.cw-q{opacity:0;translate:0 10px}}
.cw-q legend{float:none;padding:0;margin-bottom:12px;font-size:1.05rem;font-weight:700;line-height:1.4}
.cw-q legend span{display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--cw-dark)}
.cw-opts{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.cw-opt{position:relative;display:grid;gap:2px;padding:13px 14px;border:1.5px solid var(--cw-line);border-radius:12px;cursor:pointer;transition:border-color .2s,background .2s}
.cw-opt input{position:absolute;opacity:0;inset:0;margin:0;width:100%;height:100%;cursor:pointer}
.cw-opt b{font-size:.95rem}
.cw-opt span{font-size:.8rem;color:var(--cw-muted)}
.cw-opt em{font-style:normal;font-size:.8rem;font-weight:700;color:var(--cw-dark)}
.cw-opt:has(:checked){border-color:var(--cw-accent);background:#fff5f6;box-shadow:inset 0 0 0 1px var(--cw-accent)}
.cw-opt:has(:focus-visible){outline:2px solid var(--cw-accent);outline-offset:3px}
.cw-opt input:checked{counter-increment:cw-price var(--price,0)}
/* reveal: each step waits for the one before it */
.cw-pick:not(:has([name="beans"]:checked)) .q2,
.cw-pick:not(:has([name="grind"]:checked)) .q3,
.cw-pick:not(:has([name="size"]:checked)) .q4,
.cw-pick:not(:has([name="every"]:checked)) .cw-box{display:none}
/* stepper: filled when answered, darker for the step being answered now */
.cw-pick:has([name="beans"]:checked) .c1,.cw-pick:has([name="grind"]:checked) .c2,
.cw-pick:has([name="size"]:checked) .c3,.cw-pick:has([name="every"]:checked) .c4{color:var(--cw-ok)}
.cw-pick:has([name="beans"]:checked) .c1::before,.cw-pick:has([name="grind"]:checked) .c2::before,
.cw-pick:has([name="size"]:checked) .c3::before,.cw-pick:has([name="every"]:checked) .c4::before{background:var(--cw-ok);box-shadow:none}
.cw-pick:has([name="beans"]:checked) .c1 .d,.cw-pick:has([name="grind"]:checked) .c2 .d,
.cw-pick:has([name="size"]:checked) .c3 .d,.cw-pick:has([name="every"]:checked) .c4 .d{display:inline}
.cw-pick:not(:has([name="beans"]:checked)) .c1,
.cw-pick:has([name="beans"]:checked):not(:has([name="grind"]:checked)) .c2,
.cw-pick:has([name="grind"]:checked):not(:has([name="size"]:checked)) .c3,
.cw-pick:has([name="size"]:checked):not(:has([name="every"]:checked)) .c4{color:var(--cw-dark)}
.cw-pick:not(:has([name="beans"]:checked)) .c1::before,
.cw-pick:has([name="beans"]:checked):not(:has([name="grind"]:checked)) .c2::before,
.cw-pick:has([name="grind"]:checked):not(:has([name="size"]:checked)) .c3::before,
.cw-pick:has([name="size"]:checked):not(:has([name="every"]:checked)) .c4::before{background:var(--cw-accent);box-shadow:none}
/* summary: one span per option, shown when that option is checked; the price is a CSS counter */
.cw-box{margin-top:26px;padding:18px;border-radius:14px;background:#fff5f6;border:1.5px solid #f4c2cb;display:grid;gap:12px;transition:opacity .35s ease,translate .35s ease,display .35s allow-discrete}
@starting-style{.cw-box{opacity:0;translate:0 10px}}
.cw-box h3{margin:0;font-size:1.05rem;font-weight:700}
.cw-box p{margin:0;font-size:.95rem}
.cw-v span{display:none}
.cw-pick:has(#cb-1:checked) .v-b1,.cw-pick:has(#cb-2:checked) .v-b2,.cw-pick:has(#cb-3:checked) .v-b3,
.cw-pick:has(#cg-1:checked) .v-g1,.cw-pick:has(#cg-2:checked) .v-g2,.cw-pick:has(#cg-3:checked) .v-g3,.cw-pick:has(#cg-4:checked) .v-g4,
.cw-pick:has(#cs-1:checked) .v-s1,.cw-pick:has(#cs-2:checked) .v-s2,.cw-pick:has(#cs-3:checked) .v-s3,
.cw-pick:has(#ce-1:checked) .v-e1,.cw-pick:has(#ce-2:checked) .v-e2,.cw-pick:has(#ce-3:checked) .v-e3{display:inline}
.cw-total{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px}
.cw-total p{font-size:.9rem;color:var(--cw-muted)}
.cw-total strong{font-size:1.6rem;color:var(--cw-ink);letter-spacing:-.02em}
.cw-total strong::before{content:"$" counter(cw-price)}
@media (prefers-reduced-motion:reduce){.cw *,.cw *::before,.cw ::details-content{transition:none!important}}
@media (max-width:600px){.cw{padding:24px 18px}.cw-track li{font-size:.72rem}.cw-opts{grid-template-columns:1fr}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-cw-muted uppercase">Accordion steps, completion from :has()</span>
<form class="group/acc rounded-[18px] bg-white px-8 py-[30px] text-cw-ink shadow-[0_1px_2px_rgba(35,22,26,.06),0_12px_32px_-14px_rgba(136,19,55,.22)] max-[600px]:px-[18px] max-[600px]:py-6 [counter-reset:cw-done] [interpolate-size:allow-keywords] has-[.s1_fieldset:valid]:[--cw-d1:1] has-[.s2_fieldset:valid]:[--cw-d2:1] has-[.s3_fieldset:valid]:[--cw-d3:1]" action="#cw-sent" aria-labelledby="cab-title">
  <h2 class="text-[1.3rem] font-bold tracking-[-.015em]" id="cab-title">Book Cabin 7 at Pinecrest Lake</h2>
  <p class="mt-1 text-[.92rem] text-cw-muted">Lakeside, sleeps 4 · $148 a night · free cancellation until 7 days before</p>
  <div class="mt-6 grid gap-2.5">
    <details class="s1 group/step rounded-[14px] border-[1.5px] border-[#e7dcdf] bg-white transition-[border-color,box-shadow] duration-250 open:border-cw-accent open:shadow-[0_0_0_4px_var(--color-cw-soft)] has-[fieldset:valid]:[counter-increment:cw-done] motion-reduce:transition-none [&::details-content]:[block-size:0] [&::details-content]:overflow-hidden [&::details-content]:[transition:block-size_.3s_ease,content-visibility_.3s_allow-discrete] open:[&::details-content]:[block-size:auto] motion-reduce:[&::details-content]:transition-none" name="cabin" open>
      <summary class="flex cursor-pointer list-none items-center gap-3.5 rounded-xl px-4 py-3.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cw-accent [&::-webkit-details-marker]:hidden"><span class="grid size-[34px] flex-none place-items-center rounded-full border-2 border-cw-line text-[.9rem] font-bold text-cw-muted transition-colors duration-250 group-open/step:border-cw-accent group-open/step:text-cw-dark group-has-[fieldset:valid]/step:border-cw-ok! group-has-[fieldset:valid]/step:bg-cw-ok group-has-[fieldset:valid]/step:text-white! motion-reduce:transition-none" aria-hidden="true"><b class="group-has-[fieldset:valid]/step:hidden">1</b><svg class="hidden size-[18px] fill-none stroke-current stroke-[2.5] group-has-[fieldset:valid]/step:block" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="grid flex-1 font-bold">Dates <small class="text-[.8rem] font-medium text-cw-muted"><span class="group-has-[fieldset:valid]/step:hidden">Step 1 of 3</span><span class="hidden text-cw-ok group-has-[fieldset:valid]/step:inline">Step 1 of 3, complete</span></small></span>
        <svg class="size-[18px] flex-none fill-none stroke-cw-muted stroke-[2.5] transition-[rotate] duration-250 group-open/step:rotate-180 motion-reduce:transition-none" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="grid scroll-mt-24 gap-4 px-4 pt-1 pb-[18px]" id="cab-dates"><fieldset class="grid min-w-0 gap-4"><legend class="sr-only">Dates</legend>
        <div class="grid grid-cols-[repeat(auto-fit,minmax(160px,1fr))] gap-3.5">
          <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-in">Check-in</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-in" name="checkin" type="date" required value="2026-10-16"></div>
          <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-nights">Nights</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-nights" name="nights" type="number" min="2" max="14" required value="3"></div>
        </div></fieldset>
        <div class="flex flex-wrap gap-2.5"><a class="ms-auto inline-flex min-h-11 cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] px-5 text-[.95rem] font-semibold no-underline transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-cw-accent)] focus-visible:outline-none motion-reduce:transition-none border-cw-accent bg-cw-accent text-white hover:bg-cw-dark" href="#cab-guests">Continue to guests</a></div>
      </div>
    </details>
    <details class="s2 group/step rounded-[14px] border-[1.5px] border-[#e7dcdf] bg-white transition-[border-color,box-shadow] duration-250 open:border-cw-accent open:shadow-[0_0_0_4px_var(--color-cw-soft)] has-[fieldset:valid]:[counter-increment:cw-done] motion-reduce:transition-none [&::details-content]:[block-size:0] [&::details-content]:overflow-hidden [&::details-content]:[transition:block-size_.3s_ease,content-visibility_.3s_allow-discrete] open:[&::details-content]:[block-size:auto] motion-reduce:[&::details-content]:transition-none" name="cabin">
      <summary class="flex cursor-pointer list-none items-center gap-3.5 rounded-xl px-4 py-3.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cw-accent [&::-webkit-details-marker]:hidden"><span class="grid size-[34px] flex-none place-items-center rounded-full border-2 border-cw-line text-[.9rem] font-bold text-cw-muted transition-colors duration-250 group-open/step:border-cw-accent group-open/step:text-cw-dark group-has-[fieldset:valid]/step:border-cw-ok! group-has-[fieldset:valid]/step:bg-cw-ok group-has-[fieldset:valid]/step:text-white! motion-reduce:transition-none" aria-hidden="true"><b class="group-has-[fieldset:valid]/step:hidden">2</b><svg class="hidden size-[18px] fill-none stroke-current stroke-[2.5] group-has-[fieldset:valid]/step:block" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="grid flex-1 font-bold">Guests <small class="text-[.8rem] font-medium text-cw-muted"><span class="group-has-[fieldset:valid]/step:hidden">Step 2 of 3</span><span class="hidden text-cw-ok group-has-[fieldset:valid]/step:inline">Step 2 of 3, complete</span></small></span>
        <svg class="size-[18px] flex-none fill-none stroke-cw-muted stroke-[2.5] transition-[rotate] duration-250 group-open/step:rotate-180 motion-reduce:transition-none" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="grid scroll-mt-24 gap-4 px-4 pt-1 pb-[18px]" id="cab-guests"><fieldset class="grid min-w-0 gap-4"><legend class="sr-only">Guests</legend>
        <div class="grid grid-cols-[repeat(auto-fit,minmax(160px,1fr))] gap-3.5">
          <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-adults">Adults</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-adults" name="adults" type="number" min="1" max="4" required value="2"></div>
          <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-kids">Children</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-kids" name="children" type="number" min="0" max="3" value="1"></div>
        </div>
        <label class="flex items-center gap-2.5 text-[.92rem]"><input class="size-[18px] accent-cw-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cw-accent" type="checkbox" name="dog">Bringing a dog ($25 cleaning fee)</label></fieldset>
        <div class="flex flex-wrap gap-2.5"><a class="inline-flex min-h-11 cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] px-5 text-[.95rem] font-semibold no-underline transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-cw-accent)] focus-visible:outline-none motion-reduce:transition-none border-cw-line bg-white text-cw-dark hover:bg-[#fff5f6]" href="#cab-dates">Back</a><a class="ms-auto inline-flex min-h-11 cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] px-5 text-[.95rem] font-semibold no-underline transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-cw-accent)] focus-visible:outline-none motion-reduce:transition-none border-cw-accent bg-cw-accent text-white hover:bg-cw-dark" href="#cab-contact">Continue to contact</a></div>
      </div>
    </details>
    <details class="s3 group/step rounded-[14px] border-[1.5px] border-[#e7dcdf] bg-white transition-[border-color,box-shadow] duration-250 open:border-cw-accent open:shadow-[0_0_0_4px_var(--color-cw-soft)] has-[fieldset:valid]:[counter-increment:cw-done] motion-reduce:transition-none [&::details-content]:[block-size:0] [&::details-content]:overflow-hidden [&::details-content]:[transition:block-size_.3s_ease,content-visibility_.3s_allow-discrete] open:[&::details-content]:[block-size:auto] motion-reduce:[&::details-content]:transition-none" name="cabin">
      <summary class="flex cursor-pointer list-none items-center gap-3.5 rounded-xl px-4 py-3.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cw-accent [&::-webkit-details-marker]:hidden"><span class="grid size-[34px] flex-none place-items-center rounded-full border-2 border-cw-line text-[.9rem] font-bold text-cw-muted transition-colors duration-250 group-open/step:border-cw-accent group-open/step:text-cw-dark group-has-[fieldset:valid]/step:border-cw-ok! group-has-[fieldset:valid]/step:bg-cw-ok group-has-[fieldset:valid]/step:text-white! motion-reduce:transition-none" aria-hidden="true"><b class="group-has-[fieldset:valid]/step:hidden">3</b><svg class="hidden size-[18px] fill-none stroke-current stroke-[2.5] group-has-[fieldset:valid]/step:block" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
        <span class="grid flex-1 font-bold">Contact <small class="text-[.8rem] font-medium text-cw-muted"><span class="group-has-[fieldset:valid]/step:hidden">Step 3 of 3</span><span class="hidden text-cw-ok group-has-[fieldset:valid]/step:inline">Step 3 of 3, complete</span></small></span>
        <svg class="size-[18px] flex-none fill-none stroke-cw-muted stroke-[2.5] transition-[rotate] duration-250 group-open/step:rotate-180 motion-reduce:transition-none" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="grid scroll-mt-24 gap-4 px-4 pt-1 pb-[18px]" id="cab-contact"><fieldset class="grid min-w-0 gap-4"><legend class="sr-only">Contact</legend>
        <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-name">Full name</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-name" name="name" required autocomplete="name"></div>
        <div class="grid grid-cols-[repeat(auto-fit,minmax(160px,1fr))] gap-3.5">
          <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-email">Email</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-email" name="email" type="email" required autocomplete="email"></div>
          <div class="grid min-w-0 gap-1.5"><label class="text-[.88rem] font-semibold" for="cab-phone">Phone</label><input class="min-h-11 w-full rounded-[10px] border-[1.5px] border-cw-line bg-white px-3 py-2.5 text-[.95rem] focus-visible:border-cw-accent focus-visible:shadow-[0_0_0_4px_var(--color-cw-soft)] focus-visible:outline-none user-invalid:border-[#b91c1c] user-invalid:bg-[#fff7f7]" id="cab-phone" name="phone" type="tel" autocomplete="tel"></div>
        </div></fieldset>
        <div class="flex flex-wrap gap-2.5"><a class="inline-flex min-h-11 cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] px-5 text-[.95rem] font-semibold no-underline transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-cw-accent)] focus-visible:outline-none motion-reduce:transition-none border-cw-line bg-white text-cw-dark hover:bg-[#fff5f6]" href="#cab-guests">Back</a></div>
      </div>
    </details>
  </div>
  <div class="mt-[22px] grid gap-3">
    <div class="h-2 overflow-hidden rounded-full bg-[#efe6e8] shadow-[inset_0_0_0_1px_#8e7a80]" aria-hidden="true"><i class="block h-full w-[calc((var(--cw-d1,0)+var(--cw-d2,0)+var(--cw-d3,0))/3*100%)] rounded-full bg-cw-accent transition-[width] duration-350 motion-reduce:transition-none"></i></div>
    <p class="flex flex-wrap justify-between gap-x-4 gap-y-2 text-[.88rem] text-cw-muted"><span><b class="text-cw-ink before:content-[counter(cw-done)]"></b> of 3 steps complete</span><span class="hidden flex-wrap items-center gap-1.5 group-has-[fieldset:invalid]/acc:flex">Still to do: <span class="hidden rounded-full bg-[#fff0f2] px-[9px] py-px text-[.8rem] font-semibold text-cw-dark group-has-[.s1_fieldset:invalid]/acc:inline">Dates</span><span class="hidden rounded-full bg-[#fff0f2] px-[9px] py-px text-[.8rem] font-semibold text-cw-dark group-has-[.s2_fieldset:invalid]/acc:inline">Guests</span><span class="hidden rounded-full bg-[#fff0f2] px-[9px] py-px text-[.8rem] font-semibold text-cw-dark group-has-[.s3_fieldset:invalid]/acc:inline">Contact</span></span></p>
    <button class="justify-self-end inline-flex min-h-11 cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] px-5 text-[.95rem] font-semibold no-underline transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-cw-accent)] focus-visible:outline-none motion-reduce:transition-none border-cw-accent bg-cw-accent text-white hover:bg-cw-dark group-has-[fieldset:invalid]/acc:hidden" type="submit">Request booking</button>
    <p class="hidden rounded-[10px] border border-[#a7f3d0] bg-[#ecfdf5] px-3.5 py-3 text-[.92rem] font-semibold text-[#065f46] target:block" id="cw-sent" tabindex="-1">Request sent. Pinecrest Lake Cabins will confirm by email within a day.</p>
  </div>
</form></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-cw-muted uppercase">Choices that reveal the next step</span>
<form class="group/pick rounded-[18px] bg-white px-8 py-[30px] text-cw-ink shadow-[0_1px_2px_rgba(35,22,26,.06),0_12px_32px_-14px_rgba(136,19,55,.22)] max-[600px]:px-[18px] max-[600px]:py-6 [counter-reset:cw-price]" aria-labelledby="cof-title">
  <h2 class="text-[1.3rem] font-bold tracking-[-.015em]" id="cof-title">Build your coffee subscription</h2>
  <p class="mt-1 text-[.92rem] text-cw-muted">Northbound Roasters · roasted to order, ships every Monday</p>
  <ol class="mt-[22px] grid grid-cols-4 gap-1.5" aria-label="Progress">
    <li class="c1 grid gap-1.5 text-[.8rem] font-semibold text-cw-muted before:h-1.5 before:rounded-full before:bg-[#efe6e8] before:shadow-[inset_0_0_0_1px_#8e7a80] before:transition-colors before:duration-300 text-cw-dark before:bg-cw-accent before:shadow-none group-has-[[name=beans]:checked]/pick:text-cw-ok! group-has-[[name=beans]:checked]/pick:before:bg-cw-ok! motion-reduce:before:transition-none max-[600px]:text-[.72rem]">Beans<span class="hidden group-has-[[name=beans]:checked]/pick:inline sr-only">, done</span></li>
    <li class="c2 grid gap-1.5 text-[.8rem] font-semibold text-cw-muted before:h-1.5 before:rounded-full before:bg-[#efe6e8] before:shadow-[inset_0_0_0_1px_#8e7a80] before:transition-colors before:duration-300 group-has-[[name=beans]:checked]/pick:text-cw-dark group-has-[[name=beans]:checked]/pick:before:bg-cw-accent group-has-[[name=beans]:checked]/pick:before:shadow-none group-has-[[name=grind]:checked]/pick:text-cw-ok! group-has-[[name=grind]:checked]/pick:before:bg-cw-ok! motion-reduce:before:transition-none max-[600px]:text-[.72rem]">Grind<span class="hidden group-has-[[name=grind]:checked]/pick:inline sr-only">, done</span></li>
    <li class="c3 grid gap-1.5 text-[.8rem] font-semibold text-cw-muted before:h-1.5 before:rounded-full before:bg-[#efe6e8] before:shadow-[inset_0_0_0_1px_#8e7a80] before:transition-colors before:duration-300 group-has-[[name=grind]:checked]/pick:text-cw-dark group-has-[[name=grind]:checked]/pick:before:bg-cw-accent group-has-[[name=grind]:checked]/pick:before:shadow-none group-has-[[name=size]:checked]/pick:text-cw-ok! group-has-[[name=size]:checked]/pick:before:bg-cw-ok! motion-reduce:before:transition-none max-[600px]:text-[.72rem]">Bag size<span class="hidden group-has-[[name=size]:checked]/pick:inline sr-only">, done</span></li>
    <li class="c4 grid gap-1.5 text-[.8rem] font-semibold text-cw-muted before:h-1.5 before:rounded-full before:bg-[#efe6e8] before:shadow-[inset_0_0_0_1px_#8e7a80] before:transition-colors before:duration-300 group-has-[[name=size]:checked]/pick:text-cw-dark group-has-[[name=size]:checked]/pick:before:bg-cw-accent group-has-[[name=size]:checked]/pick:before:shadow-none group-has-[[name=every]:checked]/pick:text-cw-ok! group-has-[[name=every]:checked]/pick:before:bg-cw-ok! motion-reduce:before:transition-none max-[600px]:text-[.72rem]">Delivery<span class="hidden group-has-[[name=every]:checked]/pick:inline sr-only">, done</span></li>
  </ol>
  <fieldset class="mt-[26px] min-w-0 transition-[opacity,translate,display] transition-discrete duration-350 starting:translate-y-2.5 starting:opacity-0 motion-reduce:transition-none"><legend class="mb-3 text-[1.05rem] font-bold"><span class="block text-[.72rem] tracking-[.1em] text-cw-dark uppercase">Step 1 of 4</span>Choose your beans</legend>
    <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-2.5 max-[600px]:grid-cols-1">
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="beans" id="cb-1" value="Ethiopia Guji" required checked style="--price:19"><b class="text-[.95rem]">Ethiopia Guji</b><span class="text-[.8rem] text-cw-muted">Peach, jasmine, black tea</span><em class="text-[.8rem] font-bold text-cw-dark not-italic">$19</em></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="beans" id="cb-2" value="Northbound House" style="--price:16"><b class="text-[.95rem]">Northbound House</b><span class="text-[.8rem] text-cw-muted">Cocoa, hazelnut, brown sugar</span><em class="text-[.8rem] font-bold text-cw-dark not-italic">$16</em></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="beans" id="cb-3" value="Colombia Huila Decaf" style="--price:17"><b class="text-[.95rem]">Huila Decaf</b><span class="text-[.8rem] text-cw-muted">Red apple, caramel, no caffeine</span><em class="text-[.8rem] font-bold text-cw-dark not-italic">$17</em></label>
    </div></fieldset>
  <fieldset class="hidden group-has-[[name=beans]:checked]/pick:block mt-[26px] min-w-0 transition-[opacity,translate,display] transition-discrete duration-350 starting:translate-y-2.5 starting:opacity-0 motion-reduce:transition-none"><legend class="mb-3 text-[1.05rem] font-bold"><span class="block text-[.72rem] tracking-[.1em] text-cw-dark uppercase">Step 2 of 4</span>How do you brew?</legend>
    <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-2.5 max-[600px]:grid-cols-1">
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="grind" id="cg-1" value="Whole bean" required><b class="text-[.95rem]">Whole bean</b><span class="text-[.8rem] text-cw-muted">You grind at home</span></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="grind" id="cg-2" value="Espresso"><b class="text-[.95rem]">Espresso</b><span class="text-[.8rem] text-cw-muted">Fine grind</span></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="grind" id="cg-3" value="Filter" checked><b class="text-[.95rem]">Filter</b><span class="text-[.8rem] text-cw-muted">Medium, for pour-over</span></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="grind" id="cg-4" value="French press"><b class="text-[.95rem]">French press</b><span class="text-[.8rem] text-cw-muted">Coarse grind</span></label>
    </div></fieldset>
  <fieldset class="hidden group-has-[[name=grind]:checked]/pick:block mt-[26px] min-w-0 transition-[opacity,translate,display] transition-discrete duration-350 starting:translate-y-2.5 starting:opacity-0 motion-reduce:transition-none"><legend class="mb-3 text-[1.05rem] font-bold"><span class="block text-[.72rem] tracking-[.1em] text-cw-dark uppercase">Step 3 of 4</span>Bag size</legend>
    <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-2.5 max-[600px]:grid-cols-1">
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="size" id="cs-1" value="250 g" required><b class="text-[.95rem]">250 g</b><span class="text-[.8rem] text-cw-muted">About 16 cups</span><em class="text-[.8rem] font-bold text-cw-dark not-italic">Included</em></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="size" id="cs-2" value="500 g" style="--price:9"><b class="text-[.95rem]">500 g</b><span class="text-[.8rem] text-cw-muted">About 33 cups</span><em class="text-[.8rem] font-bold text-cw-dark not-italic">+$9</em></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="size" id="cs-3" value="1 kg" style="--price:24"><b class="text-[.95rem]">1 kg</b><span class="text-[.8rem] text-cw-muted">About 66 cups</span><em class="text-[.8rem] font-bold text-cw-dark not-italic">+$24</em></label>
    </div></fieldset>
  <fieldset class="hidden group-has-[[name=size]:checked]/pick:block mt-[26px] min-w-0 transition-[opacity,translate,display] transition-discrete duration-350 starting:translate-y-2.5 starting:opacity-0 motion-reduce:transition-none"><legend class="mb-3 text-[1.05rem] font-bold"><span class="block text-[.72rem] tracking-[.1em] text-cw-dark uppercase">Step 4 of 4</span>How often?</legend>
    <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-2.5 max-[600px]:grid-cols-1">
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="every" id="ce-1" value="Every week" required><b class="text-[.95rem]">Every week</b><span class="text-[.8rem] text-cw-muted">Ships Mondays</span></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="every" id="ce-2" value="Every 2 weeks"><b class="text-[.95rem]">Every 2 weeks</b><span class="text-[.8rem] text-cw-muted">Most popular</span></label>
      <label class="relative grid cursor-pointer gap-0.5 rounded-xl border-[1.5px] border-cw-line px-3.5 py-[13px] transition-[border-color,background-color] duration-200 has-checked:border-cw-accent has-checked:bg-[#fff5f6] has-checked:shadow-[inset_0_0_0_1px_var(--color-cw-accent)] has-focus-visible:outline-2 has-focus-visible:outline-offset-3 has-focus-visible:outline-cw-accent motion-reduce:transition-none"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0 checked:[counter-increment:cw-price_var(--price,0)]" type="radio" name="every" id="ce-3" value="Every month"><b class="text-[.95rem]">Every month</b><span class="text-[.8rem] text-cw-muted">First Monday</span></label>
    </div></fieldset>
  <div class="mt-[26px] hidden gap-3 rounded-[14px] border-[1.5px] border-[#f4c2cb] bg-[#fff5f6] p-[18px] transition-[opacity,translate,display] transition-discrete duration-350 group-has-[[name=every]:checked]/pick:grid starting:translate-y-2.5 starting:opacity-0 motion-reduce:transition-none">
    <h3 class="text-[1.05rem] font-bold">Your box</h3>
    <p class="text-[.95rem]"><span class="hidden group-has-[#cb-1:checked]/pick:inline">Ethiopia Guji</span><span class="hidden group-has-[#cb-2:checked]/pick:inline">Northbound House</span><span class="hidden group-has-[#cb-3:checked]/pick:inline">Huila Decaf</span>,
      <span class="hidden group-has-[#cg-1:checked]/pick:inline">whole bean</span><span class="hidden group-has-[#cg-2:checked]/pick:inline">ground for espresso</span><span class="hidden group-has-[#cg-3:checked]/pick:inline">ground for filter</span><span class="hidden group-has-[#cg-4:checked]/pick:inline">ground for French press</span>,
      <span class="hidden group-has-[#cs-1:checked]/pick:inline">250 g</span><span class="hidden group-has-[#cs-2:checked]/pick:inline">500 g</span><span class="hidden group-has-[#cs-3:checked]/pick:inline">1 kg</span>
      <span class="hidden group-has-[#ce-1:checked]/pick:inline">every week</span><span class="hidden group-has-[#ce-2:checked]/pick:inline">every 2 weeks</span><span class="hidden group-has-[#ce-3:checked]/pick:inline">every month</span>.</p>
    <div class="flex flex-wrap items-center justify-between gap-3"><p class="text-[.9rem] text-cw-muted"><strong class="text-[1.6rem] tracking-[-.02em] text-cw-ink before:content-['$'_counter(cw-price)]"></strong> per delivery · free shipping · skip or cancel any time</p><button class="inline-flex min-h-11 cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] px-5 text-[.95rem] font-semibold no-underline transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-cw-accent)] focus-visible:outline-none motion-reduce:transition-none border-cw-accent bg-cw-accent text-white hover:bg-cw-dark" type="submit">Start subscription</button></div>
  </div>
</form></div>
CSS
/* No JavaScript. Accordion steps: exclusive <details name>, "Continue" links open the next step by fragment
   navigation, fieldset:valid drives the ticks, a CSS counter and the bar. Choices: has-checked reveals the next
   step with starting: styles, and a counter adds up the price. */
@theme {
  --color-cw-accent: #be123c;
  --color-cw-dark: #9f1239;
  --color-cw-soft: #ffe4e6;
  --color-cw-ink: #23161a;
  --color-cw-muted: #6b5a5f;
  --color-cw-line: #8e7a80;
  --color-cw-ok: #047857;
}

About this set

Two multi-step forms that run without any JavaScript. Accordion steps, completion from :has(), books a lakeside cabin in three steps built from details elements that share a name, so only one is open at a time. Each Continue and Back button is a link to the next step’s content, and following a link into a closed details element opens it. The fields of every step sit in a fieldset, and fieldset:valid tells CSS which steps are complete: :has() swaps the step number for a tick and says complete, a CSS counter prints 2 of 3 steps complete, three custom properties size the progress bar, chips list what is still to do, and the Request booking button only appears once every step is valid. Choices that reveal the next step builds a coffee subscription from four radio groups. Each step stays hidden until the one before it has an answer, fades in with @starting-style, lights up the stepper and fills the summary, and a CSS counter adds the bean and bag size prices into the total. Use the accordion for forms with typed fields and the reveal pattern for short product configurators.

What’s included

  • No JavaScript in any of the three versions
  • Exclusive details accordion with links that open the next step
  • Completed steps, progress bar and step count from fieldset:valid and :has()
  • Submit button that appears only when every step is valid
  • Steps revealed by :has(:checked) with an @starting-style fade
  • Price total added up by a CSS counter

Accessibility

Each accordion step is a native details and summary, so it opens with Enter or Space and announces expanded or collapsed; the summary also says Step 2 of 3, complete once its fields are valid. Buttons that move between steps are real links, fields keep their labels and show :user-invalid borders only after they have been touched, and every control has a visible focus ring. There is no aria-current without script, so the coffee stepper carries visually hidden ", done" text instead, and all fades and transitions stop under prefers-reduced-motion.

Customise it

Change --cw-accent, --cw-dark, --cw-soft, --cw-line and --cw-ok on .cw in the plain CSS and Bootstrap versions, and the --price value on each priced radio. In Tailwind edit the --color-cw-* theme colours; the step logic lives in group-has-[…] variants on the form.