| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280 |
- /*!
- * Spry CSS — a light, no-JavaScript CSS framework of utilities and components.
- *
- * Optional companion to the Spry web application framework.
- * Core + default theme in one file. Themes live in themes/*.css and are
- * activated with <html data-theme="name"> (or the #spry-theme-* radio hooks
- * used by the demo page's CSS-only switcher).
- *
- * Color mode: <html data-mode="light|dark"> (omit for auto).
- */
- /* ==========================================================================
- 1. Default theme — light palette
- --------------------------------------------------------------------------
- Palette blocks use :where() so their specificity is (0,0,0): any active
- theme scope (attribute or radio hook) overrides them, including the dark
- blocks below. Themes can therefore be "fully light" and ignore dark mode.
- ========================================================================== */
- :where(:root) {
- color-scheme: light;
- /* Palette */
- --spry-bg: #f5f7f9;
- --spry-bg-alt: #edf1f5;
- --spry-bg-inset: #eef2f6;
- --spry-surface: #ffffff;
- --spry-surface-hover: #f6f9fc;
- --spry-fg: #1c2733;
- --spry-fg-muted: #5b6b7c;
- --spry-border: #d9e1e9;
- --spry-border-strong: #b9c6d2;
- --spry-accent: #346894;
- --spry-accent-hover: #2a5578;
- --spry-accent-fg: #ffffff;
- --spry-danger: #b3261e;
- --spry-success: #2e7d43;
- --spry-warning: #946200;
- --spry-info: #0b68a3;
- --spry-link: var(--spry-accent);
- --spry-link-hover: var(--spry-accent-hover);
- --spry-backdrop: rgb(15 23 36 / 0.45);
- /* Soft tints are derived — themes only set the base colors above */
- --spry-accent-soft: color-mix(in srgb, var(--spry-accent) 12%, transparent);
- --spry-danger-soft: color-mix(in srgb, var(--spry-danger) 10%, transparent);
- --spry-success-soft: color-mix(in srgb, var(--spry-success) 10%, transparent);
- --spry-warning-soft: color-mix(in srgb, var(--spry-warning) 14%, transparent);
- --spry-info-soft: color-mix(in srgb, var(--spry-info) 10%, transparent);
- --spry-focus-ring: 0 0 0 3px color-mix(in srgb, var(--spry-accent) 25%, transparent);
- /* Typography */
- --spry-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
- --spry-font-heading: var(--spry-font);
- --spry-font-mono: ui-monospace, "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
- --spry-font-size: 1rem;
- --spry-line-height: 1.6;
- --spry-heading-weight: 650;
- --spry-heading-color: var(--spry-fg);
- /* Shape, depth, motion */
- --spry-radius: 0.5rem;
- --spry-radius-sm: 0.3rem;
- --spry-radius-lg: 0.75rem;
- --spry-radius-pill: 999px;
- --spry-border-width: 1px;
- --spry-shadow: 0 1px 2px rgb(16 24 40 / 0.05), 0 1px 3px rgb(16 24 40 / 0.08);
- --spry-shadow-lg: 0 16px 40px -12px rgb(16 24 40 / 0.25);
- --spry-glass: none;
- --spry-transition: 140ms ease;
- --spry-dialog-duration: 180ms;
- --spry-dialog-ease: cubic-bezier(0.2, 0.9, 0.3, 1);
- --spry-dialog-close-duration: 140ms;
- --spry-dialog-close-ease: ease;
- --spry-dialog-in: translateY(0.6rem) scale(0.98);
- /* Spacing scale (0..5) */
- --spry-space-0: 0;
- --spry-space-1: 0.25rem;
- --spry-space-2: 0.5rem;
- --spry-space-3: 1rem;
- --spry-space-4: 1.5rem;
- --spry-space-5: 2.5rem;
- /* Controls (inputs, selects) */
- --spry-control-bg: var(--spry-surface);
- --spry-control-fg: var(--spry-fg);
- --spry-control-border: var(--spry-border);
- --spry-control-radius: var(--spry-radius-sm);
- --spry-control-padding-x: 0.65rem;
- --spry-control-padding-y: 0.45rem;
- /* Buttons */
- --spry-btn-bg: var(--spry-surface);
- --spry-btn-fg: var(--spry-fg);
- --spry-btn-border: var(--spry-border);
- --spry-btn-bg-hover: var(--spry-bg-alt);
- --spry-btn-bg-active: var(--spry-bg-inset);
- /* Cards */
- --spry-card-bg: var(--spry-surface);
- --spry-card-border: var(--spry-border);
- --spry-card-padding: 1.25rem;
- --spry-card-shadow: var(--spry-shadow);
- /* Tables */
- --spry-table-header-bg: var(--spry-bg-alt);
- --spry-table-hover: var(--spry-bg-alt);
- /* Progress */
- --spry-progress-bg: var(--spry-bg-inset);
- --spry-progress-fg: var(--spry-accent);
- --spry-pulse-cap: 0.4em; /* half the default bar height: stadium ends */
- /* Popovers & dialogs */
- --spry-popover-bg: var(--spry-surface);
- --spry-popover-border: var(--spry-border);
- --spry-popover-shadow: var(--spry-shadow-lg);
- --spry-popover-padding: 1.1rem 1.25rem;
- accent-color: var(--spry-accent);
- }
- /* --------------------------------------------------------------------------
- Default theme — dark palette.
- Duplicated on purpose: once for forced dark (data-mode="dark" or the
- #spry-mode-dark switcher hook), once for auto dark (system preference,
- unless disabled with data-mode="light" or #spry-mode-light).
- -------------------------------------------------------------------------- */
- :where(:root[data-mode="dark"], html:has(#spry-mode-dark:checked)) {
- color-scheme: dark;
- --spry-bg: #0f141b;
- --spry-bg-alt: #151d27;
- --spry-bg-inset: #1a2330;
- --spry-surface: #161f2b;
- --spry-surface-hover: #1c2734;
- --spry-fg: #dee7f1;
- --spry-fg-muted: #8fa1b5;
- --spry-border: #2a3646;
- --spry-border-strong: #3d4c61;
- --spry-accent: #6ba3d8;
- --spry-accent-hover: #8cbcea;
- --spry-accent-fg: #0b141d;
- --spry-danger: #e5736c;
- --spry-success: #72c08c;
- --spry-warning: #d8a850;
- --spry-info: #6cb6e8;
- --spry-backdrop: rgb(2 6 12 / 0.6);
- --spry-shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 1px 3px rgb(0 0 0 / 0.4);
- --spry-shadow-lg: 0 16px 40px -12px rgb(0 0 0 / 0.6);
- }
- @media (prefers-color-scheme: dark) {
- :where(:root:not([data-mode="light"]):not(:has(#spry-mode-light:checked)),
- html:has(#spry-mode-auto:checked):not([data-mode="light"])) {
- color-scheme: dark;
- --spry-bg: #0f141b;
- --spry-bg-alt: #151d27;
- --spry-bg-inset: #1a2330;
- --spry-surface: #161f2b;
- --spry-surface-hover: #1c2734;
- --spry-fg: #dee7f1;
- --spry-fg-muted: #8fa1b5;
- --spry-border: #2a3646;
- --spry-border-strong: #3d4c61;
- --spry-accent: #6ba3d8;
- --spry-accent-hover: #8cbcea;
- --spry-accent-fg: #0b141d;
- --spry-danger: #e5736c;
- --spry-success: #72c08c;
- --spry-warning: #d8a850;
- --spry-info: #6cb6e8;
- --spry-backdrop: rgb(2 6 12 / 0.6);
- --spry-shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 1px 3px rgb(0 0 0 / 0.4);
- --spry-shadow-lg: 0 16px 40px -12px rgb(0 0 0 / 0.6);
- }
- }
- /* ==========================================================================
- 2. Reset & sane defaults
- ========================================================================== */
- *,
- *::before,
- *::after {
- box-sizing: border-box;
- }
- * {
- margin: 0;
- }
- html {
- scroll-behavior: smooth;
- scroll-padding-top: 5rem;
- -webkit-text-size-adjust: 100%;
- text-size-adjust: 100%;
- }
- body {
- font-family: var(--spry-font);
- font-size: var(--spry-font-size);
- line-height: var(--spry-line-height);
- color: var(--spry-fg);
- background: var(--spry-bg);
- -webkit-font-smoothing: antialiased;
- }
- img,
- video,
- svg {
- display: block;
- max-width: 100%;
- height: auto;
- }
- svg:not([width]) {
- width: 1em;
- }
- input,
- button,
- select,
- textarea {
- font: inherit;
- color: inherit;
- }
- button {
- cursor: pointer;
- }
- :where(a) {
- color: var(--spry-link);
- text-underline-offset: 0.2em;
- }
- :where(a:hover) {
- color: var(--spry-link-hover);
- }
- :focus-visible {
- outline: 2px solid var(--spry-accent);
- outline-offset: 2px;
- }
- ::selection {
- background: color-mix(in srgb, var(--spry-accent) 30%, transparent);
- }
- ::placeholder {
- color: var(--spry-fg-muted);
- opacity: 0.8;
- }
- [hidden] {
- display: none !important;
- }
- @media (prefers-reduced-motion: reduce) {
- html {
- scroll-behavior: auto;
- }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
- }
- /* ==========================================================================
- 3. Base typography
- ========================================================================== */
- h1,
- h2,
- h3,
- h4,
- h5,
- h6 {
- font-family: var(--spry-font-heading);
- font-weight: var(--spry-heading-weight);
- color: var(--spry-heading-color);
- line-height: 1.2;
- text-wrap: balance;
- margin-block: 1.6em 0.6em;
- }
- h1,
- .h1 {
- font-size: clamp(1.9rem, 1.4rem + 1.8vw, 2.6rem);
- }
- h2,
- .h2 {
- font-size: clamp(1.5rem, 1.25rem + 1vw, 2rem);
- }
- h3,
- .h3 {
- font-size: 1.35rem;
- }
- h4,
- .h4 {
- font-size: 1.15rem;
- }
- h5,
- .h5 {
- font-size: 1rem;
- }
- h6,
- .h6 {
- font-size: 0.85rem;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--spry-fg-muted);
- }
- h1:first-child,
- h2:first-child,
- h3:first-child,
- h4:first-child,
- h5:first-child,
- h6:first-child {
- margin-block-start: 0;
- }
- p,
- ul,
- ol,
- dl,
- blockquote,
- figure,
- pre {
- margin-block: 0 1em;
- }
- :where(li) > ul,
- :where(li) > ol {
- margin-block: 0.25em;
- }
- :where(li + li) {
- margin-block-start: 0.25em;
- }
- :where(dt) {
- font-weight: 600;
- }
- :where(dd) {
- margin-inline-start: 1.5em;
- }
- small {
- font-size: 0.85em;
- }
- b,
- strong {
- font-weight: 700;
- }
- hr {
- border: 0;
- border-top: var(--spry-border-width) solid var(--spry-border);
- margin-block: 2rem;
- }
- blockquote {
- border-inline-start: 3px solid var(--spry-accent);
- padding: 0.25rem 1rem;
- color: var(--spry-fg-muted);
- }
- blockquote > p:last-child {
- margin-bottom: 0;
- }
- :where(code, kbd, samp) {
- font-family: var(--spry-font-mono);
- font-size: 0.9em;
- }
- :where(:not(pre) > code) {
- background: var(--spry-bg-inset);
- border: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius-sm);
- padding: 0.1em 0.35em;
- }
- pre {
- background: var(--spry-bg-inset);
- border: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius);
- padding: 1rem 1.25rem;
- overflow-x: auto;
- line-height: 1.5;
- }
- pre code {
- background: none;
- border: 0;
- padding: 0;
- font-size: 0.875rem;
- }
- kbd {
- background: var(--spry-bg-alt);
- border: var(--spry-border-width) solid var(--spry-border-strong);
- border-bottom-width: 2px;
- border-radius: var(--spry-radius-sm);
- padding: 0.1em 0.4em;
- font-size: 0.8em;
- }
- mark {
- background: var(--spry-warning-soft);
- color: inherit;
- border-radius: 0.2em;
- padding: 0 0.15em;
- }
- abbr[title] {
- text-decoration: underline dotted;
- cursor: help;
- }
- :where(figure) figcaption {
- color: var(--spry-fg-muted);
- font-size: 0.875em;
- margin-top: 0.5rem;
- }
- /* ==========================================================================
- 4. Utilities — layout
- ========================================================================== */
- .container {
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: clamp(1rem, 3vw, 2rem);
- }
- .container-sm {
- max-width: 52rem;
- }
- .container-lg {
- max-width: 96rem;
- }
- .stack {
- display: flex;
- flex-direction: column;
- gap: var(--spry-space-3);
- }
- .cluster {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--spry-space-2);
- }
- .center {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .with-sidebar {
- display: grid;
- grid-template-columns: minmax(11rem, 16rem) minmax(0, 1fr);
- gap: var(--spry-space-5);
- }
- @media (max-width: 55rem) {
- .with-sidebar {
- grid-template-columns: minmax(0, 1fr);
- }
- }
- .block { display: block; }
- .inline-block { display: inline-block; }
- .inline { display: inline; }
- .hidden { display: none; }
- .visually-hidden {
- position: absolute !important;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
- }
- .relative { position: relative; }
- .absolute { position: absolute; }
- .fixed { position: fixed; }
- .sticky { position: sticky; }
- .top-0 { top: 0; }
- .right-0 { right: 0; }
- .bottom-0 { bottom: 0; }
- .left-0 { left: 0; }
- .inset-0 { inset: 0; }
- .overflow-auto { overflow: auto; }
- .overflow-hidden { overflow: hidden; }
- .w-25 { width: 25%; }
- .w-50 { width: 50%; }
- .w-75 { width: 75%; }
- .w-100 { width: 100%; }
- .w-auto { width: auto; }
- .h-100 { height: 100%; }
- .mw-100 { max-width: 100%; }
- .min-w-0 { min-width: 0; }
- /* ==========================================================================
- 5. Utilities — spacing
- ========================================================================== */
- .m-0 { margin: var(--spry-space-0); }
- .m-1 { margin: var(--spry-space-1); }
- .m-2 { margin: var(--spry-space-2); }
- .m-3 { margin: var(--spry-space-3); }
- .m-4 { margin: var(--spry-space-4); }
- .m-5 { margin: var(--spry-space-5); }
- .mt-0 { margin-top: var(--spry-space-0); }
- .mt-1 { margin-top: var(--spry-space-1); }
- .mt-2 { margin-top: var(--spry-space-2); }
- .mt-3 { margin-top: var(--spry-space-3); }
- .mt-4 { margin-top: var(--spry-space-4); }
- .mt-5 { margin-top: var(--spry-space-5); }
- .mr-0 { margin-right: var(--spry-space-0); }
- .mr-1 { margin-right: var(--spry-space-1); }
- .mr-2 { margin-right: var(--spry-space-2); }
- .mr-3 { margin-right: var(--spry-space-3); }
- .mr-4 { margin-right: var(--spry-space-4); }
- .mr-5 { margin-right: var(--spry-space-5); }
- .mb-0 { margin-bottom: var(--spry-space-0); }
- .mb-1 { margin-bottom: var(--spry-space-1); }
- .mb-2 { margin-bottom: var(--spry-space-2); }
- .mb-3 { margin-bottom: var(--spry-space-3); }
- .mb-4 { margin-bottom: var(--spry-space-4); }
- .mb-5 { margin-bottom: var(--spry-space-5); }
- .ml-0 { margin-left: var(--spry-space-0); }
- .ml-1 { margin-left: var(--spry-space-1); }
- .ml-2 { margin-left: var(--spry-space-2); }
- .ml-3 { margin-left: var(--spry-space-3); }
- .ml-4 { margin-left: var(--spry-space-4); }
- .ml-5 { margin-left: var(--spry-space-5); }
- .mx-0 { margin-inline: var(--spry-space-0); }
- .mx-1 { margin-inline: var(--spry-space-1); }
- .mx-2 { margin-inline: var(--spry-space-2); }
- .mx-3 { margin-inline: var(--spry-space-3); }
- .mx-4 { margin-inline: var(--spry-space-4); }
- .mx-5 { margin-inline: var(--spry-space-5); }
- .my-0 { margin-block: var(--spry-space-0); }
- .my-1 { margin-block: var(--spry-space-1); }
- .my-2 { margin-block: var(--spry-space-2); }
- .my-3 { margin-block: var(--spry-space-3); }
- .my-4 { margin-block: var(--spry-space-4); }
- .my-5 { margin-block: var(--spry-space-5); }
- .mx-auto { margin-inline: auto; }
- .ml-auto { margin-left: auto; }
- .mt-auto { margin-top: auto; }
- .p-0 { padding: var(--spry-space-0); }
- .p-1 { padding: var(--spry-space-1); }
- .p-2 { padding: var(--spry-space-2); }
- .p-3 { padding: var(--spry-space-3); }
- .p-4 { padding: var(--spry-space-4); }
- .p-5 { padding: var(--spry-space-5); }
- .pt-0 { padding-top: var(--spry-space-0); }
- .pt-1 { padding-top: var(--spry-space-1); }
- .pt-2 { padding-top: var(--spry-space-2); }
- .pt-3 { padding-top: var(--spry-space-3); }
- .pt-4 { padding-top: var(--spry-space-4); }
- .pt-5 { padding-top: var(--spry-space-5); }
- .pr-0 { padding-right: var(--spry-space-0); }
- .pr-1 { padding-right: var(--spry-space-1); }
- .pr-2 { padding-right: var(--spry-space-2); }
- .pr-3 { padding-right: var(--spry-space-3); }
- .pr-4 { padding-right: var(--spry-space-4); }
- .pr-5 { padding-right: var(--spry-space-5); }
- .pb-0 { padding-bottom: var(--spry-space-0); }
- .pb-1 { padding-bottom: var(--spry-space-1); }
- .pb-2 { padding-bottom: var(--spry-space-2); }
- .pb-3 { padding-bottom: var(--spry-space-3); }
- .pb-4 { padding-bottom: var(--spry-space-4); }
- .pb-5 { padding-bottom: var(--spry-space-5); }
- .pl-0 { padding-left: var(--spry-space-0); }
- .pl-1 { padding-left: var(--spry-space-1); }
- .pl-2 { padding-left: var(--spry-space-2); }
- .pl-3 { padding-left: var(--spry-space-3); }
- .pl-4 { padding-left: var(--spry-space-4); }
- .pl-5 { padding-left: var(--spry-space-5); }
- .px-0 { padding-inline: var(--spry-space-0); }
- .px-1 { padding-inline: var(--spry-space-1); }
- .px-2 { padding-inline: var(--spry-space-2); }
- .px-3 { padding-inline: var(--spry-space-3); }
- .px-4 { padding-inline: var(--spry-space-4); }
- .px-5 { padding-inline: var(--spry-space-5); }
- .py-0 { padding-block: var(--spry-space-0); }
- .py-1 { padding-block: var(--spry-space-1); }
- .py-2 { padding-block: var(--spry-space-2); }
- .py-3 { padding-block: var(--spry-space-3); }
- .py-4 { padding-block: var(--spry-space-4); }
- .py-5 { padding-block: var(--spry-space-5); }
- /* ==========================================================================
- 6. Utilities — flex
- ========================================================================== */
- .flex { display: flex; }
- .inline-flex { display: inline-flex; }
- .flex-row { flex-direction: row; }
- .flex-col { flex-direction: column; }
- .flex-col-reverse { flex-direction: column-reverse; }
- .flex-wrap { flex-wrap: wrap; }
- .flex-nowrap { flex-wrap: nowrap; }
- .flex-1 { flex: 1 1 0%; }
- .flex-auto { flex: 1 1 auto; }
- .flex-none { flex: none; }
- .items-start { align-items: flex-start; }
- .items-center { align-items: center; }
- .items-end { align-items: flex-end; }
- .items-stretch { align-items: stretch; }
- .items-baseline { align-items: baseline; }
- .justify-start { justify-content: flex-start; }
- .justify-center { justify-content: center; }
- .justify-end { justify-content: flex-end; }
- .justify-between { justify-content: space-between; }
- .justify-around { justify-content: space-around; }
- .justify-evenly { justify-content: space-evenly; }
- .self-start { align-self: flex-start; }
- .self-center { align-self: center; }
- .self-end { align-self: flex-end; }
- .order-first { order: -1; }
- .order-last { order: 999; }
- /* ==========================================================================
- 7. Utilities — grid
- ========================================================================== */
- .grid {
- display: grid;
- gap: var(--spry-space-3);
- grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--spry-grid-min, 14rem)), 1fr));
- }
- .grid-sm { --spry-grid-min: 9rem; }
- .grid-lg { --spry-grid-min: 20rem; }
- .grid-cols-1 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(1, minmax(0, 1fr)); }
- .grid-cols-2 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .grid-cols-3 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(3, minmax(0, 1fr)); }
- .grid-cols-4 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(4, minmax(0, 1fr)); }
- .grid-cols-5 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(5, minmax(0, 1fr)); }
- .grid-cols-6 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(6, minmax(0, 1fr)); }
- .grid-cols-7 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(7, minmax(0, 1fr)); }
- .grid-cols-8 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(8, minmax(0, 1fr)); }
- .grid-cols-9 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(9, minmax(0, 1fr)); }
- .grid-cols-10 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(10, minmax(0, 1fr)); }
- .grid-cols-11 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(11, minmax(0, 1fr)); }
- .grid-cols-12 { display: grid; gap: var(--spry-space-3); grid-template-columns: repeat(12, minmax(0, 1fr)); }
- @media (max-width: 45rem) {
- .grid-cols-3,
- .grid-cols-4,
- .grid-cols-5,
- .grid-cols-6,
- .grid-cols-7,
- .grid-cols-8,
- .grid-cols-9,
- .grid-cols-10,
- .grid-cols-11,
- .grid-cols-12 {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
- }
- .col-span-1 { grid-column: span 1; }
- .col-span-2 { grid-column: span 2; }
- .col-span-3 { grid-column: span 3; }
- .col-span-4 { grid-column: span 4; }
- .col-span-5 { grid-column: span 5; }
- .col-span-6 { grid-column: span 6; }
- .col-span-7 { grid-column: span 7; }
- .col-span-8 { grid-column: span 8; }
- .col-span-9 { grid-column: span 9; }
- .col-span-10 { grid-column: span 10; }
- .col-span-11 { grid-column: span 11; }
- .col-span-12 { grid-column: span 12; }
- .col-span-full { grid-column: 1 / -1; }
- .gap-0 { gap: var(--spry-space-0); }
- .gap-1 { gap: var(--spry-space-1); }
- .gap-2 { gap: var(--spry-space-2); }
- .gap-3 { gap: var(--spry-space-3); }
- .gap-4 { gap: var(--spry-space-4); }
- .gap-5 { gap: var(--spry-space-5); }
- .gap-x-0 { column-gap: var(--spry-space-0); }
- .gap-x-1 { column-gap: var(--spry-space-1); }
- .gap-x-2 { column-gap: var(--spry-space-2); }
- .gap-x-3 { column-gap: var(--spry-space-3); }
- .gap-x-4 { column-gap: var(--spry-space-4); }
- .gap-x-5 { column-gap: var(--spry-space-5); }
- .gap-y-0 { row-gap: var(--spry-space-0); }
- .gap-y-1 { row-gap: var(--spry-space-1); }
- .gap-y-2 { row-gap: var(--spry-space-2); }
- .gap-y-3 { row-gap: var(--spry-space-3); }
- .gap-y-4 { row-gap: var(--spry-space-4); }
- .gap-y-5 { row-gap: var(--spry-space-5); }
- /* ==========================================================================
- 8. Utilities — text & color
- ========================================================================== */
- .text-xs { font-size: 0.75rem; }
- .text-sm { font-size: 0.875rem; }
- .text-base { font-size: 1rem; }
- .text-lg { font-size: 1.125rem; }
- .text-xl { font-size: 1.25rem; }
- .text-2xl { font-size: 1.5rem; }
- .text-left { text-align: left; }
- .text-center { text-align: center; }
- .text-right { text-align: right; }
- .text-nowrap { white-space: nowrap; }
- .text-muted { color: var(--spry-fg-muted); }
- .text-accent { color: var(--spry-accent); }
- .text-danger { color: var(--spry-danger); }
- .text-success { color: var(--spry-success); }
- .text-warning { color: var(--spry-warning); }
- .text-info { color: var(--spry-info); }
- .fw-light { font-weight: 300; }
- .fw-normal { font-weight: 400; }
- .fw-medium { font-weight: 500; }
- .fw-semibold { font-weight: 600; }
- .fw-bold { font-weight: 700; }
- .fs-italic { font-style: italic; }
- .fs-normal { font-style: normal; }
- .uppercase { text-transform: uppercase; }
- .lowercase { text-transform: lowercase; }
- .capitalize { text-transform: capitalize; }
- .lead {
- font-size: 1.15em;
- line-height: 1.55;
- color: var(--spry-fg-muted);
- }
- .small { font-size: 0.85em; }
- .mono { font-family: var(--spry-font-mono); font-size: 0.92em; }
- .num { font-variant-numeric: tabular-nums; text-align: right; }
- .truncate {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .clamp-2,
- .clamp-3 {
- display: -webkit-box;
- -webkit-box-orient: vertical;
- overflow: hidden;
- }
- .clamp-2 { -webkit-line-clamp: 2; line-clamp: 2; }
- .clamp-3 { -webkit-line-clamp: 3; line-clamp: 3; }
- .measure { max-width: 65ch; }
- .measure-sm { max-width: 45ch; }
- .bg-surface { background: var(--spry-surface); }
- .bg-alt { background: var(--spry-bg-alt); }
- .bg-inset { background: var(--spry-bg-inset); }
- .bg-accent { background: var(--spry-accent); color: var(--spry-accent-fg); }
- .border { border: var(--spry-border-width) solid var(--spry-border); }
- .border-0 { border: 0; }
- .rounded { border-radius: var(--spry-radius); }
- .rounded-sm { border-radius: var(--spry-radius-sm); }
- .rounded-lg { border-radius: var(--spry-radius-lg); }
- .rounded-pill { border-radius: var(--spry-radius-pill); }
- .shadow { box-shadow: var(--spry-shadow); }
- .shadow-lg { box-shadow: var(--spry-shadow-lg); }
- .shadow-none { box-shadow: none; }
- /* Long-form content (markdown, docs, help text) inside cards and dialogs.
- The page-scale headings are oversized in those containers, so .prose caps
- the measure and steps headings down to a document scale; spacing rides
- --spry-space-* so themes and dark mode compose unchanged. */
- .prose {
- max-width: 65ch;
- }
- .prose h1 { font-size: 1.5rem; margin-block: var(--spry-space-4) var(--spry-space-2); }
- .prose h2 { font-size: 1.25rem; margin-block: var(--spry-space-4) var(--spry-space-2); }
- .prose h3 { font-size: 1.1rem; margin-block: var(--spry-space-3) var(--spry-space-2); }
- .prose h4 { font-size: 1rem; margin-block: var(--spry-space-3) var(--spry-space-2); }
- .prose p,
- .prose ul,
- .prose ol,
- .prose dl,
- .prose blockquote {
- margin-block-end: var(--spry-space-3);
- }
- /* Flush at both ends — trailing/leading flow margins would sit on top of the
- card or dialog padding and make one side look heavier than the other. */
- .prose > :first-child { margin-block-start: 0; }
- .prose > :last-child { margin-block-end: 0; }
- /* ==========================================================================
- 9. Components — topbar & navigation
- ========================================================================== */
- .topbar {
- position: sticky;
- top: 0;
- z-index: 20;
- display: flex;
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: var(--spry-space-2);
- padding: 0.65rem clamp(1rem, 3vw, 2rem);
- background: var(--spry-surface);
- border-bottom: var(--spry-border-width) solid var(--spry-border);
- backdrop-filter: var(--spry-glass);
- }
- .topbar-brand {
- font-weight: 700;
- font-size: 1.05rem;
- color: var(--spry-fg);
- text-decoration: none;
- letter-spacing: 0.01em;
- }
- .topbar-brand:hover {
- color: var(--spry-accent);
- }
- .nav {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--spry-space-1);
- list-style: none;
- padding: 0;
- margin: 0;
- }
- .nav a {
- display: inline-block;
- padding: 0.35rem 0.75rem;
- border-radius: var(--spry-radius-sm);
- color: var(--spry-fg);
- text-decoration: none;
- font-weight: 500;
- transition: background-color var(--spry-transition), color var(--spry-transition);
- }
- .nav a:hover {
- background: var(--spry-bg-alt);
- color: var(--spry-accent);
- }
- .nav a.active {
- background: var(--spry-accent-soft);
- color: var(--spry-accent);
- font-weight: 600;
- }
- /* Menus with CSS-only submenus */
- .menu,
- .menu ul {
- list-style: none;
- margin: 0;
- padding: 0;
- }
- .menu {
- display: flex;
- flex-direction: column;
- gap: 2px;
- }
- .menu a {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 0.5rem;
- padding: 0.4rem 0.7rem;
- border-radius: var(--spry-radius-sm);
- color: var(--spry-fg);
- text-decoration: none;
- }
- .menu a:hover,
- .menu a.active {
- background: var(--spry-bg-alt);
- color: var(--spry-accent);
- }
- .has-submenu {
- position: relative;
- }
- .has-submenu > a::after {
- content: "▾";
- font-size: 0.75em;
- color: var(--spry-fg-muted);
- }
- .submenu {
- position: absolute;
- top: 100%;
- left: 0;
- z-index: 30;
- min-width: 11rem;
- padding: 0.35rem;
- background: var(--spry-popover-bg);
- border: var(--spry-border-width) solid var(--spry-popover-border);
- border-radius: var(--spry-radius);
- box-shadow: var(--spry-popover-shadow);
- backdrop-filter: var(--spry-glass);
- opacity: 0;
- visibility: hidden;
- transform: translateY(0.3rem);
- transition: opacity var(--spry-transition), transform var(--spry-transition), visibility var(--spry-transition);
- }
- .submenu a,
- .menu a {
- width: 100%;
- }
- .submenu a {
- display: block;
- padding: 0.4rem 0.75rem;
- color: var(--spry-fg);
- text-decoration: none;
- border-radius: var(--spry-radius-sm);
- }
- .submenu a:hover {
- background: var(--spry-accent-soft);
- color: var(--spry-accent);
- }
- .has-submenu:hover > .submenu,
- .has-submenu:focus-within > .submenu {
- opacity: 1;
- visibility: visible;
- transform: none;
- }
- .menu .has-submenu .submenu {
- position: static;
- opacity: 1;
- visibility: visible;
- transform: none;
- border: 0;
- box-shadow: none;
- padding: 0 0 0 1rem;
- margin: 2px 0;
- }
- .menu .has-submenu > a::after {
- content: "▸";
- }
- .menu .has-submenu .submenu a {
- font-size: 0.95em;
- }
- .breadcrumb {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.4rem;
- list-style: none;
- padding: 0;
- margin: 0;
- font-size: 0.9rem;
- }
- .breadcrumb li + li::before {
- content: "/";
- color: var(--spry-fg-muted);
- margin-right: 0.4rem;
- }
- .breadcrumb a {
- color: var(--spry-link);
- text-decoration: none;
- }
- .breadcrumb a:hover {
- text-decoration: underline;
- }
- .breadcrumb [aria-current] {
- color: var(--spry-fg-muted);
- }
- /* ==========================================================================
- 10. Components — tabs (CSS-only, radio based)
- --------------------------------------------------------------------------
- Markup: all radio inputs first (direct children), then .tab-list with one
- label per input (same order), then .tab-panels with one panel per input.
- ========================================================================== */
- .tabs > input[type="radio"] {
- position: absolute;
- opacity: 0;
- pointer-events: none;
- }
- .tab-list {
- display: flex;
- flex-wrap: wrap;
- gap: 0.25rem;
- border-bottom: var(--spry-border-width) solid var(--spry-border);
- }
- .tab-list label {
- padding: 0.5rem 0.9rem;
- border-radius: var(--spry-radius-sm) var(--spry-radius-sm) 0 0;
- cursor: pointer;
- font-weight: 500;
- color: var(--spry-fg-muted);
- transition: background-color var(--spry-transition), color var(--spry-transition), box-shadow var(--spry-transition);
- }
- .tab-list label:hover {
- color: var(--spry-accent);
- background: var(--spry-bg-alt);
- }
- .tab-panels > * {
- display: none;
- padding-top: var(--spry-space-3);
- }
- .tab-panels > :first-child {
- display: block;
- }
- .tabs > input:nth-of-type(1):checked ~ .tab-list label:nth-of-type(1),
- .tabs > input:nth-of-type(2):checked ~ .tab-list label:nth-of-type(2),
- .tabs > input:nth-of-type(3):checked ~ .tab-list label:nth-of-type(3),
- .tabs > input:nth-of-type(4):checked ~ .tab-list label:nth-of-type(4),
- .tabs > input:nth-of-type(5):checked ~ .tab-list label:nth-of-type(5),
- .tabs > input:nth-of-type(6):checked ~ .tab-list label:nth-of-type(6) {
- color: var(--spry-accent);
- font-weight: 600;
- box-shadow: inset 0 -3px 0 var(--spry-accent);
- }
- .tabs > input:nth-of-type(1):checked ~ .tab-panels > :nth-child(1),
- .tabs > input:nth-of-type(2):checked ~ .tab-panels > :nth-child(2),
- .tabs > input:nth-of-type(3):checked ~ .tab-panels > :nth-child(3),
- .tabs > input:nth-of-type(4):checked ~ .tab-panels > :nth-child(4),
- .tabs > input:nth-of-type(5):checked ~ .tab-panels > :nth-child(5),
- .tabs > input:nth-of-type(6):checked ~ .tab-panels > :nth-child(6) {
- display: block;
- }
- .tabs > input:focus-visible ~ .tab-list label {
- outline: 2px solid var(--spry-accent);
- outline-offset: -2px;
- }
- /* ==========================================================================
- 11. Components — buttons
- ========================================================================== */
- /* Bare buttons and submit inputs get the same base look at zero specificity
- (:where), so .btn-* variant classes always win. */
- .btn,
- :where(button, input[type="submit"], input[type="reset"], input[type="button"]) {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 0.45em;
- padding: var(--spry-control-padding-y) calc(var(--spry-control-padding-x) + 0.15rem);
- border: var(--spry-border-width) solid var(--spry-btn-border);
- border-radius: var(--spry-control-radius);
- background: var(--spry-btn-bg);
- color: var(--spry-btn-fg);
- font-weight: 550;
- font-size: inherit;
- line-height: 1.2;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: background-color var(--spry-transition), border-color var(--spry-transition),
- color var(--spry-transition), box-shadow var(--spry-transition);
- }
- .btn:hover,
- :where(button, input[type="submit"], input[type="reset"], input[type="button"]):hover {
- background: var(--spry-btn-bg-hover);
- border-color: var(--spry-border-strong);
- }
- .btn:active,
- :where(button, input[type="submit"], input[type="reset"], input[type="button"]):active {
- background: var(--spry-btn-bg-active);
- }
- .btn:focus-visible,
- :where(button, input[type="submit"], input[type="reset"], input[type="button"]):focus-visible {
- outline: 2px solid var(--spry-accent);
- outline-offset: 2px;
- }
- .btn:disabled,
- .btn[aria-disabled="true"],
- :where(button, input[type="submit"], input[type="reset"], input[type="button"]):disabled {
- opacity: 0.55;
- cursor: not-allowed;
- pointer-events: none;
- }
- .btn-primary {
- background: var(--spry-accent);
- border-color: var(--spry-accent);
- color: var(--spry-accent-fg);
- }
- .btn-primary:hover {
- background: var(--spry-accent-hover);
- border-color: var(--spry-accent-hover);
- }
- .btn-danger {
- background: var(--spry-danger);
- border-color: var(--spry-danger);
- color: #fff;
- }
- .btn-danger:hover {
- background: color-mix(in srgb, var(--spry-danger) 85%, black);
- border-color: color-mix(in srgb, var(--spry-danger) 85%, black);
- }
- .btn-outline {
- background: transparent;
- border-color: var(--spry-accent);
- color: var(--spry-accent);
- }
- .btn-outline:hover {
- background: var(--spry-accent-soft);
- border-color: var(--spry-accent-hover);
- color: var(--spry-accent-hover);
- }
- .btn-ghost {
- background: transparent;
- border-color: transparent;
- color: var(--spry-fg);
- }
- .btn-ghost:hover {
- background: var(--spry-bg-alt);
- border-color: transparent;
- }
- .btn-link {
- background: none;
- border: 0;
- color: var(--spry-link);
- text-decoration: underline;
- text-underline-offset: 0.2em;
- padding-inline: 0.25rem;
- }
- .btn-link:hover {
- color: var(--spry-link-hover);
- }
- /* Size modifiers use :is() for (0,2,0) specificity so theme base restyles
- (scoped, (0,1,0)-ish) cannot clobber the small/large padding. */
- :is(.btn, button, input[type="submit"], input[type="reset"], input[type="button"]).btn-sm {
- padding: 0.25rem 0.6rem;
- font-size: 0.85em;
- border-radius: var(--spry-radius-sm);
- }
- :is(.btn, button, input[type="submit"], input[type="reset"], input[type="button"]).btn-lg {
- padding: 0.6rem 1.2rem;
- font-size: 1.1em;
- border-radius: var(--spry-radius);
- }
- .btn-block {
- display: flex;
- width: 100%;
- }
- .btn-group {
- display: inline-flex;
- }
- .btn-group > .btn,
- .btn-group > button {
- border-radius: 0;
- margin-left: calc(-1 * var(--spry-border-width));
- }
- .btn-group > .btn:first-child,
- .btn-group > button:first-child {
- margin-left: 0;
- border-start-start-radius: var(--spry-control-radius);
- border-end-start-radius: var(--spry-control-radius);
- }
- .btn-group > .btn:last-child,
- .btn-group > button:last-child {
- border-start-end-radius: var(--spry-control-radius);
- border-end-end-radius: var(--spry-control-radius);
- }
- /* ==========================================================================
- 12. Components — forms
- ========================================================================== */
- input[type="text"],
- input[type="email"],
- input[type="password"],
- input[type="number"],
- input[type="search"],
- input[type="tel"],
- input[type="url"],
- input[type="date"],
- input[type="time"],
- input[type="datetime-local"],
- input[type="month"],
- input[type="week"],
- input[type="color"],
- select,
- textarea,
- .input {
- width: 100%;
- padding: var(--spry-control-padding-y) var(--spry-control-padding-x);
- background: var(--spry-control-bg);
- color: var(--spry-control-fg);
- border: var(--spry-border-width) solid var(--spry-control-border);
- border-radius: var(--spry-control-radius);
- box-shadow: var(--spry-glass);
- transition: border-color var(--spry-transition), box-shadow var(--spry-transition);
- }
- textarea {
- min-height: 6lh;
- resize: vertical;
- }
- select:not([size]):not([multiple]) {
- width: auto;
- }
- select[multiple] {
- height: auto;
- }
- input[type="color"] {
- width: 3.5rem;
- padding: 0.2rem;
- height: 2.4rem;
- cursor: pointer;
- }
- input[type="search"] {
- border-radius: var(--spry-radius-pill);
- }
- input:hover:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
- select:hover,
- textarea:hover {
- border-color: var(--spry-border-strong);
- }
- input:focus:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]),
- select:focus,
- textarea:focus,
- .input:focus {
- outline: none;
- border-color: var(--spry-accent);
- box-shadow: var(--spry-focus-ring);
- }
- input:disabled,
- select:disabled,
- textarea:disabled {
- opacity: 0.55;
- cursor: not-allowed;
- background: var(--spry-bg-inset);
- }
- input[readonly],
- textarea[readonly] {
- background: var(--spry-bg-inset);
- }
- .is-invalid {
- border-color: var(--spry-danger) !important;
- }
- .is-invalid:focus {
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--spry-danger) 25%, transparent) !important;
- }
- .is-valid {
- border-color: var(--spry-success) !important;
- }
- .field {
- display: flex;
- flex-direction: column;
- gap: 0.35rem;
- }
- .field .label,
- .label {
- font-weight: 600;
- font-size: 0.92em;
- }
- .hint {
- font-size: 0.85em;
- color: var(--spry-fg-muted);
- }
- .field .is-invalid ~ .hint {
- color: var(--spry-danger);
- }
- fieldset {
- border: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius);
- padding: 1rem 1.25rem;
- margin: 0 0 1rem;
- min-width: 0;
- }
- legend {
- font-weight: 600;
- padding-inline: 0.4rem;
- }
- /* Checkboxes & radios */
- input[type="checkbox"],
- input[type="radio"] {
- width: 1.05em;
- height: 1.05em;
- flex: none;
- accent-color: var(--spry-accent);
- cursor: pointer;
- }
- .choice {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- cursor: pointer;
- }
- .choices {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- gap: 0.4rem;
- }
- .choices-inline {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.4rem 1.2rem;
- }
- /* Switch (toggle) */
- .switch {
- display: inline-flex;
- align-items: center;
- gap: 0.6rem;
- cursor: pointer;
- }
- .switch input {
- position: absolute;
- opacity: 0;
- width: 1px;
- height: 1px;
- }
- .switch .track {
- position: relative;
- flex: none;
- width: 2.4rem;
- height: 1.35rem;
- border-radius: var(--spry-radius-pill);
- background: var(--spry-border-strong);
- transition: background-color var(--spry-transition);
- }
- .switch .track::after {
- content: "";
- position: absolute;
- top: 0.175rem;
- left: 0.175rem;
- width: 1rem;
- height: 1rem;
- border-radius: 50%;
- background: var(--spry-surface);
- box-shadow: var(--spry-shadow);
- transition: translate var(--spry-transition);
- }
- .switch input:checked + .track {
- background: var(--spry-accent);
- }
- .switch input:checked + .track::after {
- translate: 1.05rem 0;
- }
- .switch input:focus-visible + .track {
- outline: 2px solid var(--spry-accent);
- outline-offset: 2px;
- }
- .switch input:disabled ~ * {
- opacity: 0.55;
- cursor: not-allowed;
- }
- /* ==========================================================================
- 13. Components — cards
- ========================================================================== */
- .card {
- background: var(--spry-card-bg);
- border: var(--spry-border-width) solid var(--spry-card-border);
- border-radius: var(--spry-radius);
- box-shadow: var(--spry-card-shadow);
- backdrop-filter: var(--spry-glass);
- }
- /* Padding comes with the card, so a bare <div class="card"> already looks
- right; structural sections carry their own padding flush to the frame, so
- a card built from them drops the default. Both rules sit at zero
- specificity (:where), the same trick the reset uses — padding utilities
- (.p-0, .px-2, …) override them without a specificity fight. */
- :where(.card) {
- padding: var(--spry-card-padding);
- }
- :where(.card:has(> .card-header, > .card-body, > .card-footer)) {
- padding: 0;
- }
- .card-flat {
- box-shadow: none;
- }
- .card-header,
- .card-body,
- .card-footer {
- padding: var(--spry-card-padding);
- }
- .card-header {
- border-bottom: var(--spry-border-width) solid var(--spry-card-border);
- background: var(--spry-bg-alt);
- border-radius: var(--spry-radius) var(--spry-radius) 0 0;
- }
- .card-footer {
- border-top: var(--spry-border-width) solid var(--spry-card-border);
- background: var(--spry-bg-alt);
- border-radius: 0 0 var(--spry-radius) var(--spry-radius);
- }
- .card-header + .card-body,
- .card-body + .card-footer,
- .card-header:first-child:last-child {
- margin: 0;
- }
- .card-header + .card-body {
- border-radius: 0;
- }
- .card-body + .card-footer {
- border-radius: 0 0 var(--spry-radius) var(--spry-radius);
- }
- .card-title {
- font-size: 1.1rem;
- font-weight: 650;
- margin: 0;
- font-family: var(--spry-font-heading);
- }
- .card-subtitle {
- font-size: 0.875em;
- color: var(--spry-fg-muted);
- margin: 0.15rem 0 0;
- }
- /* ==========================================================================
- 14. Components — alerts & badges
- ========================================================================== */
- .alert {
- display: flex;
- align-items: baseline;
- gap: 0.6rem;
- padding: 0.8rem 1rem;
- border: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius);
- background: var(--spry-surface);
- }
- .alert p {
- margin: 0;
- }
- .alert-danger { background: var(--spry-danger-soft); border-color: color-mix(in srgb, var(--spry-danger) 35%, transparent); color: var(--spry-danger); }
- .alert-success { background: var(--spry-success-soft); border-color: color-mix(in srgb, var(--spry-success) 35%, transparent); color: var(--spry-success); }
- .alert-warning { background: var(--spry-warning-soft); border-color: color-mix(in srgb, var(--spry-warning) 35%, transparent); color: var(--spry-warning); }
- .alert-info { background: var(--spry-info-soft); border-color: color-mix(in srgb, var(--spry-info) 35%, transparent); color: var(--spry-info); }
- .badge {
- display: inline-flex;
- align-items: center;
- gap: 0.3em;
- padding: 0.1em 0.65em;
- border-radius: var(--spry-radius-pill);
- font-size: 0.78em;
- font-weight: 600;
- line-height: 1.6;
- background: var(--spry-accent-soft);
- color: var(--spry-accent);
- white-space: nowrap;
- }
- .badge-danger { background: var(--spry-danger-soft); color: var(--spry-danger); }
- .badge-success { background: var(--spry-success-soft); color: var(--spry-success); }
- .badge-warning { background: var(--spry-warning-soft); color: var(--spry-warning); }
- .badge-info { background: var(--spry-info-soft); color: var(--spry-info); }
- .badge-muted { background: var(--spry-bg-alt); color: var(--spry-fg-muted); border: var(--spry-border-width) solid var(--spry-border); }
- /* ==========================================================================
- 15. Components — tables
- ========================================================================== */
- .table-wrap {
- overflow-x: auto;
- }
- table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.95em;
- background: var(--spry-surface);
- border: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius);
- }
- caption {
- caption-side: bottom;
- text-align: left;
- color: var(--spry-fg-muted);
- font-size: 0.85em;
- padding-top: 0.5rem;
- }
- th,
- td {
- text-align: left;
- padding: 0.5rem 0.75rem;
- border-bottom: var(--spry-border-width) solid var(--spry-border);
- vertical-align: top;
- }
- thead th {
- background: var(--spry-table-header-bg);
- font-size: 0.75em;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--spry-fg-muted);
- border-bottom-width: 2px;
- }
- tbody tr:last-child td,
- tbody tr:last-child th {
- border-bottom: 0;
- }
- .table-striped tbody tr:nth-child(even) {
- background: color-mix(in srgb, var(--spry-bg-alt) 55%, transparent);
- }
- .table-hover tbody tr:hover {
- background: var(--spry-table-hover);
- }
- .table-compact th,
- .table-compact td {
- padding: 0.3rem 0.55rem;
- }
- .table-borderless,
- .table-borderless th,
- .table-borderless td {
- border: 0;
- background: transparent;
- }
- /* ==========================================================================
- 16. Components — progress, meter, spinners
- ========================================================================== */
- progress {
- appearance: none;
- -webkit-appearance: none;
- border: 0;
- width: 100%;
- height: 0.8rem;
- border-radius: var(--spry-radius-pill);
- overflow: hidden;
- background: var(--spry-progress-bg);
- }
- progress::-webkit-progress-bar {
- background: var(--spry-progress-bg);
- border-radius: var(--spry-radius-pill);
- }
- progress::-webkit-progress-value {
- background: var(--spry-progress-fg);
- border-radius: var(--spry-radius-pill);
- transition: width 200ms ease;
- }
- progress::-moz-progress-bar {
- background: var(--spry-progress-fg);
- border-radius: var(--spry-radius-pill);
- }
- /* Indeterminate: a GTK-style "pulse" block bouncing back and forth.
- Chromium ignores author styles on the indeterminate value pseudo
- entirely, so the slug lives on the ELEMENT's background (both engines
- animate element backgrounds reliably) and the track pseudo is made
- transparent so it doesn't paint over it. */
- /* html-prefixed so themed plain `progress { background }` rules (equal or
- lower specificity, loaded later) can never override the indeterminate
- state. The slug is a true stadium — rectangle + two half-disc caps in
- three equally-sized layers (so percentage positions move them in
- lockstep); a single radial would be a lens, which reads pointy. */
- html progress:indeterminate {
- background:
- radial-gradient(var(--spry-pulse-cap) var(--spry-pulse-cap) at var(--spry-pulse-cap) 50%, var(--spry-progress-fg) 97%, transparent 100%) 0% 50% / 25% 100% no-repeat,
- radial-gradient(var(--spry-pulse-cap) var(--spry-pulse-cap) at calc(100% - var(--spry-pulse-cap)) 50%, var(--spry-progress-fg) 97%, transparent 100%) 0% 50% / 25% 100% no-repeat,
- linear-gradient(90deg, transparent 0 var(--spry-pulse-cap), var(--spry-progress-fg) var(--spry-pulse-cap) calc(100% - var(--spry-pulse-cap)), transparent calc(100% - var(--spry-pulse-cap))) 0% 50% / 25% 100% no-repeat,
- var(--spry-progress-bg);
- animation: spry-pulse 1.4s linear infinite alternate;
- }
- html progress:indeterminate::-webkit-progress-bar,
- progress:indeterminate::-webkit-progress-bar {
- background: transparent !important;
- }
- html progress:indeterminate::-moz-progress-bar,
- progress:indeterminate::-moz-progress-bar {
- background: transparent !important;
- }
- .progress-thin {
- height: 0.4rem;
- }
- meter {
- width: 100%;
- height: 1.1rem;
- }
- .spinner {
- display: inline-block;
- width: 1.5rem;
- height: 1.5rem;
- border-radius: 50%;
- border: 0.18em solid var(--spry-border);
- border-top-color: var(--spry-accent);
- animation: spry-spin 0.9s linear infinite;
- vertical-align: -0.25em;
- }
- .spinner-sm { width: 1rem; height: 1rem; border-width: 0.14em; }
- .spinner-lg { width: 2.5rem; height: 2.5rem; border-width: 0.12em; }
- @keyframes spry-spin {
- to { transform: rotate(1turn); }
- }
- @keyframes spry-stripes {
- to { background-position: 1.7rem 0; }
- }
- @keyframes spry-pulse {
- /* three slug layers + the track — identical percentage positions keep
- the stadium parts glued together */
- from { background-position: 0% 50%, 0% 50%, 0% 50%, 0 0; }
- to { background-position: 100% 50%, 100% 50%, 100% 50%, 0 0; }
- }
- /* ==========================================================================
- 17. Components — dialogs
- --------------------------------------------------------------------------
- Native <dialog> (open non-modally with the open attribute, or modally with
- dialog.showModal()). Dialog-like windows without any JavaScript: use
- <div popover> with a popovertarget button (see the popover section).
- ========================================================================== */
- dialog {
- width: min(92vw, 36rem);
- max-height: min(85vh, 100%);
- margin: auto; /* re-assert UA centering — the reset above zeroes margins */
- padding: 0;
- border: var(--spry-border-width) solid var(--spry-popover-border);
- border-radius: var(--spry-radius-lg);
- background: var(--spry-popover-bg);
- color: var(--spry-fg);
- box-shadow: var(--spry-popover-shadow);
- backdrop-filter: var(--spry-glass);
- }
- dialog.sm,
- .dialog-sm { width: min(92vw, 24rem); }
- dialog.lg,
- .dialog-lg { width: min(92vw, 56rem); }
- /* A dialog without structural parts (titlebar/body/footer/card sections)
- would render its content flush against the frame, so pad it like a
- popover. Structural dialogs keep padding: 0 above. */
- dialog:not(:has(.dialog-titlebar, .dialog-body, .dialog-footer, .card-header, .card-body, .card-footer)) {
- padding: var(--spry-popover-padding);
- }
- dialog::backdrop {
- background: var(--spry-backdrop);
- }
- .dialog-titlebar {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.55rem 0.65rem 0.55rem 1rem;
- background: var(--spry-bg-alt);
- border-bottom: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius-lg) var(--spry-radius-lg) 0 0;
- user-select: none;
- }
- .dialog-title {
- font-weight: 650;
- font-size: 0.95rem;
- flex: 1;
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .dialog-close {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 1.7rem;
- height: 1.7rem;
- flex: none;
- padding: 0;
- border: 0;
- border-radius: var(--spry-radius-sm);
- background: transparent;
- color: var(--spry-fg-muted);
- font-size: 1.1rem;
- line-height: 1;
- cursor: pointer;
- transition: background-color var(--spry-transition), color var(--spry-transition);
- }
- .dialog-close:hover {
- background: var(--spry-danger-soft);
- color: var(--spry-danger);
- }
- .dialog-close:focus-visible {
- outline: 2px solid var(--spry-accent);
- outline-offset: 1px;
- }
- .dialog-body {
- padding: 1.25rem;
- }
- .dialog-footer {
- display: flex;
- justify-content: flex-end;
- flex-wrap: wrap;
- gap: 0.5rem;
- padding: 0.8rem 1.25rem;
- border-top: var(--spry-border-width) solid var(--spry-border);
- background: var(--spry-bg-alt);
- border-radius: 0 0 var(--spry-radius-lg) var(--spry-radius-lg);
- }
- /* Open/close animation. Two-state pattern: the closed state carries the
- "hidden" values and the EXIT timing; the open state carries the ENTRY
- timing — each direction reads the transition of the state it lands in.
- @starting-style makes even a dialog with a static open attribute fade in.
- Browsers without support simply don't animate. */
- dialog,
- [popover] {
- opacity: 0;
- transform: var(--spry-dialog-in);
- transition:
- opacity var(--spry-dialog-close-duration) var(--spry-dialog-close-ease),
- transform var(--spry-dialog-close-duration) var(--spry-dialog-close-ease),
- display var(--spry-dialog-close-duration) allow-discrete,
- overlay var(--spry-dialog-close-duration) allow-discrete;
- }
- dialog[open],
- :popover-open {
- opacity: 1;
- transform: none;
- transition:
- opacity var(--spry-dialog-duration) var(--spry-dialog-ease),
- transform var(--spry-dialog-duration) var(--spry-dialog-ease),
- display var(--spry-dialog-duration) allow-discrete,
- overlay var(--spry-dialog-duration) allow-discrete;
- @starting-style {
- opacity: 0;
- transform: var(--spry-dialog-in);
- }
- }
- dialog::backdrop,
- [popover]::backdrop {
- opacity: 0;
- transition:
- opacity var(--spry-dialog-close-duration) var(--spry-dialog-close-ease),
- display var(--spry-dialog-close-duration) allow-discrete,
- overlay var(--spry-dialog-close-duration) allow-discrete;
- }
- dialog[open]::backdrop,
- :popover-open::backdrop {
- opacity: 1;
- transition:
- opacity var(--spry-dialog-duration) var(--spry-dialog-ease),
- display var(--spry-dialog-duration) allow-discrete,
- overlay var(--spry-dialog-duration) allow-discrete;
- @starting-style {
- opacity: 0;
- }
- }
- /* ==========================================================================
- 18. Components — popovers & menus (no JavaScript)
- --------------------------------------------------------------------------
- Any element with the popover attribute opens/closes via a button with
- popovertarget="id" (or the light-dismiss "auto" behavior by default).
- ========================================================================== */
- [popover] {
- /* re-assert the UA popover centering model (inset 0 + margin auto);
- the reset above zeroes margins, which parks popovers in the top-left */
- margin: auto;
- width: min(92vw, 26rem);
- padding: var(--spry-popover-padding);
- border: var(--spry-border-width) solid var(--spry-popover-border);
- border-radius: var(--spry-radius-lg);
- background: var(--spry-popover-bg);
- color: var(--spry-fg);
- box-shadow: var(--spry-popover-shadow);
- backdrop-filter: var(--spry-glass);
- }
- [popover]::backdrop {
- background: var(--spry-backdrop);
- }
- /* A popover built from dialog layout parts is a "window": drop the generic
- popover padding so the titlebar/body/footer run flush to the frame. */
- [popover]:has(> .dialog-titlebar, > .dialog-body, > .dialog-footer) {
- padding: 0;
- }
- /* Adwaita-style anchored popovers: give the trigger `.anchor` and the popover
- `.popover-anchor`, and set the same --anchor-name custom property on both.
- The popover drops below the trigger and flips at the viewport edges; its
- backdrop is transparent (menus light-dismiss without a modal scrim).
- Without anchor positioning support, popovers stay centered. */
- .anchor {
- anchor-name: var(--anchor-name, --spry-anchor);
- }
- @supports (position-area: bottom) {
- .popover-anchor {
- position-anchor: var(--anchor-name, --spry-anchor);
- position-area: bottom;
- position-try: flip-block, flip-inline;
- margin: 0.4rem 0 0;
- width: auto;
- max-width: min(92vw, 26rem);
- }
- .popover-anchor::backdrop {
- background: transparent;
- }
- }
- .popover-title {
- font-weight: 650;
- margin-bottom: 0.4rem;
- }
- .popover-menu {
- padding: 0.4rem;
- min-width: 12rem;
- }
- /* Only set display in the open state: an author `display` on a closed
- [popover] overrides the UA's display:none and the menu never hides. */
- .popover-menu:popover-open {
- display: flex;
- flex-direction: column;
- gap: 1px;
- }
- .popover-menu a,
- .popover-menu button {
- display: flex;
- align-items: center;
- gap: 0.6rem;
- width: 100%;
- padding: 0.45rem 0.7rem;
- border: 0;
- border-radius: var(--spry-radius-sm);
- background: none;
- color: var(--spry-fg);
- text-align: left;
- text-decoration: none;
- font-weight: 450;
- }
- .popover-menu a:hover,
- .popover-menu button:hover {
- background: var(--spry-accent-soft);
- color: var(--spry-accent);
- }
- .popover-footer {
- display: flex;
- justify-content: flex-end;
- gap: 0.5rem;
- margin-top: 0.9rem;
- }
- /* ==========================================================================
- 19. Components — expanders (details/summary)
- ========================================================================== */
- details {
- border: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius);
- background: var(--spry-surface);
- }
- details + details {
- margin-top: 0.6rem;
- }
- summary {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.7rem 1rem;
- border-radius: var(--spry-radius);
- font-weight: 600;
- cursor: pointer;
- list-style: none;
- user-select: none;
- transition: background-color var(--spry-transition);
- }
- summary:hover {
- background: var(--spry-bg-alt);
- }
- summary::-webkit-details-marker {
- display: none;
- }
- summary::before {
- content: "";
- width: 0.45rem;
- height: 0.45rem;
- flex: none;
- margin-right: 0.15rem;
- border-right: 2px solid var(--spry-fg-muted);
- border-bottom: 2px solid var(--spry-fg-muted);
- rotate: -45deg;
- transition: rotate var(--spry-transition);
- }
- details[open] > summary::before {
- rotate: 45deg;
- }
- details[open] > summary {
- border-bottom: var(--spry-border-width) solid var(--spry-border);
- border-radius: var(--spry-radius) var(--spry-radius) 0 0;
- }
- details > :not(summary):not(:last-child) {
- padding: 1rem 1rem 0;
- }
- details > :not(summary):last-child {
- padding: 1rem;
- }
- details > *:not(summary) {
- margin: 0;
- }
- .expander-group > details + details {
- margin-top: calc(-1 * var(--spry-border-width));
- border-radius: 0;
- }
- .expander-group > details:first-child {
- border-radius: var(--spry-radius) var(--spry-radius) 0 0;
- }
- .expander-group > details:last-child {
- border-radius: 0 0 var(--spry-radius) var(--spry-radius);
- }
- .expander-group > details:only-child {
- border-radius: var(--spry-radius);
- }
- .expander-group > details[open]:not(:last-child) > summary {
- border-bottom-color: transparent;
- }
- /* ==========================================================================
- 20. Components — hero, avatars, OTP, drawers, pagination
- ========================================================================== */
- .hero {
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
- gap: var(--spry-space-3);
- padding: calc(var(--spry-space-5) * 1.4) var(--spry-space-3);
- background:
- radial-gradient(60rem 24rem at 50% -8rem, var(--spry-accent-soft), transparent 70%),
- var(--spry-bg-alt);
- border-block: var(--spry-border-width) solid var(--spry-border);
- }
- .hero-compact {
- padding-block: var(--spry-space-4);
- }
- .hero-eyebrow {
- font-size: 0.78rem;
- font-weight: 700;
- letter-spacing: 0.12em;
- text-transform: uppercase;
- color: var(--spry-accent);
- }
- .hero-title {
- font-size: clamp(2rem, 1.2rem + 3vw, 3.25rem);
- max-width: 24ch;
- margin: 0;
- }
- .hero-sub {
- max-width: 52ch;
- color: var(--spry-fg-muted);
- margin: 0;
- }
- .hero-actions {
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- gap: var(--spry-space-2);
- }
- .avatar {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 2.5rem;
- height: 2.5rem;
- flex: none;
- border-radius: 50%;
- background: var(--spry-accent-soft);
- color: var(--spry-accent);
- font-weight: 650;
- font-size: 0.9rem;
- letter-spacing: 0.02em;
- overflow: hidden;
- user-select: none;
- }
- .avatar img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- .avatar-sm { width: 1.75rem; height: 1.75rem; font-size: 0.68rem; }
- .avatar-lg { width: 3.5rem; height: 3.5rem; font-size: 1.2rem; }
- .avatar-group {
- display: inline-flex;
- align-items: center;
- }
- .avatar-group .avatar {
- border: 2px solid var(--spry-bg);
- margin-left: -0.65rem;
- box-shadow: none;
- }
- .avatar-group .avatar:first-child {
- margin-left: 0;
- }
- /* OTP / verification-code input. One character per field; moving focus
- automatically takes one line of JS in apps that want it. */
- .otp {
- display: inline-flex;
- align-items: center;
- gap: var(--spry-space-2);
- }
- .otp input {
- width: 2.9rem;
- height: 3.4rem;
- padding: 0;
- text-align: center;
- font-family: var(--spry-font-mono);
- font-size: 1.35rem;
- line-height: 1;
- }
- .otp-separator {
- color: var(--spry-fg-muted);
- font-weight: 600;
- }
- /* Drawers: popover-based side panels, no JavaScript. The slide direction
- comes from the same --spry-dialog-in variable the dialog animation reads. */
- .drawer-left,
- .drawer-right {
- width: min(22rem, 90vw);
- height: 100dvh;
- padding: 0;
- margin: 0;
- border-radius: 0;
- border-block: 0;
- box-shadow: var(--spry-shadow-lg);
- }
- .drawer-left {
- inset: 0 auto 0 0;
- border-right-width: var(--spry-border-width);
- --spry-dialog-in: translateX(-100%);
- }
- .drawer-right {
- inset: 0 0 0 auto;
- border-left-width: var(--spry-border-width);
- --spry-dialog-in: translateX(100%);
- }
- .drawer-left .dialog-titlebar,
- .drawer-right .dialog-titlebar {
- border-radius: 0;
- }
- .drawer-left .dialog-footer,
- .drawer-right .dialog-footer {
- border-radius: 0;
- }
- /* Pagination */
- .pagination {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.3rem;
- list-style: none;
- padding: 0;
- margin: 0;
- }
- .pagination a,
- .pagination span {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- min-width: 2.2rem;
- height: 2.2rem;
- padding: 0 0.55rem;
- border: var(--spry-border-width) solid transparent;
- border-radius: var(--spry-radius-sm);
- color: var(--spry-fg);
- text-decoration: none;
- font-weight: 500;
- transition: background-color var(--spry-transition), color var(--spry-transition);
- }
- .pagination a:hover {
- background: var(--spry-bg-alt);
- color: var(--spry-accent);
- }
- .pagination [aria-current="page"] {
- background: var(--spry-accent);
- color: var(--spry-accent-fg);
- font-weight: 650;
- }
- .pagination [aria-disabled="true"] {
- opacity: 0.45;
- pointer-events: none;
- }
|