Open demo

CSS code

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="neu-i-power" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v8"/><path d="M6.3 6.8a8 8 0 1 0 11.4 0"/></symbol>
  <symbol id="neu-i-x" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.5 6.5l11 11M17.5 6.5l-11 11"/></symbol>
  <symbol id="neu-i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.8h.01"/></symbol>
  <symbol id="neu-i-checkCircle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="m8 12.3 2.8 2.8L16.2 9.5"/></symbol>
  <symbol id="neu-i-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4 2.8 19.5h18.4z"/><path d="M12 10v4.5M12 17.2h.01"/></symbol>
  <symbol id="neu-i-xCircle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="m9 9 6 6M15 9l-6 6"/></symbol>
  <symbol id="neu-i-film" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5" width="17" height="14" rx="2"/><path d="M3.5 9.5h17M8 5l2 4.5M13 5l2 4.5"/></symbol>
  <symbol id="neu-i-lock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="10.5" width="14" height="10" rx="2"/><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/></symbol>
  <symbol id="neu-i-leaf" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 20c0-9 5.5-14 15-15-.5 9.5-6 15-15 15z"/><path d="M5 20c3.5-4.5 6.5-7 10-8.5"/></symbol>
  <symbol id="neu-i-help" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9.6 9.3a2.5 2.5 0 0 1 4.8 1c0 1.7-2.4 2.2-2.4 3.7M12 17.2h.01"/></symbol>
  <symbol id="neu-i-sofa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 11V8a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v3"/><path d="M3 12a2 2 0 0 1 4 0v2h10v-2a2 2 0 0 1 4 0v5H3z"/><path d="M5 17v2M19 17v2"/></symbol>
  <symbol id="neu-i-chevDown" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></symbol>
  <symbol id="neu-i-edit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="m13.5 6.5 4 4"/></symbol>
  <symbol id="neu-i-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="8.5" y="8.5" width="11" height="11" rx="2"/><path d="M15.5 8.5V6A1.5 1.5 0 0 0 14 4.5H6A1.5 1.5 0 0 0 4.5 6v8A1.5 1.5 0 0 0 6 15.5h2.5"/></symbol>
  <symbol id="neu-i-star" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L12 16.8l-5.2 2.8 1-5.8-4.3-4.1 5.9-.8z"/></symbol>
  <symbol id="neu-i-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 7h15M9.5 7V4.5h5V7M6.5 7l1 13h9l1-13"/></symbol>
</svg>
<div class="two">
<section><span class="lbl">Alerts · icon, title and hidden type text</span><div class="neu-alerts">
<div class="neu-alert"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-info"/></svg></span><div><p class="neu-alert__title"><span class="neu-sr">Information: </span>Update ready for the hallway hub</p><p class="neu-alert__text">Firmware 2.4 installs tonight at 03:00. Lights keep working during the update.</p></div></div>
<div class="neu-alert neu-alert--success"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-checkCircle"/></svg></span><div><p class="neu-alert__title"><span class="neu-sr">Success: </span>Back door locked</p><p class="neu-alert__text">Locked automatically at 22:41, two minutes after the last person left.</p></div></div>
<div class="neu-alert neu-alert--warning"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-alert"/></svg></span><div><p class="neu-alert__title"><span class="neu-sr">Warning: </span>Bedroom window open while heating</p><p class="neu-alert__text">The radiator has paused. Close the window to resume at 19 °C.</p></div></div>
<div class="neu-alert neu-alert--danger"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-xCircle"/></svg></span><div><p class="neu-alert__title"><span class="neu-sr">Error: </span>Garage camera offline</p><p class="neu-alert__text">No signal since 14:05. Check the power adapter or move the Wi-Fi extender closer.</p></div></div>
</div></section>
<section><span class="lbl">Toasts · polite live region</span><div class="neu-toasts" role="status" aria-live="polite">
<div class="neu-toast" data-neu-toast><span class="neu-toast__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-film"/></svg></span><p class="neu-toast__text"><strong>Movie night is on</strong><span>6 lights dimmed, blinds closed</span></p><button class="neu-btn neu-btn--sm" type="button">Undo</button><button class="neu-btn neu-btn--icon neu-btn--icon-sm" type="button" data-neu-dismiss aria-label="Dismiss notification"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button></div>
<div class="neu-toast" data-neu-toast><span class="neu-toast__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-lock"/></svg></span><p class="neu-toast__text"><strong>Front door unlocked</strong><span>By Sam, just now</span></p><button class="neu-btn neu-btn--icon neu-btn--icon-sm" type="button" data-neu-dismiss aria-label="Dismiss notification"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button></div>
</div></section>
</div>
<div class="three">
<section class="drop-col"><span class="lbl">Dropdown</span><div class="neu-dropdown">
<button class="neu-btn neu-dropdown__btn" type="button" aria-expanded="true" aria-controls="dd-room" data-neu-dropdown><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-sofa"/></svg>Living room<svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-chevDown"/></svg></button>
<ul class="neu-menu" id="dd-room"><li><button class="neu-menu__item" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-edit"/></svg>Rename room</button></li><li><button class="neu-menu__item" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-copy"/></svg>Duplicate as scene</button></li><li><button class="neu-menu__item" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-star"/></svg>Set as default room</button></li><li class="neu-menu__sep" aria-hidden="true"></li><li><button class="neu-menu__item neu-menu__item--danger" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-trash"/></svg>Remove room</button></li></ul>
</div></section>
<section><span class="lbl">Tooltips · hover or focus, Escape hides</span><div class="neu-tips">
<span class="neu-tip neu-tip--open" data-neu-tip><button class="neu-btn neu-btn--icon" type="button" aria-label="Eco mode" aria-describedby="tip-eco"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-leaf"/></svg></button><span class="neu-tip__bubble" role="tooltip" id="tip-eco">Holds 18 °C while everyone is out</span></span>
<span class="neu-tip" data-neu-tip><span class="neu-tip__label">Away temperature <button class="neu-btn neu-btn--icon neu-btn--icon-sm" type="button" aria-label="About away temperature" aria-describedby="tip-away"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-help"/></svg></button></span><span class="neu-tip__bubble" role="tooltip" id="tip-away">Used when the last phone leaves home</span></span>
</div></section>
<section><span class="lbl">Modal · native dialog</span><button class="neu-btn" type="button" aria-haspopup="dialog" data-neu-open="dlg-lights"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-power"/></svg>Turn off all lights…</button>
<dialog class="neu-dialog" id="dlg-lights" aria-labelledby="dlg-lights-title" aria-describedby="dlg-lights-desc">
<form class="neu-dialog__body" method="dialog">
<button class="neu-dialog__close neu-btn neu-btn--icon neu-btn--icon-sm" type="submit" value="close" aria-label="Close"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button>
<span class="neu-dialog__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-power"/></svg></span>
<h2 class="neu-dialog__title" id="dlg-lights-title">Turn off all 9 lights?</h2>
<p class="neu-dialog__text" id="dlg-lights-desc">Lights in the kitchen, hallway and three other rooms switch off now. Your Evening scene stays saved.</p>
<div class="neu-dialog__actions"><button class="neu-btn" type="submit" value="cancel">Keep them on</button><button class="neu-btn neu-btn--accent" type="submit" value="off">Turn off</button></div>
</form>
</dialog></section>
</div>
CSS
/* ── Neumorphism UI kit tokens (uiCookies) — identical in every set ──────────────
   Every component is moulded from --neu-bg and lit from the top left. Change a token and
   the whole kit follows; the shadow recipes below are built from these values. */
:root{
  --neu-bg:#e0e5ec;          /* the one surface colour */
  --neu-light:#ffffff;       /* highlight, top left */
  --neu-dark:#a3b1c6;        /* shade, bottom right */
  --neu-distance:6px;        /* how far a shape rises */
  --neu-blur:14px;           /* how soft its shadow is */
  --neu-radius:18px;         /* cards; buttons use .75 of it, fields .6 */
  --neu-accent:#4f46e5;      /* focus ring and on / selected / current states, 4.9:1 on --neu-bg */
  --neu-on-accent:#ffffff;   /* text and marks on accent fills, 6.3:1 */
  --neu-ink:#1f2937;         /* text, 11.6:1 */
  --neu-muted:#4a5568;       /* secondary text, 5.9:1 */
  --neu-edge:#74819a;        /* control boundary (fields, tracks, boxes, buttons), 3.1:1 */
  --neu-line:rgba(255,255,255,.6); /* decorative edge on cards and panels */
  --neu-bw:1px;              /* control border width */
  --neu-success:#126b35;--neu-warning:#8a5300;--neu-danger:#b42318;
}
/* Dark neumorphism: data-neu="dark" on any wrapper, or a checked .neu-theme-input inside a [data-neu] element.
   :is() is a forgiving list, so browsers without :has() still apply data-neu="dark" */
[data-neu]:is([data-neu="dark"],:has(.neu-theme-input:checked)){
  --neu-bg:#262b33;--neu-light:#323944;--neu-dark:#14171c;
  --neu-accent:#8f88ff;--neu-on-accent:#14161b;--neu-ink:#e7ebf2;--neu-muted:#aab4c3;--neu-edge:#717d90;
  --neu-line:rgba(255,255,255,.06);--neu-success:#6fdc9a;--neu-warning:#f3c164;--neu-danger:#ff8f84;color-scheme:dark}
/* More contrast requested: the soft shadows go, every control and panel gets a solid outline */
@media (prefers-contrast:more){:root,[data-neu]:is([data-neu],:has(.neu-theme-input:checked)){
  --neu-light:transparent;--neu-dark:transparent;--neu-edge:var(--neu-ink);--neu-line:var(--neu-ink);--neu-muted:var(--neu-ink);--neu-bw:2px}}
:root,[data-neu]{
  --neu-raised:var(--neu-distance) var(--neu-distance) var(--neu-blur) var(--neu-dark),calc(var(--neu-distance)*-1) calc(var(--neu-distance)*-1) var(--neu-blur) var(--neu-light);
  --neu-raised-sm:calc(var(--neu-distance)*.5) calc(var(--neu-distance)*.5) calc(var(--neu-blur)*.5) var(--neu-dark),calc(var(--neu-distance)*-.5) calc(var(--neu-distance)*-.5) calc(var(--neu-blur)*.5) var(--neu-light);
  --neu-inset:inset calc(var(--neu-distance)*.6) calc(var(--neu-distance)*.6) calc(var(--neu-blur)*.6) var(--neu-dark),inset calc(var(--neu-distance)*-.6) calc(var(--neu-distance)*-.6) calc(var(--neu-blur)*.6) var(--neu-light);
  --neu-inset-sm:inset calc(var(--neu-distance)*.35) calc(var(--neu-distance)*.35) calc(var(--neu-blur)*.35) var(--neu-dark),inset calc(var(--neu-distance)*-.35) calc(var(--neu-distance)*-.35) calc(var(--neu-blur)*.35) var(--neu-light);
}
[data-neu]{background:var(--neu-bg);color:var(--neu-ink)}
/* Components */
:where([class*="neu-"]),:where([class*="neu-"])::before,:where([class*="neu-"])::after{box-sizing:border-box}
.neu-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.neu-ico{width:20px;height:20px;flex:none}
/* Buttons: raised by default, pressed (inset) while held, accent ring on keyboard focus */
.neu-btn{display:inline-flex;align-items:center;justify-content:center;gap:.55rem;min-height:46px;padding:.65rem 1.35rem;
  border:var(--neu-bw) solid var(--neu-edge);border-radius:calc(var(--neu-radius)*.75);background:var(--neu-bg);color:var(--neu-ink);
  font-family:inherit;font-size:.95rem;font-weight:600;line-height:1.2;text-decoration:none;cursor:pointer;
  box-shadow:var(--neu-raised-sm);transition:box-shadow .2s,color .2s,background-color .2s}
.neu-btn:hover{box-shadow:var(--neu-raised)}
.neu-btn:active{box-shadow:var(--neu-inset-sm)}
.neu-btn:focus-visible{outline:3px solid var(--neu-accent);outline-offset:3px}
.neu-btn--accent{background:var(--neu-accent);border-color:var(--neu-accent);color:var(--neu-on-accent)}
.neu-btn--sm{min-height:38px;padding:.45rem 1rem;font-size:.85rem}
.neu-btn--block{width:100%}
.neu-btn--icon{width:50px;height:50px;min-height:0;padding:0;border-radius:50%}
.neu-btn--square{border-radius:calc(var(--neu-radius)*.75)}
.neu-btn--icon-sm{width:42px;height:42px}
.neu-btn--icon-lg{width:64px;height:64px}
.neu-btn--icon .neu-ico{width:22px;height:22px}
/* Alerts: the type is carried by an icon, a title and hidden "Warning:" style text, not by colour alone */
.neu-alerts{display:grid;gap:16px}
.neu-alert{--tone:var(--neu-accent);position:relative;display:flex;align-items:flex-start;gap:.9rem;padding:1rem 1.1rem 1rem 1.35rem;border:var(--neu-bw) solid var(--neu-line);
  border-radius:var(--neu-radius);background:var(--neu-bg);box-shadow:var(--neu-raised-sm)}
.neu-alert::before{content:"";position:absolute;left:.55rem;top:1rem;bottom:1rem;width:4px;border-radius:4px;background:var(--tone)}
.neu-alert--success{--tone:var(--neu-success)}.neu-alert--warning{--tone:var(--neu-warning)}.neu-alert--danger{--tone:var(--neu-danger)}
.neu-alert__icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:50%;color:var(--tone);box-shadow:var(--neu-inset-sm)}
.neu-alert__title{margin:0;font-weight:700;line-height:1.3}
.neu-alert__text{margin:.15rem 0 0;font-size:.9rem;color:var(--neu-muted)}
/* Toasts: a polite live region; each toast can be dismissed with its close button */
.neu-toasts{display:grid;gap:14px}
.neu-toast{display:flex;align-items:center;gap:.85rem;padding:.85rem .85rem .85rem 1rem;border:var(--neu-bw) solid var(--neu-line);border-radius:var(--neu-radius);background:var(--neu-bg);box-shadow:var(--neu-raised)}
.neu-toast[hidden]{display:none}
.neu-toast__icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:50%;background:var(--neu-accent);color:var(--neu-on-accent);box-shadow:var(--neu-raised-sm)}
.neu-toast__text{flex:1;min-width:0;margin:0;font-size:.92rem;line-height:1.35}
.neu-toast__text strong{display:block}
.neu-toast__text span{color:var(--neu-muted)}
/* Tooltips: shown on hover and keyboard focus, hidden again with Escape; the trigger points at the bubble with aria-describedby */
.neu-tips{display:flex;flex-wrap:wrap;align-items:flex-end;gap:22px;padding-top:84px}
.neu-tip{position:relative;display:inline-flex}
.neu-tip__bubble{position:absolute;left:50%;bottom:calc(100% + 12px);z-index:5;width:max-content;max-width:210px;padding:.55rem .8rem;border-radius:calc(var(--neu-radius)*.6);
  background:var(--neu-ink);color:var(--neu-bg);font-size:.85rem;font-weight:500;line-height:1.35;text-align:center;
  box-shadow:var(--neu-raised-sm);opacity:0;visibility:hidden;transform:translate(-50%,4px);transition:opacity .15s,transform .15s,visibility .15s;pointer-events:none}
.neu-tip__bubble::after{content:"";position:absolute;left:50%;top:100%;width:10px;height:10px;margin:-5px 0 0 -5px;background:inherit;transform:rotate(45deg)}
.neu-tip:hover .neu-tip__bubble,.neu-tip:focus-within .neu-tip__bubble,.neu-tip--open .neu-tip__bubble{opacity:1;visibility:visible;transform:translate(-50%,0)}
.neu-tip.is-dismissed .neu-tip__bubble{opacity:0;visibility:hidden}
.neu-tip__label{display:inline-flex;align-items:center;gap:.5rem;font-weight:600}
/* Dropdown: a disclosure button (aria-expanded) and a raised panel of buttons; Escape or a click outside closes it */
.neu-dropdown{position:relative;display:inline-block}
.neu-dropdown__btn .neu-ico:last-child{transition:transform .2s}
.neu-dropdown__btn[aria-expanded="true"]{border-color:var(--neu-accent);box-shadow:var(--neu-inset-sm)}
.neu-dropdown__btn[aria-expanded="true"] .neu-ico:last-child{transform:rotate(180deg)}
.neu-menu{position:absolute;top:calc(100% + 12px);left:0;z-index:10;display:grid;gap:4px;min-width:230px;margin:0;padding:.5rem;list-style:none;
  border:var(--neu-bw) solid var(--neu-line);border-radius:var(--neu-radius);background:var(--neu-bg);box-shadow:var(--neu-raised)}
.neu-menu[hidden]{display:none}
.neu-menu__item{display:flex;align-items:center;gap:.7rem;width:100%;min-height:42px;padding:.5rem .75rem;border:var(--neu-bw) solid transparent;border-radius:calc(var(--neu-radius)*.55);
  background:none;color:var(--neu-ink);font-family:inherit;font-size:.92rem;font-weight:600;text-align:left;cursor:pointer}
.neu-menu__item .neu-ico{color:var(--neu-muted)}
.neu-menu__item:hover{box-shadow:var(--neu-inset-sm)}
.neu-menu__item:focus-visible{outline:3px solid var(--neu-accent);outline-offset:-1px}
.neu-menu__item--danger,.neu-menu__item--danger .neu-ico{color:var(--neu-danger)}
.neu-menu__sep{height:1px;margin:.3rem .5rem;background:var(--neu-edge);opacity:.5}
/* Modal: the native <dialog>. showModal() traps focus, makes the page inert and closes on Escape;
   buttons inside <form method="dialog"> close it without script */
.neu-dialog{width:min(100% - 32px,420px);padding:0;border:var(--neu-bw) solid var(--neu-line);border-radius:var(--neu-radius);background:var(--neu-bg);color:var(--neu-ink);
  box-shadow:var(--neu-raised),0 30px 60px -20px rgba(15,23,42,.35)}
.neu-dialog::backdrop{background:rgba(30,41,59,.5)}
.neu-dialog[open]{animation:neu-pop .2s ease-out}
@keyframes neu-pop{from{opacity:0;transform:translateY(8px) scale(.98)}}
.neu-dialog__body{position:relative;display:grid;justify-items:center;gap:.6rem;margin:0;padding:2rem 1.75rem 1.75rem;text-align:center}
.neu-dialog__close{position:absolute;top:.9rem;right:.9rem}
.neu-dialog__icon{display:grid;place-items:center;width:64px;height:64px;margin-bottom:.4rem;border-radius:50%;color:var(--neu-accent);box-shadow:var(--neu-inset)}
.neu-dialog__icon .neu-ico{width:28px;height:28px}
.neu-dialog__title{margin:0;font-size:1.3rem;font-weight:700;line-height:1.3}
.neu-dialog__text{margin:0;color:var(--neu-muted)}
.neu-dialog__actions{display:flex;flex-wrap:wrap;justify-content:center;gap:14px;margin-top:1rem}
@media (prefers-reduced-motion:reduce){.neu-btn,.neu-tip__bubble,.neu-dropdown__btn .neu-ico,.neu-dialog[open]{transition:none;animation:none}}
JavaScript
// Modal: any button with data-neu-open="dialog-id" opens that <dialog>; focus returns to the button on close
document.querySelectorAll('[data-neu-open]').forEach(function (btn) {
  var dialog = document.getElementById(btn.getAttribute('data-neu-open'));
  if (!dialog) return;
  btn.addEventListener('click', function () {
    dialog.showModal();
    dialog.addEventListener('close', function () { btn.focus(); }, { once: true });
  });
  dialog.addEventListener('click', function (e) { if (e.target === dialog) dialog.close(); }); // backdrop click
});
// Tooltips: Escape hides the visible tooltip until the pointer or focus leaves it
document.addEventListener('keydown', function (e) {
  if (e.key !== 'Escape') return;
  document.querySelectorAll('[data-neu-tip]').forEach(function (t) { if (t.matches(':hover, :focus-within')) t.classList.add('is-dismissed'); });
});
document.querySelectorAll('[data-neu-tip]').forEach(function (t) {
  ['mouseleave', 'focusout'].forEach(function (ev) { t.addEventListener(ev, function () { t.classList.remove('is-dismissed'); }); });
});
// Toasts: a close button removes its toast
document.querySelectorAll('[data-neu-dismiss]').forEach(function (b) {
  b.addEventListener('click', function () { b.closest('[data-neu-toast]').hidden = true; });
});
// Dropdown: toggle on click; Escape (focus back to the button) or a click outside closes it
document.querySelectorAll('[data-neu-dropdown]').forEach(function (btn) {
  var menu = document.getElementById(btn.getAttribute('aria-controls'));
  function set(open) { btn.setAttribute('aria-expanded', open); menu.hidden = !open; }
  btn.addEventListener('click', function () { set(btn.getAttribute('aria-expanded') !== 'true'); });
  document.addEventListener('click', function (e) { if (!btn.parentNode.contains(e.target)) set(false); });
  btn.parentNode.addEventListener('keydown', function (e) { if (e.key === 'Escape' && btn.getAttribute('aria-expanded') === 'true') { set(false); btn.focus(); } });
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS, Bootstrap 5.3.8 JS bundle

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="neu-i-power" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v8"/><path d="M6.3 6.8a8 8 0 1 0 11.4 0"/></symbol>
  <symbol id="neu-i-x" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.5 6.5l11 11M17.5 6.5l-11 11"/></symbol>
  <symbol id="neu-i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.8h.01"/></symbol>
  <symbol id="neu-i-checkCircle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="m8 12.3 2.8 2.8L16.2 9.5"/></symbol>
  <symbol id="neu-i-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4 2.8 19.5h18.4z"/><path d="M12 10v4.5M12 17.2h.01"/></symbol>
  <symbol id="neu-i-xCircle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="m9 9 6 6M15 9l-6 6"/></symbol>
  <symbol id="neu-i-film" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5" width="17" height="14" rx="2"/><path d="M3.5 9.5h17M8 5l2 4.5M13 5l2 4.5"/></symbol>
  <symbol id="neu-i-lock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="10.5" width="14" height="10" rx="2"/><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/></symbol>
  <symbol id="neu-i-leaf" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 20c0-9 5.5-14 15-15-.5 9.5-6 15-15 15z"/><path d="M5 20c3.5-4.5 6.5-7 10-8.5"/></symbol>
  <symbol id="neu-i-help" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9.6 9.3a2.5 2.5 0 0 1 4.8 1c0 1.7-2.4 2.2-2.4 3.7M12 17.2h.01"/></symbol>
  <symbol id="neu-i-sofa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 11V8a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v3"/><path d="M3 12a2 2 0 0 1 4 0v2h10v-2a2 2 0 0 1 4 0v5H3z"/><path d="M5 17v2M19 17v2"/></symbol>
  <symbol id="neu-i-chevDown" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></symbol>
  <symbol id="neu-i-edit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="m13.5 6.5 4 4"/></symbol>
  <symbol id="neu-i-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="8.5" y="8.5" width="11" height="11" rx="2"/><path d="M15.5 8.5V6A1.5 1.5 0 0 0 14 4.5H6A1.5 1.5 0 0 0 4.5 6v8A1.5 1.5 0 0 0 6 15.5h2.5"/></symbol>
  <symbol id="neu-i-star" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L12 16.8l-5.2 2.8 1-5.8-4.3-4.1 5.9-.8z"/></symbol>
  <symbol id="neu-i-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 7h15M9.5 7V4.5h5V7M6.5 7l1 13h9l1-13"/></symbol>
</svg>
<div class="two">
<section><span class="lbl">Alerts · icon, title and hidden type text</span><div class="neu-alerts">
<div class="alert neu-alert"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-info"/></svg></span><div><p class="alert-heading"><span class="visually-hidden">Information: </span>Update ready for the hallway hub</p><p class="neu-alert__text">Firmware 2.4 installs tonight at 03:00. Lights keep working during the update.</p></div></div>
<div class="alert neu-alert neu-alert--success"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-checkCircle"/></svg></span><div><p class="alert-heading"><span class="visually-hidden">Success: </span>Back door locked</p><p class="neu-alert__text">Locked automatically at 22:41, two minutes after the last person left.</p></div></div>
<div class="alert neu-alert neu-alert--warning"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-alert"/></svg></span><div><p class="alert-heading"><span class="visually-hidden">Warning: </span>Bedroom window open while heating</p><p class="neu-alert__text">The radiator has paused. Close the window to resume at 19 °C.</p></div></div>
<div class="alert neu-alert neu-alert--danger"><span class="neu-alert__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-xCircle"/></svg></span><div><p class="alert-heading"><span class="visually-hidden">Error: </span>Garage camera offline</p><p class="neu-alert__text">No signal since 14:05. Check the power adapter or move the Wi-Fi extender closer.</p></div></div>
</div></section>
<section><span class="lbl">Toasts · polite live region</span><div class="neu-toasts">
<div class="toast show neu-toast" role="status" aria-atomic="true" data-bs-autohide="false"><span class="neu-toast__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-film"/></svg></span><p class="neu-toast__text"><strong>Movie night is on</strong><span>6 lights dimmed, blinds closed</span></p><button class="btn btn-neu btn-sm" type="button">Undo</button><button class="btn btn-neu btn-neu-icon btn-neu-icon-sm" type="button" data-bs-dismiss="toast" aria-label="Dismiss notification"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button></div>
<div class="toast show neu-toast" role="status" aria-atomic="true" data-bs-autohide="false"><span class="neu-toast__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-lock"/></svg></span><p class="neu-toast__text"><strong>Front door unlocked</strong><span>By Sam, just now</span></p><button class="btn btn-neu btn-neu-icon btn-neu-icon-sm" type="button" data-bs-dismiss="toast" aria-label="Dismiss notification"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button></div>
</div></section>
</div>
<div class="three">
<section class="drop-col"><span class="lbl">Dropdown</span><div class="dropdown neu-dropdown">
<button class="btn btn-neu dropdown-toggle neu-dropdown__btn show" type="button" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="true"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-sofa"/></svg>Living room<svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-chevDown"/></svg></button>
<ul class="dropdown-menu show" data-bs-popper="static"><li><button class="dropdown-item" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-edit"/></svg>Rename room</button></li><li><button class="dropdown-item" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-copy"/></svg>Duplicate as scene</button></li><li><button class="dropdown-item" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-star"/></svg>Set as default room</button></li><li><hr class="dropdown-divider"></li><li><button class="dropdown-item text-danger" type="button"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-trash"/></svg>Remove room</button></li></ul>
</div></section>
<section><span class="lbl">Tooltips · hover or focus, Escape hides</span><div class="neu-tips">
<span class="neu-tip neu-tip--open" data-neu-tip><button class="btn btn-neu btn-neu-icon" type="button" aria-label="Eco mode" aria-describedby="tip-eco"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-leaf"/></svg></button><span class="tooltip bs-tooltip-top" role="tooltip" id="tip-eco"><span class="tooltip-inner">Holds 18 °C while everyone is out</span></span></span>
<span class="neu-tip" data-neu-tip><span class="neu-tip__label">Away temperature <button class="btn btn-neu btn-neu-icon btn-neu-icon-sm" type="button" aria-label="About away temperature" aria-describedby="tip-away"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-help"/></svg></button></span><span class="tooltip bs-tooltip-top" role="tooltip" id="tip-away"><span class="tooltip-inner">Used when the last phone leaves home</span></span></span>
</div></section>
<section><span class="lbl">Modal · native dialog</span><button class="btn btn-neu" type="button" aria-haspopup="dialog" data-neu-open="dlg-lights"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-power"/></svg>Turn off all lights…</button>
<dialog class="neu-dialog" id="dlg-lights" aria-labelledby="dlg-lights-title" aria-describedby="dlg-lights-desc">
<form class="neu-dialog__body" method="dialog">
<button class="neu-dialog__close btn btn-neu btn-neu-icon btn-neu-icon-sm" type="submit" value="close" aria-label="Close"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button>
<span class="neu-dialog__icon"><svg class="neu-ico" aria-hidden="true" focusable="false"><use href="#neu-i-power"/></svg></span>
<h2 class="neu-dialog__title" id="dlg-lights-title">Turn off all 9 lights?</h2>
<p class="neu-dialog__text" id="dlg-lights-desc">Lights in the kitchen, hallway and three other rooms switch off now. Your Evening scene stays saved.</p>
<div class="neu-dialog__actions"><button class="btn btn-neu" type="submit" value="cancel">Keep them on</button><button class="btn btn-neu btn-neu-accent" type="submit" value="off">Turn off</button></div>
</form>
</dialog></section>
</div>
CSS
/* ── Neumorphism UI kit tokens (uiCookies) — identical in every set ──────────────
   Every component is moulded from --neu-bg and lit from the top left. Change a token and
   the whole kit follows; the shadow recipes below are built from these values. */
:root{
  --neu-bg:#e0e5ec;          /* the one surface colour */
  --neu-light:#ffffff;       /* highlight, top left */
  --neu-dark:#a3b1c6;        /* shade, bottom right */
  --neu-distance:6px;        /* how far a shape rises */
  --neu-blur:14px;           /* how soft its shadow is */
  --neu-radius:18px;         /* cards; buttons use .75 of it, fields .6 */
  --neu-accent:#4f46e5;      /* focus ring and on / selected / current states, 4.9:1 on --neu-bg */
  --neu-on-accent:#ffffff;   /* text and marks on accent fills, 6.3:1 */
  --neu-ink:#1f2937;         /* text, 11.6:1 */
  --neu-muted:#4a5568;       /* secondary text, 5.9:1 */
  --neu-edge:#74819a;        /* control boundary (fields, tracks, boxes, buttons), 3.1:1 */
  --neu-line:rgba(255,255,255,.6); /* decorative edge on cards and panels */
  --neu-bw:1px;              /* control border width */
  --neu-success:#126b35;--neu-warning:#8a5300;--neu-danger:#b42318;
}
/* Dark neumorphism: data-neu="dark" on any wrapper, or a checked .neu-theme-input inside a [data-neu] element.
   :is() is a forgiving list, so browsers without :has() still apply data-neu="dark" */
[data-neu]:is([data-neu="dark"],:has(.neu-theme-input:checked)){
  --neu-bg:#262b33;--neu-light:#323944;--neu-dark:#14171c;
  --neu-accent:#8f88ff;--neu-on-accent:#14161b;--neu-ink:#e7ebf2;--neu-muted:#aab4c3;--neu-edge:#717d90;
  --neu-line:rgba(255,255,255,.06);--neu-success:#6fdc9a;--neu-warning:#f3c164;--neu-danger:#ff8f84;color-scheme:dark}
/* More contrast requested: the soft shadows go, every control and panel gets a solid outline */
@media (prefers-contrast:more){:root,[data-neu]:is([data-neu],:has(.neu-theme-input:checked)){
  --neu-light:transparent;--neu-dark:transparent;--neu-edge:var(--neu-ink);--neu-line:var(--neu-ink);--neu-muted:var(--neu-ink);--neu-bw:2px}}
:root,[data-neu]{
  --neu-raised:var(--neu-distance) var(--neu-distance) var(--neu-blur) var(--neu-dark),calc(var(--neu-distance)*-1) calc(var(--neu-distance)*-1) var(--neu-blur) var(--neu-light);
  --neu-raised-sm:calc(var(--neu-distance)*.5) calc(var(--neu-distance)*.5) calc(var(--neu-blur)*.5) var(--neu-dark),calc(var(--neu-distance)*-.5) calc(var(--neu-distance)*-.5) calc(var(--neu-blur)*.5) var(--neu-light);
  --neu-inset:inset calc(var(--neu-distance)*.6) calc(var(--neu-distance)*.6) calc(var(--neu-blur)*.6) var(--neu-dark),inset calc(var(--neu-distance)*-.6) calc(var(--neu-distance)*-.6) calc(var(--neu-blur)*.6) var(--neu-light);
  --neu-inset-sm:inset calc(var(--neu-distance)*.35) calc(var(--neu-distance)*.35) calc(var(--neu-blur)*.35) var(--neu-dark),inset calc(var(--neu-distance)*-.35) calc(var(--neu-distance)*-.35) calc(var(--neu-blur)*.35) var(--neu-light);
}
[data-neu]{background:var(--neu-bg);color:var(--neu-ink)}
/* Bootstrap's own variables mapped onto the kit tokens */
:root,[data-neu]{--bs-body-bg:var(--neu-bg);--bs-body-color:var(--neu-ink);--bs-emphasis-color:var(--neu-ink);
  --bs-heading-color:var(--neu-ink);--bs-secondary-color:var(--neu-muted);--bs-tertiary-color:var(--neu-muted);
  --bs-border-color:var(--neu-edge);--bs-border-width:var(--neu-bw);--bs-border-radius:calc(var(--neu-radius)*.6);
  --bs-border-radius-lg:var(--neu-radius);--bs-focus-ring-color:var(--neu-accent)}
/* Components */
.neu-ico{width:20px;height:20px;flex:none}
/* Buttons: Bootstrap .btn with a .btn-neu variant set through --bs-btn-* variables */
.btn-neu{--bs-btn-padding-x:1.35rem;--bs-btn-padding-y:.65rem;--bs-btn-font-size:.95rem;--bs-btn-font-weight:600;--bs-btn-line-height:1.2;
  --bs-btn-border-width:var(--neu-bw);--bs-btn-border-radius:calc(var(--neu-radius)*.75);
  --bs-btn-bg:var(--neu-bg);--bs-btn-color:var(--neu-ink);--bs-btn-border-color:var(--neu-edge);
  --bs-btn-hover-bg:var(--neu-bg);--bs-btn-hover-color:var(--neu-ink);--bs-btn-hover-border-color:var(--neu-edge);
  --bs-btn-active-bg:var(--neu-bg);--bs-btn-active-color:var(--neu-ink);--bs-btn-active-border-color:var(--neu-edge);
  --neu-btn-shadow:var(--neu-raised-sm);
  display:inline-flex;align-items:center;justify-content:center;gap:.55rem;min-height:46px;
  box-shadow:var(--neu-btn-shadow);transition:box-shadow .2s,color .2s,background-color .2s}
.btn-neu:hover{--neu-btn-shadow:var(--neu-raised)}
.btn-neu:active{--neu-btn-shadow:var(--neu-inset-sm)}
.btn-neu:focus-visible,.btn-check:focus-visible+.btn-neu{box-shadow:var(--neu-btn-shadow);outline:3px solid var(--neu-accent);outline-offset:3px}
.btn-neu-accent{--bs-btn-bg:var(--neu-accent);--bs-btn-color:var(--neu-on-accent);--bs-btn-border-color:var(--neu-accent);
  --bs-btn-hover-bg:var(--neu-accent);--bs-btn-hover-color:var(--neu-on-accent);--bs-btn-hover-border-color:var(--neu-accent);
  --bs-btn-active-bg:var(--neu-accent);--bs-btn-active-color:var(--neu-on-accent);--bs-btn-active-border-color:var(--neu-accent)}
.btn-neu.btn-sm{--bs-btn-padding-x:1rem;--bs-btn-padding-y:.45rem;--bs-btn-font-size:.85rem;min-height:38px}
.btn-neu-icon{--bs-btn-padding-x:0;--bs-btn-padding-y:0;width:50px;height:50px;min-height:0;border-radius:50%}
.btn-neu-icon.btn-neu-square{border-radius:calc(var(--neu-radius)*.75)}
.btn-neu-icon-sm{width:42px;height:42px}
.btn-neu-icon-lg{width:64px;height:64px}
.btn-neu-icon .neu-ico{width:22px;height:22px}
/* Alerts (.alert with --bs-alert-* set to the kit): the type is carried by an icon, a title and hidden "Warning:" style text, not by colour alone */
.neu-alerts{display:grid;gap:16px}
.alert.neu-alert{--bs-alert-bg:var(--neu-bg);--bs-alert-color:var(--neu-ink);--bs-alert-border-color:var(--neu-line);--bs-alert-margin-bottom:0;--tone:var(--neu-accent);position:relative;display:flex;align-items:flex-start;gap:.9rem;padding:1rem 1.1rem 1rem 1.35rem;border:var(--neu-bw) solid var(--neu-line);
  border-radius:var(--neu-radius);background:var(--neu-bg);box-shadow:var(--neu-raised-sm)}
.neu-alert::before{content:"";position:absolute;left:.55rem;top:1rem;bottom:1rem;width:4px;border-radius:4px;background:var(--tone)}
.alert.neu-alert--success{--tone:var(--neu-success)}.alert.neu-alert--warning{--tone:var(--neu-warning)}.alert.neu-alert--danger{--tone:var(--neu-danger)}
.neu-alert__icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:50%;color:var(--tone);box-shadow:var(--neu-inset-sm)}
.neu-alert .alert-heading{margin:0;font-size:1rem;color:var(--neu-ink);font-weight:700;line-height:1.3}
.neu-alert__text{margin:.15rem 0 0;font-size:.9rem;color:var(--neu-muted)}
/* Toasts (.toast, closed by Bootstrap's data-bs-dismiss="toast"): a polite live region; each toast can be dismissed with its close button */
.neu-toasts{display:grid;gap:14px}
.toast.neu-toast{--bs-toast-max-width:100%;--bs-toast-bg:var(--neu-bg);--bs-toast-color:var(--neu-ink);--bs-toast-border-color:var(--neu-line);--bs-toast-border-width:var(--neu-bw);--bs-toast-border-radius:var(--neu-radius);--bs-toast-box-shadow:var(--neu-raised);--bs-toast-font-size:1rem;width:100%;display:flex;align-items:center;gap:.85rem;padding:.85rem .85rem .85rem 1rem;border:var(--neu-bw) solid var(--neu-line);border-radius:var(--neu-radius);background:var(--neu-bg);box-shadow:var(--neu-raised)}
.toast.neu-toast:not(.show){display:none}
.neu-toast__icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:50%;background:var(--neu-accent);color:var(--neu-on-accent);box-shadow:var(--neu-raised-sm)}
.neu-toast__text{flex:1;min-width:0;margin:0;font-size:.92rem;line-height:1.35}
.neu-toast__text strong{display:block}
.neu-toast__text span{color:var(--neu-muted)}
/* Tooltips (Bootstrap .tooltip markup, shown by CSS): shown on hover and keyboard focus, hidden again with Escape; the trigger points at the bubble with aria-describedby */
.neu-tips{display:flex;flex-wrap:wrap;align-items:flex-end;gap:22px;padding-top:84px}
.neu-tip{position:relative;display:inline-flex}
.neu-tip .tooltip{position:absolute;left:50%;top:auto;bottom:calc(100% + 12px);z-index:5;width:max-content;max-width:210px;padding:0;font-family:inherit;font-size:.85rem;font-weight:500;line-height:1.35;opacity:0;visibility:hidden;transform:translate(-50%,4px);transition:opacity .15s,transform .15s,visibility .15s;pointer-events:none}
.neu-tip .tooltip-inner{display:block;max-width:none;padding:.55rem .8rem;border-radius:calc(var(--neu-radius)*.6);background:var(--neu-ink);color:var(--neu-bg);box-shadow:var(--neu-raised-sm)}
.neu-tip .tooltip-inner::after{content:"";position:absolute;left:50%;top:100%;width:10px;height:10px;margin:-5px 0 0 -5px;background:var(--neu-ink);transform:rotate(45deg)}
.neu-tip:hover .tooltip,.neu-tip:focus-within .tooltip,.neu-tip--open .tooltip{opacity:1;visibility:visible;transform:translate(-50%,0)}
.neu-tip.is-dismissed .tooltip{opacity:0;visibility:hidden}
.neu-tip__label{display:inline-flex;align-items:center;gap:.5rem;font-weight:600}
/* Dropdown: Bootstrap .dropdown with its plugin (arrow keys, Escape, click outside). Open = pressed in, accent edge */
.neu-dropdown .dropdown-toggle::after{display:none}
.neu-dropdown__btn .neu-ico:last-child{transition:transform .2s}
.neu-dropdown__btn.show{--neu-btn-shadow:var(--neu-inset-sm);border-color:var(--neu-accent)!important}
.neu-dropdown__btn.show .neu-ico:last-child{transform:rotate(180deg)}
.neu-dropdown .dropdown-menu{--bs-dropdown-min-width:230px;--bs-dropdown-padding-x:.5rem;--bs-dropdown-padding-y:.5rem;--bs-dropdown-spacer:12px;--bs-dropdown-bg:var(--neu-bg);
  --bs-dropdown-border-color:var(--neu-line);--bs-dropdown-border-width:var(--neu-bw);--bs-dropdown-border-radius:var(--neu-radius);--bs-dropdown-box-shadow:var(--neu-raised);
  --bs-dropdown-link-color:var(--neu-ink);--bs-dropdown-link-hover-color:var(--neu-ink);--bs-dropdown-link-hover-bg:transparent;--bs-dropdown-link-active-bg:transparent;--bs-dropdown-link-active-color:var(--neu-ink);
  --bs-dropdown-divider-bg:var(--neu-edge);--bs-dropdown-divider-margin-y:.3rem;--bs-dropdown-item-padding-x:.75rem;--bs-dropdown-item-padding-y:.5rem;--bs-dropdown-item-border-radius:calc(var(--neu-radius)*.55);
  box-shadow:var(--bs-dropdown-box-shadow)}
.neu-dropdown .dropdown-menu{display:none}.neu-dropdown .dropdown-menu.show{display:grid;gap:4px}
.neu-dropdown .dropdown-item{display:flex;align-items:center;gap:.7rem;min-height:42px;border:var(--neu-bw) solid transparent;font-size:.92rem;font-weight:600}
.neu-dropdown .dropdown-item .neu-ico{color:var(--neu-muted)}
.neu-dropdown .dropdown-item:hover,.neu-dropdown .dropdown-item:focus{box-shadow:var(--neu-inset-sm)}
.neu-dropdown .dropdown-item:focus-visible{outline:3px solid var(--neu-accent);outline-offset:-1px}
.neu-dropdown .dropdown-item.text-danger,.neu-dropdown .dropdown-item.text-danger .neu-ico{color:var(--neu-danger)!important}
.neu-dropdown .dropdown-divider{margin:.3rem .5rem;opacity:.5}
/* Modal: the native <dialog>. showModal() traps focus, makes the page inert and closes on Escape;
   buttons inside <form method="dialog"> close it without script */
.neu-dialog{width:min(100% - 32px,420px);padding:0;border:var(--neu-bw) solid var(--neu-line);border-radius:var(--neu-radius);background:var(--neu-bg);color:var(--neu-ink);
  box-shadow:var(--neu-raised),0 30px 60px -20px rgba(15,23,42,.35)}
.neu-dialog::backdrop{background:rgba(30,41,59,.5)}
.neu-dialog[open]{animation:neu-pop .2s ease-out}
@keyframes neu-pop{from{opacity:0;transform:translateY(8px) scale(.98)}}
.neu-dialog__body{position:relative;display:grid;justify-items:center;gap:.6rem;margin:0;padding:2rem 1.75rem 1.75rem;text-align:center}
.neu-dialog__close{position:absolute;top:.9rem;right:.9rem}
.neu-dialog h2,.neu-dialog p{margin:0}
.neu-dialog__icon{display:grid;place-items:center;width:64px;height:64px;margin-bottom:.4rem;border-radius:50%;color:var(--neu-accent);box-shadow:var(--neu-inset)}
.neu-dialog__icon .neu-ico{width:28px;height:28px}
.neu-dialog__title{margin:0;font-size:1.3rem;font-weight:700;line-height:1.3}
.neu-dialog__text{margin:0;color:var(--neu-muted)}
.neu-dialog__actions{display:flex;flex-wrap:wrap;justify-content:center;gap:14px;margin-top:1rem}
@media (prefers-reduced-motion:reduce){.btn-neu,.neu-tip .tooltip,.neu-dropdown__btn .neu-ico,.neu-dialog[open]{transition:none;animation:none}}
JavaScript
// Modal: any button with data-neu-open="dialog-id" opens that <dialog>; focus returns to the button on close
document.querySelectorAll('[data-neu-open]').forEach(function (btn) {
  var dialog = document.getElementById(btn.getAttribute('data-neu-open'));
  if (!dialog) return;
  btn.addEventListener('click', function () {
    dialog.showModal();
    dialog.addEventListener('close', function () { btn.focus(); }, { once: true });
  });
  dialog.addEventListener('click', function (e) { if (e.target === dialog) dialog.close(); }); // backdrop click
});
// Tooltips: Escape hides the visible tooltip until the pointer or focus leaves it
document.addEventListener('keydown', function (e) {
  if (e.key !== 'Escape') return;
  document.querySelectorAll('[data-neu-tip]').forEach(function (t) { if (t.matches(':hover, :focus-within')) t.classList.add('is-dismissed'); });
});
document.querySelectorAll('[data-neu-tip]').forEach(function (t) {
  ['mouseleave', 'focusout'].forEach(function (ev) { t.addEventListener(ev, function () { t.classList.remove('is-dismissed'); }); });
});
// Dropdown: create the instance now, so a menu that starts open also closes on an outside click
document.querySelectorAll('[data-bs-toggle="dropdown"]').forEach(function (el) { bootstrap.Dropdown.getOrCreateInstance(el); });

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="neu-i-power" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v8"/><path d="M6.3 6.8a8 8 0 1 0 11.4 0"/></symbol>
  <symbol id="neu-i-x" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.5 6.5l11 11M17.5 6.5l-11 11"/></symbol>
  <symbol id="neu-i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.8h.01"/></symbol>
  <symbol id="neu-i-checkCircle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="m8 12.3 2.8 2.8L16.2 9.5"/></symbol>
  <symbol id="neu-i-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4 2.8 19.5h18.4z"/><path d="M12 10v4.5M12 17.2h.01"/></symbol>
  <symbol id="neu-i-xCircle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="m9 9 6 6M15 9l-6 6"/></symbol>
  <symbol id="neu-i-film" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5" width="17" height="14" rx="2"/><path d="M3.5 9.5h17M8 5l2 4.5M13 5l2 4.5"/></symbol>
  <symbol id="neu-i-lock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="10.5" width="14" height="10" rx="2"/><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/></symbol>
  <symbol id="neu-i-leaf" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 20c0-9 5.5-14 15-15-.5 9.5-6 15-15 15z"/><path d="M5 20c3.5-4.5 6.5-7 10-8.5"/></symbol>
  <symbol id="neu-i-help" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9.6 9.3a2.5 2.5 0 0 1 4.8 1c0 1.7-2.4 2.2-2.4 3.7M12 17.2h.01"/></symbol>
  <symbol id="neu-i-sofa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 11V8a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v3"/><path d="M3 12a2 2 0 0 1 4 0v2h10v-2a2 2 0 0 1 4 0v5H3z"/><path d="M5 17v2M19 17v2"/></symbol>
  <symbol id="neu-i-chevDown" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></symbol>
  <symbol id="neu-i-edit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="m13.5 6.5 4 4"/></symbol>
  <symbol id="neu-i-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="8.5" y="8.5" width="11" height="11" rx="2"/><path d="M15.5 8.5V6A1.5 1.5 0 0 0 14 4.5H6A1.5 1.5 0 0 0 4.5 6v8A1.5 1.5 0 0 0 6 15.5h2.5"/></symbol>
  <symbol id="neu-i-star" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L12 16.8l-5.2 2.8 1-5.8-4.3-4.1 5.9-.8z"/></symbol>
  <symbol id="neu-i-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 7h15M9.5 7V4.5h5V7M6.5 7l1 13h9l1-13"/></symbol>
</svg>
<div class="grid items-start gap-11 min-[861px]:grid-cols-2">
<section><span class="mb-[18px] block text-[.72rem] font-semibold tracking-[.12em] text-neu-muted uppercase">Alerts · icon, title and hidden type text</span><div class="grid gap-4">
<div class="relative flex items-start gap-[.9rem] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg py-4 pr-[1.1rem] pl-[1.35rem] shadow-neu-sm before:absolute before:inset-y-4 before:left-[.55rem] before:w-1 before:rounded before:bg-neu-accent"><span class="grid size-10 flex-none place-items-center rounded-full shadow-neu-in-sm text-neu-accent"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-info"/></svg></span><div><p class="leading-[1.3] font-bold"><span class="sr-only">Information: </span>Update ready for the hallway hub</p><p class="mt-[.15rem] text-[.9rem] text-neu-muted">Firmware 2.4 installs tonight at 03:00. Lights keep working during the update.</p></div></div>
<div class="relative flex items-start gap-[.9rem] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg py-4 pr-[1.1rem] pl-[1.35rem] shadow-neu-sm before:absolute before:inset-y-4 before:left-[.55rem] before:w-1 before:rounded before:bg-neu-success"><span class="grid size-10 flex-none place-items-center rounded-full shadow-neu-in-sm text-neu-success"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-checkCircle"/></svg></span><div><p class="leading-[1.3] font-bold"><span class="sr-only">Success: </span>Back door locked</p><p class="mt-[.15rem] text-[.9rem] text-neu-muted">Locked automatically at 22:41, two minutes after the last person left.</p></div></div>
<div class="relative flex items-start gap-[.9rem] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg py-4 pr-[1.1rem] pl-[1.35rem] shadow-neu-sm before:absolute before:inset-y-4 before:left-[.55rem] before:w-1 before:rounded before:bg-neu-warning"><span class="grid size-10 flex-none place-items-center rounded-full shadow-neu-in-sm text-neu-warning"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-alert"/></svg></span><div><p class="leading-[1.3] font-bold"><span class="sr-only">Warning: </span>Bedroom window open while heating</p><p class="mt-[.15rem] text-[.9rem] text-neu-muted">The radiator has paused. Close the window to resume at 19 °C.</p></div></div>
<div class="relative flex items-start gap-[.9rem] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg py-4 pr-[1.1rem] pl-[1.35rem] shadow-neu-sm before:absolute before:inset-y-4 before:left-[.55rem] before:w-1 before:rounded before:bg-neu-danger"><span class="grid size-10 flex-none place-items-center rounded-full shadow-neu-in-sm text-neu-danger"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-xCircle"/></svg></span><div><p class="leading-[1.3] font-bold"><span class="sr-only">Error: </span>Garage camera offline</p><p class="mt-[.15rem] text-[.9rem] text-neu-muted">No signal since 14:05. Check the power adapter or move the Wi-Fi extender closer.</p></div></div>
</div></section>
<section><span class="mb-[18px] block text-[.72rem] font-semibold tracking-[.12em] text-neu-muted uppercase">Toasts · polite live region</span><div class="grid gap-3.5" role="status" aria-live="polite">
<div class="flex items-center gap-[.85rem] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg py-[.85rem] pr-[.85rem] pl-4 shadow-neu" data-neu-toast><span class="grid size-10 flex-none place-items-center rounded-full bg-neu-accent text-neu-on-accent shadow-neu-sm"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-film"/></svg></span><p class="min-w-0 flex-1 text-[.92rem] leading-[1.35]"><strong class="block">Movie night is on</strong><span class="text-neu-muted">6 lights dimmed, blinds closed</span></p><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent min-h-[38px] rounded-neu-btn px-4 py-[.45rem] text-[.85rem] border-neu-edge bg-neu-bg text-neu-ink" type="button">Undo</button><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent size-[42px] rounded-full border-neu-edge bg-neu-bg text-neu-ink" type="button" data-neu-dismiss aria-label="Dismiss notification"><svg class="size-[22px] shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button></div>
<div class="flex items-center gap-[.85rem] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg py-[.85rem] pr-[.85rem] pl-4 shadow-neu" data-neu-toast><span class="grid size-10 flex-none place-items-center rounded-full bg-neu-accent text-neu-on-accent shadow-neu-sm"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-lock"/></svg></span><p class="min-w-0 flex-1 text-[.92rem] leading-[1.35]"><strong class="block">Front door unlocked</strong><span class="text-neu-muted">By Sam, just now</span></p><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent size-[42px] rounded-full border-neu-edge bg-neu-bg text-neu-ink" type="button" data-neu-dismiss aria-label="Dismiss notification"><svg class="size-[22px] shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button></div>
</div></section>
</div>
<div class="grid items-start gap-11 min-[861px]:grid-cols-3">
<section class="min-h-[330px]"><span class="mb-[18px] block text-[.72rem] font-semibold tracking-[.12em] text-neu-muted uppercase">Dropdown</span><div class="relative inline-block">
<button class="aria-expanded:border-neu-accent aria-expanded:shadow-neu-in-sm [&[aria-expanded=true]>svg:last-child]:rotate-180 [&>svg:last-child]:transition-transform [&>svg:last-child]:duration-200 inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent min-h-[46px] rounded-neu-btn px-[1.35rem] py-[.65rem] text-[.95rem] border-neu-edge bg-neu-bg text-neu-ink" type="button" aria-expanded="true" aria-controls="dd-room" data-neu-dropdown><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-sofa"/></svg>Living room<svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-chevDown"/></svg></button>
<ul class="absolute top-[calc(100%+12px)] left-0 z-10 m-0 grid min-w-[230px] list-none gap-1 rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg p-2 shadow-neu" id="dd-room"><li><button class="flex min-h-[42px] w-full cursor-pointer items-center gap-[.7rem] rounded-[calc(var(--neu-radius)*.55)] border-(length:--neu-bw) border-transparent px-3 py-2 text-left text-[.92rem] font-semibold text-neu-ink hover:shadow-neu-in-sm focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-neu-accent" type="button"><svg class="size-5 shrink-0 text-neu-muted" aria-hidden="true" focusable="false"><use href="#neu-i-edit"/></svg>Rename room</button></li><li><button class="flex min-h-[42px] w-full cursor-pointer items-center gap-[.7rem] rounded-[calc(var(--neu-radius)*.55)] border-(length:--neu-bw) border-transparent px-3 py-2 text-left text-[.92rem] font-semibold text-neu-ink hover:shadow-neu-in-sm focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-neu-accent" type="button"><svg class="size-5 shrink-0 text-neu-muted" aria-hidden="true" focusable="false"><use href="#neu-i-copy"/></svg>Duplicate as scene</button></li><li><button class="flex min-h-[42px] w-full cursor-pointer items-center gap-[.7rem] rounded-[calc(var(--neu-radius)*.55)] border-(length:--neu-bw) border-transparent px-3 py-2 text-left text-[.92rem] font-semibold text-neu-ink hover:shadow-neu-in-sm focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-neu-accent" type="button"><svg class="size-5 shrink-0 text-neu-muted" aria-hidden="true" focusable="false"><use href="#neu-i-star"/></svg>Set as default room</button></li><li class="mx-2 my-[.3rem] h-px bg-neu-edge opacity-50" aria-hidden="true"></li><li><button class="flex min-h-[42px] w-full cursor-pointer items-center gap-[.7rem] rounded-[calc(var(--neu-radius)*.55)] border-(length:--neu-bw) border-transparent px-3 py-2 text-left text-[.92rem] font-semibold text-neu-danger hover:shadow-neu-in-sm focus-visible:outline-3 focus-visible:-outline-offset-1 focus-visible:outline-neu-accent" type="button"><svg class="size-5 shrink-0 text-neu-danger" aria-hidden="true" focusable="false"><use href="#neu-i-trash"/></svg>Remove room</button></li></ul>
</div></section>
<section><span class="mb-[18px] block text-[.72rem] font-semibold tracking-[.12em] text-neu-muted uppercase">Tooltips · hover or focus, Escape hides</span><div class="flex flex-wrap items-end gap-[22px] pt-[84px]">
<span class="group relative inline-flex neu-tip--open" data-neu-tip><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent size-[50px] rounded-full border-neu-edge bg-neu-bg text-neu-ink" type="button" aria-label="Eco mode" aria-describedby="tip-eco"><svg class="size-[22px] shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-leaf"/></svg></button><span class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-[5] w-max max-w-[210px] -translate-x-1/2 translate-y-1 rounded-neu-field bg-neu-ink px-[.8rem] py-[.55rem] text-center text-[.85rem] leading-[1.35] font-medium text-neu-bg opacity-0 shadow-neu-sm transition-[opacity,translate,visibility] duration-150 group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:visible group-focus-within:translate-y-0 group-focus-within:opacity-100 group-[.neu-tip--open]:visible group-[.neu-tip--open]:translate-y-0 group-[.neu-tip--open]:opacity-100 group-[.is-dismissed]:invisible group-[.is-dismissed]:opacity-0 motion-reduce:transition-none after:absolute after:top-full after:left-1/2 after:-mt-[5px] after:-ml-[5px] after:size-2.5 after:rotate-45 after:bg-neu-ink" role="tooltip" id="tip-eco">Holds 18 °C while everyone is out</span></span>
<span class="group relative inline-flex" data-neu-tip><span class="inline-flex items-center gap-2 font-semibold">Away temperature <button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent size-[42px] rounded-full border-neu-edge bg-neu-bg text-neu-ink" type="button" aria-label="About away temperature" aria-describedby="tip-away"><svg class="size-[22px] shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-help"/></svg></button></span><span class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-[5] w-max max-w-[210px] -translate-x-1/2 translate-y-1 rounded-neu-field bg-neu-ink px-[.8rem] py-[.55rem] text-center text-[.85rem] leading-[1.35] font-medium text-neu-bg opacity-0 shadow-neu-sm transition-[opacity,translate,visibility] duration-150 group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:visible group-focus-within:translate-y-0 group-focus-within:opacity-100 group-[.neu-tip--open]:visible group-[.neu-tip--open]:translate-y-0 group-[.neu-tip--open]:opacity-100 group-[.is-dismissed]:invisible group-[.is-dismissed]:opacity-0 motion-reduce:transition-none after:absolute after:top-full after:left-1/2 after:-mt-[5px] after:-ml-[5px] after:size-2.5 after:rotate-45 after:bg-neu-ink" role="tooltip" id="tip-away">Used when the last phone leaves home</span></span>
</div></section>
<section><span class="mb-[18px] block text-[.72rem] font-semibold tracking-[.12em] text-neu-muted uppercase">Modal · native dialog</span><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent min-h-[46px] rounded-neu-btn px-[1.35rem] py-[.65rem] text-[.95rem] border-neu-edge bg-neu-bg text-neu-ink" type="button" aria-haspopup="dialog" data-neu-open="dlg-lights"><svg class="size-5 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-power"/></svg>Turn off all lights…</button>
<dialog class="w-[min(100%-32px,420px)] rounded-neu border-(length:--neu-bw) border-neu-line bg-neu-bg p-0 text-neu-ink shadow-[var(--neu-raised),0_30px_60px_-20px_rgba(15,23,42,.35)] m-auto backdrop:bg-[rgba(30,41,59,.5)] open:animate-[neu-pop_.2s_ease-out] motion-reduce:open:animate-none" id="dlg-lights" aria-labelledby="dlg-lights-title" aria-describedby="dlg-lights-desc">
<form class="relative m-0 grid justify-items-center gap-[.6rem] px-7 pt-8 pb-7 text-center" method="dialog">
<button class="absolute top-[.9rem] right-[.9rem] inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent size-[42px] rounded-full border-neu-edge bg-neu-bg text-neu-ink" type="submit" value="close" aria-label="Close"><svg class="size-[22px] shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-x"/></svg></button>
<span class="mb-[.4rem] grid size-16 place-items-center rounded-full text-neu-accent shadow-neu-in"><svg class="size-7 shrink-0" aria-hidden="true" focusable="false"><use href="#neu-i-power"/></svg></span>
<h2 class="text-[1.3rem] leading-[1.3] font-bold" id="dlg-lights-title">Turn off all 9 lights?</h2>
<p class="text-neu-muted" id="dlg-lights-desc">Lights in the kitchen, hallway and three other rooms switch off now. Your Evening scene stays saved.</p>
<div class="mt-4 flex flex-wrap justify-center gap-3.5"><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent min-h-[46px] rounded-neu-btn px-[1.35rem] py-[.65rem] text-[.95rem] border-neu-edge bg-neu-bg text-neu-ink" type="submit" value="cancel">Keep them on</button><button class="inline-flex items-center justify-center gap-[.55rem] border-(length:--neu-bw) font-semibold leading-[1.2] no-underline cursor-pointer shadow-neu-sm transition-[box-shadow,color,background-color] duration-200 hover:shadow-neu active:shadow-neu-in-sm motion-reduce:transition-none focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-neu-accent min-h-[46px] rounded-neu-btn px-[1.35rem] py-[.65rem] text-[.95rem] border-neu-accent bg-neu-accent text-neu-on-accent" type="submit" value="off">Turn off</button></div>
</form>
</dialog></section>
</div>
CSS
/* ── Neumorphism UI kit tokens (uiCookies) — identical in every set ──────────────
   Every component is moulded from --neu-bg and lit from the top left. Change a token and
   the whole kit follows; the shadow recipes below are built from these values. */
:root{
  --neu-bg:#e0e5ec;          /* the one surface colour */
  --neu-light:#ffffff;       /* highlight, top left */
  --neu-dark:#a3b1c6;        /* shade, bottom right */
  --neu-distance:6px;        /* how far a shape rises */
  --neu-blur:14px;           /* how soft its shadow is */
  --neu-radius:18px;         /* cards; buttons use .75 of it, fields .6 */
  --neu-accent:#4f46e5;      /* focus ring and on / selected / current states, 4.9:1 on --neu-bg */
  --neu-on-accent:#ffffff;   /* text and marks on accent fills, 6.3:1 */
  --neu-ink:#1f2937;         /* text, 11.6:1 */
  --neu-muted:#4a5568;       /* secondary text, 5.9:1 */
  --neu-edge:#74819a;        /* control boundary (fields, tracks, boxes, buttons), 3.1:1 */
  --neu-line:rgba(255,255,255,.6); /* decorative edge on cards and panels */
  --neu-bw:1px;              /* control border width */
  --neu-success:#126b35;--neu-warning:#8a5300;--neu-danger:#b42318;
}
/* Dark neumorphism: data-neu="dark" on any wrapper, or a checked .neu-theme-input inside a [data-neu] element.
   :is() is a forgiving list, so browsers without :has() still apply data-neu="dark" */
[data-neu]:is([data-neu="dark"],:has(.neu-theme-input:checked)){
  --neu-bg:#262b33;--neu-light:#323944;--neu-dark:#14171c;
  --neu-accent:#8f88ff;--neu-on-accent:#14161b;--neu-ink:#e7ebf2;--neu-muted:#aab4c3;--neu-edge:#717d90;
  --neu-line:rgba(255,255,255,.06);--neu-success:#6fdc9a;--neu-warning:#f3c164;--neu-danger:#ff8f84;color-scheme:dark}
/* More contrast requested: the soft shadows go, every control and panel gets a solid outline */
@media (prefers-contrast:more){:root,[data-neu]:is([data-neu],:has(.neu-theme-input:checked)){
  --neu-light:transparent;--neu-dark:transparent;--neu-edge:var(--neu-ink);--neu-line:var(--neu-ink);--neu-muted:var(--neu-ink);--neu-bw:2px}}
:root,[data-neu]{
  --neu-raised:var(--neu-distance) var(--neu-distance) var(--neu-blur) var(--neu-dark),calc(var(--neu-distance)*-1) calc(var(--neu-distance)*-1) var(--neu-blur) var(--neu-light);
  --neu-raised-sm:calc(var(--neu-distance)*.5) calc(var(--neu-distance)*.5) calc(var(--neu-blur)*.5) var(--neu-dark),calc(var(--neu-distance)*-.5) calc(var(--neu-distance)*-.5) calc(var(--neu-blur)*.5) var(--neu-light);
  --neu-inset:inset calc(var(--neu-distance)*.6) calc(var(--neu-distance)*.6) calc(var(--neu-blur)*.6) var(--neu-dark),inset calc(var(--neu-distance)*-.6) calc(var(--neu-distance)*-.6) calc(var(--neu-blur)*.6) var(--neu-light);
  --neu-inset-sm:inset calc(var(--neu-distance)*.35) calc(var(--neu-distance)*.35) calc(var(--neu-blur)*.35) var(--neu-dark),inset calc(var(--neu-distance)*-.35) calc(var(--neu-distance)*-.35) calc(var(--neu-blur)*.35) var(--neu-light);
}
[data-neu]{background:var(--neu-bg);color:var(--neu-ink)}
/* The tokens above, exposed as Tailwind utilities: bg-neu-bg, text-neu-muted, border-neu-edge,
   shadow-neu, shadow-neu-sm, shadow-neu-in, shadow-neu-in-sm, rounded-neu, rounded-neu-btn, rounded-neu-field… */
@theme inline {
  --color-neu-bg: var(--neu-bg); --color-neu-ink: var(--neu-ink); --color-neu-muted: var(--neu-muted);
  --color-neu-edge: var(--neu-edge); --color-neu-line: var(--neu-line);
  --color-neu-accent: var(--neu-accent); --color-neu-on-accent: var(--neu-on-accent);
  --color-neu-success: var(--neu-success); --color-neu-warning: var(--neu-warning); --color-neu-danger: var(--neu-danger);
  --shadow-neu: var(--neu-raised); --shadow-neu-sm: var(--neu-raised-sm);
  --shadow-neu-in: var(--neu-inset); --shadow-neu-in-sm: var(--neu-inset-sm);
  --radius-neu: var(--neu-radius); --radius-neu-btn: calc(var(--neu-radius) * .75); --radius-neu-field: calc(var(--neu-radius) * .6);
}
@keyframes neu-pop{from{opacity:0;transform:translateY(8px) scale(.98)}}
JavaScript
// Modal: any button with data-neu-open="dialog-id" opens that <dialog>; focus returns to the button on close
document.querySelectorAll('[data-neu-open]').forEach(function (btn) {
  var dialog = document.getElementById(btn.getAttribute('data-neu-open'));
  if (!dialog) return;
  btn.addEventListener('click', function () {
    dialog.showModal();
    dialog.addEventListener('close', function () { btn.focus(); }, { once: true });
  });
  dialog.addEventListener('click', function (e) { if (e.target === dialog) dialog.close(); }); // backdrop click
});
// Tooltips: Escape hides the visible tooltip until the pointer or focus leaves it
document.addEventListener('keydown', function (e) {
  if (e.key !== 'Escape') return;
  document.querySelectorAll('[data-neu-tip]').forEach(function (t) { if (t.matches(':hover, :focus-within')) t.classList.add('is-dismissed'); });
});
document.querySelectorAll('[data-neu-tip]').forEach(function (t) {
  ['mouseleave', 'focusout'].forEach(function (ev) { t.addEventListener(ev, function () { t.classList.remove('is-dismissed'); }); });
});
// Toasts: a close button removes its toast
document.querySelectorAll('[data-neu-dismiss]').forEach(function (b) {
  b.addEventListener('click', function () { b.closest('[data-neu-toast]').hidden = true; });
});
// Dropdown: toggle on click; Escape (focus back to the button) or a click outside closes it
document.querySelectorAll('[data-neu-dropdown]').forEach(function (btn) {
  var menu = document.getElementById(btn.getAttribute('aria-controls'));
  function set(open) { btn.setAttribute('aria-expanded', open); menu.hidden = !open; }
  btn.addEventListener('click', function () { set(btn.getAttribute('aria-expanded') !== 'true'); });
  document.addEventListener('click', function (e) { if (!btn.parentNode.contains(e.target)) set(false); });
  btn.parentNode.addEventListener('keydown', function (e) { if (e.key === 'Escape' && btn.getAttribute('aria-expanded') === 'true') { set(false); btn.focus(); } });
});

About this set

Feedback and overlay components for a soft UI. Four alerts for information, success, a warning and an error carry their type in an icon, a coloured bar, a title and hidden text such as Warning:, so colour is never the only signal. Two toasts sit in a polite live region, one with an Undo action, and each closes with its own button. Tooltips appear above an icon button and beside a help icon on hover and keyboard focus, are tied to their trigger with aria-describedby, and hide again with Escape; the first is pinned open in the preview. A dropdown opens a raised panel of room actions, with Remove room set apart in red. The modal is the native dialog element: showModal() traps focus, makes the page behind inert and closes on Escape, and its buttons close it through a form with method dialog. A short script opens it and returns focus to the button. Use the alerts for persistent status, toasts for confirmations, and the dialog to confirm actions such as turning off every light. The Bootstrap version uses .alert, .toast and .dropdown with Bootstrap’s plugins.

What’s included

  • Native dialog with focus trap, Escape to close and focus return
  • Alerts that state their type in an icon, a title and hidden text
  • Toasts in a polite live region with working close buttons
  • Tooltips on hover and focus that hide with Escape
  • Dropdown that closes on Escape or an outside click

Accessibility

The dialog has aria-labelledby and aria-describedby and its trigger says aria-haspopup="dialog". Toasts are announced politely, tooltips use role="tooltip" and aria-describedby, and the dropdown button reports aria-expanded. Every control shows a 3px accent focus ring. Animations and transitions stop under prefers-reduced-motion, and prefers-contrast: more outlines every panel.

Customise it

Change the --neu-* tokens for the surface and accent, and --neu-success, --neu-warning and --neu-danger for the alert tones. Bootstrap maps them onto --bs-alert-*, --bs-toast-* and --bs-dropdown-*; Tailwind uses shadow-neu, text-neu-warning and a backdrop: utility on the dialog.