*, *::before, *::after { box-sizing: border-box; } body { margin: 0; background: var(--bg-base); color: var(--text-secondary); font-family: var(--font-sans); font-size: var(--text-sm); line-height: 1.5; -webkit-font-smoothing: antialiased; } a { color: var(--accent); } /* ── antet ─────────────────────────────────────────────────────────── */ .header { position: sticky; top: 0; z-index: 50; display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3) var(--space-4); padding: var(--space-4) var(--space-6); background: var(--header-bg); backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); } .logo { display: flex; align-items: center; gap: var(--space-2); font-weight: 700; font-size: var(--text-lg); color: var(--text-primary); text-decoration: none; } .logo .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--text-muted); box-shadow: 0 0 0 4px var(--bg-surface); } .logo .dot.on { background: var(--success); } .logo .dot.off { background: var(--error); } .header .spacer { flex: 1; } .header .meta { color: var(--text-muted); font-size: var(--text-xs); } /* ── structura ─────────────────────────────────────────────────────── */ .wrap { max-width: 1100px; margin: 0 auto; padding: var(--space-6); display: grid; gap: var(--space-6); } .grid-2 { display: grid; gap: var(--space-6); grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); } /* Fara asta, un copil de grid se dimensioneaza dupa continutul lui (min-width:auto): liniile lungi din `pre.log` si tabelul de fire dilatau coloana la ~2600px si toata pagina derula orizontal pe telefon. Derularea trebuie sa ramana INAUNTRUL containerelor cu overflow, nu pe body. */ .wrap > *, .grid-2 > *, .card > * { min-width: 0; } .card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-5); } .card > h2 { margin: 0 0 var(--space-4); font-size: var(--text-base); font-weight: 600; color: var(--text-primary); display: flex; align-items: center; gap: var(--space-2); } .card > h2 .count { font-weight: 400; font-size: var(--text-xs); color: var(--text-muted); } /* ── metrici ───────────────────────────────────────────────────────── */ .metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--space-3); } .metric { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3) var(--space-4); } .metric .label { font-size: var(--text-xs); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; } .metric .value { font-size: var(--text-xl); font-weight: 600; color: var(--text-primary); font-variant-numeric: tabular-nums; } /* ── pastile de stare ──────────────────────────────────────────────── */ .pill { display: inline-flex; align-items: center; gap: var(--space-2); padding: 2px var(--space-3); border-radius: 999px; font-size: var(--text-xs); font-weight: 600; background: var(--bg-surface); border: 1px solid var(--border); color: var(--text-secondary); } .pill.ok { color: var(--success); border-color: rgba(34, 197, 94, 0.5); } .pill.bad { color: var(--error); border-color: rgba(239, 68, 68, 0.5); } .pill.warn { color: var(--warning); border-color: rgba(234, 179, 8, 0.5); } .pill.busy { color: var(--accent); border-color: var(--border-focus); } /* ── butoane ───────────────────────────────────────────────────────── */ .actions { display: flex; flex-wrap: wrap; gap: var(--space-2); } button { font: inherit; font-weight: 600; color: var(--text-primary); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-2) var(--space-4); cursor: pointer; transition: background 0.12s ease, border-color 0.12s ease; } button:hover:not(:disabled) { background: var(--bg-surface-hover); border-color: var(--border-focus); } button:active:not(:disabled) { background: var(--bg-surface-active); } button:disabled { opacity: 0.45; cursor: not-allowed; } button.primary { background: var(--accent); border-color: var(--accent); color: #fff; } button.primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); } button.danger { color: var(--error); border-color: rgba(239, 68, 68, 0.5); } button.small { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); } /* ── tabele ────────────────────────────────────────────────────────── */ .table-scroll { overflow-x: auto; } table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); } th { text-align: left; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); font-weight: 600; padding: 0 var(--space-3) var(--space-2); white-space: nowrap; } td { padding: var(--space-3); border-top: 1px solid var(--border); vertical-align: middle; } td.mono, .mono { font-family: var(--font-mono); font-size: var(--text-xs); } td.num { font-variant-numeric: tabular-nums; text-align: right; } .empty { color: var(--text-muted); font-style: italic; padding: var(--space-4) 0; } /* ── verificari ────────────────────────────────────────────────────── */ .check { display: flex; align-items: baseline; gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--border); } .check:first-child { border-top: 0; } .check .name { font-weight: 500; color: var(--text-primary); min-width: 200px; } .check .detail { color: var(--text-muted); font-size: var(--text-xs); } .check .mark { font-weight: 700; } .check-actions { display: flex; gap: var(--space-2); flex: none; } .check.pass .mark { color: var(--success); } .check.fail .mark { color: var(--error); } /* ── jurnal ────────────────────────────────────────────────────────── */ pre.log { margin: 0; max-height: 420px; overflow: auto; background: rgba(0, 0, 0, 0.25); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-4); font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1.6; white-space: pre; color: var(--text-secondary); } :root[data-theme="light"] pre.log { background: rgba(0, 0, 0, 0.04); } /* ── notificari ────────────────────────────────────────────────────── */ #toast { position: fixed; right: var(--space-6); bottom: var(--space-6); z-index: 100; display: grid; gap: var(--space-2); max-width: 380px; } .toast { background: var(--bg-elevated); color: var(--text-primary); border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: var(--radius); padding: var(--space-3) var(--space-4); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); font-size: var(--text-sm); } .toast.ok { border-left-color: var(--success); } .toast.bad { border-left-color: var(--error); } /* ── autentificare ─────────────────────────────────────────────────── */ .login { min-height: 100vh; display: grid; place-items: center; padding: var(--space-6); } .login form { width: min(380px, 100%); display: grid; gap: var(--space-4); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-8); } .login h1 { margin: 0; font-size: var(--text-xl); color: var(--text-primary); } .login p { margin: 0; color: var(--text-muted); font-size: var(--text-xs); } input[type="password"] { font: inherit; font-family: var(--font-mono); width: 100%; padding: var(--space-3); color: var(--text-primary); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); } input[type="password"]:focus { outline: none; border-color: var(--border-focus); } .error-msg { color: var(--error); font-size: var(--text-xs); min-height: 1em; } /* ── telefon ─────────────────────────────────────────────────────── Praguri: 640px = telefon in portret; 380px = ecranele mici (SE). Regula de aur pe mobil: nimic nu iese din viewport pe orizontala — tabelul si jurnalul deruleaza in propriul container. */ @media (max-width: 640px) { body { font-size: var(--text-base); } /* 16px: iOS nu mai da zoom pe input */ .header { padding: var(--space-3) var(--space-4); gap: var(--space-2); } .logo { font-size: var(--text-base); } .header .meta { order: 3; width: 100%; } /* ora, pe randul ei */ .wrap { padding: var(--space-4); gap: var(--space-4); } .card { padding: var(--space-4); border-radius: var(--radius); } .metrics { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); } .metric { padding: var(--space-2) var(--space-3); } .metric .value { font-size: var(--text-lg); } /* Butoanele: tinta de atins de minim 44px si doua pe rand, nu sase inghesuite. */ .actions { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-2); } .actions .spacer { display: none; } .actions button { min-height: 44px; padding: var(--space-2) var(--space-3); font-size: var(--text-sm); } .actions button.small { font-size: var(--text-sm); } .header button { min-height: 36px; } /* Diagnostic si confirmari: eticheta peste detaliu, nu una langa alta. */ .check { display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-2); row-gap: var(--space-1); padding: var(--space-3) 0; } .check .name { min-width: 0; grid-column: 2; } .check .detail { grid-column: 2; overflow-wrap: anywhere; } .check .mark { grid-row: 1; grid-column: 1; } .check > div[style] { grid-column: 1 / -1; } /* corpul unei confirmari */ .check-actions { grid-column: 1 / -1; margin-top: var(--space-2); } .check-actions button { flex: 1; min-height: 44px; } th, td { padding: var(--space-2); } .mono { font-size: 0.75rem; } /* Un tabel de 5 coloane pe un ecran de 390px inseamna derulare orizontala la fiecare rand. Pe telefon randul devine card: capul de tabel dispare, iar eticheta fiecarei celule vine din `data-label`. */ table.stack-mobil, table.stack-mobil tbody, table.stack-mobil tr, table.stack-mobil td { display: block; width: 100%; } table.stack-mobil thead { display: none; } table.stack-mobil tr { border-top: 1px solid var(--border); padding: var(--space-3) 0; } table.stack-mobil tr:first-child { border-top: 0; } table.stack-mobil td { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); border: 0; padding: var(--space-1) 0; text-align: left; } table.stack-mobil td::before { content: attr(data-label); flex: none; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); } table.stack-mobil td.mono { overflow-wrap: anywhere; text-align: right; } table.stack-mobil td.empty::before { content: none; } pre.log { max-height: 320px; padding: var(--space-3); } #toast { left: var(--space-4); right: var(--space-4); bottom: var(--space-4); max-width: none; } .login form { padding: var(--space-5); } .login button, input[type="password"] { min-height: 44px; } } @media (max-width: 380px) { .actions { grid-template-columns: 1fr; } .metrics { grid-template-columns: 1fr 1fr; } }