diff --git a/app/assets/images/add.svg b/app/assets/images/add.svg new file mode 100644 index 000000000..1a598b952 --- /dev/null +++ b/app/assets/images/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/arrow-left.svg b/app/assets/images/arrow-left.svg new file mode 100644 index 000000000..261f04a68 --- /dev/null +++ b/app/assets/images/arrow-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/bolt.svg b/app/assets/images/bolt.svg new file mode 100644 index 000000000..78cb2c57d --- /dev/null +++ b/app/assets/images/bolt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/chart.svg b/app/assets/images/chart.svg new file mode 100644 index 000000000..8a42e538e --- /dev/null +++ b/app/assets/images/chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/check.svg b/app/assets/images/check.svg new file mode 100644 index 000000000..3d70a50ee --- /dev/null +++ b/app/assets/images/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/hourglass.svg b/app/assets/images/hourglass.svg new file mode 100644 index 000000000..50d90d9c9 --- /dev/null +++ b/app/assets/images/hourglass.svg @@ -0,0 +1 @@ +hourglass \ No newline at end of file diff --git a/app/assets/images/inbox.svg b/app/assets/images/inbox.svg new file mode 100644 index 000000000..50252472c --- /dev/null +++ b/app/assets/images/inbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/pencil.svg b/app/assets/images/pencil.svg new file mode 100644 index 000000000..b8224adbb --- /dev/null +++ b/app/assets/images/pencil.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/settings.svg b/app/assets/images/settings.svg new file mode 100644 index 000000000..3237d6970 --- /dev/null +++ b/app/assets/images/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/splat-1.svg b/app/assets/images/splat-1.svg new file mode 100644 index 000000000..e2097e4f1 --- /dev/null +++ b/app/assets/images/splat-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/temperature.svg b/app/assets/images/temperature.svg new file mode 100644 index 000000000..7f02650ac --- /dev/null +++ b/app/assets/images/temperature.svg @@ -0,0 +1 @@ +temperature-thermometer-high \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 000000000..288b9ab71 --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/app/assets/stylesheets/avatars.css b/app/assets/stylesheets/avatars.css new file mode 100644 index 000000000..6aeeba783 --- /dev/null +++ b/app/assets/stylesheets/avatars.css @@ -0,0 +1,16 @@ +.avatar { + --avatar-border-radius: 50%; + + aspect-ratio: 1; + block-size: var(--avatar-size, 2.65em); + border-radius: var(--avatar-border-radius); + display: grid; + inline-size: var(--avatar-size, 2.65em); + margin: 0; + place-items: center; + + > * { + aspect-ratio: 1; + grid-area: 1/1; + } +} diff --git a/app/assets/stylesheets/buttons.css b/app/assets/stylesheets/buttons.css new file mode 100644 index 000000000..dc89a877c --- /dev/null +++ b/app/assets/stylesheets/buttons.css @@ -0,0 +1,183 @@ +:root { + --btn-size: 2.65em; +} + +.btn { + --transition: 300ms ease; + + align-items: center; + background-color: var(--btn-background, var(--color-bg)); + border-radius: var(--btn-border-radius, 2em); + border: var(--btn-border-size, 1px) solid var(--btn-border-color, var(--color-subtle-dark)); + color: var(--btn-color, var(--color-ink)); + cursor: pointer; + display: inline-flex; + font-size: 1em; + font-weight: 600; + gap: var(--btn-gap, 0.5em); + justify-content: center; + padding: var(--btn-padding, 0.5em 1.1em); + pointer-events: auto; + transition: + background-color var( --transition), + border var( --transition), + color var( --transition), + filter var( --transition), + opacity var( --transition); + + img { + -webkit-touch-callout: none; + + pointer-events: none; + user-select: none; + } + + /* Default icon styles */ + &:where(:has(img, svg)) { + text-align: start; + + img, svg { + block-size: var(--btn-icon-size, 1.3em); + inline-size: var(--btn-icon-size, 1.3em); + max-inline-size: unset; + } + + img:not([class]) { + filter: invert(0); + + @media (prefers-color-scheme: dark) { + filter: invert(1); + } + } + } + + /* Circle buttons */ + &.btn--circle, + &:where(:has(.for-screen-reader):has(img, svg)) { + --btn-border-radius: 50%; + --btn-padding: 0; + + aspect-ratio: 1; + block-size: var(--btn-size); + display: grid; + inline-size: var(--btn-size); + place-items: center; + + > * { + grid-area: 1/1; + } + } + + /* With radios and checkboxes */ + &:has(input[type=radio], input[type=checkbox]) { + :is(input[type=radio], input[type=checkbox]) { + appearance: none; + block-size: calc(var(--btn-size) - var(--outline-size)); + border-radius: var(--btn-border-radius); + cursor: pointer; + display: flex; + inline-size: calc(var(--btn-size) - var(--outline-size)); + margin: 0; + padding: 0; + } + + img.checked { + display: none; + } + } + + &:has(input:checked) { + --btn-background: var(--color-ink); + --btn-color: var(--color-ink-reversed); + --outline-color: var(--color-ink); + + img { + filter: invert(1); + } + + @media (prefers-color-scheme: dark) { + img { + filter: invert(0); + } + } + + img.checked { + display: block; + } + } + + &[disabled], + &:has([disabled]), + [disabled] &[type=submit], + &[type=submit]:disabled { + cursor: not-allowed; + opacity: 0.3; + pointer-events: none; + } + + @media print { + display: none; + } +} + +/* Variants */ +.btn--link { + --btn-background: var(--color-link); + --btn-color: var(--color-ink-reversed); + --outline-color: var(--color-link); +} + +.btn--negative { + --btn-background: var(--color-negative); + --btn-color: var(--color-ink-reversed); + --outline-color: var(--color-negative); +} + +.btn--placeholder { + pointer-events: none; + visibility: hidden; +} + +.btn--plain { + --btn-border-radius: 0.5em; + --btn-border-size: 0; + --btn-icon-size: 100%; + --btn-padding: 0; + --hover-size: 0; +} + +.btn--positive { + --btn-background: var(--color-positive); + --btn-color: var(--color-ink-reversed); + --outline-color: var(--color-positive); +} + +.btn--reversed { + --btn-background: var(--color-ink); + --btn-color: var(--color-bg); + --outline-color: var(--color-ink); +} + +:is(.btn--link, .btn--negative, .btn--positive, .btn--reversed) { + --btn-border-color: var(--color-bg); + + img:not([class]) { + filter: invert(1); + + @media (prefers-color-scheme: dark) { + filter: invert(0); + } + } +} + +.btn--small { + font-size: 0.8em; +} + +.btn--success { + animation: success 1s ease-out; + + img { + animation: zoom-fade 300ms ease-out; + } +} diff --git a/app/assets/stylesheets/colors.css b/app/assets/stylesheets/colors.css new file mode 100644 index 000000000..7c286dcd2 --- /dev/null +++ b/app/assets/stylesheets/colors.css @@ -0,0 +1,65 @@ +:root { + /* Named color values */ + --lch-black: 0% 0 0; + --lch-white: 100% 0 0; + --lch-gray-light: 96% 0.005 96; + --lch-gray: 92% 0.005 96; + --lch-gray-dark: 75% 0.005 96; + --lch-blue: 54% 0.15 255; + --lch-blue-light: 95% 0.03 255; + --lch-blue-dark: 80% 0.08 255; + --lch-orange: 70% 0.2 44; + --lch-red: 51% 0.2 31; + --lch-green: 65.59% 0.234 142.49; + --lch-green-light: 95% 0.03 142.49; + --lch-always-black: 0% 0 0; + --lch-always-white: 100% 0 0; + + /* Abstractions */ + --color-negative: oklch(var(--lch-red)); + --color-positive: oklch(var(--lch-green)); + --color-positive-light: oklch(var(--lch-green-light)); + --color-bg: oklch(var(--lch-white)); + --color-ink: oklch(var(--lch-black)); + --color-ink-reversed: oklch(var(--lch-white)); + --color-link: oklch(var(--lch-blue)); + --color-subtle-light: oklch(var(--lch-gray-light)); + --color-subtle: oklch(var(--lch-gray)); + --color-subtle-dark: oklch(var(--lch-gray-dark)); + --color-selected: oklch(var(--lch-blue-light)); + --color-selected-dark: oklch(var(--lch-blue-dark)); + --color-marker: oklch(var(--lch-orange)); + --color-always-black: oklch(var(--lch-always-black)); + --color-always-white: oklch(var(--lch-always-white)); + + /* Redefine named color values for dark mode */ + @media (prefers-color-scheme: dark) { + --lch-black: 100% 0 0; + --lch-white: 0% 0 0; + --lch-gray-light: 25.2% 0 0; + --lch-gray: 30.12% 0 0; + --lch-gray-dark: 44.95% 0 0; + --lch-blue: 72.25% 0.16 248; + --lch-blue-light: 28.11% 0.053 248; + --lch-blue-dark: 42.25% 0.07 248; + --lch-red: 73.8% 0.184 29.18; + --lch-green: 75% 0.21 141.89; + --lch-green-light: 28.11% 0.02 142.49; + } +} + +.colorize--white { + filter: invert(1); + + @media (prefers-color-scheme: dark) { + filter: invert(0); + } +} + +.colorize--black { + filter: invert(0); + + @media (prefers-color-scheme: dark) { + filter: invert(1); + } +} diff --git a/app/assets/stylesheets/inputs.css b/app/assets/stylesheets/inputs.css new file mode 100644 index 000000000..f0a56e4ff --- /dev/null +++ b/app/assets/stylesheets/inputs.css @@ -0,0 +1,181 @@ +/* Text inputs */ +.input { + accent-color: var(--input-accent-color, var(--color-ink)); + background-color: var(--input-background, transparent); + border-radius: var(--input-border-radius, 0.5em); + border: var(--input-border-size, 1px) solid var(--input-border-color, var(--color-subtle-dark)); + color: var(--input-color, var(--color-ink)); + font-size: max(16px, 1em); + inline-size: 100%; + line-height: 1.2; + max-inline-size: 100%; + padding: var(--input-padding, 0.5em 0.8em); + resize: none; + + &:autofill, + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus { + -webkit-text-fill-color: var(--color-ink); + -webkit-box-shadow: 0 0 0px 1000px var(--color-selected) inset; + } + + &:where(:not(:active)):focus { + --input-border-color: var(--color-selected-dark); + --hover-color: var(--color-selected-dark); + --outline-size: 0; + --outline-color: transparent; + + filter: var(--hover-filter); + box-shadow: 0 0 0 var(--hover-size) var(--hover-color); + } +} + +.input--file { + border: 0; + cursor: pointer; + display: grid; + inline-size: auto; + place-items: center; + + > * { + grid-area: 1 / 1; + } + + img { + border-radius: 0.4em; + } + + input[type="file"] { + --input-border-color: transparent; + --input-border-radius: 8px; + + block-size: 100%; + cursor: pointer; + font-size: 0; + inline-size: 100%; + overflow: clip; + + &::file-selector-button { + appearance: none; + cursor: pointer; + opacity: 0; + } + + &:focus, + &:focus-visible { + --input-border-color: var(--color-selected-dark); + --input-border-radius: 8px; + --input-border-size: 0.15rem; + } + } +} + +.input--textara { + --input-padding: 0.5em; + + line-height: 1.1; + min-block-size: calc(4lh + (2 * var(--input-padding))); + min-inline-size: 100%; + padding-block: var(--input-padding); + padding-inline: calc(var(--input-padding) + calc((1lh - 1ex) / 2)); + + @supports (field-sizing: content) { + field-sizing: content; + max-block-size: calc(10lh + (2 * var(--input-padding))); + min-block-size: calc(1lh + (2 * var(--input-padding))); + } +} + +/* Switches */ +.switch { + block-size: 1.75em; + border-radius: 2em; + display: inline-flex; + inline-size: 3em; + position: relative; + + &:has(:focus-visible) { + .switch__btn { + box-shadow: + 0 0 0 var(--outline-size) var(--color-bg), + 0 0 0 calc(var(--outline-size) * 2) var(--color-ink); + } + } +} + +.switch__input { + block-size: 0; + inline-size: 0; + opacity: 0.1; +} + +.switch__btn { + background-color: var(--color-subtle-dark); + border-radius: 2em; + cursor: pointer; + inset: 0; + position: absolute; + transition: 150ms ease; + + &::before { + background-color: var(--color-ink-reversed); + block-size: 1.35em; + border-radius: 50%; + content: ""; + inline-size: 1.35em; + inset-block-end: 0.2em; + inset-inline-start: 0.2em; + position: absolute; + transition: 150ms ease; + } + + .switch__input:disabled + & { + background-color: var(--color-subtle-dark) !important; + cursor: not-allowed; + } + + .switch__input:checked + & { + background-color: var(--color-link); + + &::before { + transform: translateX(1.2em); + } + } +} + +/* Containers that act like (and contain) inputs */ +.input--actor { + transition: box-shadow 150ms ease, outline-offset 150ms ease; + + &:focus-within { + --input-border-color: var(--color-selected-dark); + --hover-color: var(--color-selected-dark); + --outline-size: 0; + + filter: var(--hover-filter); + box-shadow: 0 0 0 var(--hover-size) var(--hover-color); + } + + .input { + --input-padding: 0; + --input-border-radius: 0; + --input-background: transparent; + --input-border-size: 0; + --hover-size: 0; + --outline-size: 0; + --outline-color: transparent; + + inline-size: 100%; + outline: 0; + } + + &:has(.input:is( + :autofill, + :-webkit-autofill, + :-webkit-autofill:hover, + :-webkit-autofill:focus)) { + -webkit-text-fill-color: var(--color-text); + -webkit-box-shadow: 0 0 0px 1000px var(--color-selected) inset; + } +} diff --git a/app/assets/stylesheets/layout.css b/app/assets/stylesheets/layout.css new file mode 100644 index 000000000..adffe4101 --- /dev/null +++ b/app/assets/stylesheets/layout.css @@ -0,0 +1,87 @@ +body { + display: grid; + grid-template-rows: auto auto 1fr auto var(--block-space); +} + +:where(#main) { + container-type: inline-size; + font-size: var(--font-medium-responsive); + /* inline-size: 67ch; */ + inline-size: 90vw; + margin-inline: auto; + max-inline-size: 100vw; + padding-block-end: clamp(var(--block-space), 5%, calc(var(--block-space) * 3)); + padding-inline: clamp(var(--inline-space), 5%, calc(var(--inline-space) * 3)); + text-align: center; + + @media (max-width: 70ch) { + padding-inline: var(--inline-space); + } + + @media print { + font-size: 11pt; + inline-size: unset; + line-height: 1.3; + margin: 0; + orphans: 3; + padding: 0; + text-align: justify; + text-justify: distribute; + widows: 2; + } +} + +:where(#footer) { + max-inline-size: 100vw; + view-transition-name: footer; + + > nav { + padding-inline: var(--inline-space); + view-transition-name: footer-nav; + } + + &:has(.new-book-btn) { + inset-block-end: 0; + pointer-events: none; + position: sticky; + } +} + +:where(#header) { + max-inline-size: 100vw; + view-transition-name: header; + + > nav { + view-transition-name: nav; + } + + > * { + align-items: center; + display: flex; + gap: 1ch; + justify-content: center; + padding: var(--block-space-half) var(--inline-space); + } + + .btn { + flex-shrink: 0; + } +} + +:where(#toolbar) { + display: flex; + inset: 0 0 auto; + justify-content: center; + min-width: 0; + overflow: hidden; + padding-inline: var(--inline-space); + position: sticky; + view-transition-name: toolbar; + z-index: 1; +} + +:is(#header, #footer, #toolbar) { + @media print { + display: none; + } +} diff --git a/app/assets/stylesheets/panels.css b/app/assets/stylesheets/panels.css new file mode 100644 index 000000000..2ca61bd17 --- /dev/null +++ b/app/assets/stylesheets/panels.css @@ -0,0 +1,13 @@ +.panel { + background-color: var(--color-bg); + border: 1px solid var(--panel-border-color, var(--color-subtle)); + color: var(--color-ink); + border-radius: var(--panel-border-radius, 1em); + inline-size: var(--panel-size, 60ch); + max-inline-size: 100%; + padding: calc(var(--block-space) * 2); + + @media (prefers-color-scheme: dark) { + --panel-border-color: var(--color-subtle-dark); + } +} diff --git a/app/assets/stylesheets/splats.css b/app/assets/stylesheets/splats.css new file mode 100644 index 000000000..8d69e1c42 --- /dev/null +++ b/app/assets/stylesheets/splats.css @@ -0,0 +1,111 @@ +.windshield { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(15vw, 1fr)); + justify-content: center; + + > * { + flex-shrink: 1; + } +} + +.splat { + --hover-size: 0; + --splat-color: red; + --splat-rotate: 20deg; + --splat-size: 30vw; + + aspect-ratio: 1; + block-size: var(--splat-size); + color: var(--color-ink-reversed); + container-type: inline-size; + display: grid; + place-items: center; + position: relative; + + > * { + grid-area: 1/1; + } +} + +.splat__date { + aspect-ratio: 1; + background-color: var(--splat-color); + border-radius: 50%; + display: flex; + font-size: 5cqi; + font-weight: 800; + inset: 10cqi 5cqi auto auto; + padding: 0.5em 1em; + place-items: center; + position: absolute; +} + +.splat__link { + color: var(--color-ink-reversed); +} + +.splat__svg { + fill: var(--splat-color); + position: absolute; + scale: 120%; + transform: rotate(var(--splat-rotate)); + z-index: -1; +} + +.splat__tag { + aspect-ratio: 1; + background-color: var(--splat-color); + border-radius: 50%; + display: flex; + font-size: 5cqi; + font-weight: 800; + inset: auto auto 3cqi 3cqi; + padding: 0.5em 1em; + place-items: center; + position: absolute; + + + & { + inset: auto auto 0 24cqi; + } +} + +.splat__title { + font-size: 10cqi; + line-height: 1.2; + margin: 12cqi 14cqi; + + -webkit-line-clamp: var(--lines, 3); + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + text-overflow: clip; + white-space: normal; +} + +.splats-list { + --hover-size: 0; + + a { + color: var(--color-txt); + text-decoration: none; + } + + li { + border-radius: 0.6em; + list-style: none; + padding: 0.5em 1em; + transition: background-color 0.2s ease; + + &:hover{ + background-color: var(--color-selected); + } + } +} + +.splats-filter { + li { + list-style: none; + margin: 0; + padding: 0; + } +} diff --git a/app/assets/stylesheets/utilities.css b/app/assets/stylesheets/utilities.css new file mode 100644 index 000000000..61dde2d9a --- /dev/null +++ b/app/assets/stylesheets/utilities.css @@ -0,0 +1,240 @@ +:root { + --inline-space: 1ch; + --inline-space-half: calc(var(--inline-space) / 2); + --inline-space-double: calc(var(--inline-space) * 2); + + --block-space: 1rem; + --block-space-half: calc(var(--block-space) / 2); + --block-space-double: calc(var(--block-space) * 2); + + --font-small-responsive: clamp(0.8rem, 2cqi, 1rem); + --font-medium-responsive: clamp(1rem, 2.5cqi, 1.4rem); + --font-large-responsive: clamp(1.3rem, 4cqi, 1.8rem); + --font-x-large-responsive: clamp(1.8rem, 5cqi, 3.2rem); +} + +/* Text */ +.txt-small { font-size: 0.8rem; } +.txt-medium { font-size: 1rem; } +.txt-large { font-size: 1.4rem; } +.txt-x-large { font-size: 1.8rem; } +.txt-xx-large { font-size: 2.4rem; } + +.txt-small--responsive { font-size: var(--font-small-responsive); } +.txt-medium--responsive { font-size: var(--font-medium-responsive); } +.txt-large--responsive { font-size: var(--font-large-responsive); } +.txt-x-large--responsive { font-size: var(--font-x-large-responsive); } + +.txt-align-center { text-align: center; } +.txt-align-start { text-align: start; } +.txt-align-end { text-align: end; } + +.txt-ink { color: var(--color-ink); } +.txt-reversed { color: var(--color-ink-reversed); } +.txt-negative { color: var(--color-negative); } +.txt-subtle { color: var(--color-subtle-dark); } +.txt-undecorated { text-decoration: none; } +.txt-tight-lines { line-height: 1.2; } +.txt-normal { font-weight: 400; font-style: normal; } +.txt-nowrap { white-space: nowrap; } +.txt-uppercase { text-transform: uppercase; } + +/* Flexbox and Grid */ +.justify-end { justify-content: end; } +.justify-start { justify-content: start; } +.justify-center { justify-content: center; } +.justify-space-between { justify-content: space-between; } + +.align-center { align-items: center; } +.align-start { align-items: start; } +.align-end { align-items: end; } + +.align-self-start { align-self: start; } + +.contain { contain: inline-size; } + +.flex { display: flex; } +.flex-inline { display: inline-flex; } +.flex-column { flex-direction: column; } +.flex-wrap { flex-wrap: wrap; } + +.flex-item-grow { flex-grow: 1; } +.flex-item-shrink { flex-shrink: 1; } +.flex-item-no-shrink { flex-shrink: 0; } +.flex-item-justify-start { margin-inline-end: auto; } +.flex-item-justify-end { margin-inline-start: auto; } + +.gap { + column-gap: var(--column-gap, var(--inline-space)); + row-gap: var(--row-gap, var(--block-space)); +} + +.gap-half { + column-gap: var(--inline-space-half); + row-gap: var(--block-space-half); +} + +/* Sizing */ +.full-width { inline-size: 100%; } +.min-width { min-inline-size: 0; } +.half-width { inline-size: 50%; } +.max-width { max-inline-size: 100%; } +.min-content { inline-size: min-content; } +.max-inline-size { max-inline-size: 100%; } + +/* Overflow */ +.overflow-x { overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; } +.overflow-y { overflow-y: auto; scroll-snap-type: y mandatory; scroll-behavior: smooth; } +.overflow-clip { text-overflow: clip; white-space: nowrap; overflow: hidden; } +.overflow-ellipsis { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } + +.overflow-hide-scrollbar::-webkit-scrollbar { + @media (pointer: course) { + display: none; + } +} + +.overflow-line-clamp { + -webkit-line-clamp: var(--lines, 2); + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + text-overflow: clip; + white-space: normal; +} + +/* Padding */ +.pad { padding: var(--block-space) var(--inline-space); } +.pad-double { padding: var(--block-space-double) var(--inline-space-double); } + +.pad-block { padding-block: var(--block-space); } +.pad-block-start { padding-block-start: var(--block-space); } +.pad-block-end { padding-block-end: var(--block-space); } +.pad-block-half { padding-block: var(--block-space-half); } +.pad-block-start-half { padding-block-start: var(--block-space-half); } + +.pad-inline { padding-inline: var(--inline-space); } +.pad-inline-start { padding-inline-start: var(--inline-space); } +.pad-inline-end { padding-inline-end: var(--inline-space); } +.pad-inline-half { padding-inline: var(--inline-space-half); } +.pad-inline-double { padding-inline: var(--inline-space-double); } + +.unpad { padding: 0; } + +/* Margins */ +.margin { margin: var(--block-space) var(--inline-space); } +.margin-block { margin-block: var(--block-space); } +.margin-block-half { margin-block: var(--block-space-half); } +.margin-block-start { margin-block-start: var(--block-space); } +.margin-block-start-half { margin-block-start: var(--block-space-half); } +.margin-block-end { margin-block-end: var(--block-space); } +.margin-block-end-half { margin-block-end: var(--block-space-half); } +.margin-block-double { margin-block: var(--block-space-double); } +.margin-block-end-double { margin-block-end: var(--block-space-double); } +.margin-block-start-double { margin-block-start: var(--block-space-double); } + +.margin-inline { margin-inline: var(--inline-space); } +.margin-inline-start { margin-inline-start: var(--inline-space); } +.margin-inline-start-half { margin-inline-start: var(--inline-space-half); } +.margin-inline-end { margin-inline-end: var(--inline-space); } +.margin-inline-end-half { margin-inline-end: var(--inline-space-half); } +.margin-inline-half { margin-inline: var(--inline-space-half); } +.margin-inline-double { margin-inline: var(--inline-space-double); } + +.margin-none { margin: 0; } +.margin-none-block { margin-block: 0; } +.margin-none-block-start { margin-block-start: 0; } +.margin-none-block-end { margin-block-end: 0; } + +.margin-none-inline { margin-inline: 0; } +.margin-none-inline-start { margin-inline-start: 0; } +.margin-none-inline-end { margin-inline-end: 0; } + +.center { margin-inline: auto; } +.center-block { margin-block: auto; } + +/* Position */ +.position-relative { position: relative; } +.position-sticky { position: sticky; } + +/* Fills */ +.fill { background-color: var(--color-bg); } +.fill-black { background-color: var(--color-ink); } +.fill-white { background-color: var(--color-ink-reversed); } +.fill-shade { background-color: var(--color-subtle-light); } +.fill-selected { background-color: var(--color-selected); } +.fill-transparent { background-color: transparent; } + +.translucent { opacity: var(--opacity, 0.5); } + +/* Borders */ +.border { border: var(--border-size, 1px) solid var(--border-color, var(--color-subtle)); } +.border-top { border-top: var(--border-size, 1px) solid var(--border-color, var(--color-subtle)); } +.borderless { border: 0; } + +/* Border radius */ +.border-radius { border-radius: var(--border-radius, 1em); } + +/* Shadows */ +.shadow { + box-shadow: + 0 0 0 1px oklch(var(--lch-always-black) / 0.02), + 0 .2em 1.6em -0.8em oklch(var(--lch-always-black) / 0.2), + 0 .4em 2.4em -1em oklch(var(--lch-always-black) / 0.3), + 0 .4em .8em -1.2em oklch(var(--lch-always-black) / 0.4), + 0 .8em 1.2em -1.6em oklch(var(--lch-always-black) / 0.5), + 0 1.2em 1.6em -2em oklch(var(--lch-always-black) / 0.6); + + @media (prefers-color-scheme: dark) { + box-shadow: + 0 0 0 1px oklch(var(--lch-always-black) / 0.42), + 0 .2em 1.6em -0.8em oklch(var(--lch-always-black) / 0.6), + 0 .4em 2.4em -1em oklch(var(--lch-always-black) / 0.7), + 0 .4em .8em -1.2em oklch(var(--lch-always-black) / 0.8), + 0 .8em 1.2em -1.6em oklch(var(--lch-always-black) / 0.9), + 0 1.2em 1.6em -2em oklch(var(--lch-always-black) / 1); + } +} + +/* Seperators */ +.separator { + border-inline-start: 1px solid var(--color-subtle-dark); + display: inline-flex; + inline-size: 0; +} + +/* Spinners */ +.spinner { + position: relative; + + &::before { + --mask: no-repeat radial-gradient(#000 68%, #0000 71%); + --dot-size: 1.25em; + + -webkit-mask: var(--mask), var(--mask), var(--mask); + -webkit-mask-size: 28% 45%; + animation: submitting 1.3s infinite linear; + aspect-ratio: 8/5; + background: currentColor; + content: ""; + inline-size: var(--dot-size); + inset: 50% 0.25em; + margin-block: calc((var(--dot-size) / 3) * -1); + margin-inline: calc((var(--dot-size) / 2) * -1); + position: absolute; + } +} + +/* Accessibility */ +.for-screen-reader { + block-size: 1px; + clip-path: inset(50%); + inline-size: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; +} + +/* Visibility */ +[hidden] { display: none; } +[contents] { display: contents; }