Open demo

CSS code

HTML
<div><span class="lbl">Segmented progress</span>
<form class="ob" data-wizard aria-labelledby="pw-title">
  <div class="ob-brand"><span class="ob-logo"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7.5 4.5 4 4.5v13c3.5 0 6 .5 8 2 2-1.5 4.5-2 8-2v-13c-3.5 0-6 .5-8 2zM12 6.5v13"/></svg></span>
    <h2 class="ob-title" id="pw-title">Welcome to Pagewise</h2></div>
  <div class="ob-top"><span class="ob-pos" data-pos aria-hidden="true">Step 1 of 4</span><button type="button" class="ob-skip" data-skip hidden>Skip</button></div>
  <ol class="ob-segs" data-stepper aria-label="Progress">
    <li><span class="sr-only">Topics</span><span class="sr-only" data-sr></span></li>
    <li><span class="sr-only">Daily goal</span><span class="sr-only" data-sr></span></li>
    <li><span class="sr-only">Reminders</span><span class="sr-only" data-sr></span></li>
    <li><span class="sr-only">Friends</span><span class="sr-only" data-sr></span></li>
  </ol>

  <section class="ob-panel" data-step aria-labelledby="pw-h1">
    <h3 class="ob-h" id="pw-h1" tabindex="-1"><span class="sr-only">Step 1 of 4: </span>What do you like to read about?</h3>
    <p class="ob-lead">We use these to fill your first reading list.</p>
    <fieldset class="ob-field" data-min="3" aria-describedby="pw-topics-hint"><legend class="sr-only">Topics</legend>
      <div class="ob-chips">
        <label class="ob-chip"><input type="checkbox" name="topics" value="History" checked><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>History</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Design" checked><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Design</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Climate"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Climate</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Economics"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Economics</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Psychology"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Psychology</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Space" checked><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Space</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Food"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Food</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Music"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Music</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Travel"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Travel</label>
        <label class="ob-chip"><input type="checkbox" name="topics" value="Philosophy"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Philosophy</label>
      </div>
      <p class="ob-hint" id="pw-topics-hint">Pick at least 3 · <b data-count>3 picked</b></p></fieldset>
  </section>

  <section class="ob-panel" data-step aria-labelledby="pw-h2">
    <h3 class="ob-h" id="pw-h2" tabindex="-1"><span class="sr-only">Step 2 of 4: </span>Set a daily reading goal</h3>
    <p class="ob-lead">Small and steady wins. You can change it any day.</p>
    <fieldset class="ob-field"><legend class="sr-only">Minutes a day</legend>
      <div class="ob-goals">
        <label class="ob-goal"><input type="radio" name="goal" value="10 minutes" required><b>10</b><span class="unit">minutes a day</span><span class="line">A chapter with your morning coffee.</span></label>
        <label class="ob-goal"><input type="radio" name="goal" value="20 minutes" checked><span class="ob-tag">Most picked</span><b>20</b><span class="unit">minutes a day</span><span class="line">About one book every two weeks.</span></label>
        <label class="ob-goal"><input type="radio" name="goal" value="30 minutes"><b>30</b><span class="unit">minutes a day</span><span class="line">Roughly 40 books by next September.</span></label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step data-optional aria-labelledby="pw-h3">
    <h3 class="ob-h" id="pw-h3" tabindex="-1"><span class="sr-only">Step 3 of 4: </span>When should we remind you?</h3>
    <p class="ob-lead">One quiet nudge, only on the days you choose.</p>
    <div class="ob-field ob-time"><label for="pw-time">Reminder time</label>
      <input class="ob-input" id="pw-time" name="time" type="time" required value="07:45"></div>
    <fieldset class="ob-field"><legend class="ob-legend">Remind me on</legend>
      <div class="ob-chips">
        <label class="ob-chip day"><input type="checkbox" name="days" value="Mon" checked>Mon</label>
        <label class="ob-chip day"><input type="checkbox" name="days" value="Tue" checked>Tue</label>
        <label class="ob-chip day"><input type="checkbox" name="days" value="Wed" checked>Wed</label>
        <label class="ob-chip day"><input type="checkbox" name="days" value="Thu" checked>Thu</label>
        <label class="ob-chip day"><input type="checkbox" name="days" value="Fri" checked>Fri</label>
        <label class="ob-chip day"><input type="checkbox" name="days" value="Sat">Sat</label>
        <label class="ob-chip day"><input type="checkbox" name="days" value="Sun">Sun</label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step data-optional aria-labelledby="pw-h4">
    <h3 class="ob-h" id="pw-h4" tabindex="-1"><span class="sr-only">Step 4 of 4: </span>Follow a few readers</h3>
    <p class="ob-lead">See what they finish and borrow their best picks. Optional.</p>
    <ul class="ob-people">
      <li class="ob-person"><span class="ob-avatar" style="background:#fde68a;color:#78350f" aria-hidden="true">AO</span>
        <span class="ob-who">Amara Okafor<span>History and memoirs · 41 books this year</span></span>
        <button type="button" class="ob-follow" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>Follow<span class="sr-only"> Amara Okafor</span></button></li>
      <li class="ob-person"><span class="ob-avatar" style="background:#bbf7d0;color:#14532d" aria-hidden="true">LF</span>
        <span class="ob-who">Luis Ferreira<span>Climate and science writing · 27 books</span></span>
        <button type="button" class="ob-follow" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>Follow<span class="sr-only"> Luis Ferreira</span></button></li>
      <li class="ob-person"><span class="ob-avatar" style="background:#fbcfe8;color:#831843" aria-hidden="true">HS</span>
        <span class="ob-who">Hana Sato<span>Design and architecture · 33 books</span></span>
        <button type="button" class="ob-follow" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>Follow<span class="sr-only"> Hana Sato</span></button></li>
    </ul>
  </section>

  <section class="ob-panel ob-done" data-done hidden aria-labelledby="pw-h5">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7.5 4.5 4 4.5v13c3.5 0 6 .5 8 2 2-1.5 4.5-2 8-2v-13c-3.5 0-6 .5-8 2zM12 6.5v13"/></svg></span>
    <h3 class="ob-h" id="pw-h5" tabindex="-1">Your first reading list is ready</h3>
    <p class="ob-lead">Twelve picks from <span data-out="topics">History, Design, Space</span>. We'll nudge you at <span data-out="time">07:45</span>.</p>
    <button type="button" class="ob-btn ghost" data-restart>Start over</button>
  </section>

  <div class="ob-nav">
    <button type="button" class="ob-btn ghost" data-back hidden>Back</button>
    <button type="button" class="ob-btn" data-next hidden>Continue</button>
    <button type="submit" class="ob-btn">Build my list</button>
  </div>
</form></div>

<div><span class="lbl">Progress bar with percentage</span>
<form class="ob ob-lg" data-wizard aria-labelledby="cw-title">
  <div class="ob-brand"><span class="ob-logo"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 15c2.5-7 5.5-7 8.5 0s6 7 8.5 0"/></svg></span><b>Crewline</b></div>
  <h2 class="ob-title" id="cw-title">Set up your team profile</h2>
  <div class="ob-meter"><label for="cw-progress">Setup progress</label><span data-pct aria-hidden="true">20%</span></div>
  <progress class="ob-progress" id="cw-progress" data-progress max="100" value="20">20%</progress>
  <ol class="ob-names" data-stepper aria-label="Progress">
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Name<span class="sr-only" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Size<span class="sr-only" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Role<span class="sr-only" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Tools<span class="sr-only" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Invite<span class="sr-only" data-sr></span></li>
  </ol>

  <section class="ob-panel" data-step aria-labelledby="cw-h1">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 21V4M5 4h12l-2 4 2 4H5"/></svg></span>
    <h3 class="ob-h" id="cw-h1" tabindex="-1"><span class="ob-kick">Step 1 of 5</span>What's your team called?</h3>
    <p class="ob-lead">This is how teammates will find you in Crewline.</p>
    <div class="ob-field ob-col"><label for="cw-team">Team name</label>
      <input class="ob-input" id="cw-team" name="team" required autocomplete="organization" value="Northbeam Studio"></div>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h2">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6M16 4.6a3.5 3.5 0 0 1 0 6.8M18 14.3c2.1.7 3.5 2.8 3.5 5.7"/></svg></span>
    <h3 class="ob-h" id="cw-h2" tabindex="-1"><span class="ob-kick">Step 2 of 5</span>How big is the team?</h3>
    <p class="ob-lead">We size your plan and workspace to match.</p>
    <fieldset class="ob-field ob-col"><legend class="sr-only">Team size</legend>
      <div class="ob-chips">
        <label class="ob-chip pill"><input type="radio" name="size" value="1–10 people" required>1–10</label>
        <label class="ob-chip pill"><input type="radio" name="size" value="11–50 people" checked>11–50</label>
        <label class="ob-chip pill"><input type="radio" name="size" value="51–200 people">51–200</label>
        <label class="ob-chip pill"><input type="radio" name="size" value="200+ people">200+</label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h3">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18"/></svg></span>
    <h3 class="ob-h" id="cw-h3" tabindex="-1"><span class="ob-kick">Step 3 of 5</span>What do you do there?</h3>
    <p class="ob-lead">Your home screen starts with the views your role uses most.</p>
    <div class="ob-field ob-col"><label for="cw-role">Your role</label>
      <select class="ob-input" id="cw-role" name="role" required>
        <option value="">Choose your role</option><option>Founder or executive</option><option>Product manager</option>
        <option selected>Product designer</option><option>Engineer</option><option>Marketing</option><option>Operations</option></select></div>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h4">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><path d="M17.5 14v7M14 17.5h7"/></svg></span>
    <h3 class="ob-h" id="cw-h4" tabindex="-1"><span class="ob-kick">Step 4 of 5</span>Which tools do you use?</h3>
    <p class="ob-lead">We'll suggest the integrations to connect first.</p>
    <fieldset class="ob-field ob-col"><legend class="sr-only">Tools</legend>
      <div class="ob-chips">
        <label class="ob-chip"><input type="checkbox" name="tools" value="Slack"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Slack</label>
        <label class="ob-chip"><input type="checkbox" name="tools" value="Figma" checked><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Figma</label>
        <label class="ob-chip"><input type="checkbox" name="tools" value="GitHub" checked><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>GitHub</label>
        <label class="ob-chip"><input type="checkbox" name="tools" value="Notion" checked><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Notion</label>
        <label class="ob-chip"><input type="checkbox" name="tools" value="Jira"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Jira</label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h5">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M10 14a4.5 4.5 0 0 0 6.4 0l3-3a4.5 4.5 0 0 0-6.4-6.4l-1 1M14 10a4.5 4.5 0 0 0-6.4 0l-3 3a4.5 4.5 0 0 0 6.4 6.4l1-1"/></svg></span>
    <h3 class="ob-h" id="cw-h5" tabindex="-1"><span class="ob-kick">Step 5 of 5</span>Invite your crew</h3>
    <p class="ob-lead">Anyone with this link can join for the next 7 days.</p>
    <div class="ob-field ob-col"><label for="cw-link">Invite link</label>
      <div class="ob-copy"><input class="ob-input" id="cw-link" name="link" readonly value="https://crewline.app/join/northbeam-7kq2">
        <button type="button" class="ob-btn ghost" data-copy="cw-link"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V6a2 2 0 0 1 2-2h8"/></svg>Copy</button></div>
      <p class="ob-status" role="status" data-status></p></div>
  </section>

  <section class="ob-panel ob-done" data-done hidden aria-labelledby="cw-h6">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
    <h3 class="ob-h" id="cw-h6" tabindex="-1">Your team profile is ready</h3>
    <p class="ob-lead"><span data-out="team">Northbeam Studio</span> is set up for <span data-out="size">11–50 people</span>. Connect <span data-out="tools">Figma, GitHub, Notion</span> from Settings.</p>
    <button type="button" class="ob-btn ghost" data-restart>Set up another team</button>
  </section>

  <div class="ob-nav">
    <button type="button" class="ob-btn ghost" data-back hidden>Back</button>
    <button type="button" class="ob-btn" data-next hidden>Continue</button>
    <button type="submit" class="ob-btn">Finish setup</button>
  </div>
</form></div>
CSS
/* Onboarding wizards: a progress indicator on top, one <section data-step> per step and a Back / Continue bar.
   The script hides every step but the current one, sets data-state and aria-current="step" on the <ol data-stepper>,
   fills the segments or the <progress> bar and moves focus to the new step's heading. Without JavaScript every step shows. */
.ob{--ob-accent:#6d28d9;--ob-dark:#5b21b6;--ob-soft:#ede9fe;--ob-pink:#db2777;--ob-ink:#1e1b2e;--ob-muted:#5c5670;--ob-field:#8a82a3;--ob-track:#e4ddf8;--ob-tint:#faf8ff;
  background:#fff;border-radius:20px;padding:28px 32px 30px;box-shadow:0 1px 2px rgba(30,27,46,.06),0 16px 40px -18px rgba(76,29,149,.3);color:var(--ob-ink)}
.ob [hidden]{display:none!important}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.ob svg{fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ob-brand{display:flex;align-items:center;gap:10px}
.ob-logo{width:34px;height:34px;flex:none;border-radius:10px;display:grid;place-items:center;background:var(--ob-accent);color:#fff}
.ob-logo svg{width:20px;height:20px}
.ob-title{margin:0;font-size:1.05rem;font-weight:700;letter-spacing:-.01em;line-height:1.3}

/* A: "Step 2 of 4" + Skip, then one bar segment per step (the segments are the stepper <li>s, names visually hidden) */
.ob-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:24px;min-height:34px}
.ob-pos{font-size:.85rem;font-weight:700;color:var(--ob-dark)}
.ob-skip{font:inherit;font-size:.88rem;font-weight:600;color:var(--ob-dark);background:none;border:0;border-radius:8px;padding:6px 10px;margin-right:-10px;cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.ob-skip:hover{background:var(--ob-soft)}
.ob-skip:focus-visible{outline:2px solid var(--ob-accent);outline-offset:1px}
.ob-segs{list-style:none;margin:8px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.ob-segs li{position:relative;height:6px;border-radius:99px;background:var(--ob-track);overflow:hidden}
.ob-segs li::after{content:"";position:absolute;inset:0;border-radius:inherit;background:var(--ob-accent);transform:scaleX(0);transform-origin:left;transition:transform .4s ease}
.ob-segs [data-state="done"]::after{transform:none}
.ob-segs [data-state="current"]::after{transform:none;background:linear-gradient(90deg,var(--ob-accent) 55%,var(--ob-pink))}

/* B: labelled <progress> with a % figure, and a row of step names under it */
.ob-lg{padding:40px 44px 36px}
.ob-lg .ob-brand{justify-content:center}
.ob-lg .ob-title{font-size:1.35rem;text-align:center;margin-top:14px}
.ob-meter{display:flex;justify-content:space-between;align-items:baseline;margin-top:26px;font-size:.85rem;font-weight:600;color:var(--ob-muted)}
.ob-meter span{color:var(--ob-dark);font-weight:700;font-variant-numeric:tabular-nums}
.ob-progress{display:block;width:100%;height:10px;margin-top:8px;border:0;border-radius:99px;background:var(--ob-track);overflow:hidden;-webkit-appearance:none;appearance:none}
.ob-progress::-webkit-progress-bar{background:var(--ob-track);border-radius:99px}
.ob-progress::-webkit-progress-value{background:linear-gradient(90deg,var(--ob-accent),var(--ob-pink));border-radius:99px;transition:width .4s ease}
.ob-progress::-moz-progress-bar{background:linear-gradient(90deg,var(--ob-accent),var(--ob-pink));border-radius:99px}
.ob-names{list-style:none;margin:12px 0 0;padding:0;display:grid;grid-template-columns:repeat(5,1fr);gap:4px}
.ob-names li{display:flex;flex-direction:column;align-items:center;gap:5px;font-size:.78rem;color:var(--ob-muted);text-align:center}
.ob-mark{width:16px;height:16px;border-radius:50%;border:2px solid var(--ob-field);background:#fff;display:grid;place-items:center;color:#fff;transition:background .25s,border-color .25s}
.ob-mark svg{display:none;width:10px;height:10px;stroke-width:3.5}
.ob-names [data-state="current"]{color:var(--ob-ink);font-weight:700}
.ob-names [data-state="current"] .ob-mark{border-color:var(--ob-pink);background:var(--ob-pink);box-shadow:0 0 0 4px #fce7f3}
.ob-names [data-state="done"]{color:var(--ob-dark);font-weight:600}
.ob-names [data-state="done"] .ob-mark{border-color:var(--ob-accent);background:var(--ob-accent)}
.ob-names [data-state="done"] .ob-mark svg{display:block}

/* step panels */
.ob-panel{margin-top:26px;display:grid;gap:18px;animation:ob-in .3s ease}
@keyframes ob-in{from{opacity:0;transform:translateY(6px)}}
.ob-h{margin:0;font-size:1.45rem;font-weight:700;letter-spacing:-.02em;line-height:1.25}
.ob-h:focus{outline:none}
.ob-kick{display:block;font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ob-dark);margin-bottom:4px}
.ob-lead{margin:-10px 0 0;color:var(--ob-muted);font-size:.95rem}
.ob-lg .ob-panel{justify-items:center;text-align:center;margin-top:30px}
.ob-lg .ob-h{font-size:1.3rem}
.ob-icon{width:56px;height:56px;border-radius:16px;display:grid;place-items:center;background:var(--ob-soft);color:var(--ob-dark)}
.ob-icon svg{width:26px;height:26px}
.ob-col{width:100%;max-width:440px;text-align:left}
.ob-field{display:grid;gap:6px;min-width:0}
.ob-field > label,.ob-legend{font-size:.88rem;font-weight:600}
fieldset.ob-field{border:0;margin:0;padding:0}
.ob-legend{padding:0;margin-bottom:8px}
.ob-hint{font-size:.82rem;color:var(--ob-muted);margin:4px 0 0}
.ob-hint b{color:var(--ob-dark)}
.ob-input{width:100%;font:inherit;font-size:.95rem;color:var(--ob-ink);background:#fff;border:1.5px solid var(--ob-field);border-radius:12px;padding:10px 14px;min-height:46px}
.ob-input:focus-visible{outline:none;border-color:var(--ob-accent);box-shadow:0 0 0 4px var(--ob-soft)}
.ob-input[readonly]{background:var(--ob-tint);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86rem}

/* chips and pills: the checkbox/radio sits invisibly over its label, the label follows :has(:checked) */
.ob-chips{display:flex;flex-wrap:wrap;gap:10px}
.ob-lg .ob-chips{justify-content:center}
.ob-chip{position:relative;display:inline-flex;align-items:center;gap:7px;padding:9px 16px 9px 13px;border:1.5px solid var(--ob-field);border-radius:999px;background:#fff;font-size:.92rem;font-weight:500;cursor:pointer;transition:background .2s,border-color .2s,color .2s}
.ob-chip input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
.ob-chip svg{width:16px;height:16px;stroke-width:2.5}
.ob-chip .tick,.ob-chip:has(:checked) .plus{display:none}
.ob-chip:has(:checked) .tick{display:block}
.ob-chip:hover{border-color:var(--ob-accent)}
.ob-chip:has(:checked){background:var(--ob-accent);border-color:var(--ob-accent);color:#fff}
.ob-chip:has(:focus-visible){outline:2px solid var(--ob-accent);outline-offset:2px}
.ob-chip.day{padding:7px 12px;font-size:.85rem;min-width:52px;justify-content:center}
.ob-chip.pill{padding:10px 18px}

/* A step 2: goal cards with a visible radio */
.ob-goals{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}
.ob-goal{position:relative;display:grid;gap:2px;align-content:start;padding:16px 16px 18px;border:1.5px solid var(--ob-field);border-radius:16px;cursor:pointer;transition:border-color .2s,background .2s,box-shadow .2s}
.ob-goal input{position:absolute;top:16px;right:16px;width:18px;height:18px;margin:0;accent-color:var(--ob-accent)}
.ob-goal input:focus-visible{outline:2px solid var(--ob-accent);outline-offset:3px}
.ob-goal b{font-size:2rem;line-height:1;font-weight:800;letter-spacing:-.03em;color:var(--ob-dark)}
.ob-goal .unit{font-size:.85rem;font-weight:600}
.ob-goal .line{font-size:.85rem;color:var(--ob-muted);margin-top:6px}
.ob-goal:has(:checked){border-color:var(--ob-accent);background:var(--ob-tint);box-shadow:0 0 0 3px var(--ob-soft)}
.ob-tag{justify-self:start;margin-bottom:8px;padding:2px 8px;border-radius:99px;background:var(--ob-pink);color:#fff;font-size:.68rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase}
.ob-time{max-width:220px}

/* A step 4: people with Follow toggle buttons (aria-pressed) */
.ob-people{list-style:none;margin:0;padding:0;display:grid;border:1px solid #e7e2f3;border-radius:16px}
.ob-person{display:flex;align-items:center;gap:14px;padding:14px 16px}
.ob-person + .ob-person{border-top:1px solid #e7e2f3}
.ob-avatar{width:44px;height:44px;flex:none;border-radius:50%;display:grid;place-items:center;font-size:.9rem;font-weight:700}
.ob-who{flex:1;min-width:0;display:grid;font-size:.95rem;font-weight:600}
.ob-who span{font-size:.82rem;font-weight:400;color:var(--ob-muted)}
.ob-follow{flex:none;display:inline-flex;align-items:center;gap:6px;min-height:38px;padding:0 16px;border-radius:999px;border:1.5px solid var(--ob-accent);background:#fff;color:var(--ob-dark);font:inherit;font-size:.88rem;font-weight:600;cursor:pointer;transition:background .2s,color .2s}
.ob-follow svg{display:none;width:15px;height:15px;stroke-width:3}
.ob-follow:hover{background:var(--ob-soft)}
.ob-follow[aria-pressed="true"]{background:var(--ob-accent);color:#fff}
.ob-follow[aria-pressed="true"]:hover{background:var(--ob-dark);border-color:var(--ob-dark)}
.ob-follow[aria-pressed="true"] svg{display:block}
.ob-follow:focus-visible{outline:none;box-shadow:0 0 0 3px #fff,0 0 0 5px var(--ob-accent)}

/* B step 5: read-only link + Copy, with a polite status line */
.ob-copy{display:flex;gap:8px}
.ob-copy .ob-input{flex:1;min-width:0}
.ob-status{margin:8px 0 0;min-height:1.4em;font-size:.85rem;font-weight:600;color:var(--ob-dark)}

/* Back / Continue bar */
.ob-nav{display:flex;gap:10px;margin-top:28px;padding-top:20px;border-top:1px solid #ece8f6}
.ob-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:46px;padding:0 24px;border-radius:999px;border:1.5px solid var(--ob-accent);background:var(--ob-accent);color:#fff;font:inherit;font-size:.95rem;font-weight:600;cursor:pointer;transition:background .2s,box-shadow .2s}
.ob-btn:hover{background:var(--ob-dark)}
.ob-btn:focus-visible{outline:none;box-shadow:0 0 0 3px #fff,0 0 0 5px var(--ob-accent)}
.ob-btn.ghost{background:#fff;color:var(--ob-dark);border-color:var(--ob-field)}
.ob-btn.ghost:hover{background:var(--ob-tint)}
.ob-btn svg{width:18px;height:18px}
.ob-nav .ob-btn:not(.ghost){margin-left:auto}
.ob-done{justify-items:center;text-align:center;padding:10px 0 4px}
.ob-done .ob-icon{border-radius:50%;background:#fce7f3;color:#be185d}
.ob-done .ob-lead{margin:0;max-width:440px}
@media (prefers-reduced-motion:reduce){.ob *,.ob *::before,.ob *::after{transition:none!important;animation:none!important}.ob-progress::-webkit-progress-value{transition:none}}
@media (max-width:600px){.ob,.ob-lg{padding:24px 18px}.ob-h,.ob-lg .ob-h{font-size:1.25rem}.ob-names li{font-size:.7rem}.ob-person{flex-wrap:wrap}.ob-who{flex-basis:calc(100% - 58px)}.ob-follow{margin-left:58px}}
JavaScript
// Onboarding wizard: one step at a time, stepper marked with data-state and aria-current="step", focus on the new heading.
// Also keeps "Step 2 of 4", the <progress> value and its % text in sync, and handles Skip, pick-at-least-N groups, toggles and Copy.
document.querySelectorAll('[data-wizard]').forEach(function (wz) {
  var panels = wz.querySelectorAll('[data-step]'), steps = wz.querySelectorAll('[data-stepper] > li');
  var back = wz.querySelector('[data-back]'), next = wz.querySelector('[data-next]'), skip = wz.querySelector('[data-skip]');
  var submit = wz.querySelector('[type="submit"]'), done = wz.querySelector('[data-done]'), at = 0;
  var bar = wz.querySelector('[data-progress]'), pct = wz.querySelector('[data-pct]'), pos = wz.querySelector('[data-pos]');
  function mark(i) {
    steps.forEach(function (s, n) {
      s.dataset.state = n < i ? 'done' : n === i ? 'current' : 'next';
      if (n === i) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
      s.querySelector('[data-sr]').textContent = n < i ? ', completed' : '';
    });
    var p = Math.round(Math.min(i + 1, steps.length) / steps.length * 100);
    if (bar) bar.value = p;
    if (pct) pct.textContent = p + '%';
    if (pos) pos.textContent = i < steps.length ? 'Step ' + (i + 1) + ' of ' + steps.length : 'All done';
  }
  function picks() { // [data-min] groups: fewer than N ticked boxes puts a custom error on the first box
    wz.querySelectorAll('[data-min]').forEach(function (g) {
      var boxes = g.querySelectorAll('input[type="checkbox"]'), n = g.querySelectorAll(':checked').length, min = +g.dataset.min, c = g.querySelector('[data-count]');
      boxes[0].setCustomValidity(n < min ? 'Pick at least ' + min + ' (' + n + ' picked so far).' : '');
      if (c) c.textContent = n + ' picked';
    });
  }
  function go(i, focus) {
    at = i; mark(i); picks();
    panels.forEach(function (p, n) { p.hidden = n !== i; });
    back.hidden = i === 0; next.hidden = i === panels.length - 1; submit.hidden = !next.hidden;
    if (skip) skip.hidden = !panels[i].hasAttribute('data-optional');
    wz.querySelectorAll('[data-out]').forEach(function (o) {
      var f = wz.elements[o.dataset.out], v = f && (f.length && !f.options ? [].filter.call(f, function (x) { return x.checked; }).map(function (x) { return x.value; }).join(', ') : f.value);
      o.textContent = v || 'None';
    });
    if (focus) panels[i].querySelector('[tabindex="-1"]').focus();
  }
  function valid() {
    var bad = [].find.call(panels[at].querySelectorAll('input, select, textarea'), function (f) { return !f.checkValidity(); });
    if (bad) bad.reportValidity();
    return !bad;
  }
  function finish() {
    // Last step: send the form here (fetch or wz.submit()). The demo shows the done panel instead.
    panels[at].hidden = true; back.parentNode.hidden = true; if (skip) skip.hidden = true; mark(steps.length);
    done.hidden = false; done.querySelector('[tabindex="-1"]').focus();
  }
  wz.noValidate = true;
  back.addEventListener('click', function () { go(at - 1, true); });
  next.addEventListener('click', function () { if (valid()) go(at + 1, true); });
  if (skip) skip.addEventListener('click', function () { if (at < panels.length - 1) go(at + 1, true); else finish(); });
  wz.addEventListener('change', picks);
  wz.addEventListener('submit', function (e) {
    e.preventDefault();
    if (!valid()) return;
    if (at < panels.length - 1) return go(at + 1, true);
    finish();
  });
  wz.querySelectorAll('[aria-pressed]').forEach(function (b) {
    b.addEventListener('click', function () { b.setAttribute('aria-pressed', b.getAttribute('aria-pressed') !== 'true'); });
  });
  wz.querySelectorAll('[data-copy]').forEach(function (b) {
    var f = document.getElementById(b.dataset.copy), say = wz.querySelector('[data-status]');
    function tell(t) { if (say) { say.textContent = t; clearTimeout(say.t); say.t = setTimeout(function () { say.textContent = ''; }, 4000); } }
    b.addEventListener('click', function () {
      (navigator.clipboard ? navigator.clipboard.writeText(f.value) : Promise.reject()).then(function () { tell('Link copied'); },
        function () { f.select(); tell('Link selected: press Ctrl+C or Cmd+C to copy'); });
    });
  });
  if (done) done.querySelector('[data-restart]').addEventListener('click', function () {
    wz.reset(); wz.querySelectorAll('[aria-pressed]').forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
    done.hidden = true; back.parentNode.hidden = false; go(0, true);
  });
  go(0);
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Segmented progress</span>
<form class="ob card" data-wizard aria-labelledby="pw-title"><div class="card-body">
  <div class="ob-brand"><span class="ob-logo"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7.5 4.5 4 4.5v13c3.5 0 6 .5 8 2 2-1.5 4.5-2 8-2v-13c-3.5 0-6 .5-8 2zM12 6.5v13"/></svg></span>
    <h2 class="ob-title fw-bold mb-0" id="pw-title">Welcome to Pagewise</h2></div>
  <div class="ob-top"><span class="ob-pos" data-pos aria-hidden="true">Step 1 of 4</span><button type="button" class="btn btn-link ob-skip" data-skip hidden>Skip</button></div>
  <ol class="ob-segs" data-stepper aria-label="Progress">
    <li><span class="visually-hidden">Topics</span><span class="visually-hidden" data-sr></span></li>
    <li><span class="visually-hidden">Daily goal</span><span class="visually-hidden" data-sr></span></li>
    <li><span class="visually-hidden">Reminders</span><span class="visually-hidden" data-sr></span></li>
    <li><span class="visually-hidden">Friends</span><span class="visually-hidden" data-sr></span></li>
  </ol>

  <section class="ob-panel" data-step aria-labelledby="pw-h1">
    <h3 class="ob-h fw-bold mb-0" id="pw-h1" tabindex="-1"><span class="visually-hidden">Step 1 of 4: </span>What do you like to read about?</h3>
    <p class="ob-lead">We use these to fill your first reading list.</p>
    <fieldset data-min="3" aria-describedby="pw-topics-hint"><legend class="visually-hidden">Topics</legend>
      <div class="ob-chips">
        <input type="checkbox" class="btn-check" id="pw-t1" name="topics" value="History" checked><label class="btn ob-chip" for="pw-t1"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>History</label>
        <input type="checkbox" class="btn-check" id="pw-t2" name="topics" value="Design" checked><label class="btn ob-chip" for="pw-t2"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Design</label>
        <input type="checkbox" class="btn-check" id="pw-t3" name="topics" value="Climate"><label class="btn ob-chip" for="pw-t3"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Climate</label>
        <input type="checkbox" class="btn-check" id="pw-t4" name="topics" value="Economics"><label class="btn ob-chip" for="pw-t4"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Economics</label>
        <input type="checkbox" class="btn-check" id="pw-t5" name="topics" value="Psychology"><label class="btn ob-chip" for="pw-t5"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Psychology</label>
        <input type="checkbox" class="btn-check" id="pw-t6" name="topics" value="Space" checked><label class="btn ob-chip" for="pw-t6"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Space</label>
        <input type="checkbox" class="btn-check" id="pw-t7" name="topics" value="Food"><label class="btn ob-chip" for="pw-t7"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Food</label>
        <input type="checkbox" class="btn-check" id="pw-t8" name="topics" value="Music"><label class="btn ob-chip" for="pw-t8"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Music</label>
        <input type="checkbox" class="btn-check" id="pw-t9" name="topics" value="Travel"><label class="btn ob-chip" for="pw-t9"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Travel</label>
        <input type="checkbox" class="btn-check" id="pw-t10" name="topics" value="Philosophy"><label class="btn ob-chip" for="pw-t10"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Philosophy</label>
      </div>
      <p class="ob-hint" id="pw-topics-hint">Pick at least 3 · <b data-count>3 picked</b></p></fieldset>
  </section>

  <section class="ob-panel" data-step aria-labelledby="pw-h2">
    <h3 class="ob-h fw-bold mb-0" id="pw-h2" tabindex="-1"><span class="visually-hidden">Step 2 of 4: </span>Set a daily reading goal</h3>
    <p class="ob-lead">Small and steady wins. You can change it any day.</p>
    <fieldset><legend class="visually-hidden">Minutes a day</legend>
      <div class="ob-goals">
        <label class="ob-goal"><input class="form-check-input" type="radio" name="goal" value="10 minutes" required><b>10</b><span class="unit">minutes a day</span><span class="line">A chapter with your morning coffee.</span></label>
        <label class="ob-goal"><input class="form-check-input" type="radio" name="goal" value="20 minutes" checked><span class="ob-tag">Most picked</span><b>20</b><span class="unit">minutes a day</span><span class="line">About one book every two weeks.</span></label>
        <label class="ob-goal"><input class="form-check-input" type="radio" name="goal" value="30 minutes"><b>30</b><span class="unit">minutes a day</span><span class="line">Roughly 40 books by next September.</span></label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step data-optional aria-labelledby="pw-h3">
    <h3 class="ob-h fw-bold mb-0" id="pw-h3" tabindex="-1"><span class="visually-hidden">Step 3 of 4: </span>When should we remind you?</h3>
    <p class="ob-lead">One quiet nudge, only on the days you choose.</p>
    <div class="ob-time"><label class="form-label" for="pw-time">Reminder time</label>
      <input class="form-control" id="pw-time" name="time" type="time" required value="07:45"></div>
    <fieldset><legend>Remind me on</legend>
      <div class="ob-chips">
        <input type="checkbox" class="btn-check" id="pw-d1" name="days" value="Mon" checked><label class="btn ob-chip day" for="pw-d1">Mon</label>
        <input type="checkbox" class="btn-check" id="pw-d2" name="days" value="Tue" checked><label class="btn ob-chip day" for="pw-d2">Tue</label>
        <input type="checkbox" class="btn-check" id="pw-d3" name="days" value="Wed" checked><label class="btn ob-chip day" for="pw-d3">Wed</label>
        <input type="checkbox" class="btn-check" id="pw-d4" name="days" value="Thu" checked><label class="btn ob-chip day" for="pw-d4">Thu</label>
        <input type="checkbox" class="btn-check" id="pw-d5" name="days" value="Fri" checked><label class="btn ob-chip day" for="pw-d5">Fri</label>
        <input type="checkbox" class="btn-check" id="pw-d6" name="days" value="Sat"><label class="btn ob-chip day" for="pw-d6">Sat</label>
        <input type="checkbox" class="btn-check" id="pw-d7" name="days" value="Sun"><label class="btn ob-chip day" for="pw-d7">Sun</label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step data-optional aria-labelledby="pw-h4">
    <h3 class="ob-h fw-bold mb-0" id="pw-h4" tabindex="-1"><span class="visually-hidden">Step 4 of 4: </span>Follow a few readers</h3>
    <p class="ob-lead">See what they finish and borrow their best picks. Optional.</p>
    <ul class="list-group mb-0">
      <li class="list-group-item d-flex align-items-center"><span class="ob-avatar" style="background:#fde68a;color:#78350f" aria-hidden="true">AO</span>
        <span class="ob-who">Amara Okafor<span>History and memoirs · 41 books this year</span></span>
        <button type="button" class="btn ob-follow" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>Follow<span class="visually-hidden"> Amara Okafor</span></button></li>
      <li class="list-group-item d-flex align-items-center"><span class="ob-avatar" style="background:#bbf7d0;color:#14532d" aria-hidden="true">LF</span>
        <span class="ob-who">Luis Ferreira<span>Climate and science writing · 27 books</span></span>
        <button type="button" class="btn ob-follow" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>Follow<span class="visually-hidden"> Luis Ferreira</span></button></li>
      <li class="list-group-item d-flex align-items-center"><span class="ob-avatar" style="background:#fbcfe8;color:#831843" aria-hidden="true">HS</span>
        <span class="ob-who">Hana Sato<span>Design and architecture · 33 books</span></span>
        <button type="button" class="btn ob-follow" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>Follow<span class="visually-hidden"> Hana Sato</span></button></li>
    </ul>
  </section>

  <section class="ob-panel ob-done" data-done hidden aria-labelledby="pw-h5">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7.5 4.5 4 4.5v13c3.5 0 6 .5 8 2 2-1.5 4.5-2 8-2v-13c-3.5 0-6 .5-8 2zM12 6.5v13"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="pw-h5" tabindex="-1">Your first reading list is ready</h3>
    <p class="ob-lead">Twelve picks from <span data-out="topics">History, Design, Space</span>. We'll nudge you at <span data-out="time">07:45</span>.</p>
    <button type="button" class="btn btn-outline-secondary" data-restart>Start over</button>
  </section>

  <div class="ob-nav">
    <button type="button" class="btn btn-outline-secondary" data-back hidden>Back</button>
    <button type="button" class="btn btn-primary" data-next hidden>Continue</button>
    <button type="submit" class="btn btn-primary">Build my list</button>
  </div>
</div></form></div>

<div><span class="lbl">Progress bar with percentage</span>
<form class="ob ob-lg card" data-wizard aria-labelledby="cw-title"><div class="card-body">
  <div class="ob-brand"><span class="ob-logo"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 15c2.5-7 5.5-7 8.5 0s6 7 8.5 0"/></svg></span><b>Crewline</b></div>
  <h2 class="ob-title fw-bold mb-0" id="cw-title">Set up your team profile</h2>
  <div class="ob-meter"><label for="cw-progress">Setup progress</label><span data-pct aria-hidden="true">20%</span></div>
  <progress class="ob-progress" id="cw-progress" data-progress max="100" value="20">20%</progress>
  <ol class="ob-names" data-stepper aria-label="Progress">
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Name<span class="visually-hidden" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Size<span class="visually-hidden" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Role<span class="visually-hidden" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Tools<span class="visually-hidden" data-sr></span></li>
    <li><span class="ob-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>Invite<span class="visually-hidden" data-sr></span></li>
  </ol>

  <section class="ob-panel" data-step aria-labelledby="cw-h1">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 21V4M5 4h12l-2 4 2 4H5"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="cw-h1" tabindex="-1"><span class="ob-kick">Step 1 of 5</span>What's your team called?</h3>
    <p class="ob-lead">This is how teammates will find you in Crewline.</p>
    <div class="ob-col"><label class="form-label" for="cw-team">Team name</label>
      <input class="form-control" id="cw-team" name="team" required autocomplete="organization" value="Northbeam Studio"></div>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h2">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6M16 4.6a3.5 3.5 0 0 1 0 6.8M18 14.3c2.1.7 3.5 2.8 3.5 5.7"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="cw-h2" tabindex="-1"><span class="ob-kick">Step 2 of 5</span>How big is the team?</h3>
    <p class="ob-lead">We size your plan and workspace to match.</p>
    <fieldset class="ob-col"><legend class="visually-hidden">Team size</legend>
      <div class="ob-chips">
        <input type="radio" class="btn-check" id="cw-s1" name="size" value="1–10 people" required><label class="btn ob-chip pill" for="cw-s1">1–10</label>
        <input type="radio" class="btn-check" id="cw-s2" name="size" value="11–50 people" checked><label class="btn ob-chip pill" for="cw-s2">11–50</label>
        <input type="radio" class="btn-check" id="cw-s3" name="size" value="51–200 people"><label class="btn ob-chip pill" for="cw-s3">51–200</label>
        <input type="radio" class="btn-check" id="cw-s4" name="size" value="200+ people"><label class="btn ob-chip pill" for="cw-s4">200+</label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h3">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="cw-h3" tabindex="-1"><span class="ob-kick">Step 3 of 5</span>What do you do there?</h3>
    <p class="ob-lead">Your home screen starts with the views your role uses most.</p>
    <div class="ob-col"><label class="form-label" for="cw-role">Your role</label>
      <select class="form-select" id="cw-role" name="role" required>
        <option value="">Choose your role</option><option>Founder or executive</option><option>Product manager</option>
        <option selected>Product designer</option><option>Engineer</option><option>Marketing</option><option>Operations</option></select></div>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h4">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><path d="M17.5 14v7M14 17.5h7"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="cw-h4" tabindex="-1"><span class="ob-kick">Step 4 of 5</span>Which tools do you use?</h3>
    <p class="ob-lead">We'll suggest the integrations to connect first.</p>
    <fieldset class="ob-col"><legend class="visually-hidden">Tools</legend>
      <div class="ob-chips">
        <input type="checkbox" class="btn-check" id="cw-k1" name="tools" value="Slack"><label class="btn ob-chip" for="cw-k1"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Slack</label>
        <input type="checkbox" class="btn-check" id="cw-k2" name="tools" value="Figma" checked><label class="btn ob-chip" for="cw-k2"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Figma</label>
        <input type="checkbox" class="btn-check" id="cw-k3" name="tools" value="GitHub" checked><label class="btn ob-chip" for="cw-k3"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>GitHub</label>
        <input type="checkbox" class="btn-check" id="cw-k4" name="tools" value="Notion" checked><label class="btn ob-chip" for="cw-k4"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Notion</label>
        <input type="checkbox" class="btn-check" id="cw-k5" name="tools" value="Jira"><label class="btn ob-chip" for="cw-k5"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="plus" d="M12 5v14M5 12h14"/><path class="tick" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Jira</label>
      </div></fieldset>
  </section>

  <section class="ob-panel" data-step aria-labelledby="cw-h5">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M10 14a4.5 4.5 0 0 0 6.4 0l3-3a4.5 4.5 0 0 0-6.4-6.4l-1 1M14 10a4.5 4.5 0 0 0-6.4 0l-3 3a4.5 4.5 0 0 0 6.4 6.4l1-1"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="cw-h5" tabindex="-1"><span class="ob-kick">Step 5 of 5</span>Invite your crew</h3>
    <p class="ob-lead">Anyone with this link can join for the next 7 days.</p>
    <div class="ob-col"><label class="form-label" for="cw-link">Invite link</label>
      <div class="d-flex gap-2"><input class="form-control" id="cw-link" name="link" readonly value="https://crewline.app/join/northbeam-7kq2">
        <button type="button" class="btn btn-outline-secondary" data-copy="cw-link"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V6a2 2 0 0 1 2-2h8"/></svg>Copy</button></div>
      <p class="ob-status" role="status" data-status></p></div>
  </section>

  <section class="ob-panel ob-done" data-done hidden aria-labelledby="cw-h6">
    <span class="ob-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg></span>
    <h3 class="ob-h fw-bold mb-0" id="cw-h6" tabindex="-1">Your team profile is ready</h3>
    <p class="ob-lead"><span data-out="team">Northbeam Studio</span> is set up for <span data-out="size">11–50 people</span>. Connect <span data-out="tools">Figma, GitHub, Notion</span> from Settings.</p>
    <button type="button" class="btn btn-outline-secondary" data-restart>Set up another team</button>
  </section>

  <div class="ob-nav">
    <button type="button" class="btn btn-outline-secondary" data-back hidden>Back</button>
    <button type="button" class="btn btn-primary" data-next hidden>Continue</button>
    <button type="submit" class="btn btn-primary">Finish setup</button>
  </div>
</div></form></div>
CSS
/* Onboarding wizards on Bootstrap 5: .card, .form-control, .form-select, .btn-check + .btn chips, .form-check-input,
   .list-group and .btn, restyled through Bootstrap's CSS variables. The segments, the <progress> bar and the step names
   are the custom parts. The script hides every step but the current one, sets data-state and aria-current="step" on the
   <ol data-stepper>, fills the segments or the bar and moves focus to the new step's heading. Without JavaScript every step shows. */
.ob{--ob-accent:#6d28d9;--ob-dark:#5b21b6;--ob-soft:#ede9fe;--ob-pink:#db2777;--ob-ink:#1e1b2e;--ob-muted:#5c5670;--ob-field:#8a82a3;--ob-track:#e4ddf8;--ob-tint:#faf8ff;
  --bs-border-color:#8a82a3;--bs-body-color:#1e1b2e;--bs-secondary-color:#5c5670;
  border:0;border-radius:20px;box-shadow:0 1px 2px rgba(30,27,46,.06),0 16px 40px -18px rgba(76,29,149,.3)}
.ob > .card-body{padding:28px 32px 30px}
.ob.ob-lg > .card-body{padding:40px 44px 36px}
.ob svg{fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ob .form-control,.ob .form-select{border-width:1.5px;border-radius:12px;min-height:46px;padding:10px 14px;font-size:.95rem;color:var(--ob-ink)}
.ob .form-select{padding-right:38px}
.ob .form-control:focus,.ob .form-select:focus{border-color:var(--ob-accent);box-shadow:0 0 0 4px var(--ob-soft)}
.ob .form-control[readonly]{background:var(--ob-tint);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86rem}
.ob .form-label,.ob legend{font-size:.88rem;font-weight:600;margin-bottom:6px}
.ob .form-check-input{border-width:1.5px;border-color:var(--ob-field)}
.ob .form-check-input:checked{background-color:var(--ob-accent);border-color:var(--ob-accent)}
.ob .form-check-input:focus{border-color:var(--ob-accent);box-shadow:0 0 0 3px var(--ob-soft)}
.ob .form-check-input:focus-visible{outline:2px solid var(--ob-accent);outline-offset:3px}
.ob .btn{--bs-btn-padding-x:24px;--bs-btn-font-weight:600;--bs-btn-font-size:.95rem;--bs-btn-border-width:1.5px;--bs-btn-border-radius:999px;min-height:46px;display:inline-flex;align-items:center;justify-content:center;gap:8px}
.ob .btn-primary{--bs-btn-bg:var(--ob-accent);--bs-btn-border-color:var(--ob-accent);--bs-btn-hover-bg:var(--ob-dark);--bs-btn-hover-border-color:var(--ob-dark);--bs-btn-active-bg:var(--ob-dark);--bs-btn-active-border-color:var(--ob-dark)}
.ob .btn-outline-secondary{--bs-btn-bg:#fff;--bs-btn-color:var(--ob-dark);--bs-btn-border-color:var(--ob-field);--bs-btn-hover-bg:var(--ob-tint);--bs-btn-hover-color:var(--ob-dark);--bs-btn-hover-border-color:var(--ob-field);--bs-btn-active-bg:var(--ob-soft);--bs-btn-active-color:var(--ob-dark);--bs-btn-active-border-color:var(--ob-field)}
.ob .btn:focus-visible{box-shadow:0 0 0 3px #fff,0 0 0 5px var(--ob-accent);outline:0}
.ob .btn svg{width:18px;height:18px}
.ob-brand{display:flex;align-items:center;gap:10px}
.ob-logo{width:34px;height:34px;flex:none;border-radius:10px;display:grid;place-items:center;background:var(--ob-accent);color:#fff}
.ob-logo svg{width:20px;height:20px}
.ob-title{font-size:1.05rem;letter-spacing:-.01em;line-height:1.3}

/* A: "Step 2 of 4" + Skip, then one bar segment per step (the segments are the stepper <li>s, names visually hidden) */
.ob-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:24px;min-height:34px}
.ob-pos{font-size:.85rem;font-weight:700;color:var(--ob-dark)}
.ob .ob-skip{--bs-btn-padding-x:10px;--bs-btn-padding-y:6px;--bs-btn-font-size:.88rem;--bs-btn-color:var(--ob-dark);--bs-btn-hover-color:var(--ob-dark);--bs-btn-hover-bg:var(--ob-soft);--bs-btn-active-color:var(--ob-dark);--bs-btn-border-radius:8px;--bs-btn-border-width:0;min-height:0;margin-right:-10px;text-underline-offset:3px}
.ob .ob-skip:focus-visible{box-shadow:none;outline:2px solid var(--ob-accent);outline-offset:1px}
.ob-segs{list-style:none;margin:8px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.ob-segs li{position:relative;height:6px;border-radius:99px;background:var(--ob-track);overflow:hidden}
.ob-segs li::after{content:"";position:absolute;inset:0;border-radius:inherit;background:var(--ob-accent);transform:scaleX(0);transform-origin:left;transition:transform .4s ease}
.ob-segs [data-state="done"]::after{transform:none}
.ob-segs [data-state="current"]::after{transform:none;background:linear-gradient(90deg,var(--ob-accent) 55%,var(--ob-pink))}

/* B: labelled <progress> with a % figure, and a row of step names under it */
.ob-lg .ob-brand{justify-content:center}
.ob-lg .ob-title{font-size:1.35rem;text-align:center;margin-top:14px}
.ob-meter{display:flex;justify-content:space-between;align-items:baseline;margin-top:26px;font-size:.85rem;font-weight:600;color:var(--ob-muted)}
.ob-meter span{color:var(--ob-dark);font-weight:700;font-variant-numeric:tabular-nums}
.ob-progress{display:block;width:100%;height:10px;margin-top:8px;border:0;border-radius:99px;background:var(--ob-track);overflow:hidden;-webkit-appearance:none;appearance:none}
.ob-progress::-webkit-progress-bar{background:var(--ob-track);border-radius:99px}
.ob-progress::-webkit-progress-value{background:linear-gradient(90deg,var(--ob-accent),var(--ob-pink));border-radius:99px;transition:width .4s ease}
.ob-progress::-moz-progress-bar{background:linear-gradient(90deg,var(--ob-accent),var(--ob-pink));border-radius:99px}
.ob-names{list-style:none;margin:12px 0 0;padding:0;display:grid;grid-template-columns:repeat(5,1fr);gap:4px}
.ob-names li{display:flex;flex-direction:column;align-items:center;gap:5px;font-size:.78rem;color:var(--ob-muted);text-align:center}
.ob-mark{width:16px;height:16px;border-radius:50%;border:2px solid var(--ob-field);background:#fff;display:grid;place-items:center;color:#fff;transition:background .25s,border-color .25s}
.ob-mark svg{display:none;width:10px;height:10px;stroke-width:3.5}
.ob-names [data-state="current"]{color:var(--ob-ink);font-weight:700}
.ob-names [data-state="current"] .ob-mark{border-color:var(--ob-pink);background:var(--ob-pink);box-shadow:0 0 0 4px #fce7f3}
.ob-names [data-state="done"]{color:var(--ob-dark);font-weight:600}
.ob-names [data-state="done"] .ob-mark{border-color:var(--ob-accent);background:var(--ob-accent)}
.ob-names [data-state="done"] .ob-mark svg{display:block}

/* step panels */
.ob-panel{margin-top:26px;display:grid;gap:18px;animation:ob-in .3s ease}
@keyframes ob-in{from{opacity:0;transform:translateY(6px)}}
.ob-h{font-size:1.45rem;letter-spacing:-.02em;line-height:1.25}
.ob-h:focus{outline:none}
.ob-kick{display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ob-dark);margin-bottom:4px}
.ob-lead{margin:-10px 0 0;color:var(--ob-muted);font-size:.95rem}
.ob-lg .ob-panel{justify-items:center;text-align:center;margin-top:30px}
.ob-lg .ob-h{font-size:1.3rem}
.ob-icon{width:56px;height:56px;border-radius:16px;display:grid;place-items:center;background:var(--ob-soft);color:var(--ob-dark)}
.ob-icon svg{width:26px;height:26px}
.ob-col{width:100%;max-width:440px;text-align:left}
.ob-hint{font-size:.82rem;color:var(--ob-muted);margin:10px 0 0}
.ob-hint b{color:var(--ob-dark)}

/* chips and pills: .btn-check + .btn, the label turns violet when its box is checked */
.ob-chips{display:flex;flex-wrap:wrap;gap:10px}
.ob-lg .ob-chips{justify-content:center}
.ob .ob-chip{--bs-btn-padding-x:16px;--bs-btn-padding-y:9px;--bs-btn-font-size:.92rem;--bs-btn-font-weight:500;--bs-btn-color:var(--ob-ink);--bs-btn-bg:#fff;--bs-btn-border-color:var(--ob-field);
  --bs-btn-hover-color:var(--ob-ink);--bs-btn-hover-bg:#fff;--bs-btn-hover-border-color:var(--ob-accent);--bs-btn-active-color:#fff;--bs-btn-active-bg:var(--ob-accent);--bs-btn-active-border-color:var(--ob-accent);
  min-height:0;gap:7px;padding-left:13px;line-height:1.5}
.ob .btn-check:focus-visible + .ob-chip{box-shadow:none;outline:2px solid var(--ob-accent);outline-offset:2px}
.ob .ob-chip svg{width:16px;height:16px;stroke-width:2.5}
.ob-chip .tick,.btn-check:checked + .ob-chip .plus{display:none}
.btn-check:checked + .ob-chip .tick{display:block}
.ob .ob-chip.day{--bs-btn-padding-x:12px;--bs-btn-padding-y:7px;--bs-btn-font-size:.85rem;min-width:52px}
.ob .ob-chip.pill{--bs-btn-padding-x:18px;--bs-btn-padding-y:10px}

/* A step 2: goal cards with a visible .form-check-input radio, the card follows :has(:checked) */
.ob-goals{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}
.ob-goal{position:relative;display:grid;gap:2px;align-content:start;padding:16px 16px 18px;border:1.5px solid var(--ob-field);border-radius:16px;cursor:pointer;transition:border-color .2s,background .2s,box-shadow .2s}
.ob-goal .form-check-input{position:absolute;top:16px;right:16px;width:18px;height:18px;margin:0}
.ob-goal b{font-size:2rem;line-height:1;font-weight:800;letter-spacing:-.03em;color:var(--ob-dark)}
.ob-goal .unit{font-size:.85rem;font-weight:600}
.ob-goal .line{font-size:.85rem;color:var(--ob-muted);margin-top:6px}
.ob-goal:has(:checked){border-color:var(--ob-accent);background:var(--ob-tint);box-shadow:0 0 0 3px var(--ob-soft)}
.ob-tag{justify-self:start;margin-bottom:8px;padding:2px 8px;border-radius:99px;background:var(--ob-pink);color:#fff;font-size:.68rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase}
.ob-time{max-width:220px}

/* A step 4: .list-group of people with Follow toggle buttons (aria-pressed) */
.ob .list-group{--bs-list-group-border-color:#e7e2f3;--bs-list-group-border-radius:16px;--bs-list-group-item-padding-x:16px;--bs-list-group-item-padding-y:14px}
.ob .list-group-item{gap:14px}
.ob-avatar{width:44px;height:44px;flex:none;border-radius:50%;display:grid;place-items:center;font-size:.9rem;font-weight:700}
.ob-who{flex:1;min-width:0;display:grid;font-size:.95rem;font-weight:600}
.ob-who span{font-size:.82rem;font-weight:400;color:var(--ob-muted)}
.ob .ob-follow{--bs-btn-padding-x:16px;--bs-btn-font-size:.88rem;--bs-btn-color:var(--ob-dark);--bs-btn-bg:#fff;--bs-btn-border-color:var(--ob-accent);--bs-btn-hover-color:var(--ob-dark);--bs-btn-hover-bg:var(--ob-soft);--bs-btn-hover-border-color:var(--ob-accent);
  --bs-btn-active-color:#fff;--bs-btn-active-bg:var(--ob-accent);--bs-btn-active-border-color:var(--ob-accent);flex:none;min-height:38px;gap:6px}
.ob .ob-follow svg{display:none;width:15px;height:15px;stroke-width:3}
.ob .ob-follow[aria-pressed="true"]{--bs-btn-bg:var(--ob-accent);--bs-btn-color:#fff;--bs-btn-hover-bg:var(--ob-dark);--bs-btn-hover-color:#fff;--bs-btn-hover-border-color:var(--ob-dark)}
.ob .ob-follow[aria-pressed="true"] svg{display:block}

/* B step 5: read-only link + Copy, with a polite status line */
.ob-status{margin:14px 0 0;min-height:1.4em;font-size:.85rem;font-weight:600;color:var(--ob-dark)}

/* Back / Continue bar */
.ob-nav{display:flex;gap:10px;margin-top:28px;padding-top:20px;border-top:1px solid #ece8f6}
.ob-nav .btn-primary{margin-left:auto}
.ob-done{justify-items:center;text-align:center;padding:10px 0 4px}
.ob-done .ob-icon{border-radius:50%;background:#fce7f3;color:#be185d}
.ob-done .ob-lead{margin:0;max-width:440px}
@media (prefers-reduced-motion:reduce){.ob *,.ob *::before,.ob *::after{transition:none!important;animation:none!important}.ob-progress::-webkit-progress-value{transition:none}}
@media (max-width:600px){.ob > .card-body,.ob.ob-lg > .card-body{padding:24px 18px}.ob-h{font-size:1.25rem}.ob-lg .ob-h{font-size:1.25rem}.ob-names li{font-size:.7rem}
  .ob .list-group-item{flex-wrap:wrap}.ob-who{flex-basis:calc(100% - 58px)}.ob .ob-follow{margin-left:58px}}
JavaScript
// Onboarding wizard: one step at a time, stepper marked with data-state and aria-current="step", focus on the new heading.
// Also keeps "Step 2 of 4", the <progress> value and its % text in sync, and handles Skip, pick-at-least-N groups, toggles and Copy.
document.querySelectorAll('[data-wizard]').forEach(function (wz) {
  var panels = wz.querySelectorAll('[data-step]'), steps = wz.querySelectorAll('[data-stepper] > li');
  var back = wz.querySelector('[data-back]'), next = wz.querySelector('[data-next]'), skip = wz.querySelector('[data-skip]');
  var submit = wz.querySelector('[type="submit"]'), done = wz.querySelector('[data-done]'), at = 0;
  var bar = wz.querySelector('[data-progress]'), pct = wz.querySelector('[data-pct]'), pos = wz.querySelector('[data-pos]');
  function mark(i) {
    steps.forEach(function (s, n) {
      s.dataset.state = n < i ? 'done' : n === i ? 'current' : 'next';
      if (n === i) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
      s.querySelector('[data-sr]').textContent = n < i ? ', completed' : '';
    });
    var p = Math.round(Math.min(i + 1, steps.length) / steps.length * 100);
    if (bar) bar.value = p;
    if (pct) pct.textContent = p + '%';
    if (pos) pos.textContent = i < steps.length ? 'Step ' + (i + 1) + ' of ' + steps.length : 'All done';
  }
  function picks() { // [data-min] groups: fewer than N ticked boxes puts a custom error on the first box
    wz.querySelectorAll('[data-min]').forEach(function (g) {
      var boxes = g.querySelectorAll('input[type="checkbox"]'), n = g.querySelectorAll(':checked').length, min = +g.dataset.min, c = g.querySelector('[data-count]');
      boxes[0].setCustomValidity(n < min ? 'Pick at least ' + min + ' (' + n + ' picked so far).' : '');
      if (c) c.textContent = n + ' picked';
    });
  }
  function go(i, focus) {
    at = i; mark(i); picks();
    panels.forEach(function (p, n) { p.hidden = n !== i; });
    back.hidden = i === 0; next.hidden = i === panels.length - 1; submit.hidden = !next.hidden;
    if (skip) skip.hidden = !panels[i].hasAttribute('data-optional');
    wz.querySelectorAll('[data-out]').forEach(function (o) {
      var f = wz.elements[o.dataset.out], v = f && (f.length && !f.options ? [].filter.call(f, function (x) { return x.checked; }).map(function (x) { return x.value; }).join(', ') : f.value);
      o.textContent = v || 'None';
    });
    if (focus) panels[i].querySelector('[tabindex="-1"]').focus();
  }
  function valid() {
    var bad = [].find.call(panels[at].querySelectorAll('input, select, textarea'), function (f) { return !f.checkValidity(); });
    if (bad) bad.reportValidity();
    return !bad;
  }
  function finish() {
    // Last step: send the form here (fetch or wz.submit()). The demo shows the done panel instead.
    panels[at].hidden = true; back.parentNode.hidden = true; if (skip) skip.hidden = true; mark(steps.length);
    done.hidden = false; done.querySelector('[tabindex="-1"]').focus();
  }
  wz.noValidate = true;
  back.addEventListener('click', function () { go(at - 1, true); });
  next.addEventListener('click', function () { if (valid()) go(at + 1, true); });
  if (skip) skip.addEventListener('click', function () { if (at < panels.length - 1) go(at + 1, true); else finish(); });
  wz.addEventListener('change', picks);
  wz.addEventListener('submit', function (e) {
    e.preventDefault();
    if (!valid()) return;
    if (at < panels.length - 1) return go(at + 1, true);
    finish();
  });
  wz.querySelectorAll('[aria-pressed]').forEach(function (b) {
    b.addEventListener('click', function () { b.setAttribute('aria-pressed', b.getAttribute('aria-pressed') !== 'true'); });
  });
  wz.querySelectorAll('[data-copy]').forEach(function (b) {
    var f = document.getElementById(b.dataset.copy), say = wz.querySelector('[data-status]');
    function tell(t) { if (say) { say.textContent = t; clearTimeout(say.t); say.t = setTimeout(function () { say.textContent = ''; }, 4000); } }
    b.addEventListener('click', function () {
      (navigator.clipboard ? navigator.clipboard.writeText(f.value) : Promise.reject()).then(function () { tell('Link copied'); },
        function () { f.select(); tell('Link selected: press Ctrl+C or Cmd+C to copy'); });
    });
  });
  if (done) done.querySelector('[data-restart]').addEventListener('click', function () {
    wz.reset(); wz.querySelectorAll('[aria-pressed]').forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
    done.hidden = true; back.parentNode.hidden = false; go(0, true);
  });
  go(0);
});

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#5c5670] uppercase">Segmented progress</span>
<form class="rounded-[20px] bg-white text-ob-ink shadow-[0_1px_2px_rgba(30,27,46,.06),0_16px_40px_-18px_rgba(76,29,149,.3)] max-[600px]:px-[18px] max-[600px]:py-6 px-8 pt-7 pb-[30px]" data-wizard aria-labelledby="pw-title">
  <div class="flex items-center gap-2.5"><span class="grid size-[34px] flex-none place-items-center rounded-[10px] bg-ob-accent text-white"><svg class="size-5 fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7.5 4.5 4 4.5v13c3.5 0 6 .5 8 2 2-1.5 4.5-2 8-2v-13c-3.5 0-6 .5-8 2zM12 6.5v13"/></svg></span>
    <h2 class="text-[1.05rem] leading-[1.3] font-bold tracking-[-.01em]" id="pw-title">Welcome to Pagewise</h2></div>
  <div class="mt-6 flex min-h-[34px] items-center justify-between gap-3"><span class="text-[.85rem] font-bold text-ob-dark" data-pos aria-hidden="true">Step 1 of 4</span><button type="button" class="-mr-2.5 cursor-pointer rounded-lg px-2.5 py-1.5 text-[.88rem] font-semibold text-ob-dark underline underline-offset-3 hover:bg-ob-soft focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ob-accent" data-skip hidden>Skip</button></div>
  <ol class="mt-2 grid grid-cols-4 gap-1.5" data-stepper aria-label="Progress">
    <li class="relative h-1.5 overflow-hidden rounded-full bg-ob-track after:absolute after:inset-0 after:origin-left after:scale-x-0 after:rounded-[inherit] after:bg-ob-accent after:transition-transform after:duration-400 after:ease-[ease] data-[state=done]:after:scale-x-100 data-[state=current]:after:scale-x-100 data-[state=current]:after:bg-[linear-gradient(90deg,var(--color-ob-accent)_55%,var(--color-ob-pink))] motion-reduce:after:transition-none"><span class="sr-only">Topics</span><span class="sr-only" data-sr></span></li>
    <li class="relative h-1.5 overflow-hidden rounded-full bg-ob-track after:absolute after:inset-0 after:origin-left after:scale-x-0 after:rounded-[inherit] after:bg-ob-accent after:transition-transform after:duration-400 after:ease-[ease] data-[state=done]:after:scale-x-100 data-[state=current]:after:scale-x-100 data-[state=current]:after:bg-[linear-gradient(90deg,var(--color-ob-accent)_55%,var(--color-ob-pink))] motion-reduce:after:transition-none"><span class="sr-only">Daily goal</span><span class="sr-only" data-sr></span></li>
    <li class="relative h-1.5 overflow-hidden rounded-full bg-ob-track after:absolute after:inset-0 after:origin-left after:scale-x-0 after:rounded-[inherit] after:bg-ob-accent after:transition-transform after:duration-400 after:ease-[ease] data-[state=done]:after:scale-x-100 data-[state=current]:after:scale-x-100 data-[state=current]:after:bg-[linear-gradient(90deg,var(--color-ob-accent)_55%,var(--color-ob-pink))] motion-reduce:after:transition-none"><span class="sr-only">Reminders</span><span class="sr-only" data-sr></span></li>
    <li class="relative h-1.5 overflow-hidden rounded-full bg-ob-track after:absolute after:inset-0 after:origin-left after:scale-x-0 after:rounded-[inherit] after:bg-ob-accent after:transition-transform after:duration-400 after:ease-[ease] data-[state=done]:after:scale-x-100 data-[state=current]:after:scale-x-100 data-[state=current]:after:bg-[linear-gradient(90deg,var(--color-ob-accent)_55%,var(--color-ob-pink))] motion-reduce:after:transition-none"><span class="sr-only">Friends</span><span class="sr-only" data-sr></span></li>
  </ol>

  <section class="mt-[26px] grid animate-ob-in gap-[18px] motion-reduce:animate-none" data-step aria-labelledby="pw-h1">
    <h3 class="text-[1.45rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="pw-h1" tabindex="-1"><span class="sr-only">Step 1 of 4: </span>What do you like to read about?</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">We use these to fill your first reading list.</p>
    <fieldset class="grid min-w-0 gap-1.5" data-min="3" aria-describedby="pw-topics-hint"><legend class="sr-only">Topics</legend>
      <div class="flex flex-wrap gap-2.5">
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="History" checked><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>History</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Design" checked><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Design</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Climate"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Climate</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Economics"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Economics</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Psychology"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Psychology</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Space" checked><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Space</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Food"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Food</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Music"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Music</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Travel"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Travel</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="topics" value="Philosophy"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Philosophy</label>
      </div>
      <p class="mt-1 text-[.82rem] text-ob-muted" id="pw-topics-hint">Pick at least 3 · <b class="text-ob-dark" data-count>3 picked</b></p></fieldset>
  </section>

  <section class="mt-[26px] grid animate-ob-in gap-[18px] motion-reduce:animate-none" data-step aria-labelledby="pw-h2">
    <h3 class="text-[1.45rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="pw-h2" tabindex="-1"><span class="sr-only">Step 2 of 4: </span>Set a daily reading goal</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">Small and steady wins. You can change it any day.</p>
    <fieldset class="grid min-w-0 gap-1.5"><legend class="sr-only">Minutes a day</legend>
      <div class="grid grid-cols-[repeat(auto-fit,minmax(170px,1fr))] gap-3">
        <label class="relative grid cursor-pointer content-start gap-0.5 rounded-2xl border-[1.5px] border-ob-field px-4 pt-4 pb-[18px] transition-[border-color,background-color,box-shadow] has-checked:border-ob-accent has-checked:bg-ob-tint has-checked:shadow-[0_0_0_3px_var(--color-ob-soft)] motion-reduce:transition-none"><input class="absolute top-4 right-4 m-0 size-[18px] accent-ob-accent focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ob-accent" type="radio" name="goal" value="10 minutes" required><b class="text-[2rem] leading-none font-extrabold tracking-[-.03em] text-ob-dark">10</b><span class="text-[.85rem] font-semibold">minutes a day</span><span class="mt-1.5 text-[.85rem] text-ob-muted">A chapter with your morning coffee.</span></label>
        <label class="relative grid cursor-pointer content-start gap-0.5 rounded-2xl border-[1.5px] border-ob-field px-4 pt-4 pb-[18px] transition-[border-color,background-color,box-shadow] has-checked:border-ob-accent has-checked:bg-ob-tint has-checked:shadow-[0_0_0_3px_var(--color-ob-soft)] motion-reduce:transition-none"><input class="absolute top-4 right-4 m-0 size-[18px] accent-ob-accent focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ob-accent" type="radio" name="goal" value="20 minutes" checked><span class="mb-2 justify-self-start rounded-full bg-ob-pink px-2 py-0.5 text-[.68rem] font-bold tracking-[.06em] text-white uppercase">Most picked</span><b class="text-[2rem] leading-none font-extrabold tracking-[-.03em] text-ob-dark">20</b><span class="text-[.85rem] font-semibold">minutes a day</span><span class="mt-1.5 text-[.85rem] text-ob-muted">About one book every two weeks.</span></label>
        <label class="relative grid cursor-pointer content-start gap-0.5 rounded-2xl border-[1.5px] border-ob-field px-4 pt-4 pb-[18px] transition-[border-color,background-color,box-shadow] has-checked:border-ob-accent has-checked:bg-ob-tint has-checked:shadow-[0_0_0_3px_var(--color-ob-soft)] motion-reduce:transition-none"><input class="absolute top-4 right-4 m-0 size-[18px] accent-ob-accent focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-ob-accent" type="radio" name="goal" value="30 minutes"><b class="text-[2rem] leading-none font-extrabold tracking-[-.03em] text-ob-dark">30</b><span class="text-[.85rem] font-semibold">minutes a day</span><span class="mt-1.5 text-[.85rem] text-ob-muted">Roughly 40 books by next September.</span></label>
      </div></fieldset>
  </section>

  <section class="mt-[26px] grid animate-ob-in gap-[18px] motion-reduce:animate-none" data-step data-optional aria-labelledby="pw-h3">
    <h3 class="text-[1.45rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="pw-h3" tabindex="-1"><span class="sr-only">Step 3 of 4: </span>When should we remind you?</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">One quiet nudge, only on the days you choose.</p>
    <div class="grid min-w-0 gap-1.5 max-w-[220px]"><label class="text-[.88rem] font-semibold" for="pw-time">Reminder time</label>
      <input class="min-h-[46px] w-full rounded-xl border-[1.5px] border-ob-field bg-white px-3.5 py-2.5 text-[.95rem] text-ob-ink focus-visible:border-ob-accent focus-visible:shadow-[0_0_0_4px_var(--color-ob-soft)] focus-visible:outline-none" id="pw-time" name="time" type="time" required value="07:45"></div>
    <fieldset class="grid min-w-0 gap-1.5"><legend class="mb-2 text-[.88rem] font-semibold">Remind me on</legend>
      <div class="flex flex-wrap gap-2.5">
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Mon" checked>Mon</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Tue" checked>Tue</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Wed" checked>Wed</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Thu" checked>Thu</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Fri" checked>Fri</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Sat">Sat</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none min-w-[52px] justify-center px-3 py-[7px] text-[.85rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="days" value="Sun">Sun</label>
      </div></fieldset>
  </section>

  <section class="mt-[26px] grid animate-ob-in gap-[18px] motion-reduce:animate-none" data-step data-optional aria-labelledby="pw-h4">
    <h3 class="text-[1.45rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="pw-h4" tabindex="-1"><span class="sr-only">Step 4 of 4: </span>Follow a few readers</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">See what they finish and borrow their best picks. Optional.</p>
    <ul class="grid divide-y divide-[#e7e2f3] rounded-2xl border border-[#e7e2f3]">
      <li class="flex items-center gap-3.5 px-4 py-3.5 max-[600px]:flex-wrap"><span class="grid size-11 flex-none place-items-center rounded-full text-[.9rem] font-bold" style="background:#fde68a;color:#78350f" aria-hidden="true">AO</span>
        <span class="grid min-w-0 flex-1 text-[.95rem] font-semibold max-[600px]:basis-[calc(100%-58px)]">Amara Okafor<span class="text-[.82rem] font-normal text-ob-muted">History and memoirs · 41 books this year</span></span>
        <button type="button" class="group inline-flex min-h-[38px] flex-none cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-ob-accent bg-white px-4 text-[.88rem] font-semibold text-ob-dark transition-colors hover:bg-ob-soft aria-pressed:bg-ob-accent aria-pressed:text-white aria-pressed:hover:border-ob-dark aria-pressed:hover:bg-ob-dark focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none max-[600px]:ml-[58px]" aria-pressed="false"><svg class="hidden size-[15px] fill-none stroke-current stroke-3 group-aria-pressed: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>Follow<span class="sr-only"> Amara Okafor</span></button></li>
      <li class="flex items-center gap-3.5 px-4 py-3.5 max-[600px]:flex-wrap"><span class="grid size-11 flex-none place-items-center rounded-full text-[.9rem] font-bold" style="background:#bbf7d0;color:#14532d" aria-hidden="true">LF</span>
        <span class="grid min-w-0 flex-1 text-[.95rem] font-semibold max-[600px]:basis-[calc(100%-58px)]">Luis Ferreira<span class="text-[.82rem] font-normal text-ob-muted">Climate and science writing · 27 books</span></span>
        <button type="button" class="group inline-flex min-h-[38px] flex-none cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-ob-accent bg-white px-4 text-[.88rem] font-semibold text-ob-dark transition-colors hover:bg-ob-soft aria-pressed:bg-ob-accent aria-pressed:text-white aria-pressed:hover:border-ob-dark aria-pressed:hover:bg-ob-dark focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none max-[600px]:ml-[58px]" aria-pressed="false"><svg class="hidden size-[15px] fill-none stroke-current stroke-3 group-aria-pressed: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>Follow<span class="sr-only"> Luis Ferreira</span></button></li>
      <li class="flex items-center gap-3.5 px-4 py-3.5 max-[600px]:flex-wrap"><span class="grid size-11 flex-none place-items-center rounded-full text-[.9rem] font-bold" style="background:#fbcfe8;color:#831843" aria-hidden="true">HS</span>
        <span class="grid min-w-0 flex-1 text-[.95rem] font-semibold max-[600px]:basis-[calc(100%-58px)]">Hana Sato<span class="text-[.82rem] font-normal text-ob-muted">Design and architecture · 33 books</span></span>
        <button type="button" class="group inline-flex min-h-[38px] flex-none cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-ob-accent bg-white px-4 text-[.88rem] font-semibold text-ob-dark transition-colors hover:bg-ob-soft aria-pressed:bg-ob-accent aria-pressed:text-white aria-pressed:hover:border-ob-dark aria-pressed:hover:bg-ob-dark focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none max-[600px]:ml-[58px]" aria-pressed="false"><svg class="hidden size-[15px] fill-none stroke-current stroke-3 group-aria-pressed: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>Follow<span class="sr-only"> Hana Sato</span></button></li>
    </ul>
  </section>

  <section class="mt-[26px] grid animate-ob-in gap-[18px] motion-reduce:animate-none justify-items-center pt-2.5 pb-1 text-center" data-done hidden aria-labelledby="pw-h5">
    <span class="grid size-14 place-items-center rounded-full bg-[#fce7f3] text-[#be185d]"><svg class="size-[26px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7.5 4.5 4 4.5v13c3.5 0 6 .5 8 2 2-1.5 4.5-2 8-2v-13c-3.5 0-6 .5-8 2zM12 6.5v13"/></svg></span>
    <h3 class="text-[1.45rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="pw-h5" tabindex="-1">Your first reading list is ready</h3>
    <p class="max-w-[440px] text-[.95rem] text-ob-muted">Twelve picks from <span data-out="topics">History, Design, Space</span>. We'll nudge you at <span data-out="time">07:45</span>.</p>
    <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-field bg-white text-ob-dark hover:bg-ob-tint" data-restart>Start over</button>
  </section>

  <div class="mt-7 flex gap-2.5 border-t border-[#ece8f6] pt-5">
    <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-field bg-white text-ob-dark hover:bg-ob-tint" data-back hidden>Back</button>
    <button type="button" class="ms-auto inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-accent bg-ob-accent text-white hover:bg-ob-dark" data-next hidden>Continue</button>
    <button type="submit" class="ms-auto inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-accent bg-ob-accent text-white hover:bg-ob-dark">Build my list</button>
  </div>
</form></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#5c5670] uppercase">Progress bar with percentage</span>
<form class="rounded-[20px] bg-white text-ob-ink shadow-[0_1px_2px_rgba(30,27,46,.06),0_16px_40px_-18px_rgba(76,29,149,.3)] max-[600px]:px-[18px] max-[600px]:py-6 px-11 pt-10 pb-9" data-wizard aria-labelledby="cw-title">
  <div class="flex items-center justify-center gap-2.5"><span class="grid size-[34px] flex-none place-items-center rounded-[10px] bg-ob-accent text-white"><svg class="size-5 fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 15c2.5-7 5.5-7 8.5 0s6 7 8.5 0"/></svg></span><b>Crewline</b></div>
  <h2 class="mt-3.5 text-center text-[1.35rem] leading-[1.3] font-bold tracking-[-.01em]" id="cw-title">Set up your team profile</h2>
  <div class="mt-[26px] flex items-baseline justify-between text-[.85rem] font-semibold text-ob-muted"><label for="cw-progress">Setup progress</label><span class="font-bold text-ob-dark tabular-nums" data-pct aria-hidden="true">20%</span></div>
  <progress class="mt-2 block h-2.5 w-full appearance-none overflow-hidden rounded-full border-0 bg-ob-track [&::-webkit-progress-bar]:rounded-full [&::-webkit-progress-bar]:bg-ob-track [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:bg-[linear-gradient(90deg,var(--color-ob-accent),var(--color-ob-pink))] [&::-webkit-progress-value]:transition-[width] [&::-webkit-progress-value]:duration-400 motion-reduce:[&::-webkit-progress-value]:transition-none [&::-moz-progress-bar]:rounded-full [&::-moz-progress-bar]:bg-[linear-gradient(90deg,var(--color-ob-accent),var(--color-ob-pink))]" id="cw-progress" data-progress max="100" value="20">20%</progress>
  <ol class="mt-3 grid grid-cols-5 gap-1" data-stepper aria-label="Progress">
    <li class="group flex flex-col items-center gap-[5px] text-center text-[.78rem] text-ob-muted data-[state=current]:font-bold data-[state=current]:text-ob-ink data-[state=done]:font-semibold data-[state=done]:text-ob-dark max-[600px]:text-[.7rem]"><span class="grid size-4 place-items-center rounded-full border-2 border-ob-field bg-white text-white transition-colors duration-250 group-data-[state=current]:border-ob-pink group-data-[state=current]:bg-ob-pink group-data-[state=current]:shadow-[0_0_0_4px_#fce7f3] group-data-[state=done]:border-ob-accent group-data-[state=done]:bg-ob-accent motion-reduce:transition-none"><svg class="hidden size-2.5 fill-none stroke-current stroke-[3.5] group-data-[state=done]: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>Name<span class="sr-only" data-sr></span></li>
    <li class="group flex flex-col items-center gap-[5px] text-center text-[.78rem] text-ob-muted data-[state=current]:font-bold data-[state=current]:text-ob-ink data-[state=done]:font-semibold data-[state=done]:text-ob-dark max-[600px]:text-[.7rem]"><span class="grid size-4 place-items-center rounded-full border-2 border-ob-field bg-white text-white transition-colors duration-250 group-data-[state=current]:border-ob-pink group-data-[state=current]:bg-ob-pink group-data-[state=current]:shadow-[0_0_0_4px_#fce7f3] group-data-[state=done]:border-ob-accent group-data-[state=done]:bg-ob-accent motion-reduce:transition-none"><svg class="hidden size-2.5 fill-none stroke-current stroke-[3.5] group-data-[state=done]: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>Size<span class="sr-only" data-sr></span></li>
    <li class="group flex flex-col items-center gap-[5px] text-center text-[.78rem] text-ob-muted data-[state=current]:font-bold data-[state=current]:text-ob-ink data-[state=done]:font-semibold data-[state=done]:text-ob-dark max-[600px]:text-[.7rem]"><span class="grid size-4 place-items-center rounded-full border-2 border-ob-field bg-white text-white transition-colors duration-250 group-data-[state=current]:border-ob-pink group-data-[state=current]:bg-ob-pink group-data-[state=current]:shadow-[0_0_0_4px_#fce7f3] group-data-[state=done]:border-ob-accent group-data-[state=done]:bg-ob-accent motion-reduce:transition-none"><svg class="hidden size-2.5 fill-none stroke-current stroke-[3.5] group-data-[state=done]: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>Role<span class="sr-only" data-sr></span></li>
    <li class="group flex flex-col items-center gap-[5px] text-center text-[.78rem] text-ob-muted data-[state=current]:font-bold data-[state=current]:text-ob-ink data-[state=done]:font-semibold data-[state=done]:text-ob-dark max-[600px]:text-[.7rem]"><span class="grid size-4 place-items-center rounded-full border-2 border-ob-field bg-white text-white transition-colors duration-250 group-data-[state=current]:border-ob-pink group-data-[state=current]:bg-ob-pink group-data-[state=current]:shadow-[0_0_0_4px_#fce7f3] group-data-[state=done]:border-ob-accent group-data-[state=done]:bg-ob-accent motion-reduce:transition-none"><svg class="hidden size-2.5 fill-none stroke-current stroke-[3.5] group-data-[state=done]: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>Tools<span class="sr-only" data-sr></span></li>
    <li class="group flex flex-col items-center gap-[5px] text-center text-[.78rem] text-ob-muted data-[state=current]:font-bold data-[state=current]:text-ob-ink data-[state=done]:font-semibold data-[state=done]:text-ob-dark max-[600px]:text-[.7rem]"><span class="grid size-4 place-items-center rounded-full border-2 border-ob-field bg-white text-white transition-colors duration-250 group-data-[state=current]:border-ob-pink group-data-[state=current]:bg-ob-pink group-data-[state=current]:shadow-[0_0_0_4px_#fce7f3] group-data-[state=done]:border-ob-accent group-data-[state=done]:bg-ob-accent motion-reduce:transition-none"><svg class="hidden size-2.5 fill-none stroke-current stroke-[3.5] group-data-[state=done]: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>Invite<span class="sr-only" data-sr></span></li>
  </ol>

  <section class="mt-[30px] grid animate-ob-in justify-items-center gap-[18px] text-center motion-reduce:animate-none" data-step aria-labelledby="cw-h1">
    <span class="grid size-14 place-items-center rounded-2xl bg-ob-soft text-ob-dark"><svg class="size-[26px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 21V4M5 4h12l-2 4 2 4H5"/></svg></span>
    <h3 class="text-[1.3rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="cw-h1" tabindex="-1"><span class="mb-1 block text-[.72rem] font-bold tracking-[.1em] text-ob-dark uppercase">Step 1 of 5</span>What's your team called?</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">This is how teammates will find you in Crewline.</p>
    <div class="grid min-w-0 gap-1.5 w-full max-w-[440px] text-left"><label class="text-[.88rem] font-semibold" for="cw-team">Team name</label>
      <input class="min-h-[46px] w-full rounded-xl border-[1.5px] border-ob-field bg-white px-3.5 py-2.5 text-[.95rem] text-ob-ink focus-visible:border-ob-accent focus-visible:shadow-[0_0_0_4px_var(--color-ob-soft)] focus-visible:outline-none" id="cw-team" name="team" required autocomplete="organization" value="Northbeam Studio"></div>
  </section>

  <section class="mt-[30px] grid animate-ob-in justify-items-center gap-[18px] text-center motion-reduce:animate-none" data-step aria-labelledby="cw-h2">
    <span class="grid size-14 place-items-center rounded-2xl bg-ob-soft text-ob-dark"><svg class="size-[26px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6M16 4.6a3.5 3.5 0 0 1 0 6.8M18 14.3c2.1.7 3.5 2.8 3.5 5.7"/></svg></span>
    <h3 class="text-[1.3rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="cw-h2" tabindex="-1"><span class="mb-1 block text-[.72rem] font-bold tracking-[.1em] text-ob-dark uppercase">Step 2 of 5</span>How big is the team?</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">We size your plan and workspace to match.</p>
    <fieldset class="grid min-w-0 gap-1.5 w-full max-w-[440px] text-left"><legend class="sr-only">Team size</legend>
      <div class="flex flex-wrap justify-center gap-2.5">
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none px-[18px] py-2.5 text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="size" value="1–10 people" required>1–10</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none px-[18px] py-2.5 text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="size" value="11–50 people" checked>11–50</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none px-[18px] py-2.5 text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="size" value="51–200 people">51–200</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none px-[18px] py-2.5 text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="size" value="200+ people">200+</label>
      </div></fieldset>
  </section>

  <section class="mt-[30px] grid animate-ob-in justify-items-center gap-[18px] text-center motion-reduce:animate-none" data-step aria-labelledby="cw-h3">
    <span class="grid size-14 place-items-center rounded-2xl bg-ob-soft text-ob-dark"><svg class="size-[26px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18"/></svg></span>
    <h3 class="text-[1.3rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="cw-h3" tabindex="-1"><span class="mb-1 block text-[.72rem] font-bold tracking-[.1em] text-ob-dark uppercase">Step 3 of 5</span>What do you do there?</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">Your home screen starts with the views your role uses most.</p>
    <div class="grid min-w-0 gap-1.5 w-full max-w-[440px] text-left"><label class="text-[.88rem] font-semibold" for="cw-role">Your role</label>
      <select class="min-h-[46px] w-full rounded-xl border-[1.5px] border-ob-field bg-white px-3.5 py-2.5 text-[.95rem] text-ob-ink focus-visible:border-ob-accent focus-visible:shadow-[0_0_0_4px_var(--color-ob-soft)] focus-visible:outline-none" id="cw-role" name="role" required>
        <option value="">Choose your role</option><option>Founder or executive</option><option>Product manager</option>
        <option selected>Product designer</option><option>Engineer</option><option>Marketing</option><option>Operations</option></select></div>
  </section>

  <section class="mt-[30px] grid animate-ob-in justify-items-center gap-[18px] text-center motion-reduce:animate-none" data-step aria-labelledby="cw-h4">
    <span class="grid size-14 place-items-center rounded-2xl bg-ob-soft text-ob-dark"><svg class="size-[26px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><path d="M17.5 14v7M14 17.5h7"/></svg></span>
    <h3 class="text-[1.3rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="cw-h4" tabindex="-1"><span class="mb-1 block text-[.72rem] font-bold tracking-[.1em] text-ob-dark uppercase">Step 4 of 5</span>Which tools do you use?</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">We'll suggest the integrations to connect first.</p>
    <fieldset class="grid min-w-0 gap-1.5 w-full max-w-[440px] text-left"><legend class="sr-only">Tools</legend>
      <div class="flex flex-wrap justify-center gap-2.5">
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="tools" value="Slack"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Slack</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="tools" value="Figma" checked><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Figma</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="tools" value="GitHub" checked><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>GitHub</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="tools" value="Notion" checked><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Notion</label>
        <label class="group relative inline-flex cursor-pointer items-center gap-[7px] rounded-full border-[1.5px] border-ob-field bg-white font-medium transition-[background-color,border-color,color] hover:border-ob-accent has-checked:border-ob-accent has-checked:bg-ob-accent has-checked:text-white has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-ob-accent motion-reduce:transition-none py-[9px] pr-4 pl-[13px] text-[.92rem]"><input class="absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="checkbox" name="tools" value="Jira"><svg class="size-4 fill-none stroke-current stroke-[2.5]" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path class="group-has-[:checked]:hidden" d="M12 5v14M5 12h14"/><path class="hidden group-has-[:checked]:block" d="m5 12.5 4.5 4.5L19 7.5"/></svg>Jira</label>
      </div></fieldset>
  </section>

  <section class="mt-[30px] grid animate-ob-in justify-items-center gap-[18px] text-center motion-reduce:animate-none" data-step aria-labelledby="cw-h5">
    <span class="grid size-14 place-items-center rounded-2xl bg-ob-soft text-ob-dark"><svg class="size-[26px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><path d="M10 14a4.5 4.5 0 0 0 6.4 0l3-3a4.5 4.5 0 0 0-6.4-6.4l-1 1M14 10a4.5 4.5 0 0 0-6.4 0l-3 3a4.5 4.5 0 0 0 6.4 6.4l1-1"/></svg></span>
    <h3 class="text-[1.3rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="cw-h5" tabindex="-1"><span class="mb-1 block text-[.72rem] font-bold tracking-[.1em] text-ob-dark uppercase">Step 5 of 5</span>Invite your crew</h3>
    <p class="-mt-2.5 text-[.95rem] text-ob-muted">Anyone with this link can join for the next 7 days.</p>
    <div class="grid min-w-0 gap-1.5 w-full max-w-[440px] text-left"><label class="text-[.88rem] font-semibold" for="cw-link">Invite link</label>
      <div class="flex gap-2"><input class="min-h-[46px] w-full rounded-xl border-[1.5px] border-ob-field bg-ob-tint px-3.5 py-2.5 text-[.86rem] text-ob-ink focus-visible:border-ob-accent focus-visible:shadow-[0_0_0_4px_var(--color-ob-soft)] focus-visible:outline-none min-w-0 flex-1 font-mono" id="cw-link" name="link" readonly value="https://crewline.app/join/northbeam-7kq2">
        <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-field bg-white text-ob-dark hover:bg-ob-tint" data-copy="cw-link"><svg class="size-[18px] fill-none stroke-current stroke-2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V6a2 2 0 0 1 2-2h8"/></svg>Copy</button></div>
      <p class="mt-2 min-h-[1.4em] text-[.85rem] font-semibold text-ob-dark" role="status" data-status></p></div>
  </section>

  <section class="mt-[30px] grid animate-ob-in justify-items-center gap-[18px] text-center motion-reduce:animate-none pt-2.5 pb-1" data-done hidden aria-labelledby="cw-h6">
    <span class="grid size-14 place-items-center rounded-full bg-[#fce7f3] text-[#be185d]"><svg class="size-[26px] fill-none stroke-current stroke-2" 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>
    <h3 class="text-[1.3rem] leading-[1.25] font-bold tracking-[-.02em] focus:outline-none max-[600px]:text-[1.25rem]" id="cw-h6" tabindex="-1">Your team profile is ready</h3>
    <p class="max-w-[440px] text-[.95rem] text-ob-muted"><span data-out="team">Northbeam Studio</span> is set up for <span data-out="size">11–50 people</span>. Connect <span data-out="tools">Figma, GitHub, Notion</span> from Settings.</p>
    <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-field bg-white text-ob-dark hover:bg-ob-tint" data-restart>Set up another team</button>
  </section>

  <div class="mt-7 flex gap-2.5 border-t border-[#ece8f6] pt-5">
    <button type="button" class="inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-field bg-white text-ob-dark hover:bg-ob-tint" data-back hidden>Back</button>
    <button type="button" class="ms-auto inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-accent bg-ob-accent text-white hover:bg-ob-dark" data-next hidden>Continue</button>
    <button type="submit" class="ms-auto inline-flex min-h-[46px] cursor-pointer items-center justify-center gap-2 rounded-full border-[1.5px] px-6 text-[.95rem] font-semibold transition-colors focus-visible:shadow-[0_0_0_3px_#fff,0_0_0_5px_var(--color-ob-accent)] focus-visible:outline-none motion-reduce:transition-none border-ob-accent bg-ob-accent text-white hover:bg-ob-dark">Finish setup</button>
  </div>
</form></div>
CSS
@theme {
  --color-ob-accent: #6d28d9;
  --color-ob-dark: #5b21b6;
  --color-ob-soft: #ede9fe;
  --color-ob-pink: #db2777;
  --color-ob-ink: #1e1b2e;
  --color-ob-muted: #5c5670;
  --color-ob-field: #8a82a3;
  --color-ob-track: #e4ddf8;
  --color-ob-tint: #faf8ff;
  --animate-ob-in: ob-in .3s ease;
  @keyframes ob-in { from { opacity: 0; transform: translateY(6px); } }
}
JavaScript
// Onboarding wizard: one step at a time, stepper marked with data-state and aria-current="step", focus on the new heading.
// Also keeps "Step 2 of 4", the <progress> value and its % text in sync, and handles Skip, pick-at-least-N groups, toggles and Copy.
document.querySelectorAll('[data-wizard]').forEach(function (wz) {
  var panels = wz.querySelectorAll('[data-step]'), steps = wz.querySelectorAll('[data-stepper] > li');
  var back = wz.querySelector('[data-back]'), next = wz.querySelector('[data-next]'), skip = wz.querySelector('[data-skip]');
  var submit = wz.querySelector('[type="submit"]'), done = wz.querySelector('[data-done]'), at = 0;
  var bar = wz.querySelector('[data-progress]'), pct = wz.querySelector('[data-pct]'), pos = wz.querySelector('[data-pos]');
  function mark(i) {
    steps.forEach(function (s, n) {
      s.dataset.state = n < i ? 'done' : n === i ? 'current' : 'next';
      if (n === i) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
      s.querySelector('[data-sr]').textContent = n < i ? ', completed' : '';
    });
    var p = Math.round(Math.min(i + 1, steps.length) / steps.length * 100);
    if (bar) bar.value = p;
    if (pct) pct.textContent = p + '%';
    if (pos) pos.textContent = i < steps.length ? 'Step ' + (i + 1) + ' of ' + steps.length : 'All done';
  }
  function picks() { // [data-min] groups: fewer than N ticked boxes puts a custom error on the first box
    wz.querySelectorAll('[data-min]').forEach(function (g) {
      var boxes = g.querySelectorAll('input[type="checkbox"]'), n = g.querySelectorAll(':checked').length, min = +g.dataset.min, c = g.querySelector('[data-count]');
      boxes[0].setCustomValidity(n < min ? 'Pick at least ' + min + ' (' + n + ' picked so far).' : '');
      if (c) c.textContent = n + ' picked';
    });
  }
  function go(i, focus) {
    at = i; mark(i); picks();
    panels.forEach(function (p, n) { p.hidden = n !== i; });
    back.hidden = i === 0; next.hidden = i === panels.length - 1; submit.hidden = !next.hidden;
    if (skip) skip.hidden = !panels[i].hasAttribute('data-optional');
    wz.querySelectorAll('[data-out]').forEach(function (o) {
      var f = wz.elements[o.dataset.out], v = f && (f.length && !f.options ? [].filter.call(f, function (x) { return x.checked; }).map(function (x) { return x.value; }).join(', ') : f.value);
      o.textContent = v || 'None';
    });
    if (focus) panels[i].querySelector('[tabindex="-1"]').focus();
  }
  function valid() {
    var bad = [].find.call(panels[at].querySelectorAll('input, select, textarea'), function (f) { return !f.checkValidity(); });
    if (bad) bad.reportValidity();
    return !bad;
  }
  function finish() {
    // Last step: send the form here (fetch or wz.submit()). The demo shows the done panel instead.
    panels[at].hidden = true; back.parentNode.hidden = true; if (skip) skip.hidden = true; mark(steps.length);
    done.hidden = false; done.querySelector('[tabindex="-1"]').focus();
  }
  wz.noValidate = true;
  back.addEventListener('click', function () { go(at - 1, true); });
  next.addEventListener('click', function () { if (valid()) go(at + 1, true); });
  if (skip) skip.addEventListener('click', function () { if (at < panels.length - 1) go(at + 1, true); else finish(); });
  wz.addEventListener('change', picks);
  wz.addEventListener('submit', function (e) {
    e.preventDefault();
    if (!valid()) return;
    if (at < panels.length - 1) return go(at + 1, true);
    finish();
  });
  wz.querySelectorAll('[aria-pressed]').forEach(function (b) {
    b.addEventListener('click', function () { b.setAttribute('aria-pressed', b.getAttribute('aria-pressed') !== 'true'); });
  });
  wz.querySelectorAll('[data-copy]').forEach(function (b) {
    var f = document.getElementById(b.dataset.copy), say = wz.querySelector('[data-status]');
    function tell(t) { if (say) { say.textContent = t; clearTimeout(say.t); say.t = setTimeout(function () { say.textContent = ''; }, 4000); } }
    b.addEventListener('click', function () {
      (navigator.clipboard ? navigator.clipboard.writeText(f.value) : Promise.reject()).then(function () { tell('Link copied'); },
        function () { f.select(); tell('Link selected: press Ctrl+C or Cmd+C to copy'); });
    });
  });
  if (done) done.querySelector('[data-restart]').addEventListener('click', function () {
    wz.reset(); wz.querySelectorAll('[aria-pressed]').forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
    done.hidden = true; back.parentNode.hidden = false; go(0, true);
  });
  go(0);
});

About this set

Two first-run onboarding flows where progress is shown as a bar rather than numbered steps. Segmented progress is a four-step setup for a reading app: pick at least three topics from checkbox chips, choose a daily goal from radio cards, set a reminder time and weekdays, then follow suggested readers with toggle buttons. A Step 2 of 4 line and a Skip button sit above four segments that fill as you advance. Skip appears only on steps marked optional and moves on without validating. Progress bar with percentage is a five-step team profile with an icon per step, centred in a larger card: team name, team size pills, role select, tool chips and an invite link with a Copy button. A native progress element with a visible label shows the percentage, and a row of step names under it carries aria-current. Use the segments for four or five quick taste questions and the percentage bar when a setup has more steps and people want to know how far along they are. The shared vanilla script validates each step with constraint validation, enforces the minimum of three topics through setCustomValidity, keeps the bar and text in sync and moves focus to each new heading. Without JavaScript every step shows and the form submits.

What’s included

  • Segmented bar built from the stepper list itself
  • Native progress element with a label and a live percentage figure
  • Skip button that appears only on optional steps
  • Pick-at-least-three rule enforced with setCustomValidity and a running count
  • Follow toggle buttons with aria-pressed and a Copy button with a polite status message
  • Every step visible and submittable without JavaScript

Accessibility

Each stepper is an ordered list labelled Progress with aria-current="step" on the current item and a visually hidden ", completed" on finished ones; the progress element is labelled Setup progress. Focus moves to each new step heading, which starts with its Step 2 of 4 kicker, and chips, cards, toggles and buttons show visible focus rings. Follow buttons expose their state with aria-pressed, the copy result is announced through role="status", and animations and transitions stop under prefers-reduced-motion.

Customise it

Change --ob-accent, --ob-dark, --ob-soft, --ob-pink and --ob-track on .ob in the plain CSS and Bootstrap versions; Bootstrap buttons, chips and fields read them through --bs-btn-* and --bs-border-color. In Tailwind edit the --color-ob-* theme colours.