Open demo

CSS code

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="dk-i-tick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.8 2.8L16.5 9.5"/></symbol>
  <symbol id="dk-i-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></symbol>
  <symbol id="dk-i-wave" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h2M7 8v8M11 5v14M15 9v6M19 11v2M21 12h0"/></symbol>
</svg>

<div><span class="lbl">Developer newsletter bar</span>
<section class="dk dk-dev" aria-labelledby="st-title">
  <div>
    <p class="dk-mono">// issue #212 ships Friday</p>
    <h3 id="st-title">Stack Trace Weekly</h3>
    <p>Five links worth your time on databases, performance and the occasional war story. No hot takes.</p>
  </div>
  <div>
    <form class="dk-form" action="#" method="post" data-nf="st-done">
      <label class="dk-label" for="st-email">Email address</label>
      <div class="dk-join">
        <input class="dk-input" id="st-email" name="email" type="email" autocomplete="email" required placeholder="[email protected]" aria-describedby="st-email-err st-hint" data-err="st-email-err"
          data-missing="Enter your email address to subscribe." data-bad="Enter an email address with an @ and a domain, like [email protected].">
        <button class="dk-btn" type="submit">Subscribe</button>
      </div>
      <p class="dk-err" id="st-email-err"></p>
      <p class="dk-hint" id="st-hint">Fridays only. Plain-text friendly. <a href="#privacy">Privacy</a></p>
    </form>
    <div class="dk-done" id="st-done" tabindex="-1" hidden>
      <div class="dk-done-row"><svg aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b>Check your inbox</b><p>Confirm <span data-email>your address</span> and issue #212 is yours on Friday.</p></div></div>
    </div>
    <p class="dk-stat"><span class="dk-dot" aria-hidden="true"></span>Read by 41,800 engineers</p>
  </div>
</section>
</div>

<div class="demo-grid">
<div><span class="lbl">Star-field card with topics</span>
<section class="dk dk-sky" aria-labelledby="ns-title">
  <div class="dk-sky-head"><span>New moon edition</span></div>
  <div class="dk-sky-body">
    <h3 id="ns-title">Nightshift</h3>
    <p>What's worth looking up at this month, from a club of 300 amateur astronomers in the Peak District.</p>
    <form class="dk-form" action="#" method="post" data-nf="ns-done">
      <fieldset class="dk-set">
        <legend>Topics (optional)</legend>
        <div class="dk-chips">
          <label class="dk-chip"><input type="checkbox" name="topics" value="events" checked><svg aria-hidden="true"><use href="#dk-i-check"/></svg>Dark-sky events</label>
          <label class="dk-chip"><input type="checkbox" name="topics" value="gear"><svg aria-hidden="true"><use href="#dk-i-check"/></svg>Telescope reviews</label>
          <label class="dk-chip"><input type="checkbox" name="topics" value="photo" checked><svg aria-hidden="true"><use href="#dk-i-check"/></svg>Astrophotography</label>
          <label class="dk-chip"><input type="checkbox" name="topics" value="kids"><svg aria-hidden="true"><use href="#dk-i-check"/></svg>For kids</label>
        </div>
      </fieldset>
      <label class="dk-label" for="ns-email">Email address</label>
      <div class="dk-row">
        <input class="dk-input" id="ns-email" name="email" type="email" autocomplete="email" required aria-describedby="ns-email-err ns-hint" data-err="ns-email-err"
          data-missing="Enter your email address to subscribe." data-bad="Enter an email address with an @ and a domain, like [email protected].">
        <button class="dk-btn" type="submit">Join</button>
      </div>
      <p class="dk-err" id="ns-email-err"></p>
      <p class="dk-hint" id="ns-hint">One email around each new moon.</p>
    </form>
    <div class="dk-done" id="ns-done" tabindex="-1" hidden>
      <div class="dk-done-row"><svg aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b>Clear skies</b><p>Confirm <span data-email>your address</span> from the email we sent. The next edition goes out on 20 October.</p></div></div>
    </div>
  </div>
</section>
</div>

<div><span class="lbl">Gradient-edge card</span>
<section class="dk dk-edge" aria-labelledby="sn-title">
  <div class="dk-ep"><i aria-hidden="true"><svg><use href="#dk-i-wave"/></svg></i><div><h3 id="sn-title">Signal & Noise</h3><small>ep. 94 · 38 min</small></div></div>
  <p>Show notes, links and a transcript in your inbox the morning each episode drops.</p>
  <form class="dk-form" action="#" method="post" data-nf="sn-done">
    <label class="dk-label" for="sn-email">Email address</label>
    <input class="dk-input" id="sn-email" name="email" type="email" autocomplete="email" required aria-describedby="sn-email-err sn-hint" data-err="sn-email-err"
      data-missing="Enter your email address to get the show notes." data-bad="Enter an email address with an @ and a domain, like [email protected].">
    <p class="dk-err" id="sn-email-err"></p>
    <button class="dk-btn" type="submit">Get the show notes</button>
    <p class="dk-hint" id="sn-hint">Every other Tuesday. Leave whenever you like.</p>
  </form>
  <div class="dk-done" id="sn-done" tabindex="-1" hidden>
    <div class="dk-done-row"><svg aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b>You're in</b><p>Episode 95's notes will reach <span data-email>you</span> once you confirm.</p></div></div>
  </div>
</section>
</div>
</div>
CSS
/* Dark newsletter sign-ups. On a dark ground a light-theme form turns to mud, so every grey here is tuned:
   body text and hints stay above 4.5:1, field borders above 3:1, and the accent is a light colour with dark text
   on the button. Focus is a bright ring, errors use a light red that reads on the dark card. */
.dk{--dk-bg:#121826;--dk-field:#0b111d;--dk-ink:#e6eaf2;--dk-muted:#a3adc2;--dk-line:#66738f;--dk-edge:#263043;--dk-accent:#22d3ee;--dk-accent-ink:#062a33;
  --dk-ring:rgba(34,211,238,.35);--dk-error:#fca5a5;--dk-ok:#86efac;--dk-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  background:var(--dk-bg);color:var(--dk-ink);border:1px solid var(--dk-edge);border-radius:20px;padding:30px;font-size:.92rem;line-height:1.5;
  box-shadow:0 24px 60px -30px rgba(0,0,0,.8)}
.dk a{color:var(--dk-accent);font-weight:600;text-underline-offset:2px}
.dk a:focus-visible{outline:2px solid var(--dk-accent);outline-offset:2px;border-radius:3px}
.dk-label{display:block;font-size:.84rem;font-weight:650;margin-bottom:6px}
.dk-input{display:block;width:100%;min-width:0;font:inherit;color:var(--dk-ink);background:var(--dk-field);border:1.5px solid var(--dk-line);border-radius:10px;padding:10px 13px;
  transition:border-color .15s,box-shadow .15s}
.dk-input::placeholder{color:#8994ab;opacity:1}
.dk-input:focus{outline:none;border-color:var(--dk-accent);box-shadow:0 0 0 4px var(--dk-ring)}
.dk-input.is-invalid{border-color:var(--dk-error)}
.dk-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;font:inherit;font-weight:700;color:var(--dk-accent-ink);background:var(--dk-accent);border:0;border-radius:10px;
  padding:10px 18px;cursor:pointer;transition:background-color .15s,box-shadow .15s}
.dk-btn:hover{background:#67e8f9;box-shadow:0 0 24px -4px rgba(34,211,238,.6)}
.dk-btn:focus-visible{outline:2px solid var(--dk-accent);outline-offset:3px}
.dk-btn svg{width:18px;height:18px}
.dk-err{display:flex;gap:7px;align-items:flex-start;font-size:.82rem;font-weight:600;color:var(--dk-error);margin-top:7px}
.dk-err:empty{display:none}
.dk-err::before{content:"!";flex:none;display:grid;place-items:center;width:16px;height:16px;margin-top:2px;border-radius:50%;background:var(--dk-error);color:#3b0a0a;font-size:.7rem;font-weight:800}
.dk-hint{font-size:.8rem;color:var(--dk-muted);margin-top:8px}
.dk-done{outline:none}
.dk-done[hidden],.dk-form[hidden]{display:none}
.dk-done:focus-visible{outline:2px solid var(--dk-accent);outline-offset:4px;border-radius:12px}
.dk-done-row{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;border:1px solid rgba(134,239,172,.3);border-radius:12px;background:rgba(134,239,172,.08)}
.dk-done-row svg{flex:none;width:22px;height:22px;color:var(--dk-ok)}
.dk-done b{display:block}
.dk-done p{color:var(--dk-muted);font-size:.86rem}
.dk-done span[data-email]{color:var(--dk-ink);font-weight:600;overflow-wrap:anywhere}

/* 1. Developer newsletter bar */
.dk-dev{display:grid;grid-template-columns:1fr 1.1fr;gap:30px;align-items:center;padding:30px 32px;
  background:radial-gradient(120% 140% at 100% 0%,rgba(34,211,238,.12),transparent 55%),var(--dk-bg)}
.dk-mono{font-family:var(--dk-mono);font-size:.78rem;color:var(--dk-accent)}
.dk-dev h3{font-size:1.5rem;font-weight:750;letter-spacing:-.02em;line-height:1.2;margin:6px 0}
.dk-dev p:not(.dk-mono){color:var(--dk-muted)}
.dk-join{display:flex;gap:6px;padding:5px;background:var(--dk-field);border:1.5px solid var(--dk-line);border-radius:13px;transition:border-color .15s,box-shadow .15s}
.dk-join:focus-within{border-color:var(--dk-accent);box-shadow:0 0 0 4px var(--dk-ring)}
.dk-join:has(.is-invalid){border-color:var(--dk-error)}
.dk-join .dk-input,.dk-join .dk-input:focus{border:0;box-shadow:none;background:transparent;padding:9px 10px;font-family:var(--dk-mono);font-size:.88rem}
.dk-join .dk-btn{border-radius:9px}
.dk-stat{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:.8rem;color:var(--dk-muted)}
.dk-dot{width:8px;height:8px;border-radius:50%;background:var(--dk-ok);box-shadow:0 0 0 3px rgba(134,239,172,.18)}

/* 2. Card with a star-field header and topic chips */
.dk-sky{padding:0;overflow:hidden}
.dk-sky-head{position:relative;height:120px;padding:20px 24px;display:flex;align-items:flex-end;
  background:radial-gradient(1.5px 1.5px at 12% 30%,#fff,transparent),radial-gradient(1px 1px at 28% 62%,#fff,transparent),radial-gradient(1.5px 1.5px at 46% 22%,#fff,transparent),
    radial-gradient(1px 1px at 63% 48%,#fff,transparent),radial-gradient(2px 2px at 78% 26%,#fff,transparent),radial-gradient(1px 1px at 90% 66%,#fff,transparent),
    radial-gradient(1px 1px at 8% 80%,#fff,transparent),radial-gradient(1.5px 1.5px at 56% 82%,#fff,transparent),
    radial-gradient(ellipse at 70% 120%,rgba(167,139,250,.55),transparent 60%),linear-gradient(180deg,#0b1020,#1b1640)}
.dk-sky-head span{font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#c4b5fd;background:rgba(10,14,22,.6);border-radius:999px;padding:3px 10px}
.dk-sky-body{padding:22px 24px 24px}
.dk-sky h3{font-size:1.35rem;font-weight:750;letter-spacing:-.02em}
.dk-sky-body>p{color:var(--dk-muted);margin:4px 0 16px}
.dk-set{border:0;min-width:0;margin-bottom:16px}
.dk-set legend{font-size:.84rem;font-weight:650;padding:0;margin-bottom:8px}
.dk-chips{display:flex;flex-wrap:wrap;gap:8px}
.dk-chip{position:relative;display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1.5px solid var(--dk-line);border-radius:999px;font-size:.84rem;font-weight:600;color:var(--dk-ink);cursor:pointer;
  transition:background-color .15s,border-color .15s,color .15s}
.dk-chip input{position:absolute;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
.dk-chip svg{width:14px;height:14px;display:none}
.dk-chip:hover{border-color:#c4b5fd}
.dk-chip:has(:checked){background:#c4b5fd;border-color:#c4b5fd;color:#1e1240}
.dk-chip:has(:checked) svg{display:block}
.dk-chip:has(:focus-visible){outline:2px solid #c4b5fd;outline-offset:2px}
.dk-row{display:flex;gap:8px}
.dk-row .dk-input{flex:1 1 0}
.dk-sky .dk-btn{background:#c4b5fd;color:#1e1240}
.dk-sky .dk-btn:hover{background:#ddd6fe;box-shadow:0 0 24px -4px rgba(196,181,253,.6)}
.dk-sky .dk-btn:focus-visible{outline-color:#c4b5fd}
.dk-sky .dk-input:focus{border-color:#c4b5fd;box-shadow:0 0 0 4px rgba(196,181,253,.3)}

/* 3. Gradient-edged compact card */
.dk-edge{position:relative;border:1px solid transparent;
  background:linear-gradient(var(--dk-bg),var(--dk-bg)) padding-box,linear-gradient(135deg,#22d3ee,#a78bfa 50%,#f472b6) border-box}
.dk-edge h3{font-size:1.2rem;font-weight:750;letter-spacing:-.01em}
.dk-edge>p{color:var(--dk-muted);margin:4px 0 16px}
.dk-edge .dk-btn{width:100%;margin-top:10px}
.dk-ep{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.dk-ep i{flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:12px;background:linear-gradient(135deg,#22d3ee,#a78bfa);color:#0a0e16;font-style:normal}
.dk-ep svg{width:24px;height:24px}
.dk-ep small{display:block;font-family:var(--dk-mono);font-size:.74rem;color:var(--dk-muted)}

@media (max-width:640px){.dk-dev{grid-template-columns:1fr;gap:20px;padding:26px 22px}}
@media (max-width:420px){.dk{padding:22px 18px}.dk-dev{padding:22px 18px}.dk-sky{padding:0}.dk-sky-body{padding:20px 18px 22px}.dk-row{flex-direction:column}.dk-join .dk-btn{padding:9px 12px}}
@media (prefers-reduced-motion:reduce){.dk-input,.dk-btn,.dk-join,.dk-chip{transition:none}}
JavaScript
// Front-end demo only: nothing is sent. On submit the script checks each field that has data-err, writes the message
// into the element the input already points to with aria-describedby, and moves focus to the first problem.
// A valid submit swaps the form for its success state and focuses it. Replace that branch with your fetch() call.
// Without JavaScript the browser validates the form itself and posts it to the action URL.
(function () {
  function check(el) {
    var msg = el.checkValidity() ? '' : el.getAttribute(el.validity.valueMissing ? 'data-missing' : 'data-bad');
    var err = document.getElementById(el.getAttribute('data-err'));
    if (err) err.textContent = msg || '';
    el.classList.toggle('is-invalid', !!msg);
    if (msg) el.setAttribute('aria-invalid', 'true'); else el.removeAttribute('aria-invalid');
    return !msg;
  }
  document.querySelectorAll('form[data-nf]').forEach(function (form) {
    var done = document.getElementById(form.getAttribute('data-nf'));
    var email = form.querySelector('input[type=email]');
    form.noValidate = true;
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      var first = null;
      form.querySelectorAll('[data-err]').forEach(function (el) { if (!check(el) && !first) first = el; });
      if (first) { first.focus(); return; }
      done.querySelectorAll('[data-email]').forEach(function (n) { n.textContent = email.value; });
      form.hidden = true; done.hidden = false; done.focus();
    });
    form.addEventListener('input', function (e) { if (e.target.classList.contains('is-invalid')) check(e.target); });
  });
})();

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="dk-i-tick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.8 2.8L16.5 9.5"/></symbol>
  <symbol id="dk-i-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></symbol>
  <symbol id="dk-i-wave" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h2M7 8v8M11 5v14M15 9v6M19 11v2M21 12h0"/></symbol>
</svg>

<div><span class="lbl">Developer newsletter bar</span>
<section class="card dk dk-dev" data-bs-theme="dark" aria-labelledby="st-title"><div class="card-body">
  <div class="dk-pitch">
    <p class="dk-mono">// issue #212 ships Friday</p>
    <h3 id="st-title">Stack Trace Weekly</h3>
    <p>Five links worth your time on databases, performance and the occasional war story. No hot takes.</p>
  </div>
  <div>
    <form action="#" method="post" data-nf="st-done">
      <label class="form-label" for="st-email">Email address</label>
      <div class="input-group dk-join">
        <input class="form-control" id="st-email" name="email" type="email" autocomplete="email" required placeholder="[email protected]" aria-describedby="st-email-err st-hint" data-err="st-email-err"
          data-missing="Enter your email address to subscribe." data-bad="Enter an email address with an @ and a domain, like [email protected].">
        <button class="btn dk-btn" type="submit">Subscribe</button>
      </div>
      <p class="dk-err" id="st-email-err"></p>
      <p class="form-text" id="st-hint">Fridays only. Plain-text friendly. <a href="#privacy">Privacy</a></p>
    </form>
    <div class="dk-done" id="st-done" tabindex="-1" hidden>
      <div class="dk-done-row"><svg aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b>Check your inbox</b><p>Confirm <span data-email>your address</span> and issue #212 is yours on Friday.</p></div></div>
    </div>
    <p class="dk-stat"><span class="dk-dot" aria-hidden="true"></span>Read by 41,800 engineers</p>
  </div>
</div></section>
</div>

<div class="demo-grid">
<div><span class="lbl">Star-field card with topics</span>
<section class="card dk dk-sky" data-bs-theme="dark" aria-labelledby="ns-title">
  <div class="dk-sky-head"><span class="badge rounded-pill">New moon edition</span></div>
  <div class="card-body">
    <h3 id="ns-title">Nightshift</h3>
    <p class="dk-sky-intro">What's worth looking up at this month, from a club of 300 amateur astronomers in the Peak District.</p>
    <form action="#" method="post" data-nf="ns-done">
      <fieldset class="dk-set">
        <legend>Topics (optional)</legend>
        <div class="d-flex flex-wrap gap-2">
          <input class="btn-check" type="checkbox" name="topics" value="events" id="ns-t1" checked><label class="btn dk-chip" for="ns-t1"><svg aria-hidden="true"><use href="#dk-i-check"/></svg>Dark-sky events</label>
          <input class="btn-check" type="checkbox" name="topics" value="gear" id="ns-t2"><label class="btn dk-chip" for="ns-t2"><svg aria-hidden="true"><use href="#dk-i-check"/></svg>Telescope reviews</label>
          <input class="btn-check" type="checkbox" name="topics" value="photo" id="ns-t3" checked><label class="btn dk-chip" for="ns-t3"><svg aria-hidden="true"><use href="#dk-i-check"/></svg>Astrophotography</label>
          <input class="btn-check" type="checkbox" name="topics" value="kids" id="ns-t4"><label class="btn dk-chip" for="ns-t4"><svg aria-hidden="true"><use href="#dk-i-check"/></svg>For kids</label>
        </div>
      </fieldset>
      <label class="form-label" for="ns-email">Email address</label>
      <div class="d-flex gap-2 dk-row">
        <input class="form-control" id="ns-email" name="email" type="email" autocomplete="email" required aria-describedby="ns-email-err ns-hint" data-err="ns-email-err"
          data-missing="Enter your email address to subscribe." data-bad="Enter an email address with an @ and a domain, like [email protected].">
        <button class="btn dk-btn" type="submit">Join</button>
      </div>
      <p class="dk-err" id="ns-email-err"></p>
      <p class="form-text" id="ns-hint">One email around each new moon.</p>
    </form>
    <div class="dk-done" id="ns-done" tabindex="-1" hidden>
      <div class="dk-done-row"><svg aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b>Clear skies</b><p>Confirm <span data-email>your address</span> from the email we sent. The next edition goes out on 20 October.</p></div></div>
    </div>
  </div>
</section>
</div>

<div><span class="lbl">Gradient-edge card</span>
<section class="card dk dk-edge" data-bs-theme="dark" aria-labelledby="sn-title"><div class="card-body">
  <div class="dk-ep"><i aria-hidden="true"><svg><use href="#dk-i-wave"/></svg></i><div><h3 id="sn-title">Signal & Noise</h3><small>ep. 94 · 38 min</small></div></div>
  <p class="dk-edge-intro">Show notes, links and a transcript in your inbox the morning each episode drops.</p>
  <form action="#" method="post" data-nf="sn-done">
    <label class="form-label" for="sn-email">Email address</label>
    <input class="form-control" id="sn-email" name="email" type="email" autocomplete="email" required aria-describedby="sn-email-err sn-hint" data-err="sn-email-err"
      data-missing="Enter your email address to get the show notes." data-bad="Enter an email address with an @ and a domain, like [email protected].">
    <p class="dk-err" id="sn-email-err"></p>
    <button class="btn dk-btn" type="submit">Get the show notes</button>
    <p class="form-text" id="sn-hint">Every other Tuesday. Leave whenever you like.</p>
  </form>
  <div class="dk-done" id="sn-done" tabindex="-1" hidden>
    <div class="dk-done-row"><svg aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b>You're in</b><p>Episode 95's notes will reach <span data-email>you</span> once you confirm.</p></div></div>
  </div>
</div></section>
</div>
</div>
CSS
/* Bootstrap's dark colour mode (data-bs-theme="dark") with .card, .form-control, .input-group, .btn-check + .btn chips,
   .btn and .form-text, retuned through Bootstrap's CSS variables so greys, borders and focus keep their contrast. */
.dk{--dk-bg:#121826;--dk-field:#0b111d;--dk-ink:#e6eaf2;--dk-muted:#a3adc2;--dk-line:#66738f;--dk-edge:#263043;--dk-accent:#22d3ee;--dk-accent-ink:#062a33;
  --dk-ring:rgba(34,211,238,.35);--dk-error:#fca5a5;--dk-ok:#86efac;--dk-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --bs-body-bg:var(--dk-bg);--bs-body-color:var(--dk-ink);--bs-card-bg:var(--dk-bg);--bs-card-color:var(--dk-ink);--bs-card-border-color:var(--dk-edge);--bs-card-border-radius:20px;
  --bs-card-spacer-x:30px;--bs-card-spacer-y:30px;color:var(--dk-ink);font-size:.92rem;line-height:1.5;box-shadow:0 24px 60px -30px rgba(0,0,0,.8)}
.dk p,.dk h3,.dk legend{margin:0}
.dk a{color:var(--dk-accent);font-weight:600;text-underline-offset:2px}
.dk a:focus-visible{outline:2px solid var(--dk-accent);outline-offset:2px;border-radius:3px}
.dk .form-label{display:block;font-size:.84rem;font-weight:650;margin-bottom:6px}
.dk .form-control{min-width:0;font-size:inherit;line-height:inherit;color:var(--dk-ink);background-color:var(--dk-field);border:1.5px solid var(--dk-line);border-radius:10px;padding:10px 13px;
  transition:border-color .15s,box-shadow .15s}
.dk .form-control::placeholder{color:#8994ab;opacity:1}
.dk .form-control:focus{border-color:var(--dk-accent);box-shadow:0 0 0 4px var(--dk-ring)}
.dk .form-control.is-invalid{border-color:var(--dk-error);background-image:none;padding-right:13px}
.dk .dk-btn{--bs-btn-color:var(--dk-accent-ink);--bs-btn-bg:var(--dk-accent);--bs-btn-border-color:var(--dk-accent);--bs-btn-hover-color:var(--dk-accent-ink);--bs-btn-hover-bg:#67e8f9;
  --bs-btn-hover-border-color:#67e8f9;--bs-btn-active-color:var(--dk-accent-ink);--bs-btn-active-bg:#67e8f9;--bs-btn-active-border-color:#67e8f9;--bs-btn-focus-box-shadow:none;
  --bs-btn-font-weight:700;--bs-btn-font-size:.92rem;--bs-btn-line-height:1.5;--bs-btn-padding-x:18px;--bs-btn-padding-y:10px;--bs-btn-border-width:0;--bs-btn-border-radius:10px;
  flex:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;transition:background-color .15s,box-shadow .15s}
.dk .dk-btn:hover{box-shadow:0 0 24px -4px rgba(34,211,238,.6)}
.dk .dk-btn:focus-visible{outline:2px solid var(--dk-accent);outline-offset:3px}
.dk .dk-err{display:flex;gap:7px;align-items:flex-start;font-size:.82rem;font-weight:600;color:var(--dk-error);margin-top:7px}
.dk .dk-err:empty{display:none}
.dk .dk-err::before{content:"!";flex:none;display:grid;place-items:center;width:16px;height:16px;margin-top:2px;border-radius:50%;background:var(--dk-error);color:#3b0a0a;font-size:.7rem;font-weight:800}
.dk .form-text{font-size:.8rem;color:var(--dk-muted);margin-top:8px}
.dk .dk-done{outline:none}
.dk .dk-done[hidden],.dk form[hidden]{display:none}
.dk .dk-done:focus-visible{outline:2px solid var(--dk-accent);outline-offset:4px;border-radius:12px}
.dk-done-row{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;border:1px solid rgba(134,239,172,.3);border-radius:12px;background:rgba(134,239,172,.08)}
.dk-done-row svg{flex:none;width:22px;height:22px;color:var(--dk-ok)}
.dk-done b{display:block}
.dk .dk-done p{color:var(--dk-muted);font-size:.86rem}
.dk-done span[data-email]{color:var(--dk-ink);font-weight:600;overflow-wrap:anywhere}

/* 1. Developer newsletter bar */
.dk-dev .card-body{display:grid;grid-template-columns:1fr 1.1fr;gap:30px;align-items:center;padding:30px 32px}
.dk-dev{background:radial-gradient(120% 140% at 100% 0%,rgba(34,211,238,.12),transparent 55%),var(--dk-bg)}
.dk .dk-mono{font-family:var(--dk-mono);font-size:.78rem;color:var(--dk-accent)}
.dk-dev h3{font-size:1.5rem;font-weight:750;letter-spacing:-.02em;line-height:1.2;margin:6px 0!important}
.dk-dev .dk-pitch p:not(.dk-mono){color:var(--dk-muted)}
.dk .dk-join{flex-wrap:nowrap;gap:6px;padding:5px;background:var(--dk-field);border:1.5px solid var(--dk-line);border-radius:13px;transition:border-color .15s,box-shadow .15s}
.dk .dk-join:focus-within{border-color:var(--dk-accent);box-shadow:0 0 0 4px var(--dk-ring)}
.dk .dk-join:has(.is-invalid){border-color:var(--dk-error)}
.dk .dk-join>.form-control,.dk .dk-join>.form-control:focus{border:0;box-shadow:none;background:transparent;padding:9px 10px;font-family:var(--dk-mono);font-size:.88rem;border-radius:9px!important}
.dk .dk-join>.dk-btn{border-radius:9px!important;margin-left:0!important}
.dk .dk-stat{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:.8rem;color:var(--dk-muted)}
.dk-dot{width:8px;height:8px;border-radius:50%;background:var(--dk-ok);box-shadow:0 0 0 3px rgba(134,239,172,.18)}

/* 2. Star-field card with topic chips */
.dk-sky{overflow:hidden}
.dk-sky-head{position:relative;height:120px;padding:20px 24px;display:flex;align-items:flex-end;
  background:radial-gradient(1.5px 1.5px at 12% 30%,#fff,transparent),radial-gradient(1px 1px at 28% 62%,#fff,transparent),radial-gradient(1.5px 1.5px at 46% 22%,#fff,transparent),
    radial-gradient(1px 1px at 63% 48%,#fff,transparent),radial-gradient(2px 2px at 78% 26%,#fff,transparent),radial-gradient(1px 1px at 90% 66%,#fff,transparent),
    radial-gradient(1px 1px at 8% 80%,#fff,transparent),radial-gradient(1.5px 1.5px at 56% 82%,#fff,transparent),
    radial-gradient(ellipse at 70% 120%,rgba(167,139,250,.55),transparent 60%),linear-gradient(180deg,#0b1020,#1b1640)}
.dk-sky-head .badge{--bs-badge-font-size:.72rem;--bs-badge-font-weight:700;--bs-badge-padding-x:10px;--bs-badge-padding-y:3px;--bs-badge-color:#c4b5fd;letter-spacing:.12em;text-transform:uppercase;background:rgba(10,14,22,.6);line-height:1.5}
.dk-sky .card-body{padding:22px 24px 24px}
.dk-sky h3{font-size:1.35rem;font-weight:750;letter-spacing:-.02em}
.dk .dk-sky-intro{color:var(--dk-muted);margin:4px 0 16px}
.dk-set{min-width:0;margin-bottom:16px}
.dk .dk-set legend{float:none;width:auto;font-size:.84rem;font-weight:650;line-height:1.5;padding:0;margin-bottom:8px}
.dk .dk-chip{--bs-btn-color:var(--dk-ink);--bs-btn-border-color:var(--dk-line);--bs-btn-hover-color:var(--dk-ink);--bs-btn-hover-bg:transparent;--bs-btn-hover-border-color:#c4b5fd;
  --bs-btn-active-color:#1e1240;--bs-btn-active-bg:#c4b5fd;--bs-btn-active-border-color:#c4b5fd;--bs-btn-focus-box-shadow:none;--bs-btn-font-size:.84rem;--bs-btn-font-weight:600;
  --bs-btn-line-height:1.5;--bs-btn-padding-x:12px;--bs-btn-padding-y:6px;--bs-btn-border-width:1.5px;--bs-btn-border-radius:999px;display:inline-flex;align-items:center;gap:6px;
  transition:background-color .15s,border-color .15s,color .15s}
.dk .dk-chip svg{width:14px;height:14px;display:none}
.dk .btn-check:checked+.dk-chip svg{display:block}
.dk .btn-check:focus-visible+.dk-chip{outline:2px solid #c4b5fd;outline-offset:2px;box-shadow:none}
.dk-sky .dk-btn{--bs-btn-color:#1e1240;--bs-btn-bg:#c4b5fd;--bs-btn-hover-color:#1e1240;--bs-btn-hover-bg:#ddd6fe;--bs-btn-active-color:#1e1240;--bs-btn-active-bg:#ddd6fe}
.dk-sky .dk-btn:hover{box-shadow:0 0 24px -4px rgba(196,181,253,.6)}
.dk-sky .dk-btn:focus-visible{outline-color:#c4b5fd}
.dk-sky .form-control:focus{border-color:#c4b5fd;box-shadow:0 0 0 4px rgba(196,181,253,.3)}
.dk .dk-row .form-control{flex:1 1 0}

/* 3. Gradient-edged compact card */
.dk-edge{border:1px solid transparent;background:linear-gradient(var(--dk-bg),var(--dk-bg)) padding-box,linear-gradient(135deg,#22d3ee,#a78bfa 50%,#f472b6) border-box}
.dk-edge h3{font-size:1.2rem;font-weight:750;letter-spacing:-.01em}
.dk .dk-edge-intro{color:var(--dk-muted);margin:4px 0 16px}
.dk-edge .dk-btn{width:100%;margin-top:10px}
.dk-ep{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.dk-ep i{flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:12px;background:linear-gradient(135deg,#22d3ee,#a78bfa);color:#0a0e16;font-style:normal}
.dk-ep svg{width:24px;height:24px}
.dk-ep small{display:block;font-family:var(--dk-mono);font-size:.74rem;color:var(--dk-muted)}

@media (max-width:640px){.dk-dev .card-body{grid-template-columns:1fr;gap:20px;padding:26px 22px}}
@media (max-width:420px){.dk{--bs-card-spacer-x:18px;--bs-card-spacer-y:22px}.dk-dev .card-body{padding:22px 18px}.dk-sky .card-body{padding:20px 18px 22px}.dk .dk-row{flex-direction:column}
  .dk .dk-join>.dk-btn{--bs-btn-padding-x:12px;--bs-btn-padding-y:9px}}
@media (prefers-reduced-motion:reduce){.dk .form-control,.dk .dk-btn,.dk .dk-join,.dk .dk-chip{transition:none}}
JavaScript
// Front-end demo only: nothing is sent. On submit the script checks each field that has data-err, writes the message
// into the element the input already points to with aria-describedby, and moves focus to the first problem.
// A valid submit swaps the form for its success state and focuses it. Replace that branch with your fetch() call.
// Without JavaScript the browser validates the form itself and posts it to the action URL.
(function () {
  function check(el) {
    var msg = el.checkValidity() ? '' : el.getAttribute(el.validity.valueMissing ? 'data-missing' : 'data-bad');
    var err = document.getElementById(el.getAttribute('data-err'));
    if (err) err.textContent = msg || '';
    el.classList.toggle('is-invalid', !!msg);
    if (msg) el.setAttribute('aria-invalid', 'true'); else el.removeAttribute('aria-invalid');
    return !msg;
  }
  document.querySelectorAll('form[data-nf]').forEach(function (form) {
    var done = document.getElementById(form.getAttribute('data-nf'));
    var email = form.querySelector('input[type=email]');
    form.noValidate = true;
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      var first = null;
      form.querySelectorAll('[data-err]').forEach(function (el) { if (!check(el) && !first) first = el; });
      if (first) { first.focus(); return; }
      done.querySelectorAll('[data-email]').forEach(function (n) { n.textContent = email.value; });
      form.hidden = true; done.hidden = false; done.focus();
    });
    form.addEventListener('input', function (e) { if (e.target.classList.contains('is-invalid')) check(e.target); });
  });
})();

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="dk-i-tick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.8 2.8L16.5 9.5"/></symbol>
  <symbol id="dk-i-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></symbol>
  <symbol id="dk-i-wave" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h2M7 8v8M11 5v14M15 9v6M19 11v2M21 12h0"/></symbol>
</svg>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#9aa4b8] uppercase">Developer newsletter bar</span>
<section class="grid grid-cols-[1fr_1.1fr] items-center gap-[30px] rounded-[20px] border border-dk-edge bg-dk-bg bg-dk-glow px-8 py-[30px] text-[.92rem] leading-normal text-dk-ink shadow-[0_24px_60px_-30px_rgba(0,0,0,.8)] max-[640px]:grid-cols-1 max-[640px]:gap-5 max-[640px]:px-[22px] max-[640px]:py-[26px] max-[420px]:px-[18px] max-[420px]:py-[22px]" aria-labelledby="st-title">
  <div>
    <p class="font-dk-mono text-[.78rem] text-dk-accent">// issue #212 ships Friday</p>
    <h3 class="my-1.5 text-[1.5rem] leading-[1.2] font-[750] tracking-[-.02em]" id="st-title">Stack Trace Weekly</h3>
    <p class="text-dk-muted">Five links worth your time on databases, performance and the occasional war story. No hot takes.</p>
  </div>
  <div>
    <form action="#" method="post" data-nf="st-done">
      <label class="mb-1.5 block text-[.84rem] font-[650]" for="st-email">Email address</label>
      <div class="flex gap-1.5 rounded-[13px] border-[1.5px] border-dk-line bg-dk-field p-[5px] transition-[border-color,box-shadow] duration-150 focus-within:border-dk-accent focus-within:shadow-[0_0_0_4px_rgba(34,211,238,.35)] has-[.is-invalid]:border-dk-error motion-reduce:transition-none">
        <input class="block w-full min-w-0 bg-transparent px-2.5 py-[9px] font-dk-mono text-[.88rem] text-dk-ink placeholder:text-[#8994ab] focus:outline-none" id="st-email" name="email" type="email" autocomplete="email" required placeholder="[email protected]" aria-describedby="st-email-err st-hint" data-err="st-email-err"
          data-missing="Enter your email address to subscribe." data-bad="Enter an email address with an @ and a domain, like [email protected].">
        <button class="inline-flex flex-none cursor-pointer items-center justify-center gap-2 rounded-[9px] bg-dk-accent px-[18px] py-2.5 font-bold text-dk-accent-ink transition-[background-color,box-shadow] duration-150 hover:bg-[#67e8f9] hover:shadow-[0_0_24px_-4px_rgba(34,211,238,.6)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-dk-accent motion-reduce:transition-none max-[420px]:px-3 max-[420px]:py-[9px]" type="submit">Subscribe</button>
      </div>
      <p class="mt-[7px] flex items-start gap-[7px] text-[.82rem] font-semibold text-dk-error empty:hidden before:mt-0.5 before:grid before:size-4 before:flex-none before:place-items-center before:rounded-full before:bg-dk-error before:text-[.7rem] before:font-extrabold before:text-[#3b0a0a] before:content-['!']" id="st-email-err"></p>
      <p class="mt-2 text-[.8rem] text-dk-muted" id="st-hint">Fridays only. Plain-text friendly. <a class="font-semibold text-dk-accent underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dk-accent" href="#privacy">Privacy</a></p>
    </form>
    <div class="focus-visible:rounded-xl focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-dk-accent" id="st-done" tabindex="-1" hidden>
      <div class="flex items-start gap-3 rounded-xl border border-[rgba(134,239,172,.3)] bg-[rgba(134,239,172,.08)] px-4 py-3.5"><svg class="size-[22px] flex-none text-dk-ok" aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b class="block">Check your inbox</b><p class="text-[.86rem] text-dk-muted">Confirm <span class="font-semibold wrap-anywhere text-dk-ink" data-email>your address</span> and issue #212 is yours on Friday.</p></div></div>
    </div>
    <p class="mt-3 flex items-center gap-2 text-[.8rem] text-dk-muted"><span class="size-2 rounded-full bg-dk-ok shadow-[0_0_0_3px_rgba(134,239,172,.18)]" aria-hidden="true"></span>Read by 41,800 engineers</p>
  </div>
</section>
</div>

<div class="grid grid-cols-[repeat(auto-fit,minmax(300px,1fr))] items-start gap-[34px]">
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#9aa4b8] uppercase">Star-field card with topics</span>
<section class="overflow-hidden rounded-[20px] border border-dk-edge bg-dk-bg text-[.92rem] leading-normal text-dk-ink shadow-[0_24px_60px_-30px_rgba(0,0,0,.8)]" aria-labelledby="ns-title">
  <div class="relative flex h-[120px] items-end bg-dk-stars px-6 py-5"><span class="rounded-full bg-[rgba(10,14,22,.6)] px-2.5 py-[3px] text-[.72rem] font-bold tracking-[.12em] text-dk-violet uppercase">New moon edition</span></div>
  <div class="px-6 pt-[22px] pb-6 max-[420px]:px-[18px] max-[420px]:pt-5 max-[420px]:pb-[22px]">
    <h3 class="text-[1.35rem] font-[750] tracking-[-.02em]" id="ns-title">Nightshift</h3>
    <p class="mt-1 mb-4 text-dk-muted">What's worth looking up at this month, from a club of 300 amateur astronomers in the Peak District.</p>
    <form action="#" method="post" data-nf="ns-done">
      <fieldset class="mb-4 min-w-0">
        <legend class="mb-2 text-[.84rem] font-[650]">Topics (optional)</legend>
        <div class="flex flex-wrap gap-2">
          <label class="group relative inline-flex cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-dk-line px-3 py-1.5 text-[.84rem] font-semibold transition-colors duration-150 hover:border-dk-violet has-checked:border-dk-violet has-checked:bg-dk-violet has-checked:text-dk-violet-ink has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-dk-violet motion-reduce:transition-none"><input class="sr-only" type="checkbox" name="topics" value="events" checked><svg class="hidden size-3.5 group-has-checked:block" aria-hidden="true"><use href="#dk-i-check"/></svg>Dark-sky events</label>
          <label class="group relative inline-flex cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-dk-line px-3 py-1.5 text-[.84rem] font-semibold transition-colors duration-150 hover:border-dk-violet has-checked:border-dk-violet has-checked:bg-dk-violet has-checked:text-dk-violet-ink has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-dk-violet motion-reduce:transition-none"><input class="sr-only" type="checkbox" name="topics" value="gear"><svg class="hidden size-3.5 group-has-checked:block" aria-hidden="true"><use href="#dk-i-check"/></svg>Telescope reviews</label>
          <label class="group relative inline-flex cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-dk-line px-3 py-1.5 text-[.84rem] font-semibold transition-colors duration-150 hover:border-dk-violet has-checked:border-dk-violet has-checked:bg-dk-violet has-checked:text-dk-violet-ink has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-dk-violet motion-reduce:transition-none"><input class="sr-only" type="checkbox" name="topics" value="photo" checked><svg class="hidden size-3.5 group-has-checked:block" aria-hidden="true"><use href="#dk-i-check"/></svg>Astrophotography</label>
          <label class="group relative inline-flex cursor-pointer items-center gap-1.5 rounded-full border-[1.5px] border-dk-line px-3 py-1.5 text-[.84rem] font-semibold transition-colors duration-150 hover:border-dk-violet has-checked:border-dk-violet has-checked:bg-dk-violet has-checked:text-dk-violet-ink has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-dk-violet motion-reduce:transition-none"><input class="sr-only" type="checkbox" name="topics" value="kids"><svg class="hidden size-3.5 group-has-checked:block" aria-hidden="true"><use href="#dk-i-check"/></svg>For kids</label>
        </div>
      </fieldset>
      <label class="mb-1.5 block text-[.84rem] font-[650]" for="ns-email">Email address</label>
      <div class="flex gap-2 max-[420px]:flex-col">
        <input class="block w-full min-w-0 flex-1 basis-0 rounded-[10px] border-[1.5px] border-dk-line bg-dk-field px-[13px] py-2.5 text-dk-ink transition-[border-color,box-shadow] duration-150 focus:border-dk-violet focus:shadow-[0_0_0_4px_rgba(196,181,253,.3)] focus:outline-none [&.is-invalid]:border-dk-error motion-reduce:transition-none max-[420px]:basis-auto" id="ns-email" name="email" type="email" autocomplete="email" required aria-describedby="ns-email-err ns-hint" data-err="ns-email-err"
          data-missing="Enter your email address to subscribe." data-bad="Enter an email address with an @ and a domain, like [email protected].">
        <button class="inline-flex flex-none cursor-pointer items-center justify-center rounded-[10px] bg-dk-violet px-[18px] py-2.5 font-bold text-dk-violet-ink transition-[background-color,box-shadow] duration-150 hover:bg-[#ddd6fe] hover:shadow-[0_0_24px_-4px_rgba(196,181,253,.6)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-dk-violet motion-reduce:transition-none" type="submit">Join</button>
      </div>
      <p class="mt-[7px] flex items-start gap-[7px] text-[.82rem] font-semibold text-dk-error empty:hidden before:mt-0.5 before:grid before:size-4 before:flex-none before:place-items-center before:rounded-full before:bg-dk-error before:text-[.7rem] before:font-extrabold before:text-[#3b0a0a] before:content-['!']" id="ns-email-err"></p>
      <p class="mt-2 text-[.8rem] text-dk-muted" id="ns-hint">One email around each new moon.</p>
    </form>
    <div class="focus-visible:rounded-xl focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-dk-violet" id="ns-done" tabindex="-1" hidden>
      <div class="flex items-start gap-3 rounded-xl border border-[rgba(134,239,172,.3)] bg-[rgba(134,239,172,.08)] px-4 py-3.5"><svg class="size-[22px] flex-none text-dk-ok" aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b class="block">Clear skies</b><p class="text-[.86rem] text-dk-muted">Confirm <span class="font-semibold wrap-anywhere text-dk-ink" data-email>your address</span> from the email we sent. The next edition goes out on 20 October.</p></div></div>
    </div>
  </div>
</section>
</div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#9aa4b8] uppercase">Gradient-edge card</span>
<section class="rounded-[20px] border border-transparent bg-dk-ring p-[30px] text-[.92rem] leading-normal text-dk-ink shadow-[0_24px_60px_-30px_rgba(0,0,0,.8)] [background-clip:padding-box,border-box] [background-origin:padding-box,border-box] max-[420px]:px-[18px] max-[420px]:py-[22px]" aria-labelledby="sn-title">
  <div class="mb-3.5 flex items-center gap-3"><i class="grid size-11 flex-none place-items-center rounded-xl bg-[linear-gradient(135deg,#22d3ee,#a78bfa)] text-[#0a0e16] not-italic" aria-hidden="true"><svg class="size-6"><use href="#dk-i-wave"/></svg></i><div><h3 class="text-[1.2rem] font-[750] tracking-[-.01em]" id="sn-title">Signal & Noise</h3><small class="block font-dk-mono text-[.74rem] text-dk-muted">ep. 94 · 38 min</small></div></div>
  <p class="mt-1 mb-4 text-dk-muted">Show notes, links and a transcript in your inbox the morning each episode drops.</p>
  <form action="#" method="post" data-nf="sn-done">
    <label class="mb-1.5 block text-[.84rem] font-[650]" for="sn-email">Email address</label>
    <input class="block w-full min-w-0 rounded-[10px] border-[1.5px] border-dk-line bg-dk-field px-[13px] py-2.5 text-dk-ink transition-[border-color,box-shadow] duration-150 focus:border-dk-accent focus:shadow-[0_0_0_4px_rgba(34,211,238,.35)] focus:outline-none [&.is-invalid]:border-dk-error motion-reduce:transition-none" id="sn-email" name="email" type="email" autocomplete="email" required aria-describedby="sn-email-err sn-hint" data-err="sn-email-err"
      data-missing="Enter your email address to get the show notes." data-bad="Enter an email address with an @ and a domain, like [email protected].">
    <p class="mt-[7px] flex items-start gap-[7px] text-[.82rem] font-semibold text-dk-error empty:hidden before:mt-0.5 before:grid before:size-4 before:flex-none before:place-items-center before:rounded-full before:bg-dk-error before:text-[.7rem] before:font-extrabold before:text-[#3b0a0a] before:content-['!']" id="sn-email-err"></p>
    <button class="mt-2.5 inline-flex w-full cursor-pointer items-center justify-center rounded-[10px] bg-dk-accent px-[18px] py-2.5 font-bold text-dk-accent-ink transition-[background-color,box-shadow] duration-150 hover:bg-[#67e8f9] hover:shadow-[0_0_24px_-4px_rgba(34,211,238,.6)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-dk-accent motion-reduce:transition-none" type="submit">Get the show notes</button>
    <p class="mt-2 text-[.8rem] text-dk-muted" id="sn-hint">Every other Tuesday. Leave whenever you like.</p>
  </form>
  <div class="focus-visible:rounded-xl focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-dk-accent" id="sn-done" tabindex="-1" hidden>
    <div class="flex items-start gap-3 rounded-xl border border-[rgba(134,239,172,.3)] bg-[rgba(134,239,172,.08)] px-4 py-3.5"><svg class="size-[22px] flex-none text-dk-ok" aria-hidden="true"><use href="#dk-i-tick"/></svg><div><b class="block">You're in</b><p class="text-[.86rem] text-dk-muted">Episode 95's notes will reach <span class="font-semibold wrap-anywhere text-dk-ink" data-email>you</span> once you confirm.</p></div></div>
  </div>
</section>
</div>
</div>
CSS
@theme {
  --color-dk-bg: #121826;
  --color-dk-field: #0b111d;
  --color-dk-ink: #e6eaf2;
  --color-dk-muted: #a3adc2;
  --color-dk-line: #66738f;
  --color-dk-edge: #263043;
  --color-dk-accent: #22d3ee;
  --color-dk-accent-ink: #062a33;
  --color-dk-violet: #c4b5fd;
  --color-dk-violet-ink: #1e1240;
  --color-dk-error: #fca5a5;
  --color-dk-ok: #86efac;
  --font-dk-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --background-image-dk-stars: radial-gradient(1.5px 1.5px at 12% 30%, #fff, transparent), radial-gradient(1px 1px at 28% 62%, #fff, transparent), radial-gradient(1.5px 1.5px at 46% 22%, #fff, transparent), radial-gradient(1px 1px at 63% 48%, #fff, transparent), radial-gradient(2px 2px at 78% 26%, #fff, transparent), radial-gradient(1px 1px at 90% 66%, #fff, transparent), radial-gradient(1px 1px at 8% 80%, #fff, transparent), radial-gradient(1.5px 1.5px at 56% 82%, #fff, transparent), radial-gradient(ellipse at 70% 120%, rgba(167,139,250,.55), transparent 60%), linear-gradient(180deg, #0b1020, #1b1640);
  --background-image-dk-glow: radial-gradient(120% 140% at 100% 0%, rgba(34,211,238,.12), transparent 55%);
  --background-image-dk-ring: linear-gradient(#121826, #121826), linear-gradient(135deg, #22d3ee, #a78bfa 50%, #f472b6);
}
JavaScript
// Front-end demo only: nothing is sent. On submit the script checks each field that has data-err, writes the message
// into the element the input already points to with aria-describedby, and moves focus to the first problem.
// A valid submit swaps the form for its success state and focuses it. Replace that branch with your fetch() call.
// Without JavaScript the browser validates the form itself and posts it to the action URL.
(function () {
  function check(el) {
    var msg = el.checkValidity() ? '' : el.getAttribute(el.validity.valueMissing ? 'data-missing' : 'data-bad');
    var err = document.getElementById(el.getAttribute('data-err'));
    if (err) err.textContent = msg || '';
    el.classList.toggle('is-invalid', !!msg);
    if (msg) el.setAttribute('aria-invalid', 'true'); else el.removeAttribute('aria-invalid');
    return !msg;
  }
  document.querySelectorAll('form[data-nf]').forEach(function (form) {
    var done = document.getElementById(form.getAttribute('data-nf'));
    var email = form.querySelector('input[type=email]');
    form.noValidate = true;
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      var first = null;
      form.querySelectorAll('[data-err]').forEach(function (el) { if (!check(el) && !first) first = el; });
      if (first) { first.focus(); return; }
      done.querySelectorAll('[data-email]').forEach(function (n) { n.textContent = email.value; });
      form.hidden = true; done.hidden = false; done.focus();
    });
    form.addEventListener('input', function (e) { if (e.target.classList.contains('is-invalid')) check(e.target); });
  });
})();

About this set

Three newsletter sign-ups for dark sites and apps, where a light-theme form loses its contrast. Developer newsletter bar is a two-column band with a monospace issue line, a joined field and button with a cyan glow on focus, a privacy link and a reader count. Star-field card has a night-sky header drawn with layered radial gradients, optional topic chips in lavender, an email row and a Join button. Gradient-edge card wraps a podcast show-notes sign-up in a cyan to pink border made with two background layers, no extra elements. Every grey is tuned against its background: body text and hints stay above 4.5:1, field borders above 3:1, buttons use a light accent with dark text, and errors use a light red that reads on the dark card. The Bootstrap version runs in Bootstrap’s own dark colour mode with data-bs-theme=”dark”. A short vanilla script validates the address, writes the error into the linked message and swaps in a green-tinted confirmation. Nothing is sent.

What’s included

  • Contrast-checked greys, borders and error colour on dark
  • Joined field with a focus glow
  • Star-field header and gradient border with CSS only
  • Optional topic chips from real checkboxes
  • Bootstrap version uses data-bs-theme="dark", .btn-check chips and .input-group

Accessibility

Each email field has a visible label, autocomplete="email", and its hint and error linked with aria-describedby; errors set aria-invalid and move focus to the field, and the confirmation is focused when it appears. Topic chips are checkboxes in a fieldset with a legend and show focus through :has(:focus-visible). Every control has a bright focus ring, and transitions switch off under prefers-reduced-motion.

Customise it

Change --dk-bg, --dk-field, --dk-line and --dk-muted on .dk for the surface, and --dk-accent with --dk-accent-ink for the button; the star-field card uses #c4b5fd for its accent. In Tailwind edit the dk-* colours and the dk-stars and dk-ring images in @theme.