Files
Lorenzo SanesiandClaude Opus 5.5 b83ce039fb
Deploy stack su Proxmox / deploy (push) Failing after 3s
Piattaforma ITI TECHNOLOGY: monorepo, Medusa, API, sito, area riservata e deploy
Monorepo npm con apps/public (Angular SSR), apps/private (Angular SPA),
apps/api (Fastify), packages/shared e packages/styles; Medusa 2.21 in medusa/;
infrastruttura Docker (Postgres PostGIS+pgvector, Redis, Caddy, backup) e
workflow Gitea Actions per il deploy via SSH a ogni push su master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018jQyT6dR9czzGwqb7FkG6u
2026-10-20 09:30:48 +02:00

301 lines
5.7 KiB
SCSS

// 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: <app-form-field> (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);
}
}