// Base globale condivisa da apps/public e apps/private: custom properties dai token, reset essenziale, // tipografia, utility di layout, pulsanti e form. Ogni app la include dal proprio styles.scss con `@use 'base';`. @use 'sass:map'; @use 'tokens'; @use 'mixins' as mq; :root { @each $name, $value in tokens.$colors { --color-#{$name}: #{$value}; } @each $name, $value in tokens.$font-sizes { --font-size-#{$name}: #{$value}; } @each $name, $value in tokens.$line-heights { --line-height-#{$name}: #{$value}; } @each $name, $value in tokens.$font-weights { --font-weight-#{$name}: #{$value}; } @each $name, $value in tokens.$spaces { --space-#{$name}: #{$value}; } @each $name, $value in tokens.$radii { --radius-#{$name}: #{$value}; } @each $name, $value in tokens.$shadows { --shadow-#{$name}: #{$value}; } --font-sans: #{tokens.$font-sans}; --font-mono: #{tokens.$font-mono}; --container-max: #{tokens.$container-max}; --header-height: #{tokens.$header-height}; --gutter: var(--space-4); color-scheme: light; @include mq.up(md) { --gutter: var(--space-5); } } // --- Reset essenziale --- *, *::before, *::after { box-sizing: border-box; } html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--header-height) + var(--space-4)); } @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } } body { margin: 0; min-height: 100vh; font-family: var(--font-sans); font-size: var(--font-size-md); line-height: var(--line-height-normal); color: var(--color-ink); background: var(--color-surface); -webkit-font-smoothing: antialiased; } img, svg, video { display: block; max-width: 100%; height: auto; } input, button, textarea, select { font: inherit; } // --- Tipografia --- h1, h2, h3, h4 { margin: 0 0 var(--space-4); line-height: var(--line-height-tight); font-weight: var(--font-weight-bold); color: var(--color-ink); text-wrap: balance; } h1 { font-size: var(--font-size-4xl); } h2 { font-size: var(--font-size-3xl); } h3 { font-size: var(--font-size-2xl); } h4 { font-size: var(--font-size-xl); } p { margin: 0 0 var(--space-4); } a { color: var(--color-primary); text-underline-offset: 0.15em; &:hover { color: var(--color-primary-strong); } @include mq.focus-ring; } button { @include mq.focus-ring; } // --- Utility --- .container { width: 100%; max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); } .visually-hidden { @include mq.visually-hidden; } .lead { font-size: var(--font-size-lg); color: var(--color-ink-muted); max-width: 65ch; } .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); min-height: 44px; padding: var(--space-2) var(--space-5); border: 2px solid transparent; border-radius: var(--radius-pill); font-weight: var(--font-weight-semibold); text-decoration: none; cursor: pointer; transition: background-color 0.15s ease, color 0.15s ease; &--primary { background: var(--color-primary); color: var(--color-on-primary); &:hover { background: var(--color-primary-strong); color: var(--color-on-primary); } } &--accent { background: var(--color-accent); color: var(--color-on-accent); &:hover { background: #{map.get(tokens.$colors, 'accent')}; color: var(--color-on-accent); filter: brightness(0.95); } } &--outline { border-color: currentColor; background: transparent; color: var(--color-primary); } } // --- Form --- // Campi: (shared/form-field.ts) ha già la classe .form-field. .form-grid { display: grid; gap: var(--space-4); @include mq.up(md) { grid-template-columns: 1fr 1fr; > .span-2 { grid-column: 1 / -1; } } } .form-field { display: flex; flex-direction: column; gap: var(--space-1); label { font-weight: var(--font-weight-semibold); } .optional { font-weight: var(--font-weight-regular); color: var(--color-ink-muted); } .hint { margin: 0; font-size: var(--font-size-sm); color: var(--color-ink-muted); } input, select, textarea { min-height: 44px; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-ink-muted); border-radius: var(--radius-md); background: var(--color-surface); color: var(--color-ink); font: inherit; &[aria-invalid='true'] { border-color: var(--color-danger); box-shadow: 0 0 0 1px var(--color-danger); } } .error { margin: 0; font-size: var(--font-size-sm); color: var(--color-danger); } } .field-error { margin: 0; font-size: var(--font-size-sm); color: var(--color-danger); } fieldset { // min-width: 0 → il contenuto largo (es. fila di giorni scorrevole) non allarga il fieldset (default min-content) min-width: 0; margin: 0 0 var(--space-5); padding: 0; border: 0; legend { margin-bottom: var(--space-3); padding: 0; font-size: var(--font-size-lg); font-weight: var(--font-weight-bold); } } // Casella o radio con etichetta, area cliccabile ≥ 44 px .check { display: flex; align-items: flex-start; gap: var(--space-3); min-height: 44px; padding-block: var(--space-2); cursor: pointer; input { flex: none; width: 1.25rem; height: 1.25rem; margin: 0.15rem 0 0; accent-color: var(--color-primary); } } .alert { margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4); border-left: 4px solid currentColor; border-radius: var(--radius-md); background: var(--color-surface-alt); &--error { color: var(--color-danger); } &--success { color: var(--color-success); } }