Book a callGitHub147

New: approval rules. Bills over $5,000 now need a second approver.

Payroll sent. 142 people get paid on Friday, Nov 14.

Your card expires in 6 days. Update it to keep paying for 18 seats.

Live preview: try it.

Source
<!-- Icons: Lucide (lucide.dev), ISC licence -->
<style>
.odl-page-banners { box-sizing: border-box; inline-size: 100%; max-inline-size: 56rem; margin-inline: auto; container-type: inline-size; font: var(--ds-text-body-md); color: var(--ds-color-text-primary); text-wrap: pretty; }
.odl-page-banners *, .odl-page-banners *::before, .odl-page-banners *::after { box-sizing: border-box; }
.odl-page-banners svg { flex: none; inline-size: var(--ds-size-icon-sm); block-size: var(--ds-size-icon-sm); fill: none; stroke: currentColor; stroke-width: var(--ds-icon-stroke-md); }
.odl-page-banners h2, .odl-page-banners h3, .odl-page-banners p, .odl-page-banners ul, .odl-page-banners ol, .odl-page-banners dl, .odl-page-banners dd { margin: 0; }
.odl-page-banners h2, .odl-page-banners h3 { text-wrap: balance; }
.odl-page-banners .odl-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--ds-space-inline-sm); min-block-size: max(var(--ds-size-control-md), var(--ds-size-target-min)); padding: 0 var(--ds-space-inset-md);
  border: var(--ds-border-width-default) solid transparent; border-radius: var(--ds-radius-control); background: var(--ds-color-bg-action-primary); color: var(--ds-color-text-on-action);
  font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-label); text-decoration: none; white-space: nowrap; cursor: pointer; transition: background-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
.odl-page-banners .odl-btn:hover { background: var(--ds-color-bg-action-primary-hover); }
.odl-page-banners .odl-btn:active { background: var(--ds-color-bg-action-primary-pressed); }
.odl-page-banners .odl-btn.is-quiet { border-color: var(--ds-color-border-default); background: var(--ds-color-surface-raised); color: var(--ds-color-text-primary); }
.odl-page-banners .odl-btn.is-quiet:hover { background: var(--ds-color-bg-neutral-subtle); }
.odl-page-banners .odl-btn.is-text { padding-inline: var(--ds-space-inset-sm); background: transparent; color: var(--ds-color-text-link); }
.odl-page-banners .odl-btn.is-text:hover { background: var(--ds-color-bg-neutral-subtle); }
.odl-page-banners .odl-btn[disabled], .odl-page-banners .odl-btn[aria-disabled="true"] { opacity: var(--ds-opacity-disabled-container); cursor: not-allowed; }
.odl-page-banners button:focus-visible, .odl-page-banners a:focus-visible, .odl-page-banners input:focus-visible, .odl-page-banners textarea:focus-visible, .odl-page-banners [tabindex]:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-color-border-focus); outline-offset: var(--ds-focus-ring-offset); }
.odl-page-banners .odl-sr { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.odl-page-banners .odl-msg { display: grid; grid-template-columns: var(--ds-size-icon-md) minmax(0, 1fr) auto; gap: var(--ds-space-inline-md); align-items: start;
  padding: var(--ds-space-inset-md) var(--ds-space-inset-lg); border: var(--ds-border-width-default) solid var(--ds-color-border-subtle); border-radius: var(--ds-radius-container); background: var(--ds-color-surface-raised); }
.odl-page-banners .odl-msg > svg { inline-size: var(--ds-size-icon-md); block-size: var(--ds-size-icon-md); margin-block-start: calc((1lh - var(--ds-size-icon-md)) / 2); }

.odl-page-banners { display: grid; gap: var(--ds-space-stack-sm); }
.odl-page-banners .odl-msg { align-items: center; }
.odl-page-banners .odl-msg p { min-inline-size: 0; }
.odl-page-banners .odl-msg strong { font-weight: var(--ds-font-weight-heading); }
.odl-page-banners .odl-msg:has(> [data-tone="info"]) { border-color: var(--ds-color-border-info); background: var(--ds-color-bg-info-subtle); }
.odl-page-banners .odl-ic[data-tone="info"] { color: var(--ds-color-text-info); }
.odl-page-banners .odl-msg:has(> [data-tone="success"]) { border-color: var(--ds-color-border-success); background: var(--ds-color-bg-success-subtle); }
.odl-page-banners .odl-ic[data-tone="success"] { color: var(--ds-color-text-success); }
.odl-page-banners .odl-msg:has(> [data-tone="warning"]) { border-color: var(--ds-color-border-warning); background: var(--ds-color-bg-warning-subtle); }
.odl-page-banners .odl-ic[data-tone="warning"] { color: var(--ds-color-text-warning); }
.odl-page-banners .odl-msg:has(> [data-tone="danger"]) { padding-block: var(--ds-state-error-inset, var(--ds-space-inset-md)); border-color: var(--ds-state-error-border, var(--ds-color-border-danger)); background: var(--ds-state-error-bg, var(--ds-color-bg-danger-subtle)); }
.odl-page-banners .odl-ic[data-tone="danger"] { color: var(--ds-state-error-text, var(--ds-color-text-danger)); }
.odl-page-banners .odl-msg:has(> [data-tone="danger"]) { grid-template-columns: var(--ds-size-icon-md) minmax(0, 1fr); }
.odl-page-banners .odl-act { display: inline-flex; align-items: center; min-block-size: var(--ds-size-target-min); margin-inline-start: var(--ds-space-inline-sm); padding: 0; border: 0; background: transparent; color: var(--ds-color-text-primary);
  font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-label); text-decoration: underline; text-underline-offset: 0.2em; cursor: pointer; }
.odl-page-banners .odl-x { display: grid; place-items: center; inline-size: var(--ds-size-target-min); block-size: var(--ds-size-target-min); margin-block: calc(var(--ds-space-inset-sm) * -1); padding: 0; border: 0; border-radius: var(--ds-radius-control);
  background: transparent; color: var(--ds-color-icon-subtle); cursor: pointer; }
.odl-page-banners .odl-x:hover { background: var(--ds-color-bg-neutral-subtle); color: var(--ds-color-text-primary); }
.odl-page-banners .odl-ic { display: grid; align-self: start; margin-block-start: calc((1lh - var(--ds-size-icon-md)) / 2); }
.odl-page-banners .odl-ic svg { display: none; inline-size: var(--ds-size-icon-md); block-size: var(--ds-size-icon-md); }
.odl-page-banners .odl-ic[data-tone="info"] .i-info, .odl-page-banners .odl-ic[data-tone="success"] .i-success, .odl-page-banners .odl-ic[data-tone="warning"] .i-warning, .odl-page-banners .odl-ic[data-tone="danger"] .i-danger { display: block; }
@media (prefers-reduced-motion: reduce) { .odl-page-banners, .odl-page-banners *, .odl-page-banners *::before, .odl-page-banners *::after { transition: none !important; animation: none !important; } }
</style>
<div class="odl-page-banners" aria-label="Account notices" role="region" tabindex="-1" data-od-list="banners"><div class="odl-msg" role="status" data-od-item><span class="odl-ic" data-od-var="tone" data-tone="info"><svg class="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg><svg class="i-success" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg><svg class="i-warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg><svg class="i-danger" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg></span><p><strong data-od-slot="title">New: approval rules.</strong> <span data-od-slot="message">Bills over $5,000 now need a second approver.</span><button type="button" class="odl-act" data-od-action="action">Set up rules</button></p><button type="button" class="odl-x" aria-label="Dismiss: New: approval rules" data-od-action="dismiss" data-od-when="tone=info|success|warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button></div><div class="odl-msg" role="status" data-od-item><span class="odl-ic" data-od-var="tone" data-tone="success"><svg class="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg><svg class="i-success" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg><svg class="i-warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg><svg class="i-danger" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg></span><p><strong data-od-slot="title">Payroll sent.</strong> <span data-od-slot="message">142 people get paid on Friday, Nov 14.</span><button type="button" class="odl-act" data-od-action="action">View run</button></p><button type="button" class="odl-x" aria-label="Dismiss: Payroll sent" data-od-action="dismiss" data-od-when="tone=info|success|warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button></div><div class="odl-msg" role="status" data-od-item><span class="odl-ic" data-od-var="tone" data-tone="warning"><svg class="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg><svg class="i-success" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg><svg class="i-warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg><svg class="i-danger" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg></span><p><strong data-od-slot="title">Your card expires in 6 days.</strong> <span data-od-slot="message">Update it to keep paying for 18 seats.</span><button type="button" class="odl-act" data-od-action="action">Update card</button></p><button type="button" class="odl-x" aria-label="Dismiss: Your card expires in 6 days" data-od-action="dismiss" data-od-when="tone=info|success|warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button></div><div class="odl-msg" role="alert" data-od-item><span class="odl-ic" data-od-var="tone" data-tone="danger"><svg class="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg><svg class="i-success" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg><svg class="i-warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg><svg class="i-danger" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg></span><p><strong data-od-slot="title">The bank feed stopped syncing.</strong> <span data-od-slot="message">Transactions after 9:12 AM aren't in yet. Reconnect to fetch them.</span><button type="button" class="odl-act" data-od-action="action">Reconnect</button></p></div></div>
<script>
document.querySelectorAll(".odl-page-banners").forEach(function (root) {
  if (root.hasAttribute("data-odl-wired")) return;
  root.setAttribute("data-odl-wired", "");
  root.addEventListener("click", function (e) {
    var x = e.target.closest("[data-od-action='dismiss']");
    if (!x) return;
    var item = x.closest(".odl-msg"), next = item.nextElementSibling || item.previousElementSibling;
    item.remove();
    if (next) (next.querySelector("[data-od-action='dismiss']") || next.querySelector("button")).focus();
    else root.focus();  // nothing left: keep focus in the region, not on the page body
  });
});
</script>

More like this

B2BQuiet · Any product

Card skeleton

A grid of cards that holds each photo, title, detail and price in place while it loads.

B2BQuiet · Any product

Maintenance page

A planned-downtime page that says what is paused.

B2BQuiet · Any product

No access page

A 403 page that says who owns the page and lets the person ask for access with an.

Your kit

Nothing here yet. Add parts with Add to kit, and a look if you want the whole system.

    Parts
    0
    Files to fetch
    0 KB
    Licence
    MIT
    Total
    Free, now and later

    How do you want it?

    Your prompt

    No sign-up. Nothing leaves your browser until you paste it.

    Free