diff --git a/public/static/css/fieber.css b/public/static/css/fieber.css new file mode 100644 index 0000000..d15789b --- /dev/null +++ b/public/static/css/fieber.css @@ -0,0 +1,965 @@ +/* SPDX-License-Identifier: MIT + SPDX-FileCopyrightText: Copyright (c) 2022-2025 zichy +*/ + +/* Custom properties +======================================== +*/ + +:root { + --f-sans: ui-sans-serif, sans-serif; + + --f-body: ui-serif; + --f-heading: var(--f-sans); + --f-form: var(--f-sans); + --f-code: ui-monospace; + + --f-size: clamp(1.6rem, 1.75vw, 2rem); + --f-size-small: 0.85em; + --f-size-large: 1.25em; + --f-line: 1.5; + + --c-gray: #666; + --c-red: #b30; + --c-yellow: #fe9; + + --i-triangle: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"%3E%3Cpolygon fill="black" points="5 10 10 0 0 0"/%3E%3C/svg%3E'); + + --w-body: 80ch; +} + +/* Dark theme */ + +@media (prefers-color-scheme: dark) { + :root { + --c-gray: #999; + --c-red: #f99; + --c-yellow: #ff9; + + --i-triangle: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"%3E%3Cpolygon fill="white" points="5 10 10 0 0 0"/%3E%3C/svg%3E'); + } +} + + +/* Globals +======================================== +*/ + +/* Box sizing */ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +/* Text rendering */ + +* { + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +/* Interaction */ + +::selection { + background: Highlight; + color: HighlightText; + text-shadow: none; +} + +*:focus { + outline: 2px solid LinkText; + outline-offset: 0.25rem; +} + +/* Font size & Scrolling */ + +html { + font-size: 62.5%; + scroll-behavior: smooth; + scroll-padding-top: 2rem; +} + +/* Backdrop */ + +::backdrop { + background-color: rgba(255, 255, 255, 0.6); +} + +@media (prefers-color-scheme: dark) { + ::backdrop { + background-color: rgba(0, 0, 0, 0.6); + } +} + +/* Hidden elements */ + +[hidden] { + display: none; +} + +/* Print spacing */ + +@page { + margin: 15mm 20mm; +} + + +/* Body +======================================== +*/ + +/* Colors & Typography */ + +body { + background-color: Canvas; + color: CanvasText; + font-size: var(--f-size); + font-family: var(--f-body); + line-height: var(--f-line); +} + +/* Body sizing */ + +@media screen { + body { + max-width: var(--w-body, 100%); + min-width: 320px; + padding: 2rem; + margin: 0 auto; + overflow-x: hidden; + overflow-y: scroll; + } +} + +/* Print colors */ + +@media print { + body { + background-color: white; + color: black; + } +} + + +/* Links +======================================== +*/ + +a:any-link { + color: LinkText; + text-decoration: underline; + text-decoration-thickness: 0.125em; +} + +a:any-link:hover { + background-color: LinkText; + color: Canvas; + text-decoration-line: none; +} + +@media print { + a[href^="http"]::after { + content: ' ('attr(href)')'; + font-size: var(--f-size-small); + word-break: break-all; + } +} + + +/* Media +======================================== +*/ + +/* Reset */ + +:where(iframe, img, svg, canvas, audio, video) { + display: block; + max-width: 100%; +} + +@media print { + :where(audio, video) { + display: none; + } +} + +figure { + margin-inline: 0; + break-inside: avoid; +} + +/* Image */ + +img { + height: auto; + position: relative; +} + +img::before { + content: ''; + background-color: Highlight; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +@media screen { + picture img { + width: 100%; + } +} + +/* Video */ + +video { + width: 100%; + height: auto; +} + +/* Iframe */ + +iframe { + border-style: none; +} + + +/* Headings +======================================== +*/ + +:where(h1, h2, h3, h4, h5, h6) { + font-family: var(--f-heading); + line-height: calc(var(--f-line) / 1.25); + hyphens: auto; +} + +:where(h3, h5) { + color: var(--c-gray); +} + +:where(h4, h5, h6) { + text-transform: uppercase; +} + +:where(h2, h3, h4, h5, h6):target { + background-color: var(--c-yellow); + color: MarkText; +} + + +/* Lists +======================================== +*/ + +:where(ul, ol) { + padding-inline-start: 1em; +} + +ul { + list-style-type: disc; +} + +li::marker { + color: var(--c-gray); +} + +li p { + margin: 0; +} + +/* Description */ + +dt { + font-style: italic; +} + +/* Navigation */ + +nav ul { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 2rem; + list-style-type: none; + padding: 0; +} + +@media print { + nav { + display: none; + } +} + + +/* Inline elements +======================================== +*/ + +/* Bold text */ + +:where(b, strong) { + font-weight: bolder; +} + +/* Small text */ + +small { + font-size: var(--f-size-small); +} + +/* Mark */ + +mark { + background-color: var(--c-yellow); +} + +/* Abbreviation */ + +abbr[title] { + text-decoration-line: underline; + text-decoration-style: dotted; + cursor: help; +} + +a abbr[title] { + text-decoration: none; +} + +/* Subscript & Superscript */ + +:where(sub, sup) { + line-height: 0; +} + +/* Quote */ + +q { + font-style: italic; + quotes: none; +} + +/* Keyboard input */ + +kbd { + background: linear-gradient(0deg, Canvas 0%, ButtonFace 100%); + font-size: var(--f-size-small); + font-family: var(--f-sans); + font-weight: bold; + padding: 0.2em 0.4em; + border-radius: 0.5rem; + box-shadow: 1px 1px 1px 0px var(--c-gray); +} + + +/* Ruby annotation +======================================== +*/ + +rt { + color: var(--c-gray); + font-family: var(--f-sans); + letter-spacing: -0.05em; + padding: 0 0.25em; +} + + +/* Horizontal rule +======================================== +*/ + +hr { + height: 0; + margin: 2em 0; + border: 0; + border-top: 2px solid var(--c-gray); +} + + +/* Blockquote +======================================== +*/ + +blockquote { + font-size: var(--f-size-large); + font-style: italic; + line-height: calc(var(--f-line) / 1.25); + margin: 0; +} + +blockquote > *:first-child { + margin-block-start: 0; +} + +blockquote > *:last-child { + margin-block-end: 0; +} + + +/* Captions +======================================== +*/ + +:where(caption, figcaption) { + color: var(--c-gray); + font-family: var(--f-heading); + font-size: var(--f-size-small); + font-style: italic; + margin-block-start: 0.5rem; +} + +caption { + text-align: left; + caption-side: bottom; +} + +[dir='rtl' i] caption { + text-align: right; +} + + +/* Code +======================================== +*/ + +:where(pre, code, samp, var) { + background-color: ButtonFace; +} + +:where(code, samp, var) { + font-size: var(--f-size-small); + font-family: var(--f-code); + padding: 0.2em 0.4em; +} + +pre { + font-size: var(--f-size-small); + padding: 2rem; +} + +@media screen { + pre { + overflow-x: scroll; + } +} + +pre code { + background-color: transparent; + display: block; + white-space: pre-wrap; + padding: 0; +} + + +/* Details +======================================== +*/ + +details { + background-color: ButtonFace; + padding: 2rem; + margin: 1em 0; + border-radius: 0.5rem; +} + +details > *:nth-child(2) { + margin-block-start: 0; +} + +details > *:last-child { + margin-block-end: 0; +} + +summary { + color: LinkText; + font-family: var(--f-heading); + font-weight: bold; + cursor: pointer; +} + +summary:hover { + text-decoration: underline; +} + +details[open] summary { + margin-block-end: 2rem; +} + + +/* Aside +======================================== +*/ + +aside { + color: var(--c-gray); +} + +@media (min-width: 769px) { + aside { + font-size: var(--f-size-small); + float: right; + width: calc(var(--w-body) / 2.5); + padding-block-end: 2rem; + padding-inline-start: 4rem; + } + + aside > *:first-child { + margin-block-start: 0; + } + + aside > *:last-child { + margin-block-end: 0; + } +} + + +/* Table +======================================== +*/ + +table { + width: 100%; + margin: 1em 0; + border-collapse: collapse; + border-spacing: 0; + break-inside: avoid; +} + +@media screen and (max-width: 768px) { + table { + display: block; + overflow-x: auto; + overflow-y: hidden; + } +} + +thead { + border-bottom: 2px solid var(--c-gray); +} + +tbody tr:nth-child(odd) { + background-color: ButtonFace; +} + +tfoot { + border-top: 2px solid var(--c-gray); +} + +:where(th, td) { + padding: 0.5rem 1rem; +} + +@media (max-width: 768px) { + :where(th, td) { + min-width: 10rem; + } +} + +th { + font-family: var(--f-heading); + text-align: left; + vertical-align: bottom; +} + +[dir='rtl' i] th { + text-align: right; +} + + +/* Forms & Inputs +======================================== +*/ + +/* Reset */ + +:where(input, textarea, select, button, progress) { + -webkit-appearance: none; + background-color: transparent; + break-inside: avoid; +} + +:where(input, textarea, select, button) { + font-family: var(--f-form); + font-size: 1em; + border-radius: 0.5rem; +} + +:where(input:not([type='button' i]):not([type='submit' i]):not([type='reset' i]):not([type='checkbox' i]):not([type='radio' i]):not([type='image' i]), textarea, select) { + color: CanvasText; + font-size: var(--f-size-small); + display: block; + width: 100%; + padding: 0.75rem 1rem; + border: 2px solid LinkText; +} + +/* Placeholder */ + +::placeholder { + color: var(--c-gray); +} + +/* Fieldset */ + +fieldset { + padding: 2rem; + border: 2px solid LinkText; + border-radius: 0.5rem; + break-inside: avoid; +} + +/* Label & Legend */ + +:where(legend, label) { + font-family: var(--f-form); + font-weight: bold; + display: block; +} + +legend { + padding: 0 1rem; +} + +:where(legend, label) small { + color: var(--c-gray); + font-weight: normal; +} + +/* Textarea */ + +textarea { + resize: vertical; +} + +/* Checkbox & Radio input */ + +label:has([type='checkbox' i], [type='radio' i]) { + font-family: var(--f-form); + font-size: var(--f-size-small); + font-weight: normal; + display: grid; + grid-template-columns: 1.25em 1fr; + column-gap: 0.5em; + padding-block-end: 0; +} + +label:has([type='checkbox' i][disabled], [type='radio' i][disabled]) { + color: var(--c-gray); +} + +:where([type='checkbox' i], [type='radio' i]) { + width: 1.25em; + height: 1.25em; + position: relative; + margin: 0.2rem 0 0; + border: 2px solid LinkText; + cursor: pointer; +} + +[type='radio' i] { + border-radius: 50%; +} + +:where([type='checkbox' i], [type='radio' i]):checked { + background-color: LinkText; +} + +[type='checkbox' i]:checked::after { + content: '\2713'; + color: Canvas; + font-family: var(--f-form); + font-weight: bold; + line-height: 1; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +/* Color input */ + +[type='color' i] { + height: 4rem; + padding: 0.5rem; + cursor: pointer; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::-webkit-color-swatch { + border: 0; +} + +::-moz-color-swatch { + border: 0; +} + +/* Range input */ + +[type='range' i] { + margin: 1.25rem 0 0; + padding: 0; + border: 0; +} + +[type='range' i]:focus { + outline: none; +} + +::-webkit-slider-runnable-track { + background-color: LinkText; + height: 4px; + border-radius: 0.5rem; +} + +[disabled]::-webkit-slider-runnable-track { + background-color: var(--c-gray); +} + +::-moz-range-track { + background-color: LinkText; + height: 4px; + border-radius: 0.5rem; +} + +[disabled]::-moz-range-track { + background-color: var(--c-gray); +} + +::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + background-color: Canvas; + height: 2rem; + width: 2rem; + margin-block-start: calc(-1rem + 2px); + border: 2px solid LinkText; + border-radius: 50%; + cursor: ew-resize; +} + +[disabled]::-webkit-slider-thumb { + border-color: var(--c-gray); +} + +[type='range' i]:focus::-webkit-slider-thumb { + outline: 2px solid LinkText; + outline-offset: 0.25rem; +} + +::-moz-range-thumb { + appearance: none; + background-color: Canvas; + height: 2rem; + width: 2rem; + margin-block-start: calc(-1rem + 2px); + border: 2px solid LinkText; + border-radius: 50%; + cursor: ew-resize; +} + +[disabled]::-moz-range-thumb { + border-color: var(--c-gray); +} + +[type='range' i]:focus::-moz-range-thumb { + outline: 2px solid LinkText; + outline-offset: 0.25rem; +} + +/* Select */ + +select { + background: Canvas var(--i-triangle) no-repeat calc(100% - 1rem) center / 1.5rem; + text-overflow: ellipsis; + white-space: nowrap; + padding-inline-end: 3.5rem; + overflow: hidden; + cursor: pointer; +} + +[dir='rtl' i] select { + background-position: 1rem center; + padding-inline: 3.5rem 1rem; +} + +select[multiple] { + background-image: none; + padding-inline-end: 1rem; +} + +/* Buttons */ + +:where(button, [type='button' i], [type='submit' i], [type='reset' i]) { + font-size: var(--f-size-small); + font-weight: bold; + text-align: center; + text-decoration: none; + line-height: 1; + display: inline-block; + min-width: 5rem; + padding: 0.2em 0.4em; + border: 2px solid LinkText; + -webkit-user-select: text; + user-select: text; + cursor: pointer; + touch-action: manipulation; +} + +:where(button:not([disabled]), [type='button' i]:not([disabled]), [type='submit' i]:not([disabled]), [type='reset' i]:not([disabled])):hover { + text-decoration: underline; +} + +@media screen { + :where(button, [type='button' i], [type='submit' i], [type='reset' i]) { + background-color: LinkText; + color: Canvas; + } + + :where(button[disabled], [type='button' i][disabled], [type='submit' i][disabled], [type='reset' i][disabled]) { + background-color: var(--c-gray); + color: currentColor; + } +} + +form :where(button, [type='button' i], [type='submit' i], [type='reset' i]) { + padding: 1rem 1.5rem; +} + +/* Meter & Progress */ + +:where(meter, progress) { + width: 100%; + height: 3rem; + border: 2px solid var(--c-gray); +} + +label + :where(meter, progress) { + margin-block-start: 0.5rem; +} + +meter { + background: transparent; + display: block; + margin-block-end: 1em; + border: 2px solid var(--c-gray); +} + +::-webkit-meter-bar { + background: Canvas; + height: 3rem; + border: 2px solid var(--c-gray); + border-radius: 0; +} + +::-webkit-progress-bar { + background-color: Canvas; +} + +::-moz-progress-bar { + background-color: var(--c-gray); +} + +::-webkit-progress-value { + background-color: var(--c-gray); +} + +/* Disabled state */ + +[disabled] { + border-color: var(--c-gray); + cursor: not-allowed; +} + +/* Error state */ + +[aria-invalid] { + border-color: var(--c-red) !important; +} + +[aria-invalid]:focus { + outline-color: var(--c-red); +} + +[aria-invalid] + p[id] { + color: var(--c-red); +} + +/* Form spacing */ + +form label:not(:first-of-type) { + margin-block-start: 3rem; +} + +form label + :where(input, textarea, select) { + margin-block-start: 0.5rem; +} + +form fieldset { + margin: 3rem 0; +} + +fieldset label:not(:first-of-type) { + margin-block-start: 2rem; +} + +form p[id] { + margin-block-start: 0.5rem; +} + + +/* Dialog +======================================== +*/ + +dialog[open] { + background-color: Canvas; + color: currentColor; + display: block; + max-width: var(--w-body, 100%); + min-width: calc(var(--w-body) / 2); + padding: 2rem; + border: 2px solid var(--c-gray); + border-radius: 0.5rem; +} + +body:has(dialog[open]) { + overflow: hidden; +} + +dialog:not([open]) { + display: none; +} + +dialog > *:first-child { + margin-block-start: 0; +} + +dialog > *:last-child { + margin-block-end: 0; +} + + +/* Opinionated layout +======================================== +*/ + +@media screen { + body > header { + margin-block-end: 4em; + } + + main > :where(section, article), + body > footer { + margin-block-start: 4em; + clear: both; + } + + body > footer { + margin-block-start: 4em; + } +} diff --git a/templates/base.html.twig b/templates/base.html.twig index 9bac562..458d961 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -2,16 +2,21 @@
+ + +