CluPilotCloud/resources/css/app.css

127 lines
3.8 KiB
CSS

/* Self-hosted fonts (R14) — @fontsource ships the .woff2 locally; Vite bundles
them and serves them from our own origin. No Google Fonts / CDN request. */
@import '@fontsource/ibm-plex-sans/400.css';
@import '@fontsource/ibm-plex-sans/500.css';
@import '@fontsource/ibm-plex-sans/600.css';
@import '@fontsource/ibm-plex-sans/700.css';
@import '@fontsource/ibm-plex-mono/400.css';
@import '@fontsource/ibm-plex-mono/500.css';
@import '@fontsource/ibm-plex-mono/600.css';
/* Serif is the display voice — headlines only, matching the marketing site. */
@import '@fontsource/ibm-plex-serif/400.css';
@import '@fontsource/ibm-plex-serif/600.css';
/* Design tokens, then Tailwind v3 layers. */
@import './portal-tokens.css';
@import './admin-tokens.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
/* Stops iOS inflating body text when the phone is turned to landscape. */
-webkit-text-size-adjust: 100%;
}
body {
background: var(--bg);
color: var(--text);
font-size: var(--text-base);
line-height: var(--lh-normal);
}
/* Uniform, visible focus for every interactive element (a11y §6.4/§9). */
:focus-visible {
outline: none;
box-shadow: var(--focus-ring);
border-color: var(--accent);
}
/* Data/IDs/IPs use tabular figures. */
.font-mono {
font-variant-numeric: tabular-nums;
}
/* Alpine: hide elements until initialised. */
[x-cloak] {
display: none !important;
}
}
@layer components {
/* Registration marks — the corner crosses on a printed form. A pseudo
element rather than markup: they are decoration, and a screen reader
announcing "plus, plus" on every panel would be noise. Tailwind cannot
express ::before content, so this is the one place it lives in CSS. */
.doc-marks {
position: relative;
}
.doc-marks::before,
.doc-marks::after {
content: "+";
position: absolute;
font-family: var(--font-mono);
font-size: 0.78rem;
line-height: 1;
color: var(--border-strong);
pointer-events: none;
}
.doc-marks::before {
top: -6px;
left: -6px;
}
.doc-marks::after {
bottom: -6px;
right: -6px;
}
/* The rule that precedes an eyebrow label, in the accent. Same reasoning:
decorative, and it has to sit on the text baseline of a flex row. */
.doc-eyebrow::before {
content: "";
display: block;
width: 22px;
height: 1px;
background: var(--accent);
flex: none;
}
}
/* iOS zooms the whole page when a field smaller than 16px takes focus, and
* then leaves the page zoomed — every tap into a form throws the layout about.
*
* There is no way to decline it: the meta-viewport switch that used to suppress
* it also kills pinch-zoom, which takes a genuine accessibility feature away
* from everyone to fix a cosmetic problem for some. Making the fields 16px on
* touch devices removes the reason instead.
*
* !important, and deliberately: this has to beat every text-size utility on
* every field in the application, and a rule that loses to `text-sm` on one
* form is worth nothing. Checkboxes and radios are excluded — they have no text
* to inflate and sizing them here would break their box.
*/
@media (pointer: coarse) {
input:not([type='checkbox']):not([type='radio']),
select,
textarea {
font-size: 16px !important;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
}
}