@abraham/modern.css 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +236 -2
- package/dist/modern.css +2241 -0
- package/dist/modern.min.css +1 -0
- package/package.json +64 -4
- package/skills/modern-css/SKILL.md +101 -0
- package/skills/modern-css/assets/page.html +64 -0
- package/skills/modern-css/references/markup.md +219 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer m.reset{:where(*){box-sizing:border-box}:where(:not(dialog,[popover])){margin:0}:where(html){-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}:where(img,picture,video,canvas,svg,iframe){vertical-align:middle}:where(input,button,select,textarea){font:inherit;letter-spacing:inherit;color:inherit}:where(p,h1,h2,h3,h4,h5,h6,li,dd,blockquote,figcaption){overflow-wrap:break-word}}@layer m.tokens{:where(:root){--m-primary:oklch(55% .19 40);--m-density:1;--m-radius:.5rem;--m-font-sans:system-ui, sans-serif;--m-font-mono:ui-monospace, SFMono-Regular, monospace;--m-font-size:1rem;--m-measure:100ch}:where(*){--_m-space-1:calc(var(--m-density,1) * .25rem);--_m-space-2:calc(var(--m-density,1) * .5rem);--_m-space-3:calc(var(--m-density,1) * .75rem);--_m-space-4:calc(var(--m-density,1) * 1rem);--_m-space-6:calc(var(--m-density,1) * 1.5rem);--_m-space-8:calc(var(--m-density,1) * 2rem);--_m-text-sm:calc(var(--m-font-size,1rem) / 1.2);--_m-text-base:var(--m-font-size,1rem);--_m-text-lg:calc(var(--m-font-size,1rem) * 1.2);--_m-text-xl:calc(var(--m-font-size,1rem) * pow(1.2, 2));--_m-text-2xl:calc(var(--m-font-size,1rem) * pow(1.2, 3));--_m-leading:calc(1.4 + .2 * var(--m-density,1));--_m-leading-tight:calc(1.05 + .15 * var(--m-density,1))}:where(:root){--_m-bar-size:calc(2 * var(--_m-space-3) + var(--_m-text-base) * var(--_m-leading));--_m-sticky-offset:0px}:where(:root:has(>body>header>nav)){--_m-sticky-offset:var(--_m-bar-size)}:where(:root:has(>body>header>nav+nav)){--_m-sticky-offset:calc(2 * var(--_m-bar-size))}:where(:root,:host){--_m-surface:light-dark(oklch(99% .006 80),oklch(18% .008 60));--_m-surface-raised:light-dark(oklch(97% .004 260),oklch(23% .008 260));--_m-surface-overlay:light-dark(oklch(100% 0 0),oklch(24% .008 60));--_m-text:light-dark(oklch(22% .012 260),oklch(93% .006 260));--_m-edge:color-mix(in oklch, var(--_m-text), transparent 80%);--_m-shadow-overlay:0 2px 6px -2px light-dark(oklch(0% 0 0/.15),oklch(0% 0 0/.4)), 0 12px 32px -8px light-dark(oklch(0% 0 0/.3),oklch(0% 0 0/.7))}:where(:root){--_m-host-surface:transparent}:where(:root,:host,[data-contrast]){--_m-control-border:var(--_m-in-control-border,light-dark(oklch(62% .01 260),oklch(56% .01 260)));--_m-border:var(--_m-in-border,light-dark(oklch(89% .006 260),oklch(34% .01 260)));--_m-text-muted:var(--_m-in-text-muted,light-dark(oklch(48% .012 260),oklch(72% .01 260)));--_m-tint:color-mix(in oklch, var(--_m-text), transparent var(--_m-in-tint,92%));--_m-danger:var(--_m-in-danger,light-dark(oklch(53% .2 27),oklch(70% .17 27)));--_m-success:var(--_m-in-success,light-dark(oklch(50% .13 150),oklch(72% .15 150)));--_m-underline-mix:var(--_m-in-underline-mix,60%);--_m-focus-width:var(--_m-in-focus-width,2px)}:where([data-theme=light]){--_m-scheme:light}:where([data-theme=dark]){--_m-scheme:dark}:where(:root,:host,[data-theme]){color-scheme:var(--_m-scheme,light dark)}:where([data-theme]){background-color:var(--_m-surface);color:var(--_m-text)}:where(*){--_m-primary-light:oklch(from var(--m-primary,oklch(55% .19 40)) min(l, var(--_m-in-primary-max,1)) c h);--_m-primary-dark:oklch(from var(--m-primary,oklch(55% .19 40)) max(calc(l + .1), var(--_m-in-primary-min,0)) c h);--_m-primary:light-dark(var(--_m-primary-light),var(--_m-primary-dark));--_m-primary-hover:color-mix(in oklch, var(--_m-primary), light-dark(#000,#fff) 15%);--_m-primary-subtle:color-mix(in oklch, var(--_m-primary), transparent var(--_m-in-primary-subtle,85%));--_m-on-primary:var(--m-on-primary,contrast-color(var(--_m-primary)))}@supports not (color:contrast-color(red)){:where(*){--_m-on-primary:var(--m-on-primary,light-dark(oklch(from var(--_m-primary-light) calc((.565 - l) * 1000) 0 0deg),oklch(from var(--_m-primary-dark) calc((.565 - l) * 1000) 0 0deg)))}}@supports not (color:oklch(from red l c h)){:where(*){--_m-on-primary:initial}}@media (prefers-contrast:more){:where(:root,:host){--_m-in-border:var(--_m-control-border);--_m-in-control-border:light-dark(oklch(45% .01 260),oklch(72% .01 260));--_m-in-text-muted:light-dark(oklch(38% .012 260),oklch(82% .01 260));--_m-in-tint:85%;--_m-in-danger:light-dark(oklch(43% .17 27),oklch(80% .12 27));--_m-in-success:light-dark(oklch(40% .1 150),oklch(82% .13 150));--_m-in-underline-mix:0%;--_m-in-focus-width:3px;--_m-in-primary-max:.4;--_m-in-primary-min:.8;--_m-in-primary-subtle:70%}}:where([data-contrast=more]){--_m-in-border:var(--_m-control-border);--_m-in-control-border:light-dark(oklch(45% .01 260),oklch(72% .01 260));--_m-in-text-muted:light-dark(oklch(38% .012 260),oklch(82% .01 260));--_m-in-tint:85%;--_m-in-danger:light-dark(oklch(43% .17 27),oklch(80% .12 27));--_m-in-success:light-dark(oklch(40% .1 150),oklch(82% .13 150));--_m-in-underline-mix:0%;--_m-in-focus-width:3px;--_m-in-primary-max:.4;--_m-in-primary-min:.8;--_m-in-primary-subtle:70%}:where(:root,:host){--_m-ease:cubic-bezier(.2, .8, .2, 1);--_m-spring:linear(0, .18 6.25%, .53 12.5%, .84 18.75%, 1.04 25%, 1.12 34%, 1.04 50%, .99 62.5%, .985 70%, 1)}:where(:root,:host,[data-motion]){--_m-duration:var(--_m-in-duration,.15s);--_m-duration-slow:var(--_m-in-duration-slow,.25s);--_m-scroll-behavior:var(--_m-in-scroll-behavior,smooth);--_m-spin:var(--_m-in-spin,m-spin .8s linear infinite);--_m-slide:var(--_m-in-slide,m-slide 1.2s ease-in-out infinite)}@media (prefers-reduced-motion:reduce){:where(:root,:host){--_m-in-duration:0s;--_m-in-duration-slow:0s;--_m-in-scroll-behavior:auto;--_m-in-spin:m-pulse 2s ease-in-out infinite;--_m-in-slide:m-pulse 2s ease-in-out infinite}}:where([data-motion=reduce]){--_m-in-duration:0s;--_m-in-duration-slow:0s;--_m-in-scroll-behavior:auto;--_m-in-spin:m-pulse 2s ease-in-out infinite;--_m-in-slide:m-pulse 2s ease-in-out infinite}@property --_m-drop{syntax:"<length>";inherits:true;initial-value:0}@property --_m-fade-start{syntax:"<length>";inherits:false;initial-value:0}@property --_m-fade-end{syntax:"<length>";inherits:false;initial-value:0}@keyframes m-lift{to{--_m-drop:.5rem}}@keyframes m-fade{0%{--_m-fade-end:1.5em;mask-image:linear-gradient(to right, transparent, black var(--_m-fade-start) calc(100% - var(--_m-fade-end)), transparent)}10%,90%{--_m-fade-start:1.5em;--_m-fade-end:1.5em}to{--_m-fade-start:1.5em;mask-image:linear-gradient(to right, transparent, black var(--_m-fade-start) calc(100% - var(--_m-fade-end)), transparent)}}@keyframes m-spin{to{rotate:1turn}}@keyframes m-slide{0%{background-position:-43% 0}to{background-position:143% 0}}@keyframes m-pulse{50%{opacity:.4}}}@layer m.base{:where(html){background-color:var(--_m-surface);color:var(--_m-text);scroll-behavior:var(--_m-scroll-behavior);scroll-padding-block-start:var(--_m-sticky-offset)}:where(body){box-sizing:content-box;max-inline-size:var(--m-measure,100ch);padding:var(--_m-space-8) var(--_m-space-4);font-family:var(--m-font-sans,system-ui, sans-serif);font-size:var(--_m-text-base);line-height:var(--_m-leading);margin-inline:auto}:where(:host){background-color:var(--_m-host-surface,var(--_m-surface));color:var(--_m-text);font-family:var(--m-font-sans,system-ui, sans-serif);font-size:var(--m-font-size,1rem);line-height:calc(1.4 + .2 * var(--m-density,1))}::selection{background-color:var(--_m-primary-subtle)}:where(address,blockquote,details,dl,fieldset,figure,form,ol,p,pre,table,ul){margin-block-end:var(--_m-space-4)}:where(article,aside,footer,header,main,nav,section){margin-block-end:var(--_m-space-8)}:where(address,blockquote,details,dl,fieldset,figure,form,ol,p,pre,table,ul,article,aside,footer,header,main,nav,section):where(:last-child){margin-block-end:0}:where(h1,h2,h3,h4,h5,h6){margin-block:var(--_m-space-8) var(--_m-space-3);font-weight:650;line-height:var(--_m-leading-tight);text-wrap:balance}:where(h1,h2,h3,h4,h5,h6):where(:first-child){margin-block-start:0}:where(h1,h2,h3,h4,h5,h6):where(:last-child){margin-block-end:0}:where(h1){font-size:clamp(var(--_m-text-2xl), calc(var(--_m-text-2xl) + (100vw - 20rem) * .76 / 60), calc(var(--m-font-size,1rem) * pow(1.2, 5)));letter-spacing:-.02em;font-weight:700}:where(h2){font-size:clamp(var(--_m-text-xl), calc(var(--_m-text-xl) + (100vw - 20rem) * .634 / 60), calc(var(--m-font-size,1rem) * pow(1.2, 4)));letter-spacing:-.015em}:where(h3){font-size:clamp(var(--_m-text-lg), calc(var(--_m-text-lg) + (100vw - 20rem) * .528 / 60), var(--_m-text-2xl));letter-spacing:-.01em}:where(h4){font-size:var(--_m-text-lg)}:where(h5){font-size:var(--_m-text-base)}:where(h6){font-size:var(--_m-text-sm);color:var(--_m-text-muted)}:where(p){text-wrap:pretty}:where(hgroup){margin-block:var(--_m-space-8) var(--_m-space-4);&:where(:first-child){margin-block-start:0}&:where(:last-child){margin-block-end:0}&>:where(*){margin-block:0}&>:where(p:has(~:is(h1,h2,h3,h4,h5,h6))){font-size:var(--_m-text-sm);letter-spacing:.08em;text-transform:uppercase;color:var(--_m-text-muted);margin-block-end:var(--_m-space-1);font-weight:600}&>:where(:is(h1,h2,h3,h4,h5,h6)~p){font-size:var(--_m-text-lg);color:var(--_m-text-muted);text-wrap:balance;margin-block-start:var(--_m-space-2)}}:where(small){font-size:.875em}:where(mark){background-color:color-mix(in oklch, var(--_m-primary), transparent 70%);color:inherit;-webkit-box-decoration-break:clone;box-decoration-break:clone;border-radius:.2em;padding-inline:.15em}:where(abbr[title]){text-underline-offset:.2em;cursor:help;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}:where(ins){color:var(--_m-success)}:where(del){color:var(--_m-danger)}:where(time,data,output){font-variant-numeric:tabular-nums}:where(sub,sup){vertical-align:baseline;font-size:.75em;line-height:0;position:relative}:where(sup){inset-block-start:-.5em}:where(sub){inset-block-end:-.25em}@view-transition{navigation:auto}@media (prefers-reduced-motion:reduce){@view-transition{navigation:none}}:where(:root)::view-transition-group(*){animation-duration:var(--_m-duration-slow);animation-timing-function:var(--_m-ease)}@supports (animation-timeline:scroll()){:where([data-scroll-progress]:root):before{content:"";z-index:2;background-color:var(--_m-primary);transform-origin:0;block-size:3px;animation:linear both m-grow;animation-timeline:scroll(root);position:fixed;inset:0 0 auto;scale:0 1}:where([data-scroll-progress]:root:dir(rtl)):before{transform-origin:100%}}@keyframes m-grow{to{scale:1}}}@layer m.elements{:where(a){color:var(--_m-primary);text-decoration-line:underline;-webkit-text-decoration-color:color-mix(in oklch, currentcolor, transparent var(--_m-underline-mix));text-decoration-color:color-mix(in oklch, currentcolor, transparent var(--_m-underline-mix));text-underline-offset:.2em;transition-property:color,text-decoration-color,text-decoration-thickness;transition-duration:var(--_m-duration);transition-timing-function:var(--_m-ease);text-decoration-thickness:from-font}:where(a:visited){-webkit-text-decoration-color:var(--_m-text-muted);text-decoration-color:var(--_m-text-muted)}:where(a:hover){color:var(--_m-primary-hover);text-decoration-color:currentColor;text-decoration-thickness:2px}:where(h1,h2,h3,h4,h5,h6) :where(a:not([role=button])){color:inherit}:where(a>[aria-hidden=true]){font-style:normal;display:inline-block}:where(ul,ol){padding-inline-start:var(--_m-space-6)}:where(ol){font-variant-numeric:tabular-nums}:where(li)::marker{color:var(--_m-text-muted)}:where(li+li){margin-block-start:var(--_m-space-1)}:where(li)>:where(ul,ol){margin-block:var(--_m-space-1) 0}:where(menu){gap:var(--_m-space-2);flex-wrap:wrap;padding:0;list-style:none;display:flex}:where(menu>li){margin:0}:where(dt){font-weight:600}:where(dd){margin-inline-start:var(--_m-space-4)}:where(dd+dt){margin-block-start:var(--_m-space-3)}:where(blockquote){border-inline-start:3px solid var(--_m-primary);color:var(--_m-text-muted);hanging-punctuation:first last;padding-inline-start:var(--_m-space-4)}:where(q){hanging-punctuation:first last}:where(blockquote) :where(cite,footer){font-size:var(--_m-text-sm);color:var(--_m-text-muted)}:where(blockquote>footer):before{content:"— " / ""}:where(figcaption){font-size:var(--_m-text-sm);color:var(--_m-text-muted);margin-block-start:var(--_m-space-2)}:where(figcaption:first-child){margin-block:0 var(--_m-space-2)}:where(code,kbd,samp,pre){font-family:var(--m-font-mono,ui-monospace, SFMono-Regular, monospace);font-size:.875em}:where(code,kbd,samp){border-radius:calc(var(--m-radius,.5rem) / 2);background-color:var(--_m-tint);padding:.1em .3em}:where(kbd){border:1px solid var(--_m-border);border-block-end-width:2px}:where(pre){padding:var(--_m-space-4);border-radius:var(--m-radius,.5rem);background:linear-gradient(to right, var(--_m-surface-raised) 30%, transparent) left / 2em 100% no-repeat local, linear-gradient(to left, var(--_m-surface-raised) 30%, transparent) right / 2em 100% no-repeat local, linear-gradient(to right, var(--_m-edge), transparent) left / .75em 100% no-repeat, linear-gradient(to left, var(--_m-edge), transparent) right / .75em 100% no-repeat var(--_m-surface-raised);tab-size:2;line-height:1.5;overflow-x:auto}:where(pre:not([dir])){direction:ltr}:where(pre) :where(code,samp){font-size:inherit;background:0 0;border-radius:0;padding:0}:where(table){border-collapse:separate;border-spacing:0;font-variant-numeric:tabular-nums;inline-size:100%}:where(caption){font-size:var(--_m-text-sm);color:var(--_m-text-muted);text-align:start;padding-block-end:var(--_m-space-2)}:where(th,td){padding:var(--_m-space-2) var(--_m-space-3);border-block-end:1px solid var(--_m-border);text-align:start;vertical-align:top}:where(th){font-weight:600}:where(thead th){background-color:var(--_m-surface);box-shadow:0 var(--_m-drop) var(--_m-drop) calc(-1 * var(--_m-drop)) var(--_m-edge);border-block-end-width:2px;position:sticky;inset-block-start:var(--_m-sticky-offset,0)}:where(tbody tr){transition:background-color var(--_m-duration) var(--_m-ease)}:where(tbody tr:nth-child(2n)){background-color:color-mix(in oklch, var(--_m-surface-raised), transparent 40%)}:where(tbody tr:hover){background-color:var(--_m-primary-subtle)}:where(tfoot) :where(th,td){border-block-end:0;font-weight:600}:where(figure:has(>table)){overflow-x:auto}:where(figure:has(>table),:is(body>header>nav,body>nav)>:is(ul,ol,menu)){scroll-padding-inline:1.5em}@supports (animation-timeline:scroll()){:where(thead){view-timeline:--_m-table;view-timeline-inset:var(--_m-sticky-offset,0) 0}:where(thead th){animation:linear both m-lift;animation-timeline:--_m-table;animation-range:exit-crossing exit-crossing 2rem}:where(figure:has(>table),:is(body>header>nav,body>nav)>:is(ul,ol,menu)){animation:linear both m-fade;animation-timeline:scroll(self inline)}:where(figure:has(>table),:is(body>header>nav,body>nav)>:is(ul,ol,menu)):where(:dir(rtl)){animation-direction:reverse}}:where(label){display:block}:where(:not(legend)+label){margin-block-start:var(--_m-space-3)}:where(fieldset){padding:var(--_m-space-3) var(--_m-space-4) var(--_m-space-4);border:1px solid var(--_m-border);border-radius:var(--m-radius,.5rem)}:where(legend){padding-inline:var(--_m-space-1);font-weight:600}:where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=submit],[type=reset],[type=button],[type=image],[type=hidden]),select,textarea){inline-size:100%;padding:var(--_m-space-2) var(--_m-space-3);border:1px solid var(--_m-control-border);border-radius:var(--m-radius,.5rem);background-color:var(--_m-surface);color:var(--_m-text);line-height:var(--_m-leading-tight);appearance:none;transition-property:border-color,box-shadow;transition-duration:var(--_m-duration);transition-timing-function:var(--_m-ease);display:block;:where(label)>&,:where(label)+&{margin-block-start:var(--_m-space-1)}&:where(:focus-visible){border-color:var(--_m-primary);box-shadow:0 0 0 1px var(--_m-primary), 0 0 0 4px var(--_m-primary-subtle);outline:2px solid #0000}&:where(:user-invalid,[aria-invalid=true]){border-color:var(--_m-danger)}&:where(:user-invalid,[aria-invalid=true]):where(:focus-visible){box-shadow:0 0 0 1px var(--_m-danger), 0 0 0 4px color-mix(in oklch, var(--_m-danger), transparent 80%)}&:where([aria-invalid=false]){border-color:var(--_m-success)}&:where([aria-invalid=false]:focus-visible){box-shadow:0 0 0 1px var(--_m-success), 0 0 0 4px color-mix(in oklch, var(--_m-success), transparent 80%)}&:where(:not(select,[type=date],[type=datetime-local],[type=month],[type=week],[type=time])){background-image:var(--_m-field-icon,none);background-position:right var(--_m-space-3) center;background-repeat:no-repeat;background-size:1em;&:where(:dir(rtl)){background-position:left var(--_m-space-3) center}&:where(:user-invalid,[aria-invalid=true],[aria-invalid=false]){padding-inline-end:calc(var(--_m-space-3) + 1.5em)}&:where(:user-invalid,[aria-invalid=true]){--_m-field-icon:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23de3c37' stroke-width='2.5' stroke-linecap='round'><circle cx='12' cy='12' r='9.5'/><path d='M12 7v6m0 4h.01'/></svg>")}&:where([aria-invalid=false]){--_m-field-icon:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23319751' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>")}}&::placeholder{color:var(--_m-text-muted);opacity:1}&:where([readonly]){border-color:var(--_m-border);background-color:var(--_m-surface-raised)}&:where(:disabled){background-color:var(--_m-surface-raised);opacity:.6;cursor:not-allowed}}:where(textarea){field-sizing:content;min-block-size:calc(3lh + 2 * var(--_m-space-2) + 2px);line-height:var(--_m-leading);resize:vertical;background-position:right var(--_m-space-3) top calc(var(--_m-space-2) + (1lh - 1em) / 2);&:where(:dir(rtl)){background-position:left var(--_m-space-3) top calc(var(--_m-space-2) + (1lh - 1em) / 2)}}:where(input[type=search]){background-image:var(--_m-field-icon,none), url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round'><circle cx='10.5' cy='10.5' r='6.5'/><path d='m15.5 15.5 5 5'/></svg>");background-position:right var(--_m-space-3) center, left var(--_m-space-3) center;padding-inline-start:calc(var(--_m-space-3) + 1.5em);&:where(:dir(rtl)){background-position:left var(--_m-space-3) center, right var(--_m-space-3) center}&::-webkit-search-decoration{appearance:none}}:where(input,select,textarea,fieldset)+:where(small){color:var(--_m-text-muted);margin-block-start:var(--_m-space-1);display:block}:where(fieldset:has(+small)){margin-block-end:0}:where(fieldset)+:where(small){margin-block-end:var(--_m-space-4)}:where(:user-invalid,[aria-invalid=true],fieldset:has(:user-invalid,[aria-invalid=true]))+:where(small){color:var(--_m-danger)}:where([aria-invalid=false])+:where(small){color:var(--_m-success)}:where(label:has(>:disabled,+:disabled),fieldset:disabled label){color:var(--_m-text-muted);cursor:not-allowed}:where(select:not([multiple],[size])){background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:calc(100% - var(--_m-space-3) - .6em) 50%, calc(100% - var(--_m-space-3) - .3em) 50%;background-repeat:no-repeat;background-size:.3em .3em;padding-inline-end:var(--_m-space-8)}@supports (appearance:base-select){:where(select:not([multiple],[size])){background-image:none;align-items:center;padding-inline-end:var(--_m-space-3);display:flex;&{appearance:base-select}&::picker(select){appearance:base-select}&::picker-icon{color:var(--_m-text-muted);transition:rotate var(--_m-duration) var(--_m-ease);margin-inline-start:auto}&:where(:open)::picker-icon{rotate:180deg}&::picker(select){margin-block:var(--_m-space-1);padding:var(--_m-space-1);border:1px solid var(--_m-border);border-radius:var(--m-radius,.5rem);background-color:var(--_m-surface-overlay);box-shadow:var(--_m-shadow-overlay);opacity:0;translate:0 calc(-1 * var(--_m-space-1));transition:opacity var(--_m-duration) var(--_m-ease), translate var(--_m-duration) var(--_m-ease), display var(--_m-duration) allow-discrete, overlay var(--_m-duration) allow-discrete}&:where(:open)::picker(select){opacity:1;translate:0}@starting-style{&:where(:open)::picker(select){opacity:0;translate:0 calc(-1 * var(--_m-space-1))}}}:where(select:not([multiple],[size]) option){padding:var(--_m-space-2) var(--_m-space-3);border-radius:calc(var(--m-radius,.5rem) - 2px);&:where(:hover,:focus-visible){background-color:var(--_m-tint);outline:2px solid #0000}&:where(:checked){font-weight:600}&::checkmark{color:var(--_m-primary)}}}:where(input:is([type=checkbox],[type=radio])){block-size:1.125em;inline-size:1.125em;vertical-align:top;border:1px solid var(--_m-control-border);background-color:var(--_m-surface);appearance:none;cursor:pointer;transition-property:background-color,border-color,box-shadow;transition-duration:var(--_m-duration);transition-timing-function:var(--_m-ease);border-radius:.25em;place-content:center;margin-block-start:calc(.5lh - .5625em);margin-inline-end:var(--_m-space-2);display:inline-grid;&:before{content:"";background-color:var(--_m-on-primary);block-size:.625em;inline-size:.625em;transition:scale var(--_m-duration) var(--_m-ease);scale:0}&:where(:checked){border-color:var(--_m-primary);background-color:var(--_m-primary)}&:where(:checked):before{scale:1}&:where(:focus-visible){box-shadow:0 0 0 2px var(--_m-surface), 0 0 0 4px var(--_m-primary);outline:2px solid #0000}&:where(:disabled){opacity:.5;cursor:not-allowed}&:where([aria-invalid=true]){border-color:var(--_m-danger)}}:where(input[type=checkbox]):before{clip-path:polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0%,43% 62%)}:where(input[type=checkbox]:indeterminate){border-color:var(--_m-primary);background-color:var(--_m-primary);&:before{clip-path:none;block-size:.125em;scale:1}}:where(input[type=radio]){border-radius:50%;&:before{border-radius:50%;block-size:.5em;inline-size:.5em}}:where(input[type=checkbox]:is([role=switch],[switch])){--_m-switch-travel:calc(2em - 2px - .25em - .75em);background-color:var(--_m-control-border);border-radius:999px;place-content:center start;inline-size:2em;padding-inline:.125em;&:before{clip-path:none;background-color:var(--_m-surface);border-radius:50%;block-size:.75em;inline-size:.75em;transition-property:translate,background-color;scale:1;box-shadow:0 1px 2px oklch(0% 0 0/.3)}&:where(:checked){background-color:var(--_m-primary)}&:where(:checked):before{background-color:var(--_m-on-primary);translate:var(--_m-switch-travel) 0}&:where(:checked:dir(rtl)):before{translate:calc(-1 * var(--_m-switch-travel)) 0}&:where(:indeterminate:not(:checked)){border-color:var(--_m-control-border);background-color:var(--_m-control-border);&:before{block-size:.75em}}}:where(input[type=range]){--_m-range-thumb:1.25rem;--_m-range-track:.5rem;inline-size:100%;block-size:var(--_m-range-thumb);accent-color:var(--_m-primary);appearance:none;cursor:pointer;background-color:#0000;overflow:hidden;&:where(:disabled){opacity:.5;cursor:not-allowed}&::-webkit-slider-runnable-track{block-size:var(--_m-range-track);background-color:var(--_m-tint);border-radius:999px}&::-moz-range-track{block-size:var(--_m-range-track);background-color:var(--_m-tint);border-radius:999px}&::-moz-range-progress{block-size:var(--_m-range-track);background-color:var(--_m-primary);border-radius:999px}&::-webkit-slider-thumb{inline-size:var(--_m-range-thumb);block-size:var(--_m-range-thumb);background-color:var(--_m-primary);box-shadow:inset 0 0 0 2px var(--_m-surface);appearance:none;border-image:linear-gradient(90deg, var(--_m-primary) 50%, transparent 0) 0 1 / calc(50% - var(--_m-range-track) / 2) 100vw / 0 100vw;transition:background-color var(--_m-duration) var(--_m-ease);border-radius:50%;margin-block-start:calc((var(--_m-range-track) - var(--_m-range-thumb)) / 2)}&::-moz-range-thumb{box-sizing:border-box;inline-size:var(--_m-range-thumb);block-size:var(--_m-range-thumb);border:2px solid var(--_m-surface);background-color:var(--_m-primary);transition:background-color var(--_m-duration) var(--_m-ease);border-radius:50%}&:where(:dir(rtl))::-webkit-slider-thumb{border-image-source:linear-gradient(-90deg, var(--_m-primary) 50%, transparent 0)}&:where(:hover:not(:disabled))::-webkit-slider-thumb{background-color:var(--_m-primary-hover)}&:where(:hover:not(:disabled))::-moz-range-thumb{background-color:var(--_m-primary-hover)}}:where(input[type=color]){border:1px solid var(--_m-control-border);border-radius:var(--m-radius,.5rem);background-color:var(--_m-surface);cursor:pointer;block-size:2.25rem;inline-size:3rem;padding:2px}:where(input[type=color])::-webkit-color-swatch-wrapper{padding:0}:where(input[type=color])::-webkit-color-swatch{border-radius:calc(var(--m-radius,.5rem) - 2px);border:0}:where(input[type=color])::-moz-color-swatch{border-radius:calc(var(--m-radius,.5rem) - 2px);border:0}:where(input[type=file]){inline-size:100%}:where(label)>:where(input:is([type=range],[type=color],[type=file])){margin-block-start:var(--_m-space-1);display:block}:where(label:has(>span+:is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=search]),textarea,select))){position:relative;&>:where(span){color:var(--_m-text-muted);font-size:.75em;line-height:var(--_m-leading-tight);pointer-events:none;transition-property:inset-block-start,font-size;transition-duration:var(--_m-duration);transition-timing-function:var(--_m-ease);position:absolute;inset-block-start:calc(1px + var(--_m-space-1));inset-inline-start:calc(1px + var(--_m-space-3))}&>:where(input,textarea,select){padding-block:calc(var(--_m-space-2) + .75em) var(--_m-space-1);margin-block-start:0}&>:where(textarea){min-block-size:calc(3lh + var(--_m-space-2) + .75em + var(--_m-space-1) + 2px)}&:where(:has(>:placeholder-shown:not(:focus)))>:where(span){font-size:1em;inset-block-start:calc(1px + var(--_m-space-2) + .75em)}&>:where(:placeholder-shown:not(:focus))::placeholder{opacity:0}}:where(button,input:is([type=submit],[type=reset],[type=button]),a[role=button]){padding:var(--_m-space-2) var(--_m-space-4);border:1px solid var(--_m-primary);border-radius:var(--m-radius,.5rem);background-color:var(--_m-primary);color:var(--_m-on-primary);font-weight:600;line-height:var(--_m-leading-tight);text-align:center;cursor:pointer;transition-property:background-color,border-color,color,box-shadow,scale;transition-duration:var(--_m-duration);transition-timing-function:var(--_m-ease);text-decoration-line:none;display:inline-block;&:where(:hover:not(:disabled,[aria-disabled=true])){border-color:var(--_m-primary-hover);background-color:var(--_m-primary-hover)}&:where(:active:not(:disabled,[aria-disabled=true])){scale:.98}&:where(:disabled,[aria-disabled=true]){opacity:.5;cursor:not-allowed}&+&{margin-inline-start:var(--_m-space-2)}:where(label,input,select,textarea,fieldset)+&{margin-block-start:var(--_m-space-4)}}:where(button,input):where([type=reset],[formnovalidate]){border-color:var(--_m-control-border);color:var(--_m-text);background-color:#0000}:where(input[type=file])::file-selector-button{border-color:var(--_m-control-border);color:var(--_m-text);background-color:#0000}:where(button,input):where([type=reset],[formnovalidate]):where(:hover:not(:disabled)){border-color:var(--_m-control-border);background-color:var(--_m-tint)}:where(input[type=file]:hover)::file-selector-button{border-color:var(--_m-control-border);background-color:var(--_m-tint)}:where(input[type=file])::file-selector-button{padding:var(--_m-space-2) var(--_m-space-4);border:1px solid var(--_m-control-border);border-radius:var(--m-radius,.5rem);cursor:pointer;transition:background-color var(--_m-duration) var(--_m-ease);margin-inline-end:var(--_m-space-3);font-weight:600}:where([role=group],search:not(:has(>form)),search>form){vertical-align:middle;display:inline-flex;&:where(:has(>input,>select,>textarea)){display:flex}:where(label)>&,:where(label)+&{margin-block-start:var(--_m-space-1)}&>:where(*){border-radius:0;margin:0}&>:where(*+*){margin-inline-start:-1px}&>:where(:focus-visible){z-index:2;border-radius:calc(var(--m-radius,.5rem) / 2);position:relative}&>:where(:first-child){border-start-start-radius:var(--m-radius,.5rem);border-end-start-radius:var(--m-radius,.5rem)}&>:where(:last-child){border-start-end-radius:var(--m-radius,.5rem);border-end-end-radius:var(--m-radius,.5rem)}&>:where(input,select,textarea){flex:1;inline-size:auto;min-inline-size:0}&>:where(span){padding:var(--_m-space-2) var(--_m-space-3);border:1px solid var(--_m-control-border);background-color:var(--_m-surface-raised);color:var(--_m-text-muted);line-height:var(--_m-leading-tight);white-space:nowrap}&>:where(:hover:not(:focus-visible,span)){z-index:1;position:relative}&>:where(button,input:is([type=submit],[type=reset],[type=button]),a[role=button])+:where(button,input:is([type=submit],[type=reset],[type=button]),a[role=button]){border-inline-start-color:color-mix(in oklch, currentcolor, transparent 70%)}}:where(button[aria-pressed]){border-color:var(--_m-control-border);color:var(--_m-text);background-color:#0000;&:where(:hover:not(:disabled)){border-color:var(--_m-control-border);background-color:var(--_m-tint)}&:where([aria-pressed=true]){border-color:var(--_m-primary);background-color:var(--_m-primary-subtle);box-shadow:inset 0 0 0 1px var(--_m-primary)}&:where([aria-pressed=true]:not(:focus-visible)){z-index:1;position:relative}&:where([aria-pressed=true]:hover:not(:disabled)){border-color:var(--_m-primary-hover);background-color:color-mix(in oklch, var(--_m-primary), transparent 75%)}}:where(details){padding-inline:var(--_m-space-4);border:1px solid var(--_m-border);border-radius:var(--m-radius,.5rem)}:where(details[open]){padding-block-end:var(--_m-space-4)}:where(summary){margin-inline:calc(-1 * var(--_m-space-4));padding:var(--_m-space-3) var(--_m-space-4);border-radius:calc(var(--m-radius,.5rem) - 1px);cursor:pointer;font-weight:600;list-style:none;&::-webkit-details-marker{display:none}&:before{content:"";vertical-align:.15em;border-style:solid;border-color:var(--_m-text-muted);block-size:.45em;inline-size:.45em;transition:rotate var(--_m-duration) var(--_m-ease);border-width:0 2px 2px 0;margin-inline:.1em .6em;display:inline-block;rotate:-45deg}&:where(:dir(rtl)):before{rotate:135deg}}:where(details[open])>:where(summary){border-end-end-radius:0;border-end-start-radius:0}:where(details[open])>:where(summary):before{rotate:45deg}@supports (interpolate-size:allow-keywords){:where(details){transition:padding-block-end var(--_m-duration-slow) var(--_m-ease)}:where(details)::details-content{contain:layout;interpolate-size:allow-keywords;block-size:0;transition:block-size var(--_m-duration-slow) var(--_m-ease), content-visibility var(--_m-duration-slow) allow-discrete;overflow:clip}:where(details[open])::details-content{block-size:auto}}:where(dialog,[popover]){max-inline-size:min(var(--m-measure,100ch), calc(100vw - 2 * var(--_m-space-4)));padding:var(--_m-space-6);border:1px solid var(--_m-border);border-radius:calc(var(--m-radius,.5rem) * 1.5);background-color:var(--_m-surface-overlay);color:var(--_m-text);box-shadow:var(--_m-shadow-overlay);opacity:0;transition:opacity var(--_m-duration-slow) var(--_m-ease), scale var(--_m-duration-slow) var(--_m-ease), translate var(--_m-duration-slow) var(--_m-ease), display var(--_m-duration-slow) allow-discrete, overlay var(--_m-duration-slow) allow-discrete}:where(dialog){scale:.96}:where(dialog:modal){overscroll-behavior:contain}:where([popover]){translate:0 var(--_m-space-2)}:where(dialog[open],[popover]:popover-open){opacity:1;transition-timing-function:var(--_m-ease), var(--_m-spring), var(--_m-spring);translate:0;scale:1}@starting-style{:where(dialog[open]){opacity:0;scale:.96}:where([popover]:popover-open){opacity:0;translate:0 var(--_m-space-2)}}:where(dialog)::backdrop{backdrop-filter:blur(4px);opacity:0;overscroll-behavior:contain;transition:opacity var(--_m-duration-slow) var(--_m-ease), display var(--_m-duration-slow) allow-discrete, overlay var(--_m-duration-slow) allow-discrete;background-color:oklch(0% 0 0/.4);overflow:hidden}:where(dialog[open])::backdrop{opacity:1}@media (prefers-reduced-transparency:reduce){:where(dialog)::backdrop{backdrop-filter:none;background-color:oklch(0% 0 0/.6)}}@starting-style{:where(dialog[open])::backdrop{opacity:0}}:where(img,video,canvas,iframe,svg){max-inline-size:100%}:where(img,video,canvas){block-size:auto}:where(a>svg[aria-hidden=true],a>[aria-hidden=true]>:is(img,svg)){vertical-align:-.25em;block-size:1.25em;inline-size:auto}:where(img,video){border-radius:var(--m-radius,.5rem)}:where(iframe){border:1px solid var(--_m-border);border-radius:var(--m-radius,.5rem)}:where(audio){inline-size:100%}:where(figure>img,figure>video,figure>iframe,figure>canvas,figure>svg,figure>picture>img){display:block}:where(progress){background-color:var(--_m-tint);appearance:none;border:0;border-radius:999px;block-size:.5rem;inline-size:100%;display:block;overflow:hidden}:where(progress)::-webkit-progress-bar{background-color:#0000}:where(progress)::-webkit-progress-value{border-radius:inherit;background-color:var(--_m-primary)}:where(progress)::-moz-progress-bar{border-radius:inherit;background-color:var(--_m-primary)}:where(progress:indeterminate){background-image:linear-gradient(var(--_m-primary), var(--_m-primary));animation:var(--_m-slide);background-repeat:no-repeat;background-size:30% 100%}:where(progress:indeterminate)::-moz-progress-bar{background-color:#0000}:where(meter){--_m-warning:light-dark(oklch(62% .14 65),oklch(80% .14 75));vertical-align:middle;background:var(--_m-tint);appearance:none;border-radius:999px;block-size:.5rem;overflow:hidden}:where(meter)::-webkit-meter-bar{background:0 0;border:0;block-size:100%}:where(meter)::-webkit-meter-optimum-value{background:var(--_m-success)}:where(meter)::-webkit-meter-suboptimum-value{background:var(--_m-warning)}:where(meter)::-webkit-meter-even-less-good-value{background:var(--_m-danger)}:where(meter)::-moz-meter-bar{background:var(--_m-success)}:where(meter:-moz-meter-sub-optimum)::-moz-meter-bar{background:var(--_m-warning)}:where(meter:-moz-meter-sub-sub-optimum)::-moz-meter-bar{background:var(--_m-danger)}:where([aria-busy=true]){cursor:progress}:where([aria-busy=true]):before{content:"";vertical-align:middle;border:.15em solid;block-size:1em;inline-size:1em;animation:var(--_m-spin);border-inline-end-color:#0000;border-radius:50%;margin-block:-1em;margin-inline-end:.5em;display:inline-block}:where(:is(article,aside,div,fieldset,figure,form,main,ol,section,ul)[aria-busy=true]){z-index:0;position:relative;&>:where(*){opacity:.4}&:before{z-index:1;block-size:2em;inline-size:2em;margin:auto;position:absolute;inset:0}}:where(body>header){border-block-end:1px solid var(--_m-border);padding-block-end:var(--_m-space-6)}:where(body>footer){border-block-start:1px solid var(--_m-border);font-size:var(--_m-text-sm);color:var(--_m-text-muted);margin-block-start:calc(var(--m-density,1) * 3rem);padding-block-start:var(--_m-space-6)}:where(nav) :where(ul,ol,menu){gap:var(--_m-space-2) var(--_m-space-4);flex-wrap:wrap;padding:0;list-style:none;display:flex}:where(nav li){margin:0}:where(nav a:not([role=button])){color:inherit;text-decoration-color:#0000;&:where(:hover,[aria-current]:not([aria-current=false])){color:var(--_m-primary)}&:where([aria-current]:not([aria-current=false])){font-weight:600}}:where(aside){padding:var(--_m-space-4);border-radius:var(--m-radius,.5rem);background-color:var(--_m-surface-raised)}:where(address){font-style:normal}:where(hr){margin-block:var(--_m-space-8);border:0;border-block-start:1px solid var(--_m-border)}:where(body>header:has(>nav)){display:contents;&>:where(:last-child){margin-block-end:var(--_m-space-8)}}:where(body>header>nav){z-index:1;padding-block:var(--_m-space-3);background-color:var(--_m-surface);view-transition-name:m-top-nav;border-image:linear-gradient(to top, var(--_m-border) 1px, var(--_m-surface) 1px) fill 0 / 0 / 0 100vmax;position:sticky;inset-block-start:0;&:after{content:"";block-size:var(--_m-drop);border-image:linear-gradient(var(--_m-edge), transparent) fill 0 / 0 / 0 100vmax;pointer-events:none;position:absolute;inset:100% 0 auto}}@supports (animation-timeline:scroll()){:where(body>header>nav){animation:linear both m-lift;animation-timeline:scroll(root);animation-range:0 2rem}}:where(body>header>nav+nav){view-transition-name:m-sub-nav;inset-block-start:var(--_m-bar-size)}:where(body>header>nav,body>nav) :where(ul,ol,menu){scrollbar-width:thin;flex-wrap:nowrap;margin:-4px;padding:4px;overflow-x:auto;&>:where(li){flex:none}}:where(nav:not(body>nav):has(>:is(ul,ol,menu)+:is(ul,ol,menu))){justify-content:space-between;align-items:center;gap:var(--_m-space-2) var(--_m-space-6);flex-wrap:wrap;display:flex;&:where(:not(body>header>nav))>:where(ul,ol,menu){margin-block:0}&>:where(:last-child){min-inline-size:0}&:where(body>header>nav){flex-wrap:nowrap}}:where(nav:not(body>nav,body>header>nav):has(>ol)){font-size:var(--_m-text-sm);margin-block-end:var(--_m-space-4);&>:where(ol){gap:var(--_m-space-2);&>:where(li+li):before{content:"/" / "";color:var(--_m-text-muted);margin-inline-end:var(--_m-space-2)}&>:where(li:last-child),&>:where(li:last-child) :where(a){color:var(--_m-text-muted);font-weight:inherit}}}@media (width>=64rem){:where(body:has(>nav,>aside)){grid-template-columns:[full-start nav-start] fit-content(16rem) [nav-end main-start] minmax(0, var(--m-measure,100ch)) [main-end aside-start] fit-content(16rem) [aside-end full-end];grid-auto-flow:dense;justify-content:center;align-items:start;max-inline-size:none;display:grid;&>:where(*),&>:where(header:has(>nav))>:where(*){grid-column:full}&>:where(:not(nav,aside,main)),&>:where(header:has(>nav))>:where(*){contain:inline-size}&>:where(main){grid-column:main}}:where(body>header>nav){margin-inline:min(0px, (100% - min(var(--m-measure,100ch) + 32rem, 100vw - 2 * var(--_m-space-4))) / 2)}:where(body>nav,body>aside){max-block-size:calc(100dvh - var(--_m-sticky-offset) - 2 * var(--_m-space-4));overscroll-behavior:contain;position:sticky;inset-block-start:calc(var(--_m-sticky-offset) + var(--_m-space-4));overflow-y:auto}:where(body>nav){grid-column:nav;margin-inline-end:var(--_m-space-8);padding:4px;& :where(ul,ol,menu){gap:var(--_m-space-2);flex-direction:column;margin:0;padding:0;overflow:visible}& :where(li)>:where(ul,ol,menu){margin-block-start:var(--_m-space-2);padding-inline-start:var(--_m-space-3)}}:where(body>aside){font-size:var(--_m-text-sm);background-color:#0000;border-radius:0;grid-column:aside;margin-inline-start:var(--_m-space-8);padding:4px}}@media (prefers-reduced-motion:no-preference){@supports (container-type:scroll-state){:where(:root:not([data-motion=reduce]):has(>body>header>nav)){container-type:scroll-state}:where(body>header>nav){transition:translate var(--_m-duration-slow) var(--_m-ease)}@container scroll-state(scrolled:bottom){:where(:root:not(:has(>body>header>nav:focus-within)) body>header>nav){translate:0 -100%}:where(:root:not(:has(>body>header>nav:focus-within)) thead th){inset-block-start:calc(var(--_m-sticky-offset) - var(--_m-bar-size))}:where(:root:not(:has(>body>header>nav:focus-within)) body>:is(nav,aside)){inset-block-start:calc(var(--_m-sticky-offset) - var(--_m-bar-size) + var(--_m-space-4))}}}}:where(:is(ul,ol,menu)[popover],[popover]>:is(ul,ol,menu)){flex-flow:column;gap:0;margin:0;padding:0;list-style:none;display:flex;overflow:visible;&:where([popover]:not(:popover-open)){display:none}&>:where(li){margin:0;padding:0}&>:where(li)>:where(a,button){inline-size:100%;padding:var(--_m-space-2) var(--_m-space-3);border-radius:var(--m-radius,.5rem);color:var(--_m-text);font-weight:inherit;text-align:start;background-color:#0000;border:0;text-decoration-line:none;display:block;&:where(:hover:not(:disabled),:focus-visible){background-color:var(--_m-tint);color:var(--_m-text)}&:where([aria-current]:not([aria-current=false])){color:var(--_m-primary);font-weight:600}&:where(:focus-visible){outline-offset:-2px}}}:where(:is(ul,ol,menu)[popover],[popover]:has(>:is(ul,ol,menu))){min-inline-size:12rem;padding:var(--_m-space-1)}@supports (position-area:block-end){:where(:is(ul,ol,menu)[popover],[popover]:has(>:is(ul,ol,menu))){margin:var(--_m-space-1) 0;position-area:block-end span-inline-end;position-try-fallbacks:flip-block, flip-inline;inset:auto}}:where(article):where(:not(main>article:only-child)){padding:var(--_m-space-6);border:1px solid var(--_m-border);border-radius:calc(var(--m-radius,.5rem) * 1.5);background-color:var(--_m-surface-overlay);overflow:clip;&>:where(header,footer){margin-inline:calc(-1 * var(--_m-space-6));padding:var(--_m-space-4) var(--_m-space-6);background-color:color-mix(in oklch, var(--_m-text), transparent 96%)}&>:where(header:first-child){margin-block:calc(-1 * var(--_m-space-6)) var(--_m-space-6);border-block-end:1px solid var(--_m-border)}&>:where(footer:last-child){margin-block:var(--_m-space-6) calc(-1 * var(--_m-space-6));border-block-start:1px solid var(--_m-border)}}:where(div,section):where(:has(>article+article):not(:has(>:not(article)))){gap:var(--_m-space-4);grid-template-columns:repeat(auto-fit,minmax(min(16rem,100%),1fr));margin-block-end:var(--_m-space-8);display:grid;&:where(:last-child){margin-block-end:0}&>:where(article){flex-direction:column;margin:0;display:flex;&>:where(footer:last-child){margin-block-start:auto}}}}@layer m.a11y{:where(:focus-visible):where(:not(select,textarea,option,input:not([type=range],[type=color],[type=file],[type=submit],[type=reset],[type=button],[type=image]))){outline:var(--_m-focus-width) solid var(--_m-primary);outline-offset:2px;animation:m-focus-in var(--_m-duration) var(--_m-ease)}:where(a:not([role=button])){border-radius:calc(var(--m-radius,.5rem) / 2)}:where(summary:focus-visible){outline-offset:0}:where(input:is([type=range],[type=file])){border-radius:var(--m-radius,.5rem)}@keyframes m-focus-in{0%{outline-offset:0}}:where(:target){animation:m-target-in calc(var(--_m-duration) * 10) var(--_m-ease);scroll-margin-block-start:var(--_m-space-8)}@keyframes m-target-in{0%{background-color:var(--_m-primary-subtle)}}@media (forced-colors:active){:where(button[aria-pressed=true]){color:selecteditemtext;forced-color-adjust:none;background-color:selecteditem;border-color:selecteditem;&:where(:focus-visible){outline-color:canvastext}}:where(input:is([type=checkbox],[type=radio])){forced-color-adjust:none;background-color:canvas;border-color:canvastext;&:before{background-color:highlighttext}&:where(:checked){background-color:highlight;border-color:highlight}&:where(:disabled){border-color:graytext}}:where(input[type=checkbox]:indeterminate){background-color:highlight;border-color:highlight}:where(input[type=checkbox]:is([role=switch],[switch])){&:before{box-shadow:none;background-color:canvastext}&:where(:checked):before{background-color:highlighttext}&:where(:indeterminate:not(:checked)){background-color:canvas;border-color:canvastext}}:where(progress,meter){forced-color-adjust:none;background-color:canvas;border:1px solid canvastext}:where(meter){--_m-success:Highlight;--_m-warning:Highlight;--_m-danger:Highlight}:where(progress)::-webkit-progress-value{background-color:highlight}:where(progress)::-moz-progress-bar{background-color:highlight}:where(progress:indeterminate){background-image:linear-gradient(highlight,highlight)}:where(progress:indeterminate)::-moz-progress-bar{background-color:#0000}:where(input[type=range]){--_m-range-fill:Highlight;forced-color-adjust:none;&:where(:disabled){--_m-range-fill:GrayText;opacity:1}&:where(:focus-visible){outline-color:highlight}&::-webkit-slider-runnable-track{background-color:canvas;box-shadow:inset 0 0 0 1px canvastext}&::-moz-range-track{background-color:canvas;box-shadow:inset 0 0 0 1px canvastext}&::-moz-range-progress{background-color:var(--_m-range-fill)}&::-webkit-slider-thumb{background-color:var(--_m-range-fill);border-image-source:linear-gradient(90deg, var(--_m-range-fill) 50%, transparent 0);box-shadow:inset 0 0 0 2px canvas}&:where(:dir(rtl))::-webkit-slider-thumb{border-image-source:linear-gradient(-90deg, var(--_m-range-fill) 50%, transparent 0)}&::-moz-range-thumb{background-color:var(--_m-range-fill);border-color:canvas}}:where([data-scroll-progress]:root):before{forced-color-adjust:none;background-color:highlight}:where(mark){color:marktext;forced-color-adjust:none;background-color:mark}:where(aside,pre){border:1px solid canvastext}:where(body>header>nav){border-block-end:1px solid canvastext}@supports not (appearance:base-select){:where(select:not([multiple],[size])){appearance:auto;background-image:none;padding-inline-end:var(--_m-space-3)}}}@media print{:where(:root,:host){color-scheme:light}:where(*){box-shadow:none;text-shadow:none;background:0 0}:where(figure:has(>table)){animation:none}:where(body){max-inline-size:none;padding:0}:where(a[href]:not([href^=\#],[href^=javascript\:])):after{content:" (" attr(href) ")";color:var(--_m-text-muted);overflow-wrap:anywhere;font-size:.875em}:where(nav a):after{content:none}:where(pre){white-space:pre-wrap;border:1px solid var(--_m-border);overflow:visible}:where(thead th,body>header>nav,body>nav,body>aside){position:static}:where(body>header>nav,body>nav) :where(ul,ol,menu){flex-wrap:wrap;overflow:visible}:where(details)::details-content{content-visibility:visible;block-size:auto}:where(pre,blockquote,figure,img,video,table,tr,details){break-inside:avoid}:where(h1,h2,h3,h4,h5,h6){break-after:avoid}:where([data-scroll-progress]:root):before{display:none}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abraham/modern.css",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "A clean, modern classless CSS framework.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://modern.ink",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/abraham/modern.css.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=26"
|
|
14
|
+
},
|
|
15
|
+
"devEngines": {
|
|
16
|
+
"runtime": {
|
|
17
|
+
"name": "node",
|
|
18
|
+
"version": "26"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"skills"
|
|
24
|
+
],
|
|
25
|
+
"style": "dist/modern.css",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./dist/modern.css",
|
|
28
|
+
"./min": "./dist/modern.min.css"
|
|
29
|
+
},
|
|
30
|
+
"jsdelivr": "dist/modern.min.css",
|
|
31
|
+
"unpkg": "dist/modern.min.css",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"browserslist": [
|
|
36
|
+
"last 2 Chrome major versions",
|
|
37
|
+
"last 2 Edge major versions",
|
|
38
|
+
"last 2 Firefox major versions",
|
|
39
|
+
"last 2 Safari major versions",
|
|
40
|
+
"last 2 iOS major versions"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "node scripts/build.ts",
|
|
44
|
+
"start": "node scripts/dev.ts",
|
|
45
|
+
"lint": "stylelint \"src/**/*.css\"",
|
|
46
|
+
"typecheck": "tsc",
|
|
47
|
+
"format": "prettier --write .",
|
|
48
|
+
"format:check": "prettier --check .",
|
|
49
|
+
"size": "node scripts/size.ts",
|
|
50
|
+
"test": "playwright test --project=chromium --project=webkit --grep-invert \"@visual|@legacy\"",
|
|
51
|
+
"test:visual": "scripts/test-visual.sh",
|
|
52
|
+
"test:legacy": "playwright test --project=chromium --grep @legacy",
|
|
53
|
+
"prepublishOnly": "npm run build"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@axe-core/playwright": "^4.14.0",
|
|
57
|
+
"@playwright/test": "1.65.0",
|
|
58
|
+
"@types/node": "^26.6.6",
|
|
59
|
+
"browserslist": "^4.29.5",
|
|
60
|
+
"lightningcss": "^1.33.0",
|
|
61
|
+
"prettier": "3.9.10",
|
|
62
|
+
"stylelint": "^18.0.0",
|
|
63
|
+
"stylelint-config-standard": "^41.0.0",
|
|
64
|
+
"typescript": "6.0.3"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: modern-css
|
|
3
|
+
description: "Add the modern.css classless CSS framework (@abraham/modern.css) to a website or web app, or restyle existing pages with it. Use when asked to install, set up, adopt, or migrate to modern.css; to style plain semantic HTML without classes; to convert Bootstrap, Tailwind, Pico, or hand-written class-based markup to classless semantic HTML; to theme modern.css with its --m-* custom properties, dark mode, or contrast settings; or to build docs, article, sign-in, pricing, or settings pages with modern.css."
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# modern.css
|
|
8
|
+
|
|
9
|
+
modern.css is one stylesheet that styles semantic HTML elements and ARIA states directly, with no classes. Every rule sits in `@layer m` with zero specificity, so any other CSS overrides it. It also owns the document layout: the body column, sticky top bar, side nav, and rail all come from the markup structure.
|
|
10
|
+
|
|
11
|
+
Live demo and examples: https://modern.ink/
|
|
12
|
+
|
|
13
|
+
## Procedure
|
|
14
|
+
|
|
15
|
+
1. **Inspect the project.**
|
|
16
|
+
- How are pages produced: static HTML, server templates, a static site generator, or a client-side app that mounts into a wrapper element?
|
|
17
|
+
- Where is the shared `<head>` or layout template?
|
|
18
|
+
- What CSS exists: a class-based framework, a reset, component styles, inline styles?
|
|
19
|
+
2. **Add the stylesheet** once, in the shared `<head>`, before any other stylesheet:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@abraham/modern.css/dist/modern.min.css" />
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
With a bundler, run `npm install @abraham/modern.css` instead and import `@abraham/modern.css` (or `@abraham/modern.css/min`) from the main stylesheet or entry file.
|
|
26
|
+
|
|
27
|
+
3. **Deal with the existing CSS.**
|
|
28
|
+
- Unlayered CSS always beats modern.css. A class-based framework or global reset (Bootstrap, Tailwind Preflight, normalize.css) restyles every element and hides what modern.css does. Plan to remove it, and confirm with the user before deleting anything they may still need.
|
|
29
|
+
- Keep only small, site-specific rules. They work unlayered, or in a layer declared after `m`, such as `@layer m, site;`.
|
|
30
|
+
4. **Build the page shell.** Restructure each page template into the skeleton in [assets/page.html](./assets/page.html): `body > header > nav` for the top bar, optional `body > nav` and `body > aside` columns, `main`, and `footer`.
|
|
31
|
+
5. **Rewrite components as semantic HTML,** using [references/markup.md](./references/markup.md). Remove classes, wrapper `div`s, and icons that only existed for styling. Keep classes that scripts or tests rely on; they're harmless.
|
|
32
|
+
6. **Theme** with the public properties and attributes below, using the site's brand values.
|
|
33
|
+
7. **Verify** (see below), then report what changed and anything you couldn't express classlessly.
|
|
34
|
+
|
|
35
|
+
## Rules
|
|
36
|
+
|
|
37
|
+
- **No classes, IDs, or inline styles for styling.** Pick the element or attribute that means the thing; the reference lists what modern.css styles. Only if nothing fits, add a short rule in the site's own CSS. For example, modern.css has no centering rule, so a narrow sign-in card needs `main { max-inline-size: 24rem; margin-inline: auto; }`.
|
|
38
|
+
- **Never use `!important`.** It's never needed, because modern.css has zero specificity.
|
|
39
|
+
- **Never set or depend on `--_m-*` tokens.** They're internal and can change between versions. Use only the `--m-*` properties.
|
|
40
|
+
- **Structure is the API.** The layout rules match direct children: `body > header > nav`, `body > nav`, `body > aside`, `main > article:only-child`. A wrapper between `body` and these elements turns those rules off.
|
|
41
|
+
- Client-side apps often mount into `<div id="root">`, and then the sticky bar and columns don't apply, though element styles still do. Render the shell (header, navs, main, footer) in the server or static HTML when possible. Otherwise tell the user the page will flow as one column.
|
|
42
|
+
- **Styling states are real states.** `aria-current`, `aria-pressed`, `aria-invalid`, `aria-busy`, `aria-disabled`, and `disabled` change how things look. Set them only when they're true, and keep them in sync from script.
|
|
43
|
+
- **Accessibility comes with the markup:**
|
|
44
|
+
- Every form control has a label.
|
|
45
|
+
- Every image has `alt`.
|
|
46
|
+
- Tables have a `caption` and header cells with `scope`.
|
|
47
|
+
- A horizontally scrolling `pre` gets `tabindex="0"`.
|
|
48
|
+
- When a page has more than one `nav` or `aside`, each gets an `aria-label`.
|
|
49
|
+
|
|
50
|
+
## Theme
|
|
51
|
+
|
|
52
|
+
Set these on `:root` for the whole site. `--m-primary`, `--m-on-primary`, `--m-density`, `--m-radius`, and `--m-font-mono` also work on any element, for one part of a page. `--m-font-sans`, `--m-font-size`, and `--m-measure` are read on `body`, so set them on `:root`; on an inner element they don't change its body text.
|
|
53
|
+
|
|
54
|
+
| Property | Default | Controls |
|
|
55
|
+
| ---------------- | ----------------------------------------- | ---------------------------------------------- |
|
|
56
|
+
| `--m-primary` | `oklch(55% 0.19 40)` | Links, buttons, focus rings, checked controls |
|
|
57
|
+
| `--m-on-primary` | black or white, for contrast | Text on primary backgrounds |
|
|
58
|
+
| `--m-density` | `1` | All spacing; `0.75` is compact, `1.25` is airy |
|
|
59
|
+
| `--m-radius` | `0.5rem` | Corner radius; cards use 1.5 times this |
|
|
60
|
+
| `--m-font-sans` | `system-ui, sans-serif` | Body and heading font |
|
|
61
|
+
| `--m-font-mono` | `ui-monospace, SFMono-Regular, monospace` | Code font |
|
|
62
|
+
| `--m-font-size` | `1rem` | Base text size; the type scale follows it |
|
|
63
|
+
| `--m-measure` | `100ch` | Width of the main column |
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
:root {
|
|
67
|
+
--m-primary: #2563eb;
|
|
68
|
+
--m-radius: 0.25rem;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
In a web component, link modern.css inside its shadow root. The component inherits the page's theme properties and `data-theme`, `data-contrast`, and `data-motion`, or uses the defaults when the page doesn't load modern.css.
|
|
73
|
+
|
|
74
|
+
Hover, subtle, and dark-mode variants of the primary color are derived from it, so set one brand color, not a palette.
|
|
75
|
+
|
|
76
|
+
These few properties go a long way. The showcase (https://modern.ink/showcase/) has four whole pages: a magazine essay, a dark operations dashboard, a playful landing page, and a minimal event poster. Each is themed with only a `:root` block of these properties, and shows that block at the bottom of the page. Use them as starting points.
|
|
77
|
+
|
|
78
|
+
What the properties can't change: neutral surfaces and text colors, heading weight, shadows, and a separate heading font. Don't reach for `--_m-*` tokens to get them. Tell the user it's outside modern.css's theming, or add a small unlayered rule of their own.
|
|
79
|
+
|
|
80
|
+
Keep contrast in mind:
|
|
81
|
+
|
|
82
|
+
- In dark mode, modern.css lightens the primary. Its default `--m-on-primary` adapts, but an explicit one should too, for example `light-dark(white, oklch(20% 0.05 300deg))`.
|
|
83
|
+
- In dark themes, keep the primary at or below about 70% lightness. Lighter primaries can make pressed toggles fail contrast when the reader asks for more contrast.
|
|
84
|
+
|
|
85
|
+
The page follows the system's light or dark scheme, reduced motion, and contrast preferences. These attributes force them, on `<html>` or on any element:
|
|
86
|
+
|
|
87
|
+
- `data-theme="light"` or `data-theme="dark"`
|
|
88
|
+
- `data-motion="reduce"`
|
|
89
|
+
- `data-contrast="more"`
|
|
90
|
+
|
|
91
|
+
`<html data-scroll-progress>` adds a reading progress bar. Same-origin page navigations cross-fade automatically where the browser supports view transitions.
|
|
92
|
+
|
|
93
|
+
## Verify
|
|
94
|
+
|
|
95
|
+
- **Leftovers:** search the templates for `class=` and for the old framework's stylesheet or imports. Anything left should be needed by a script or test.
|
|
96
|
+
- **Browser checks.** Load the main pages:
|
|
97
|
+
- in light and dark, using `data-theme` on `<html>` if you can't switch the system setting;
|
|
98
|
+
- at about 1280px wide, where a side nav and rail become columns from 64rem up;
|
|
99
|
+
- at about 375px wide, where everything stacks and navs scroll sideways without making the page scroll sideways.
|
|
100
|
+
- **Keyboard:** tab through a page. Focus rings must be visible, and focused elements must never sit under the sticky top bar.
|
|
101
|
+
- **Accessibility scan:** if the project has Playwright or another browser test runner, run an axe check (`@axe-core/playwright`) on the changed pages.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Page title · Site name</title>
|
|
7
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@abraham/modern.css/dist/modern.min.css" />
|
|
8
|
+
<!-- Optional: one brand color and any other public properties. -->
|
|
9
|
+
<style>
|
|
10
|
+
:root {
|
|
11
|
+
--m-primary: #2563eb;
|
|
12
|
+
}
|
|
13
|
+
</style>
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<header>
|
|
17
|
+
<!-- The first nav here is the sticky top bar. Two lists split to either end. -->
|
|
18
|
+
<nav aria-label="Site">
|
|
19
|
+
<ul>
|
|
20
|
+
<li><strong>Site name</strong></li>
|
|
21
|
+
</ul>
|
|
22
|
+
<ul>
|
|
23
|
+
<li><a href="/" aria-current="page">Home</a></li>
|
|
24
|
+
<li><a href="/docs/">Docs</a></li>
|
|
25
|
+
<li><a href="/about/">About</a></li>
|
|
26
|
+
</ul>
|
|
27
|
+
</nav>
|
|
28
|
+
<h1>Page title</h1>
|
|
29
|
+
<p>One or two sentences about this page.</p>
|
|
30
|
+
</header>
|
|
31
|
+
|
|
32
|
+
<!-- Optional: a side nav. Delete it for a single-column page. -->
|
|
33
|
+
<nav aria-label="Sections">
|
|
34
|
+
<ul>
|
|
35
|
+
<li><a href="#first">First section</a></li>
|
|
36
|
+
<li><a href="#second">Second section</a></li>
|
|
37
|
+
</ul>
|
|
38
|
+
</nav>
|
|
39
|
+
|
|
40
|
+
<main>
|
|
41
|
+
<section id="first" aria-labelledby="first-title">
|
|
42
|
+
<h2 id="first-title">First section</h2>
|
|
43
|
+
<p>Content goes here.</p>
|
|
44
|
+
</section>
|
|
45
|
+
<section id="second" aria-labelledby="second-title">
|
|
46
|
+
<h2 id="second-title">Second section</h2>
|
|
47
|
+
<p>More content.</p>
|
|
48
|
+
</section>
|
|
49
|
+
</main>
|
|
50
|
+
|
|
51
|
+
<!-- Optional: a rail on the other side. Delete it if you don't need one. -->
|
|
52
|
+
<aside aria-label="On this page">
|
|
53
|
+
<p><strong>On this page</strong></p>
|
|
54
|
+
<ul>
|
|
55
|
+
<li><a href="#first">First section</a></li>
|
|
56
|
+
<li><a href="#second">Second section</a></li>
|
|
57
|
+
</ul>
|
|
58
|
+
</aside>
|
|
59
|
+
|
|
60
|
+
<footer>
|
|
61
|
+
<p>© Site name</p>
|
|
62
|
+
</footer>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# modern.css markup reference
|
|
2
|
+
|
|
3
|
+
What modern.css styles, and the markup that produces each pattern. Everything here works without classes. Live versions of every pattern: https://modern.ink/components/typography.html
|
|
4
|
+
|
|
5
|
+
## Converting class-based markup
|
|
6
|
+
|
|
7
|
+
| Class-based pattern | modern.css markup |
|
|
8
|
+
| ------------------------------------------ | -------------------------------------------------------------------------------------- |
|
|
9
|
+
| `.container`, `.wrapper` | Nothing. `body` is already a centered column; set `--m-measure` to change its width. |
|
|
10
|
+
| `.navbar` with brand and links | `body > header > nav` with two `ul`s: brand first, links second |
|
|
11
|
+
| `.sidebar`, `.toc` | `body > nav` (side nav) or `body > aside` (rail), next to `main` |
|
|
12
|
+
| `.btn`, `.btn-primary` | `button`, or `a role="button"` for a link |
|
|
13
|
+
| `.btn-secondary` on Cancel or Reset | `button type="reset"`, or a button with `formnovalidate` |
|
|
14
|
+
| `.btn-group`, `.input-group` | `<span role="group" aria-label="…">` around the buttons or the field and its button |
|
|
15
|
+
| `.input-group-text`, `.addon` | A `span` inside that `role="group"`, linked from the field with `aria-describedby` |
|
|
16
|
+
| `.active` in a nav or menu | `aria-current="page"` on the link |
|
|
17
|
+
| Toggle or segmented control | `button aria-pressed="true"` or `"false"`, in a `role="group"` for a segmented control |
|
|
18
|
+
| `.card` with `.card-header`/`.card-footer` | `article` with `header` and `footer` children |
|
|
19
|
+
| `.row` of cards, `.grid` | A `div` that contains only `article`s |
|
|
20
|
+
| `.form-group`, `.form-control` | `label` wrapping the text and the field |
|
|
21
|
+
| `.form-text`, `.help-block` | `small` right after the field, linked with `aria-describedby` |
|
|
22
|
+
| `.is-invalid`, `.is-valid` | `aria-invalid="true"` or `"false"` |
|
|
23
|
+
| `.form-switch`, `.toggle` | `input type="checkbox" role="switch"` |
|
|
24
|
+
| `.alert`, `.callout`, `.note` | `aside` inside `main` |
|
|
25
|
+
| `.breadcrumb` | `nav aria-label="Breadcrumb"` containing an `ol` |
|
|
26
|
+
| `.modal` | `dialog`, opened by a `command="show-modal"` button |
|
|
27
|
+
| `.dropdown-menu` | `menu popover` toggled by a `popovertarget` button |
|
|
28
|
+
| `.spinner`, `.loading` | `aria-busy="true"` on the element that's loading |
|
|
29
|
+
| `.loading-overlay` | `aria-busy="true" inert` on the container that's loading |
|
|
30
|
+
| `.lead`, `.subtitle`, `.eyebrow` | `p` after or before the heading, inside `hgroup` |
|
|
31
|
+
| `.table-responsive` | Wrap the `table` in a `figure` |
|
|
32
|
+
| `.sr-only` labels | `aria-label` on the control, or a visible `label` |
|
|
33
|
+
|
|
34
|
+
There's no utility layer: no spacing, color, or flex classes. Spacing comes from the elements themselves, so drop wrapper `div`s that only existed to add spacing.
|
|
35
|
+
|
|
36
|
+
## Page shell
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<body>
|
|
40
|
+
<header>
|
|
41
|
+
<nav aria-label="Site">
|
|
42
|
+
<ul>
|
|
43
|
+
<li><strong>Brand</strong></li>
|
|
44
|
+
</ul>
|
|
45
|
+
<ul>
|
|
46
|
+
<li><a href="/" aria-current="page">Home</a></li>
|
|
47
|
+
<li><a href="/docs/">Docs</a></li>
|
|
48
|
+
</ul>
|
|
49
|
+
</nav>
|
|
50
|
+
<nav aria-label="Docs sections"><!-- Optional subnav, sticks below the top bar --></nav>
|
|
51
|
+
<h1>Page title</h1>
|
|
52
|
+
<p>Optional intro.</p>
|
|
53
|
+
</header>
|
|
54
|
+
<nav aria-label="Docs"><!-- Optional side nav --></nav>
|
|
55
|
+
<main>…</main>
|
|
56
|
+
<aside aria-label="On this page"><!-- Optional rail --></aside>
|
|
57
|
+
<footer><p>…</p></footer>
|
|
58
|
+
</body>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- The first `nav` in `body > header` is a full-width sticky top bar that stays one line tall. Its lists scroll sideways rather than wrap, fading at an edge with more links, so keep the links short.
|
|
62
|
+
- A second `nav` right after it is a sticky subnav.
|
|
63
|
+
- `body > nav` and `body > aside` become columns beside `main` from 64rem up, and stick below the bars. Below that, everything stacks.
|
|
64
|
+
- In a side nav, an `li` can hold a group label as text and a nested `ul`.
|
|
65
|
+
- A `nav` with two lists outside the header splits them to either end too, for an account bar inside the page.
|
|
66
|
+
- A `nav` whose list is an `ol` is a breadcrumb trail. Mark the last link `aria-current="page"`.
|
|
67
|
+
- `aria-current="page"` marks the current page. `aria-current="true"` marks the current section, such as a parent link.
|
|
68
|
+
- Anchor targets, focused elements, and sticky table headers clear the sticky bars automatically.
|
|
69
|
+
|
|
70
|
+
## Text
|
|
71
|
+
|
|
72
|
+
- `h1` to `h6`. The top three levels scale with the window. A link inside a heading keeps the heading's color.
|
|
73
|
+
- `hgroup`: a `p` before the heading is an eyebrow, and a `p` after it is a muted subtitle.
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<hgroup>
|
|
77
|
+
<p>Pricing</p>
|
|
78
|
+
<h1>Plans that grow with your team</h1>
|
|
79
|
+
<p>Start free and upgrade when you need more.</p>
|
|
80
|
+
</hgroup>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- Text-level elements: `strong`, `em`, `small`, `mark`, `abbr title`, `sub`, `sup`, `del`, `ins`, `q`, `cite`, `kbd`, `samp`, `var`, `code`, `time`, `data`. Numbers in `time` and `data` line up.
|
|
84
|
+
- `ul`, `ol`, and `dl` lists nest. `menu` outside a popover is a row of commands.
|
|
85
|
+
- Quotes: a `blockquote` gets an accent border. A `footer` inside it is an attribution with an em dash. A `figure` with a `blockquote` and a `figcaption` also works.
|
|
86
|
+
- Code: `<pre tabindex="0"><code>…</code></pre>` scrolls sideways, with a shadow at each edge that has more. The `tabindex` lets keyboard users scroll it.
|
|
87
|
+
|
|
88
|
+
## Links and buttons
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<button>Save</button>
|
|
92
|
+
<button type="reset">Reset</button>
|
|
93
|
+
<a href="/signup" role="button">Sign up</a>
|
|
94
|
+
<a href="/signup" role="button" aria-disabled="true">Sign up</a>
|
|
95
|
+
<span role="group" aria-label="View">
|
|
96
|
+
<button type="button" aria-pressed="true">List</button>
|
|
97
|
+
<button type="button" aria-pressed="false">Grid</button>
|
|
98
|
+
</span>
|
|
99
|
+
<button aria-busy="true">Saving</button>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- Buttons are solid primary. `type="reset"` and `formnovalidate` buttons are outlined secondary buttons, such as a form's Cancel. There are no other variants.
|
|
103
|
+
- Adjacent buttons get a gap. Buttons right after form fields get space above them.
|
|
104
|
+
- A decorative icon in a link goes in an `aria-hidden="true"` element, e.g. `<a href="/stars"><span aria-hidden="true">★</span> Star</a>`. It isn't underlined, and an `svg` or favicon in it is sized to the text.
|
|
105
|
+
- Toggles update `aria-pressed` from script. In a segmented control, exactly one is `"true"`.
|
|
106
|
+
|
|
107
|
+
## Forms
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<form>
|
|
111
|
+
<label>
|
|
112
|
+
Email
|
|
113
|
+
<input type="email" name="email" autocomplete="email" required aria-describedby="email-help" />
|
|
114
|
+
<small id="email-help">We'll never share it.</small>
|
|
115
|
+
</label>
|
|
116
|
+
<label>
|
|
117
|
+
Plan
|
|
118
|
+
<select name="plan">
|
|
119
|
+
<option>Free</option>
|
|
120
|
+
<option>Team</option>
|
|
121
|
+
</select>
|
|
122
|
+
</label>
|
|
123
|
+
<fieldset>
|
|
124
|
+
<legend>Notifications</legend>
|
|
125
|
+
<label><input type="checkbox" name="news" role="switch" checked /> Product news</label>
|
|
126
|
+
<label><input type="radio" name="frequency" value="daily" checked /> Daily</label>
|
|
127
|
+
<label><input type="radio" name="frequency" value="weekly" /> Weekly</label>
|
|
128
|
+
</fieldset>
|
|
129
|
+
<button>Save</button>
|
|
130
|
+
</form>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- Text-like inputs, `select`, and `textarea` fill the width. Either wrap the field in its `label`, or put `label for` right before it.
|
|
134
|
+
- A `textarea` starts three lines tall and grows with its content. Where `field-sizing` is supported, `rows` doesn't set its height; set `min-block-size` instead.
|
|
135
|
+
- Validation: a field turns red after the user leaves it invalid (`:user-invalid`), or whenever it has `aria-invalid="true"`. `aria-invalid="false"` marks it valid in green. A `small` right after the field takes the same color.
|
|
136
|
+
- A `small` right after a `fieldset` is helper text for the group. Point the fieldset at it with `aria-describedby`.
|
|
137
|
+
- `readonly` fields look fixed. A `disabled` field or `fieldset` mutes its labels.
|
|
138
|
+
- Range, color, and file inputs are styled. A single `select` gets a styled picker where the browser supports it.
|
|
139
|
+
- Float label: the label's text in a `span` right before the field, and a placeholder on the field (`placeholder=" "` for none): `<label><span>Email</span><input type="email" placeholder="ada@example.com" /></label>`.
|
|
140
|
+
- Search, with or without the inner `form`:
|
|
141
|
+
|
|
142
|
+
```html
|
|
143
|
+
<search>
|
|
144
|
+
<form action="/search">
|
|
145
|
+
<input type="search" name="q" aria-label="Search" />
|
|
146
|
+
<button>Search</button>
|
|
147
|
+
</form>
|
|
148
|
+
</search>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- A field with a prefix or unit:
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<label for="price">Price</label>
|
|
155
|
+
<span role="group">
|
|
156
|
+
<input id="price" name="price" type="number" aria-describedby="price-unit" />
|
|
157
|
+
<span id="price-unit">USD</span>
|
|
158
|
+
</span>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Content
|
|
162
|
+
|
|
163
|
+
- **Cards:** every `article` is a card, except a lone `article` that is `main`'s only child, which stays plain long-form text. A `header` or `footer` as the card's first or last child is a full-width band.
|
|
164
|
+
- **Card grid:** a `div` or `section` that contains only `article`s (two or more) becomes an auto-fitting grid of equal-height cards, with footers aligned at the bottom. Any other child, such as a heading, turns the grid off, so put headings outside the container.
|
|
165
|
+
|
|
166
|
+
```html
|
|
167
|
+
<h2>Plans</h2>
|
|
168
|
+
<div>
|
|
169
|
+
<article>
|
|
170
|
+
<header><h3>Starter</h3></header>
|
|
171
|
+
<p>For personal projects.</p>
|
|
172
|
+
<footer><a href="/signup" role="button">Start free</a></footer>
|
|
173
|
+
</article>
|
|
174
|
+
<article>…</article>
|
|
175
|
+
</div>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- **Tables:** row rules, a sticky header row, and tabular numbers. Give the table a `caption` and give header cells `scope`. Wrap a wide table in a `figure` to scroll it sideways; its edges fade where there are more columns.
|
|
179
|
+
- **Media:** `img` and `video` scale to the column. Set `width`, `height`, and `alt`, and use `figure` with `figcaption` for captions.
|
|
180
|
+
- **Details:** `details` with a `summary`. It animates open where `interpolate-size` is supported.
|
|
181
|
+
- **Callouts:** an `aside` inside `main` (not a direct child of `body`) is a callout on a raised surface. `hr` and `address` are styled too.
|
|
182
|
+
|
|
183
|
+
## Overlays
|
|
184
|
+
|
|
185
|
+
```html
|
|
186
|
+
<button type="button" popovertarget="actions">Actions</button>
|
|
187
|
+
<menu id="actions" popover>
|
|
188
|
+
<li><a href="/edit">Edit</a></li>
|
|
189
|
+
<li><button type="button">Duplicate</button></li>
|
|
190
|
+
<li><button type="button" disabled>Archive</button></li>
|
|
191
|
+
</menu>
|
|
192
|
+
|
|
193
|
+
<button type="button" popovertarget="tip">More info</button>
|
|
194
|
+
<div id="tip" popover><p>Popover content.</p></div>
|
|
195
|
+
|
|
196
|
+
<dialog id="confirm" aria-labelledby="confirm-title" closedby="any">
|
|
197
|
+
<h2 id="confirm-title">Delete this project?</h2>
|
|
198
|
+
<p>This can't be undone.</p>
|
|
199
|
+
<form method="dialog">
|
|
200
|
+
<button value="cancel" autofocus>Cancel</button>
|
|
201
|
+
<button value="delete">Delete</button>
|
|
202
|
+
</form>
|
|
203
|
+
</dialog>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- A popover that is a list, or holds one, is a menu. It's anchored below its button and flips when there isn't room. Popovers need no script.
|
|
207
|
+
- Open a `dialog` from a button with `commandfor="<id>" command="show-modal"` (load `invokers-polyfill` only when `'commandForElement' in HTMLButtonElement.prototype` is false), or with `dialog.showModal()` from script. The page behind it doesn't scroll (except in Safari), and `form method="dialog"` closes it. `closedby="any"` also closes it on a click outside; leave it off dialogs that hold unsaved input. The backdrop blurs the page, or darkens it under reduced transparency.
|
|
208
|
+
|
|
209
|
+
## Feedback
|
|
210
|
+
|
|
211
|
+
```html
|
|
212
|
+
<label>Upload <progress value="40" max="100">40%</progress></label>
|
|
213
|
+
<progress>Loading…</progress>
|
|
214
|
+
<meter value="0.7" low="0.5" high="0.8" optimum="0.2">70%</meter>
|
|
215
|
+
<p aria-busy="true">Loading results</p>
|
|
216
|
+
<section aria-busy="true" inert>…</section>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
A `progress` without a value is indeterminate. A `meter` fills green in its `optimum` range, amber when suboptimal, and red when even less good. `aria-busy` on a container (`section`, `article`, `form`, `div`, list) dims it under a centered spinner; add `inert` with it and remove both when loading ends. Under reduced motion, loading animations pulse instead of sliding.
|