/* ── Claymorphism UI kit tokens (uiCookies) — identical in every set ──────────────
Every component is a puffy pastel object floating above --clay-bg: one big soft drop shadow
below it, an inset highlight top left and an inset shade bottom right. Change a token and
the whole kit follows; the shadow recipes below are built from these values. */
:root{
--clay-bg:#f3effa; /* page, a pale lilac white */
--clay-surface:#fffcf8; /* cards, fields and plain objects */
--clay-peach:#ffd2bd; /* object fills: ink text on every fill reaches 11:1 */
--clay-lilac:#dccdff;
--clay-mint:#bdeed6;
--clay-sky:#c2e0ff;
--clay-lemon:#ffe9a3;
--clay-ink:#241a3d; /* text, 14.4:1 on --clay-bg */
--clay-muted:#51476a; /* secondary text, 5.7:1 or more on every fill */
--clay-edge:#7a6e96; /* control boundary, 4.1:1 on --clay-bg, so shadows are never the only edge */
--clay-line:rgba(36,26,61,.12); /* decorative edge on cards and panels */
--clay-accent:#6236e8; /* focus ring and on / selected / current states, 5.8:1 on --clay-bg */
--clay-on-accent:#ffffff; /* text and marks on accent fills, 6.5:1 */
--clay-tint:#e9e1ff; /* light accent wash behind current items */
--clay-drop:rgba(86,56,168,.30); /* colour of the outer drop shadow */
--clay-hi:rgba(255,255,255,.88); /* inset highlight, top left */
--clay-lo:rgba(52,30,112,.20); /* inset shade, bottom right */
--clay-lift:14px; /* how high objects float; every shadow scales from it */
--clay-radius:30px; /* cards; buttons are pills, fields use .55 of it */
--clay-bw:1.5px; /* control border width */
--clay-success:#17663d;--clay-warning:#8a4b00;--clay-danger:#b3261e;
--clay-font:ui-rounded,"SF Pro Rounded","Nunito","Quicksand","Varela Round","Arial Rounded MT Bold",system-ui,sans-serif;
}
/* --clay-fill is set by .clay-peach, .clay-mint… on one object and must not leak into its children */
@property --clay-fill{syntax:"*";inherits:false}
/* Dark clay: data-clay="dark" on any wrapper, or a checked .clay-theme-input inside a [data-clay] element.
:is() is a forgiving list, so browsers without :has() still apply data-clay="dark" */
[data-clay]:is([data-clay="dark"],:has(.clay-theme-input:checked)){
--clay-bg:#1a1530;--clay-surface:#2a2347;
--clay-peach:#6e3f33;--clay-lilac:#4a3a8a;--clay-mint:#215a4a;--clay-sky:#26497c;--clay-lemon:#5f5220;
--clay-ink:#f7f3ff;--clay-muted:#d2c9ea;--clay-edge:#8f83b8;--clay-line:rgba(255,255,255,.1);
--clay-accent:#bba6ff;--clay-on-accent:#1a1530;--clay-tint:#3a2f66;
--clay-drop:rgba(4,2,14,.62);--clay-hi:rgba(255,255,255,.2);--clay-lo:rgba(0,0,0,.34);
--clay-success:#86e3b0;--clay-warning:#ffc76e;--clay-danger:#ffa196;color-scheme:dark}
/* More contrast requested: soft shading stays, but every edge and secondary text turns full ink */
@media (prefers-contrast:more){:root,[data-clay]:is([data-clay],:has(.clay-theme-input:checked)){
--clay-edge:var(--clay-ink);--clay-line:var(--clay-ink);--clay-muted:var(--clay-ink);--clay-bw:2px}}
:root,[data-clay]{
--clay-shadow:0 var(--clay-lift) calc(var(--clay-lift)*2.2) calc(var(--clay-lift)*-.3) var(--clay-drop),
inset calc(var(--clay-lift)*.45) calc(var(--clay-lift)*.5) calc(var(--clay-lift)*.9) var(--clay-hi),
inset calc(var(--clay-lift)*-.45) calc(var(--clay-lift)*-.6) calc(var(--clay-lift)*.9) var(--clay-lo);
--clay-shadow-sm:0 calc(var(--clay-lift)*.55) calc(var(--clay-lift)*1.2) calc(var(--clay-lift)*-.15) var(--clay-drop),
inset calc(var(--clay-lift)*.25) calc(var(--clay-lift)*.3) calc(var(--clay-lift)*.5) var(--clay-hi),
inset calc(var(--clay-lift)*-.25) calc(var(--clay-lift)*-.35) calc(var(--clay-lift)*.5) var(--clay-lo);
--clay-press:0 calc(var(--clay-lift)*.12) calc(var(--clay-lift)*.25) 0 var(--clay-drop),
inset calc(var(--clay-lift)*.2) calc(var(--clay-lift)*.25) calc(var(--clay-lift)*.45) var(--clay-lo),
inset calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*.3) var(--clay-hi);
--clay-well:inset calc(var(--clay-lift)*.15) calc(var(--clay-lift)*.22) calc(var(--clay-lift)*.45) var(--clay-lo),
inset calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*.3) var(--clay-hi);
}
[data-clay]{background:var(--clay-bg);color:var(--clay-ink)}
/* Components */
:where([class*="clay-"]),:where([class*="clay-"])::before,:where([class*="clay-"])::after{box-sizing:border-box}
.clay-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.clay-ico{width:22px;height:22px;flex:none}
.clay-ico--lg{width:28px;height:28px}
/* Fills: put one on any object; components read --clay-fill */
.clay-peach{--clay-fill:var(--clay-peach)}.clay-lilac{--clay-fill:var(--clay-lilac)}.clay-mint{--clay-fill:var(--clay-mint)}
.clay-sky{--clay-fill:var(--clay-sky)}.clay-lemon{--clay-fill:var(--clay-lemon)}
/* Card: a puffy panel that floats on the big drop shadow */
.clay-card{margin:0;padding:1.6rem;border:var(--clay-bw) solid var(--clay-line);border-radius:var(--clay-radius);
background:var(--clay-fill,var(--clay-surface));color:var(--clay-ink);box-shadow:var(--clay-shadow)}
/* Layout helpers */
.clay-cluster{display:flex;flex-wrap:wrap;align-items:center;gap:18px}
.clay-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:22px}
.clay-stack{display:grid;gap:1.4rem}
/* Buttons: pastel pills that float; hover lifts them, pressing squashes the shadow flat */
.clay-btn{display:inline-flex;align-items:center;justify-content:center;gap:.55rem;min-height:50px;margin:0;padding:.7rem 1.5rem;
border:var(--clay-bw) solid var(--clay-edge);border-radius:999px;background:var(--clay-fill,var(--clay-surface));color:var(--clay-ink);
font-family:inherit;font-size:1rem;font-weight:800;line-height:1.2;text-decoration:none;cursor:pointer;
box-shadow:var(--clay-shadow-sm);transition:transform .18s,box-shadow .18s}
.clay-btn:hover{transform:translateY(-2px);box-shadow:var(--clay-shadow)}
.clay-btn:active{transform:translateY(2px);box-shadow:var(--clay-press)}
.clay-btn:focus-visible{outline:3px solid var(--clay-accent);outline-offset:4px}
.clay-btn--accent{--clay-fill:var(--clay-accent);border-color:var(--clay-accent);color:var(--clay-on-accent)}
.clay-btn--sm{min-height:40px;padding:.45rem 1.05rem;font-size:.88rem}
.clay-btn--block{width:100%}
/* Icon buttons: round (or squircle) clay pebbles with a chunky icon and an aria-label */
.clay-iconbtn{display:inline-grid;place-items:center;width:58px;height:58px;margin:0;padding:0;border:var(--clay-bw) solid var(--clay-edge);border-radius:50%;
background:var(--clay-fill,var(--clay-surface));color:var(--clay-ink);cursor:pointer;box-shadow:var(--clay-shadow-sm);transition:transform .18s,box-shadow .18s}
.clay-iconbtn:hover{transform:translateY(-2px);box-shadow:var(--clay-shadow)}
.clay-iconbtn:active{transform:translateY(2px);box-shadow:var(--clay-press)}
.clay-iconbtn:focus-visible{outline:3px solid var(--clay-accent);outline-offset:4px}
.clay-iconbtn--sq{border-radius:20px}
.clay-iconbtn--sm{width:44px;height:44px}
.clay-iconbtn--lg{width:72px;height:72px}
.clay-iconbtn--accent{--clay-fill:var(--clay-accent);border-color:var(--clay-accent);color:var(--clay-on-accent)}
@media (prefers-reduced-motion:reduce){.clay-btn,.clay-iconbtn{transition:none}.clay-btn:hover,.clay-btn:active,.clay-iconbtn:hover,.clay-iconbtn:active{transform:none}}
/* Fields: soft white wells with a 4:1 edge and a label above. Focus adds an accent edge and ring */
.clay-field{display:grid;align-content:start;gap:.45rem;min-width:0}
.clay-label{font-size:.92rem;font-weight:800;line-height:1.3}
.clay-control{position:relative;display:flex;align-items:center}
.clay-control>.clay-ico{position:absolute;left:16px;color:var(--clay-muted);pointer-events:none}
.clay-input{display:block;width:100%;min-height:52px;margin:0;padding:.75rem 1.1rem;border:var(--clay-bw) solid var(--clay-edge);border-radius:calc(var(--clay-radius)*.55);
background:var(--clay-surface);color:var(--clay-ink);font-family:inherit;font-size:1rem;font-weight:600;line-height:1.35;box-shadow:var(--clay-well);
appearance:none;transition:border-color .18s,box-shadow .18s}
.clay-input::placeholder{color:var(--clay-muted);opacity:1;font-weight:500}
.clay-input:focus{outline:3px solid var(--clay-accent);outline-offset:3px;border-color:var(--clay-accent)}
.clay-input--icon{padding-left:3.05rem}
.clay-input--select{padding-right:3rem;cursor:pointer}
.clay-control>.clay-ico.clay-control__chev{left:auto;right:16px;color:var(--clay-ink)}
.clay-input--area{min-height:104px;resize:vertical}
.clay-input--error{border-color:var(--clay-danger);border-width:2px}
.clay-help{margin:0;font-size:.85rem;color:var(--clay-muted)}
.clay-error{display:flex;align-items:center;gap:.4rem;margin:0;font-size:.85rem;font-weight:700;color:var(--clay-danger)}
.clay-error .clay-ico{width:18px;height:18px}
/* Checkboxes and radios: a hidden input and a puffy box. Checked = squashed flat, accent fill and a tick or dot */
.clay-group{min-width:0;margin:0;padding:0;border:0}
.clay-group__legend{float:none;width:auto;margin:0 0 .75rem;padding:0;font-size:.92rem;font-weight:800;line-height:1.3}
.clay-group__list{display:grid;gap:.8rem}
.clay-check{position:relative;display:flex;align-items:center;gap:.8rem;font-weight:700;cursor:pointer}
.clay-check__box{display:grid;place-items:center;flex:none;width:28px;height:28px;border:var(--clay-bw) solid var(--clay-edge);border-radius:10px;
background:var(--clay-surface);color:transparent;box-shadow:var(--clay-shadow-sm);transition:transform .18s,box-shadow .18s,background-color .18s}
.clay-check__box .clay-ico{width:18px;height:18px}
.clay-check__box--radio{border-radius:50%}
.clay-check__box--radio::before{content:"";width:10px;height:10px;border-radius:50%;background:transparent}
.clay-check input:checked+.clay-check__box{transform:translateY(2px);border-color:var(--clay-accent);background:var(--clay-accent);color:var(--clay-on-accent);box-shadow:var(--clay-press)}
.clay-check input:checked+.clay-check__box--radio::before{background:var(--clay-on-accent)}
.clay-check input:focus-visible+.clay-check__box{outline:3px solid var(--clay-accent);outline-offset:3px}
.clay-check__hint{display:block;font-size:.84rem;font-weight:500;color:var(--clay-muted)}
/* Login card */
.clay-login{max-width:420px;width:100%;margin:0 auto}
.clay-login__badge{display:grid;place-items:center;width:64px;height:64px;margin:0 auto 1rem;border:var(--clay-bw) solid var(--clay-line);border-radius:22px;
background:var(--clay-fill,var(--clay-lemon));box-shadow:var(--clay-shadow-sm)}
.clay-login__title{margin:0;font-size:1.5rem;font-weight:800;line-height:1.2;text-align:center}
.clay-login__sub{margin:.35rem 0 1.5rem;color:var(--clay-muted);text-align:center}
.clay-login__row{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.75rem}
.clay-link{color:var(--clay-accent);font-weight:800;text-decoration:underline;text-underline-offset:3px;border-radius:6px}
.clay-link:hover{color:var(--clay-ink)}
.clay-link:focus-visible{outline:3px solid var(--clay-accent);outline-offset:3px}
.clay-login__foot{margin:1.25rem 0 0;font-size:.92rem;color:var(--clay-muted);text-align:center}
.clay-grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:1.4rem}
@media (prefers-reduced-motion:reduce){.clay-input,.clay-check__box{transition:none}}
/* Range: native input. The track is a well, the thumb a puffy pebble; a few lines of script paint the fill */
.clay-range-head{display:flex;justify-content:space-between;align-items:baseline;gap:1rem}
.clay-range-out{font-size:.92rem;font-weight:800;color:var(--clay-accent)}
.clay-range{--clay-val:50%;display:block;width:100%;height:30px;margin:0;background:transparent;appearance:none;cursor:pointer}
.clay-range::-webkit-slider-runnable-track{height:14px;border:var(--clay-bw) solid var(--clay-edge);border-radius:999px;box-shadow:var(--clay-well);
background:linear-gradient(90deg,var(--clay-accent) var(--clay-val),var(--clay-bg) var(--clay-val))}
.clay-range::-moz-range-track{height:14px;border:var(--clay-bw) solid var(--clay-edge);border-radius:999px;background:var(--clay-bg);box-shadow:var(--clay-well)}
.clay-range::-moz-range-progress{height:14px;border-radius:999px;background:var(--clay-accent)}
.clay-range::-webkit-slider-thumb{width:28px;height:28px;margin-top:-8.5px;border:var(--clay-bw) solid var(--clay-edge);border-radius:50%;background:var(--clay-lemon);box-shadow:var(--clay-shadow-sm);appearance:none}
.clay-range::-moz-range-thumb{width:28px;height:28px;border:var(--clay-bw) solid var(--clay-edge);border-radius:50%;background:var(--clay-lemon);box-shadow:var(--clay-shadow-sm)}
.clay-range:focus-visible{outline:3px solid var(--clay-accent);outline-offset:4px;border-radius:999px}
.clay-range-scale{display:flex;justify-content:space-between;margin:0;font-size:.8rem;color:var(--clay-muted)}
JavaScript
// Range: paint the filled part of the track and keep the visible value and aria-valuetext in step
document.querySelectorAll('[data-clay-range]').forEach(function (r) {
var out = document.getElementById(r.getAttribute('data-clay-range'));
var unit = r.getAttribute('data-unit') || '';
function paint() {
var pct = (r.value - r.min) / (r.max - r.min) * 100;
r.style.setProperty('--clay-val', pct + '%');
if (out) out.textContent = r.value + unit;
r.setAttribute('aria-valuetext', r.value + unit);
}
r.addEventListener('input', paint); paint();
});
/* ── Claymorphism UI kit tokens (uiCookies) — identical in every set ──────────────
Every component is a puffy pastel object floating above --clay-bg: one big soft drop shadow
below it, an inset highlight top left and an inset shade bottom right. Change a token and
the whole kit follows; the shadow recipes below are built from these values. */
:root{
--clay-bg:#f3effa; /* page, a pale lilac white */
--clay-surface:#fffcf8; /* cards, fields and plain objects */
--clay-peach:#ffd2bd; /* object fills: ink text on every fill reaches 11:1 */
--clay-lilac:#dccdff;
--clay-mint:#bdeed6;
--clay-sky:#c2e0ff;
--clay-lemon:#ffe9a3;
--clay-ink:#241a3d; /* text, 14.4:1 on --clay-bg */
--clay-muted:#51476a; /* secondary text, 5.7:1 or more on every fill */
--clay-edge:#7a6e96; /* control boundary, 4.1:1 on --clay-bg, so shadows are never the only edge */
--clay-line:rgba(36,26,61,.12); /* decorative edge on cards and panels */
--clay-accent:#6236e8; /* focus ring and on / selected / current states, 5.8:1 on --clay-bg */
--clay-on-accent:#ffffff; /* text and marks on accent fills, 6.5:1 */
--clay-tint:#e9e1ff; /* light accent wash behind current items */
--clay-drop:rgba(86,56,168,.30); /* colour of the outer drop shadow */
--clay-hi:rgba(255,255,255,.88); /* inset highlight, top left */
--clay-lo:rgba(52,30,112,.20); /* inset shade, bottom right */
--clay-lift:14px; /* how high objects float; every shadow scales from it */
--clay-radius:30px; /* cards; buttons are pills, fields use .55 of it */
--clay-bw:1.5px; /* control border width */
--clay-success:#17663d;--clay-warning:#8a4b00;--clay-danger:#b3261e;
--clay-font:ui-rounded,"SF Pro Rounded","Nunito","Quicksand","Varela Round","Arial Rounded MT Bold",system-ui,sans-serif;
}
/* --clay-fill is set by .clay-peach, .clay-mint… on one object and must not leak into its children */
@property --clay-fill{syntax:"*";inherits:false}
/* Dark clay: data-clay="dark" on any wrapper, or a checked .clay-theme-input inside a [data-clay] element.
:is() is a forgiving list, so browsers without :has() still apply data-clay="dark" */
[data-clay]:is([data-clay="dark"],:has(.clay-theme-input:checked)){
--clay-bg:#1a1530;--clay-surface:#2a2347;
--clay-peach:#6e3f33;--clay-lilac:#4a3a8a;--clay-mint:#215a4a;--clay-sky:#26497c;--clay-lemon:#5f5220;
--clay-ink:#f7f3ff;--clay-muted:#d2c9ea;--clay-edge:#8f83b8;--clay-line:rgba(255,255,255,.1);
--clay-accent:#bba6ff;--clay-on-accent:#1a1530;--clay-tint:#3a2f66;
--clay-drop:rgba(4,2,14,.62);--clay-hi:rgba(255,255,255,.2);--clay-lo:rgba(0,0,0,.34);
--clay-success:#86e3b0;--clay-warning:#ffc76e;--clay-danger:#ffa196;color-scheme:dark}
/* More contrast requested: soft shading stays, but every edge and secondary text turns full ink */
@media (prefers-contrast:more){:root,[data-clay]:is([data-clay],:has(.clay-theme-input:checked)){
--clay-edge:var(--clay-ink);--clay-line:var(--clay-ink);--clay-muted:var(--clay-ink);--clay-bw:2px}}
:root,[data-clay]{
--clay-shadow:0 var(--clay-lift) calc(var(--clay-lift)*2.2) calc(var(--clay-lift)*-.3) var(--clay-drop),
inset calc(var(--clay-lift)*.45) calc(var(--clay-lift)*.5) calc(var(--clay-lift)*.9) var(--clay-hi),
inset calc(var(--clay-lift)*-.45) calc(var(--clay-lift)*-.6) calc(var(--clay-lift)*.9) var(--clay-lo);
--clay-shadow-sm:0 calc(var(--clay-lift)*.55) calc(var(--clay-lift)*1.2) calc(var(--clay-lift)*-.15) var(--clay-drop),
inset calc(var(--clay-lift)*.25) calc(var(--clay-lift)*.3) calc(var(--clay-lift)*.5) var(--clay-hi),
inset calc(var(--clay-lift)*-.25) calc(var(--clay-lift)*-.35) calc(var(--clay-lift)*.5) var(--clay-lo);
--clay-press:0 calc(var(--clay-lift)*.12) calc(var(--clay-lift)*.25) 0 var(--clay-drop),
inset calc(var(--clay-lift)*.2) calc(var(--clay-lift)*.25) calc(var(--clay-lift)*.45) var(--clay-lo),
inset calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*.3) var(--clay-hi);
--clay-well:inset calc(var(--clay-lift)*.15) calc(var(--clay-lift)*.22) calc(var(--clay-lift)*.45) var(--clay-lo),
inset calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*.3) var(--clay-hi);
}
[data-clay]{background:var(--clay-bg);color:var(--clay-ink)}
/* Bootstrap's own variables mapped onto the kit tokens */
:root,[data-clay]{--bs-body-bg:var(--clay-bg);--bs-body-color:var(--clay-ink);--bs-body-font-family:var(--clay-font);
--bs-emphasis-color:var(--clay-ink);--bs-heading-color:var(--clay-ink);--bs-secondary-color:var(--clay-muted);--bs-tertiary-color:var(--clay-muted);
--bs-border-color:var(--clay-edge);--bs-border-width:var(--clay-bw);--bs-border-radius:calc(var(--clay-radius)*.55);
--bs-border-radius-lg:var(--clay-radius);--bs-border-radius-pill:999px;--bs-focus-ring-color:var(--clay-accent);
--bs-link-color:var(--clay-accent);--bs-link-color-rgb:98,54,232;--bs-link-hover-color:var(--clay-ink);--bs-link-hover-color-rgb:36,26,61}
/* Components */
:where([class*="clay-"]),:where([class*="clay-"])::before,:where([class*="clay-"])::after{box-sizing:border-box}
.clay-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.clay-ico{width:22px;height:22px;flex:none}
.clay-ico--lg{width:28px;height:28px}
/* Fills: put one on any object; components read --clay-fill */
.clay-peach{--clay-fill:var(--clay-peach)}.clay-lilac{--clay-fill:var(--clay-lilac)}.clay-mint{--clay-fill:var(--clay-mint)}
.clay-sky{--clay-fill:var(--clay-sky)}.clay-lemon{--clay-fill:var(--clay-lemon)}
/* Card: a puffy panel that floats on the big drop shadow */
.clay-card{margin:0;padding:1.6rem;border:var(--clay-bw) solid var(--clay-line);border-radius:var(--clay-radius);
background:var(--clay-fill,var(--clay-surface));color:var(--clay-ink);box-shadow:var(--clay-shadow)}
/* Layout helpers */
.clay-cluster{display:flex;flex-wrap:wrap;align-items:center;gap:18px}
.clay-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:22px}
.clay-stack{display:grid;gap:1.4rem}
/* Cards: Bootstrap .card through its --bs-card-* variables */
.card.clay-card{--bs-card-bg:var(--clay-fill,var(--clay-surface));--bs-card-color:var(--clay-ink);--bs-card-border-color:var(--clay-line);
--bs-card-border-width:var(--clay-bw);--bs-card-border-radius:var(--clay-radius);--bs-card-inner-border-radius:var(--clay-radius);
--bs-card-spacer-x:1.6rem;--bs-card-spacer-y:1.6rem;padding:0}
/* Buttons: Bootstrap .btn with a .btn-clay variant set through --bs-btn-* variables.
Hover lifts the pill, pressing squashes the shadow flat */
.btn-clay{--bs-btn-padding-x:1.5rem;--bs-btn-padding-y:.7rem;--bs-btn-font-family:inherit;--bs-btn-font-size:1rem;--bs-btn-font-weight:800;--bs-btn-line-height:1.2;
--bs-btn-border-width:var(--clay-bw);--bs-btn-border-radius:999px;
--bs-btn-bg:var(--clay-fill,var(--clay-surface));--bs-btn-color:var(--clay-ink);--bs-btn-border-color:var(--clay-edge);
--bs-btn-hover-bg:var(--bs-btn-bg);--bs-btn-hover-color:var(--bs-btn-color);--bs-btn-hover-border-color:var(--bs-btn-border-color);
--bs-btn-active-bg:var(--bs-btn-bg);--bs-btn-active-color:var(--bs-btn-color);--bs-btn-active-border-color:var(--bs-btn-border-color);
--clay-btn-shadow:var(--clay-shadow-sm);
display:inline-flex;align-items:center;justify-content:center;gap:.55rem;min-height:50px;
box-shadow:var(--clay-btn-shadow);transition:transform .18s,box-shadow .18s}
.btn-clay:hover{--clay-btn-shadow:var(--clay-shadow);transform:translateY(-2px)}
.btn-clay:active,.btn-clay:first-child:active{--clay-btn-shadow:var(--clay-press);transform:translateY(2px)}
.btn-clay:focus-visible,.btn-check:focus-visible+.btn-clay{box-shadow:var(--clay-btn-shadow);outline:3px solid var(--clay-accent);outline-offset:4px}
.btn-clay-accent{--clay-fill:var(--clay-accent);--bs-btn-color:var(--clay-on-accent);--bs-btn-border-color:var(--clay-accent)}
.btn-clay.btn-sm{--bs-btn-padding-x:1.05rem;--bs-btn-padding-y:.45rem;--bs-btn-font-size:.88rem;min-height:40px}
/* Icon buttons: a round or squircle .btn-clay with an aria-label */
.btn-clay-icon{--bs-btn-padding-x:0;--bs-btn-padding-y:0;width:58px;height:58px;min-height:0;border-radius:50%}
.btn-clay-icon.btn-clay-sq{border-radius:20px}
.btn-clay-icon.btn-clay-sm{width:44px;height:44px}
.btn-clay-icon.btn-clay-lg{width:72px;height:72px}
@media (prefers-reduced-motion:reduce){.btn-clay{transition:none}.btn-clay:hover,.btn-clay:active,.btn-clay:first-child:active{transform:none}}
/* Forms: Bootstrap .form-control, .form-select, .form-check-input and .form-range inside .clay-bform */
.clay-bform{--bs-form-invalid-color:var(--clay-danger);--bs-form-invalid-border-color:var(--clay-danger)}
.clay-bform .form-label{margin:0 0 .45rem;font-size:.92rem;font-weight:800;line-height:1.3}
.clay-bform .form-control,.clay-bform .form-select{min-height:52px;padding:.75rem 1.1rem;border:var(--clay-bw) solid var(--clay-edge);border-radius:calc(var(--clay-radius)*.55);
background-color:var(--clay-surface);color:var(--clay-ink);font-size:1rem;font-weight:600;line-height:1.35;box-shadow:var(--clay-well);transition:border-color .18s,box-shadow .18s}
.clay-bform .form-control::placeholder{color:var(--clay-muted);opacity:1;font-weight:500}
.clay-bform .form-control:focus,.clay-bform .form-select:focus{border-color:var(--clay-accent);background-color:var(--clay-surface);color:var(--clay-ink);box-shadow:var(--clay-well);outline:3px solid var(--clay-accent);outline-offset:3px}
.clay-bform .form-select{padding-right:3rem;background-image:none;cursor:pointer}
.clay-bform textarea.form-control{min-height:104px}
.clay-bform .form-control.is-invalid{padding-right:1.1rem;border-width:2px;border-color:var(--clay-danger);background-image:none}
.clay-bform .form-control.is-invalid:focus{border-color:var(--clay-danger);box-shadow:var(--clay-well)}
.clay-bform .invalid-feedback{display:flex;align-items:center;gap:.4rem;margin:.45rem 0 0;font-size:.85rem;font-weight:700;color:var(--clay-danger)}
.clay-bform .invalid-feedback .clay-ico{width:18px;height:18px}
.clay-bform .form-text{margin:.45rem 0 0;font-size:.85rem;color:var(--clay-muted)}
.clay-bform .clay-control{position:relative;display:flex;align-items:center}
.clay-bform .clay-control>.clay-ico{position:absolute;left:16px;z-index:1;color:var(--clay-muted);pointer-events:none}
.clay-bform .clay-control>.clay-ico.clay-control__chev{left:auto;right:16px;color:var(--clay-ink)}
.clay-bform .clay-control .form-control{padding-left:3.05rem}
/* Checkboxes and radios: puffy boxes that squash flat and fill with accent when checked */
.clay-bform .clay-bgroup{min-width:0;margin:0;padding:0;border:0}
.clay-bform .clay-bgroup legend{float:none;width:auto;margin:0 0 .75rem;padding:0;font-size:.92rem;font-weight:800;line-height:1.3}
.clay-bform .form-check{display:flex;align-items:center;gap:.8rem;min-height:0;margin:0 0 .8rem;padding:0}
.clay-bform .form-check:last-child{margin-bottom:0}
.clay-bform .form-check-input{--bs-form-check-bg:var(--clay-surface);flex:none;float:none;width:28px;height:28px;margin:0;border:var(--clay-bw) solid var(--clay-edge);
background-size:18px;box-shadow:var(--clay-shadow-sm);cursor:pointer;transition:transform .18s,box-shadow .18s,background-color .18s}
.clay-bform .form-check-input[type=checkbox]{border-radius:10px}
.clay-bform .form-check-input[type=radio]{background-size:12px}
.clay-bform .form-check-input:focus{border-color:var(--clay-edge);box-shadow:var(--clay-shadow-sm)}
.clay-bform .form-check-input:checked{transform:translateY(2px);border-color:var(--clay-accent);background-color:var(--clay-accent);box-shadow:var(--clay-press)}
.clay-bform .form-check-input:focus-visible{outline:3px solid var(--clay-accent);outline-offset:3px}
.clay-bform .form-check-label{font-weight:700;cursor:pointer}
.clay-bform .clay-check-hint{display:block;font-size:.84rem;font-weight:500;color:var(--clay-muted)}
/* Range: .form-range with a well track, a puffy thumb and a painted fill */
.clay-bform .clay-range-head{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;margin-bottom:.45rem}
.clay-bform .clay-range-head .form-label{margin:0}
.clay-bform .clay-range-out{font-size:.92rem;font-weight:800;color:var(--clay-accent)}
.clay-bform .form-range{--clay-val:50%;height:30px}
.clay-bform .form-range::-webkit-slider-runnable-track{height:14px;border:var(--clay-bw) solid var(--clay-edge);border-radius:999px;box-shadow:var(--clay-well);
background:linear-gradient(90deg,var(--clay-accent) var(--clay-val),var(--clay-bg) var(--clay-val))}
.clay-bform .form-range::-moz-range-track{height:14px;border:var(--clay-bw) solid var(--clay-edge);border-radius:999px;background:var(--clay-bg);box-shadow:var(--clay-well)}
.clay-bform .form-range::-moz-range-progress{height:14px;border-radius:999px;background:var(--clay-accent)}
.clay-bform .form-range::-webkit-slider-thumb{width:28px;height:28px;margin-top:-8.5px;border:var(--clay-bw) solid var(--clay-edge);border-radius:50%;background:var(--clay-lemon);box-shadow:var(--clay-shadow-sm)}
.clay-bform .form-range::-moz-range-thumb{width:28px;height:28px;border:var(--clay-bw) solid var(--clay-edge);border-radius:50%;background:var(--clay-lemon);box-shadow:var(--clay-shadow-sm)}
.clay-bform .form-range:focus::-webkit-slider-thumb{box-shadow:var(--clay-shadow-sm)}
.clay-bform .form-range:focus::-moz-range-thumb{box-shadow:var(--clay-shadow-sm)}
.clay-bform .form-range:focus-visible{outline:3px solid var(--clay-accent);outline-offset:4px;border-radius:999px}
.clay-bform .clay-range-scale{display:flex;justify-content:space-between;margin:0;font-size:.8rem;color:var(--clay-muted)}
/* Login card */
.clay-login{max-width:420px;width:100%;margin:0 auto}
.clay-login__badge{display:grid;place-items:center;width:64px;height:64px;margin:0 auto 1rem;border:var(--clay-bw) solid var(--clay-line);border-radius:22px;background:var(--clay-fill,var(--clay-lemon));box-shadow:var(--clay-shadow-sm)}
.clay-login__title{margin:0;font-size:1.5rem;font-weight:800;line-height:1.2;text-align:center}
.clay-login__sub{margin:.35rem 0 1.5rem;color:var(--clay-muted);text-align:center}
.clay-link{color:var(--clay-accent);font-weight:800;text-decoration:underline;text-underline-offset:3px;border-radius:6px}
.clay-link:hover{color:var(--clay-ink)}
.clay-link:focus-visible{outline:3px solid var(--clay-accent);outline-offset:3px}
.clay-login__foot{margin:1.25rem 0 0;font-size:.92rem;color:var(--clay-muted);text-align:center}
@media (prefers-reduced-motion:reduce){.clay-bform .form-control,.clay-bform .form-select,.clay-bform .form-check-input{transition:none}}
JavaScript
// Range: paint the filled part of the track and keep the visible value and aria-valuetext in step
document.querySelectorAll('[data-clay-range]').forEach(function (r) {
var out = document.getElementById(r.getAttribute('data-clay-range'));
var unit = r.getAttribute('data-unit') || '';
function paint() {
var pct = (r.value - r.min) / (r.max - r.min) * 100;
r.style.setProperty('--clay-val', pct + '%');
if (out) out.textContent = r.value + unit;
r.setAttribute('aria-valuetext', r.value + unit);
}
r.addEventListener('input', paint); paint();
});
/* ── Claymorphism UI kit tokens (uiCookies) — identical in every set ──────────────
Every component is a puffy pastel object floating above --clay-bg: one big soft drop shadow
below it, an inset highlight top left and an inset shade bottom right. Change a token and
the whole kit follows; the shadow recipes below are built from these values. */
:root{
--clay-bg:#f3effa; /* page, a pale lilac white */
--clay-surface:#fffcf8; /* cards, fields and plain objects */
--clay-peach:#ffd2bd; /* object fills: ink text on every fill reaches 11:1 */
--clay-lilac:#dccdff;
--clay-mint:#bdeed6;
--clay-sky:#c2e0ff;
--clay-lemon:#ffe9a3;
--clay-ink:#241a3d; /* text, 14.4:1 on --clay-bg */
--clay-muted:#51476a; /* secondary text, 5.7:1 or more on every fill */
--clay-edge:#7a6e96; /* control boundary, 4.1:1 on --clay-bg, so shadows are never the only edge */
--clay-line:rgba(36,26,61,.12); /* decorative edge on cards and panels */
--clay-accent:#6236e8; /* focus ring and on / selected / current states, 5.8:1 on --clay-bg */
--clay-on-accent:#ffffff; /* text and marks on accent fills, 6.5:1 */
--clay-tint:#e9e1ff; /* light accent wash behind current items */
--clay-drop:rgba(86,56,168,.30); /* colour of the outer drop shadow */
--clay-hi:rgba(255,255,255,.88); /* inset highlight, top left */
--clay-lo:rgba(52,30,112,.20); /* inset shade, bottom right */
--clay-lift:14px; /* how high objects float; every shadow scales from it */
--clay-radius:30px; /* cards; buttons are pills, fields use .55 of it */
--clay-bw:1.5px; /* control border width */
--clay-success:#17663d;--clay-warning:#8a4b00;--clay-danger:#b3261e;
--clay-font:ui-rounded,"SF Pro Rounded","Nunito","Quicksand","Varela Round","Arial Rounded MT Bold",system-ui,sans-serif;
}
/* --clay-fill is set by .clay-peach, .clay-mint… on one object and must not leak into its children */
@property --clay-fill{syntax:"*";inherits:false}
/* Dark clay: data-clay="dark" on any wrapper, or a checked .clay-theme-input inside a [data-clay] element.
:is() is a forgiving list, so browsers without :has() still apply data-clay="dark" */
[data-clay]:is([data-clay="dark"],:has(.clay-theme-input:checked)){
--clay-bg:#1a1530;--clay-surface:#2a2347;
--clay-peach:#6e3f33;--clay-lilac:#4a3a8a;--clay-mint:#215a4a;--clay-sky:#26497c;--clay-lemon:#5f5220;
--clay-ink:#f7f3ff;--clay-muted:#d2c9ea;--clay-edge:#8f83b8;--clay-line:rgba(255,255,255,.1);
--clay-accent:#bba6ff;--clay-on-accent:#1a1530;--clay-tint:#3a2f66;
--clay-drop:rgba(4,2,14,.62);--clay-hi:rgba(255,255,255,.2);--clay-lo:rgba(0,0,0,.34);
--clay-success:#86e3b0;--clay-warning:#ffc76e;--clay-danger:#ffa196;color-scheme:dark}
/* More contrast requested: soft shading stays, but every edge and secondary text turns full ink */
@media (prefers-contrast:more){:root,[data-clay]:is([data-clay],:has(.clay-theme-input:checked)){
--clay-edge:var(--clay-ink);--clay-line:var(--clay-ink);--clay-muted:var(--clay-ink);--clay-bw:2px}}
:root,[data-clay]{
--clay-shadow:0 var(--clay-lift) calc(var(--clay-lift)*2.2) calc(var(--clay-lift)*-.3) var(--clay-drop),
inset calc(var(--clay-lift)*.45) calc(var(--clay-lift)*.5) calc(var(--clay-lift)*.9) var(--clay-hi),
inset calc(var(--clay-lift)*-.45) calc(var(--clay-lift)*-.6) calc(var(--clay-lift)*.9) var(--clay-lo);
--clay-shadow-sm:0 calc(var(--clay-lift)*.55) calc(var(--clay-lift)*1.2) calc(var(--clay-lift)*-.15) var(--clay-drop),
inset calc(var(--clay-lift)*.25) calc(var(--clay-lift)*.3) calc(var(--clay-lift)*.5) var(--clay-hi),
inset calc(var(--clay-lift)*-.25) calc(var(--clay-lift)*-.35) calc(var(--clay-lift)*.5) var(--clay-lo);
--clay-press:0 calc(var(--clay-lift)*.12) calc(var(--clay-lift)*.25) 0 var(--clay-drop),
inset calc(var(--clay-lift)*.2) calc(var(--clay-lift)*.25) calc(var(--clay-lift)*.45) var(--clay-lo),
inset calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*.3) var(--clay-hi);
--clay-well:inset calc(var(--clay-lift)*.15) calc(var(--clay-lift)*.22) calc(var(--clay-lift)*.45) var(--clay-lo),
inset calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*-.12) calc(var(--clay-lift)*.3) var(--clay-hi);
}
[data-clay]{background:var(--clay-bg);color:var(--clay-ink)}
/* The tokens above, exposed as Tailwind utilities: bg-clay-peach, text-clay-muted, border-clay-edge,
shadow-clay, shadow-clay-sm, shadow-clay-press, shadow-clay-well, rounded-clay, rounded-clay-field, font-clay… */
@theme inline {
--color-clay-bg: var(--clay-bg); --color-clay-surface: var(--clay-surface);
--color-clay-peach: var(--clay-peach); --color-clay-lilac: var(--clay-lilac); --color-clay-mint: var(--clay-mint);
--color-clay-sky: var(--clay-sky); --color-clay-lemon: var(--clay-lemon);
--color-clay-ink: var(--clay-ink); --color-clay-muted: var(--clay-muted); --color-clay-edge: var(--clay-edge); --color-clay-line: var(--clay-line);
--color-clay-accent: var(--clay-accent); --color-clay-on-accent: var(--clay-on-accent); --color-clay-tint: var(--clay-tint);
--color-clay-success: var(--clay-success); --color-clay-warning: var(--clay-warning); --color-clay-danger: var(--clay-danger);
--shadow-clay: var(--clay-shadow); --shadow-clay-sm: var(--clay-shadow-sm); --shadow-clay-press: var(--clay-press); --shadow-clay-well: var(--clay-well);
--radius-clay: var(--clay-radius); --radius-clay-field: calc(var(--clay-radius) * .55); --radius-clay-sm: calc(var(--clay-radius) * .4);
--font-clay: var(--clay-font);
}
JavaScript
// Range: paint the filled part of the track and keep the visible value and aria-valuetext in step
document.querySelectorAll('[data-clay-range]').forEach(function (r) {
var out = document.getElementById(r.getAttribute('data-clay-range'));
var unit = r.getAttribute('data-unit') || '';
function paint() {
var pct = (r.value - r.min) / (r.max - r.min) * 100;
r.style.setProperty('--clay-val', pct + '%');
if (out) out.textContent = r.value + unit;
r.setAttribute('aria-valuetext', r.value + unit);
}
r.addEventListener('input', paint); paint();
});
About this set
Soft clay form controls and a sign-in card that uses them. Text fields are white wells with a gentle inset shade and a label above, shown plain, with a search icon, with helper text, and in an error state that thickens the edge to red and adds an icon and a message tied to the field through aria-describedby. A native select gets a matching chevron and a textarea holds a note for a teacher. Checkboxes and radios are puffy boxes that squash flat and fill with accent when chosen, and a daily goal slider has a well track, a lemon pebble thumb and its value printed beside the label. The login card stacks a rocket badge, a heading, email and password fields with icons, a keep-me-signed-in checkbox, a forgotten-password link, a full-width sign-in button and a link to create an account. Use the fields wherever a friendly, rounded interface needs input and the card as the sign-in screen of a learning or family app. Every field edge reaches 4:1 against the page and the accent focus ring is drawn outside the field. The slider is a native range input; a few lines of script paint its fill and keep the value and aria-valuetext current.
What’s included
Inset fields with a 4:1 edge, icon, helper and error variants
Checkboxes and radios that squash flat and fill with accent
Native select, textarea and range input styled to match
Login card with labelled fields and autocomplete hints
Bootstrap version built on .form-control, .form-select, .form-check-input and .form-range
Accessibility
Every field has a visible label, the error is announced through aria-invalid and aria-describedby, and the checkboxes and radios sit in fieldsets with legends. Fields show a 3px accent outline on focus and the custom boxes draw it on the visible box. The slider reports its value in minutes through aria-valuetext. Transitions stop under prefers-reduced-motion.
Customise it
Edit the --clay-* tokens for colours, depth and radius; the error colour is --clay-danger and the slider thumb uses --clay-lemon. Bootstrap reads the tokens inside .clay-bform, and Tailwind uses utilities such as rounded-clay-field, border-clay-edge and shadow-clay-well.