Files
romfast-website/efactura-generator/styles/main.css
Claude Agent 3a5076d7cd sync efactura-generator -> 0.9-beta-15
- Header reorganizat cu meniu Acțiuni (overflow dropdown)
- Buton nou PDF ANAF (transformare oficială XML->PDF prin API ANAF)
- Fix endpoint ANAF: validează default + ruta publică fără auth
2026-05-05 13:58:30 +00:00

1853 lines
42 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ============================================================================
Editor eFactura — sistem de design DESIGN.md
Industrial / utilitarian, Geist + Geist Mono, paletă warm-paper + slate-900.
============================================================================ */
:root {
/* Color tokens */
--bg: #fafaf9;
--surface: #ffffff;
--surface-muted: #f5f5f4;
--border: #e7e5e4;
--border-strong: #d6d3d1;
--text: #1c1917;
--text-muted: #57534e;
--text-faint: #a8a29e;
--header-bg: #0f172a;
--header-text: #f8fafc;
--header-sub: #94a3b8;
--primary: #1e40af;
--primary-hover: #1e3a8a;
--primary-soft: #dbeafe;
--success: #15803d;
--success-soft: #dcfce7;
--warning: #d97706;
--warning-soft: #fef3c7;
--danger: #b91c1c;
--danger-soft: #fee2e2;
/* Spacing scale */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
--space-12: 48px;
--space-16: 64px;
/* Border radius hierarchy */
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 8px;
/* Box shadow */
--shadow-card: 0 1px 2px rgba(0, 0, 0, 0.03);
--shadow-modal: 0 8px 24px rgba(0, 0, 0, 0.08);
/* Motion */
--duration-micro: 100ms;
--duration-short: 150ms;
--duration-medium: 250ms;
--easing-out: cubic-bezier(0.16, 1, 0.3, 1);
}
/* ----------------------------------------------------------------------------
Reset + base
---------------------------------------------------------------------------- */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
color-scheme: light;
}
body {
font-family: 'Geist', system-ui, -apple-system, sans-serif;
font-size: 14px;
font-weight: 400;
line-height: 1.5;
color: var(--text);
background-color: var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Tabular numerics + monospace — aplicat pe orice valoare numerică editabilă
(Price, Quantity, Amount, Total, CIF, IBAN, dates). */
.mono,
.num,
input.num,
input.mono {
font-family: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
font-variant-numeric: tabular-nums;
font-weight: 500;
}
input.num,
input.mono {
text-align: right;
}
/* Date inputs — mono dar text aliniat stânga (sunt formă dd.mm.yyyy, nu valoare). */
.date-input.num,
.date-input.mono,
input.date-input {
text-align: left;
}
/* ----------------------------------------------------------------------------
Layout
---------------------------------------------------------------------------- */
.container {
max-width: 1200px;
margin: 0 auto;
padding: var(--space-4);
}
/* ----------------------------------------------------------------------------
Header (slate-900)
---------------------------------------------------------------------------- */
.header {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-4);
margin-bottom: var(--space-4);
padding: 14px var(--space-6);
background-color: var(--header-bg);
color: var(--header-text);
border-radius: var(--radius-md);
box-shadow: var(--shadow-card);
}
.header h1 {
font-family: 'Geist', system-ui, sans-serif;
font-size: 22px;
font-weight: 600;
letter-spacing: -0.02em;
color: var(--header-text);
line-height: 1.2;
}
.app-author {
font-size: 11px;
font-weight: 500;
color: var(--header-sub);
letter-spacing: 0.04em;
margin-top: 2px;
}
.button-group {
display: flex;
gap: var(--space-2);
align-items: center;
flex-wrap: wrap;
}
/* ----------------------------------------------------------------------------
Actions overflow menu (header dropdown)
---------------------------------------------------------------------------- */
.actions-menu-wrapper {
position: relative;
display: inline-flex;
}
.actions-menu-chevron {
margin-left: 4px;
font-size: 10px;
line-height: 1;
transition: transform 120ms ease;
display: inline-block;
}
#btnActionsMenu[aria-expanded="true"] .actions-menu-chevron {
transform: rotate(180deg);
}
.actions-menu {
position: absolute;
top: calc(100% + 6px);
right: 0;
min-width: 220px;
background-color: #1e293b; /* slate-800 — slightly lighter than header-bg slate-900 */
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: var(--radius-sm);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.32);
padding: 4px 0;
z-index: 950;
display: flex;
flex-direction: column;
gap: 0;
animation: actions-menu-in 120ms ease-out;
}
.actions-menu[hidden] {
display: none;
}
@keyframes actions-menu-in {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.actions-menu-item {
appearance: none;
background: transparent;
border: none;
color: #f1f5f9;
text-align: left;
padding: 8px 14px;
font-family: inherit;
font-size: 13px;
line-height: 1.3;
cursor: pointer;
width: 100%;
transition: background-color 80ms ease, color 80ms ease;
}
.actions-menu-item:hover,
.actions-menu-item:focus-visible {
background-color: rgba(255, 255, 255, 0.06);
outline: none;
}
.actions-menu-item:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.actions-menu-item.is-success {
color: #86efac; /* green ghost — ANAF actions */
}
.actions-menu-item.is-success:hover,
.actions-menu-item.is-success:focus-visible {
background-color: rgba(134, 239, 172, 0.10);
}
.actions-menu-divider {
height: 1px;
background-color: rgba(255, 255, 255, 0.10);
margin: 4px 0;
}
.actions-menu-anaf {
display: flex;
flex-direction: column;
}
.actions-menu-anaf[hidden] {
display: none;
}
@media (max-width: 768px) {
.actions-menu-wrapper {
position: static;
}
.actions-menu {
left: var(--space-3);
right: var(--space-3);
top: auto;
margin-top: 6px;
}
}
/* ----------------------------------------------------------------------------
Cards / form sections
---------------------------------------------------------------------------- */
.form-section,
.allowance-charges,
.line-items,
.totals {
background-color: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 18px var(--space-5);
margin-bottom: var(--space-4);
box-shadow: var(--shadow-card);
}
.totals {
padding: var(--space-5) var(--space-5);
}
.section-title {
font-family: 'Geist', system-ui, sans-serif;
font-size: 14px;
font-weight: 600;
letter-spacing: -0.005em;
color: var(--text);
margin-bottom: var(--space-3);
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-2);
}
/* ----------------------------------------------------------------------------
Form fields
---------------------------------------------------------------------------- */
.form-group {
margin-bottom: var(--space-2);
}
.form-label {
display: block;
margin-bottom: 4px;
font-family: 'Geist', system-ui, sans-serif;
font-size: 12px;
font-weight: 500;
color: var(--text-muted);
}
.form-input,
input.form-input,
select.form-input,
textarea.form-input {
width: 100%;
padding: 7px 10px;
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
font-family: inherit;
font-size: 14px;
color: var(--text);
background-color: var(--surface);
transition: border-color var(--duration-short) var(--easing-out),
box-shadow var(--duration-short) var(--easing-out);
}
textarea.form-input {
line-height: 1.5;
}
.form-input::placeholder {
color: var(--text-faint);
}
.form-input:hover {
border-color: var(--text-muted);
}
.form-input:focus,
.form-input:focus-visible {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 2px rgba(30, 64, 175, 0.15);
}
.form-input.invalid,
input[aria-invalid="true"].form-input {
border-color: var(--danger);
background-color: var(--danger-soft);
}
.form-input.invalid:focus {
box-shadow: 0 0 0 2px rgba(185, 28, 28, 0.15);
}
.form-input:disabled {
background-color: var(--surface-muted);
color: var(--text-faint);
cursor: not-allowed;
}
/* Helper text / error message */
.form-helper {
display: block;
font-size: 11px;
color: var(--text-muted);
margin-top: 3px;
}
.form-helper.is-error {
color: var(--danger);
}
/* Numeric inputs — mono + right align. Aplicate prin clasa .num/.mono. */
.form-input.num,
.form-input.mono {
font-family: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
font-variant-numeric: tabular-nums;
font-weight: 500;
text-align: right;
}
.form-input.date-input.num,
.form-input.date-input.mono {
text-align: left;
}
/* ----------------------------------------------------------------------------
Grids
---------------------------------------------------------------------------- */
.details-grid {
display: grid;
grid-template-areas:
"invoice"
"supplier"
"customer";
gap: var(--space-4);
margin-bottom: var(--space-4);
}
@media (min-width: 720px) {
.details-grid {
grid-template-columns: repeat(2, 1fr);
grid-template-areas:
"invoice invoice"
"supplier customer";
}
}
.invoice-details {
grid-area: invoice;
}
.compact-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: var(--space-3);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: var(--space-3);
}
@media (max-width: 720px) {
.compact-grid,
.grid {
grid-template-columns: 1fr;
gap: var(--space-2);
}
}
/* ----------------------------------------------------------------------------
Buttons
---------------------------------------------------------------------------- */
.button,
button.button {
padding: 7px 14px;
border: 1px solid transparent;
border-radius: var(--radius-sm);
font-family: 'Geist', system-ui, sans-serif;
font-size: 13px;
font-weight: 500;
line-height: 1.2;
cursor: pointer;
background-color: var(--primary);
color: #ffffff;
min-width: fit-content;
transition: background-color var(--duration-micro) var(--easing-out),
border-color var(--duration-micro) var(--easing-out),
color var(--duration-micro) var(--easing-out);
}
.button:hover {
background-color: var(--primary-hover);
}
.button:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Secondary — header & inline secondary action */
.button.button-secondary {
background-color: var(--surface);
border: 1px solid var(--border-strong);
color: var(--text);
}
.button.button-secondary:hover {
background-color: var(--surface-muted);
border-color: var(--text-muted);
}
/* Header ghost variant — pe slate-900 background. */
.header .button.button-secondary {
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.18);
color: #f1f5f9;
}
.header .button.button-secondary:hover {
background-color: rgba(255, 255, 255, 0.06);
border-color: rgba(255, 255, 255, 0.32);
}
/* Danger — primary mode */
.button.button-danger {
background-color: transparent;
border: 1px solid var(--danger);
color: var(--danger);
}
.button.button-danger:hover {
background-color: var(--danger);
color: #ffffff;
}
/* Header danger ghost */
.header .button.button-danger {
border: 1px solid rgba(252, 165, 165, 0.35);
color: #fca5a5;
background-color: transparent;
}
.header .button.button-danger:hover {
background-color: rgba(252, 165, 165, 0.12);
border-color: rgba(252, 165, 165, 0.6);
color: #fecaca;
}
/* Header primary (Salvează XML) on slate */
.header .button:not(.button-secondary):not(.button-danger) {
background-color: var(--primary);
color: #ffffff;
border: 1px solid var(--primary);
}
.header .button:not(.button-secondary):not(.button-danger):hover {
background-color: var(--primary-hover);
border-color: var(--primary-hover);
}
/* Small size */
.button.button-small {
padding: 5px 10px;
font-size: 12px;
}
/* Success — validare ANAF ok (green ghost pe header, filled pe form) */
.button.button-success {
background-color: transparent;
border: 1px solid var(--success);
color: var(--success);
}
.button.button-success:hover {
background-color: var(--success-soft);
}
/* Header success ghost — pe slate-900 (DESIGN.md: btn-success-ghost) */
.header .button.button-success {
background-color: transparent;
border: 1px solid rgba(134, 239, 172, 0.35);
color: #86efac;
}
.header .button.button-success:hover {
background-color: rgba(134, 239, 172, 0.12);
border-color: rgba(134, 239, 172, 0.6);
color: #bbf7d0;
}
/* Input cu buton inline (CIF Caută, etc.) */
.input-with-action {
display: flex;
align-items: center;
gap: 6px;
}
.input-with-action .form-input {
flex: 1;
}
/* Add button — dashed border */
.button.button-add,
.button-add {
background-color: transparent;
border: 1px dashed var(--border-strong);
color: var(--text-muted);
padding: 7px 14px;
border-radius: var(--radius-sm);
cursor: pointer;
font-family: 'Geist', system-ui, sans-serif;
font-size: 13px;
font-weight: 500;
}
.button-add:hover {
border-color: var(--primary);
color: var(--primary);
}
.file-input {
display: none;
}
/* ----------------------------------------------------------------------------
Line items / allowance-charge cards
---------------------------------------------------------------------------- */
.line-item,
.allowance-charge {
background-color: var(--surface);
padding: var(--space-3) var(--space-8) var(--space-3) var(--space-3);
border: 1px solid var(--border);
border-radius: var(--radius-md);
margin-bottom: var(--space-2);
position: relative;
box-shadow: var(--shadow-card);
}
.line-item:hover,
.allowance-charge:hover {
border-color: var(--border-strong);
}
.vat-row,
.identification-row {
background-color: var(--surface);
padding: var(--space-2);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
margin-bottom: 6px;
position: relative;
}
.delete-line-item,
.delete-allowance-charge,
.delete-identification,
.remove-line-item {
position: absolute;
right: var(--space-2);
top: 50%;
transform: translateY(-50%);
width: 24px !important;
height: 24px !important;
padding: 0 !important;
font-size: 12px !important;
line-height: 1 !important;
min-width: 0 !important;
flex: 0 0 auto !important;
display: flex !important;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.optional-details {
margin-top: var(--space-3);
padding: var(--space-3);
background-color: var(--surface-muted);
border-radius: var(--radius-sm);
}
.optional-details-content {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.optional-details-toggle {
margin-top: var(--space-2);
}
.identifications-container {
width: 100%;
}
.identifications-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-2);
flex-wrap: wrap;
gap: var(--space-2);
}
.identifications-header h4 {
margin: 0;
font-family: 'Geist', system-ui, sans-serif;
font-size: 12px;
font-weight: 600;
color: var(--text);
}
.identification-buttons {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.identifications-list {
display: flex;
flex-direction: column;
margin-top: 0;
gap: 4px;
}
.identification-row {
margin: 0;
padding: var(--space-2);
}
.identification-content {
display: grid;
grid-template-columns: auto 1fr auto;
gap: var(--space-2);
align-items: center;
}
.identification-content .scheme-select {
width: 150px;
min-width: 150px;
}
.identification-content input[type="text"] {
flex: 1;
min-width: 0;
}
/* ----------------------------------------------------------------------------
Date input
---------------------------------------------------------------------------- */
.date-input-container {
display: flex;
gap: var(--space-2);
align-items: stretch;
}
.calendar-button {
padding: 0 10px;
background: var(--surface);
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
cursor: pointer;
font-size: 14px;
color: var(--text-muted);
transition: border-color var(--duration-short) var(--easing-out);
}
.calendar-button:hover {
border-color: var(--primary);
color: var(--primary);
}
.calendar-button:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* ----------------------------------------------------------------------------
Totals
---------------------------------------------------------------------------- */
.total-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-2) 0;
border-bottom: 1px solid var(--border);
font-size: 14px;
}
.total-row > span:first-child {
color: var(--text-muted);
font-weight: 500;
}
.total-row > span:last-child,
.editable-total {
font-family: 'Geist Mono', ui-monospace, monospace;
font-variant-numeric: tabular-nums;
font-weight: 500;
color: var(--text);
text-align: right;
}
.total-row:last-child {
border-bottom: none;
}
.total-row-final {
margin-top: var(--space-3);
padding-top: var(--space-3);
border-top: 2px solid var(--border-strong);
border-bottom: none;
}
.total-row-final > span:first-child {
font-family: 'Geist', system-ui, sans-serif;
font-size: 14px;
font-weight: 600;
color: var(--text);
}
.total-row-final > span:last-child {
font-family: 'Geist Mono', ui-monospace, monospace;
font-size: 18px;
font-weight: 700;
color: var(--text);
}
.editable-total {
cursor: pointer;
border-radius: var(--radius-sm);
padding: 2px 6px;
transition: background-color var(--duration-micro) var(--easing-out);
}
.editable-total:hover {
background-color: var(--surface-muted);
}
.editable-total:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* ----------------------------------------------------------------------------
VAT breakdown
---------------------------------------------------------------------------- */
#vatBreakdown {
margin-top: var(--space-4);
padding-top: var(--space-3);
border-top: 1px solid var(--border);
}
#vatBreakdown .section-title {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
font-weight: 500;
margin-bottom: var(--space-2);
}
.vat-row .total-row {
display: flex;
flex-direction: column;
gap: var(--space-2);
padding: var(--space-2);
position: relative;
border-bottom: none;
}
.vat-inputs {
display: flex;
flex-wrap: wrap;
gap: var(--space-2) var(--space-4);
width: 100%;
padding-right: var(--space-8);
align-items: center;
}
.vat-inputs > label {
min-width: 80px;
text-align: left;
margin: 0;
font-size: 12px;
font-weight: 500;
color: var(--text-muted);
}
.vat-inputs > input,
.vat-inputs > select {
min-width: 150px;
flex: 1;
margin: 0;
}
.vat-inputs > input.vat-rate,
.vat-inputs > input.vat-base,
.vat-inputs > input.vat-amount {
font-family: 'Geist Mono', ui-monospace, monospace;
font-variant-numeric: tabular-nums;
text-align: right;
}
.vat-exemption {
display: flex;
gap: var(--space-3);
width: 100%;
flex-wrap: wrap;
}
.vat-exemption .form-group {
flex: 1;
display: flex;
align-items: center;
gap: var(--space-2);
margin: 0;
min-width: 240px;
}
.vat-exemption label {
white-space: nowrap;
margin: 0;
min-width: 100px;
font-size: 12px;
font-weight: 500;
color: var(--text-muted);
}
.vat-exemption .form-input {
flex: 1;
}
.vat-total-group {
margin-top: var(--space-3);
padding-top: var(--space-3);
border-top: 1px solid var(--border);
}
/* ----------------------------------------------------------------------------
Note / textarea
---------------------------------------------------------------------------- */
.note-input {
resize: vertical;
min-height: 100px;
line-height: 1.5;
}
.note-counter {
text-align: right;
font-family: 'Geist Mono', ui-monospace, monospace;
font-size: 11px;
font-variant-numeric: tabular-nums;
color: var(--text-muted);
margin-top: 3px;
}
/* ----------------------------------------------------------------------------
Footer
---------------------------------------------------------------------------- */
.app-footer {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-3);
text-align: center;
margin-top: var(--space-8);
padding: var(--space-3) var(--space-4);
font-size: 11px;
color: var(--text-muted);
}
.app-footer #app-version {
font-family: 'Geist Mono', ui-monospace, monospace;
font-weight: 500;
color: var(--text-muted);
}
.app-footer a {
color: var(--text-muted);
text-decoration: none;
border-bottom: 1px dotted var(--border-strong);
padding-bottom: 1px;
transition: color var(--duration-short) var(--easing-out),
border-color var(--duration-short) var(--easing-out);
}
.app-footer a:hover {
color: var(--primary);
border-bottom-color: var(--primary);
}
.app-footer a:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* ----------------------------------------------------------------------------
Utility
---------------------------------------------------------------------------- */
.hidden {
display: none !important;
}
/* Eyebrow / section labels */
.eyebrow {
font-family: 'Geist', system-ui, sans-serif;
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
}
/* ----------------------------------------------------------------------------
Badges (validare matematică A11 — DESIGN.md spec)
---------------------------------------------------------------------------- */
.badge,
.badge-ok,
.badge-warn,
.badge-error {
display: inline-block;
padding: 1px 6px;
border-radius: 3px;
font-family: 'Geist Mono', ui-monospace, monospace;
font-size: 11px;
font-weight: 500;
line-height: 1.4;
font-variant-numeric: tabular-nums;
margin-left: var(--space-2);
}
.badge-ok {
background-color: var(--success-soft);
color: var(--success);
}
.badge-warn {
background-color: var(--warning-soft);
color: var(--warning);
}
.badge-error {
background-color: var(--danger-soft);
color: var(--danger);
}
/* Empty badge slot — invisible until populated. */
.badge:empty {
display: none;
}
/* Wrap pentru badge-ul de footer total (păstrează inline cu valoarea). */
.total-with-badge {
display: inline-flex;
align-items: baseline;
gap: var(--space-2);
}
.total-with-badge .badge {
margin-left: 0;
}
/* Linia "Total linie" la fiecare line-item (PR-A11 / D4). */
.line-total-row {
display: flex;
align-items: center;
justify-content: flex-end;
gap: var(--space-2);
margin-top: var(--space-3);
padding-top: var(--space-2);
border-top: 1px dashed var(--border);
font-size: 12px;
color: var(--text-muted);
}
.line-total-label {
font-family: 'Geist', system-ui, sans-serif;
font-weight: 500;
}
.line-total-value {
font-family: 'Geist Mono', ui-monospace, monospace;
font-variant-numeric: tabular-nums;
font-weight: 500;
color: var(--text);
min-width: 80px;
text-align: right;
}
.line-total-row .badge {
margin-left: 0;
}
/* Badge inline dupa input vat-amount (PR-A11 / D4). */
.vat-inputs .badge {
margin-left: 0;
}
/* ----------------------------------------------------------------------------
Card-actions (D6 — butoane acțiuni pe cardul unei secțiuni, ex. profil)
Variante:
- ca div standalone (sub compact-grid): cu border-top separator
- ca span inline în .section-title: fără border-top (moștenit via flex)
---------------------------------------------------------------------------- */
.card-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-2);
}
/* Standalone (nu în h2): adaugă separator top. */
div.card-actions {
margin-top: var(--space-3);
padding-top: var(--space-3);
border-top: 1px solid var(--border);
}
/* Inline pe section-title: fără border-top / padding-top / margin-top
(DESIGN.md D6 — card-actions pe partea dreaptă a card-head Furnizor). */
.section-title .card-actions {
margin-top: 0;
padding-top: 0;
border-top: 0;
}
/* ----------------------------------------------------------------------------
PaymentMeans row grid (A5)
---------------------------------------------------------------------------- */
.payment-means-grid {
display: grid;
grid-template-columns: minmax(200px, 1fr) minmax(240px, 2fr) auto;
align-items: end;
gap: var(--space-3);
padding: var(--space-3) 0;
border-bottom: 1px solid var(--border);
}
.payment-means-row:last-child .payment-means-grid {
border-bottom: none;
}
/* ----------------------------------------------------------------------------
Alerts (BR validation, system messages)
---------------------------------------------------------------------------- */
.alert {
border-left: 3px solid var(--text-muted);
background-color: var(--surface-muted);
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-sm);
font-size: 13px;
color: var(--text);
margin: var(--space-2) 0;
}
.alert-info {
border-left-color: var(--primary);
background-color: var(--primary-soft);
}
.alert-success {
border-left-color: var(--success);
background-color: var(--success-soft);
}
.alert-warn {
border-left-color: var(--warning);
background-color: var(--warning-soft);
}
.alert-error {
border-left-color: var(--danger);
background-color: var(--danger-soft);
}
.alert strong {
font-weight: 600;
}
.alert em {
font-style: normal;
color: var(--text-muted);
}
/* ----------------------------------------------------------------------------
Catalog produse — autocomplete dropdown (DESIGN.md D15, PR-A13)
Dropdown custom poziționat sub câmpul "Denumire" din linie factură.
---------------------------------------------------------------------------- */
.catalog-dropdown {
position: absolute;
background: var(--surface);
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-card);
z-index: 500;
min-width: 260px;
max-height: 240px;
overflow-y: auto;
}
.catalog-dropdown-item {
padding: 8px 12px;
cursor: pointer;
border-bottom: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 2px;
}
.catalog-dropdown-item:last-child {
border-bottom: none;
}
.catalog-dropdown-item:hover,
.catalog-dropdown-item.is-highlighted {
background: var(--surface-muted);
}
.catalog-item-name {
font-size: 13px;
font-weight: 500;
color: var(--text);
}
.catalog-item-meta {
font-size: 11px;
color: var(--text-muted);
font-family: 'Geist Mono', ui-monospace, monospace;
}
.catalog-item-empty {
padding: 10px 12px;
font-size: 12px;
color: var(--text-faint);
font-style: italic;
}
/* Wrapper pentru descriere cu dropdown → relative pentru ancorarea dropdown-ului */
.description-wrapper {
position: relative;
}
/* ----------------------------------------------------------------------------
Modal overlay (DESIGN.md D24 — Factură Nouă modal + orice modal viitor)
Fond semi-transparent + box centrată.
---------------------------------------------------------------------------- */
.modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(15, 23, 42, 0.45);
z-index: 950;
align-items: center;
justify-content: center;
}
.modal-overlay.is-open {
display: flex;
}
.modal-box {
background: var(--surface);
border-radius: var(--radius-lg);
padding: var(--space-6);
max-width: 480px;
width: 100%;
box-shadow: var(--shadow-modal);
animation: modal-in 150ms ease-out;
}
@keyframes modal-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: var(--text);
margin-bottom: var(--space-1);
letter-spacing: -0.005em;
}
.modal-sub {
font-size: 13px;
color: var(--text-muted);
margin-bottom: var(--space-4);
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: var(--space-2);
margin-top: var(--space-5);
}
.modal-preview {
background: var(--surface-muted);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: var(--space-3) var(--space-4);
font-family: 'Geist Mono', ui-monospace, monospace;
font-size: 16px;
font-weight: 600;
color: var(--text);
text-align: center;
letter-spacing: 0.02em;
margin-bottom: var(--space-2);
}
/* Year rollover banner (D24) — apare sub header dacă an ≠ an curent */
.year-rollover-banner {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--space-3);
background: var(--warning-soft);
border-left: 3px solid var(--warning);
padding: var(--space-3) var(--space-4);
font-size: 13px;
color: var(--text);
}
.year-rollover-banner p {
flex: 1;
min-width: 200px;
}
.year-rollover-banner .banner-actions {
display: flex;
gap: var(--space-2);
flex-shrink: 0;
}
/* ----------------------------------------------------------------------------
Toast component (DESIGN.md D14)
Container fixed bottom-right, stack vertical 8px gap.
---------------------------------------------------------------------------- */
.toast-container {
position: fixed;
bottom: var(--space-4);
right: var(--space-4);
display: flex;
flex-direction: column;
gap: var(--space-2);
z-index: 1000;
max-width: 360px;
pointer-events: none;
}
.toast {
background-color: var(--surface);
border: 1px solid var(--border);
border-left: 3px solid var(--text-muted);
border-radius: var(--radius-sm);
padding: var(--space-3) var(--space-4);
max-width: 360px;
box-shadow: var(--shadow-card);
font-size: 13px;
color: var(--text);
pointer-events: auto;
animation: toast-slide-in var(--duration-short) var(--easing-out);
display: flex;
align-items: flex-start;
gap: var(--space-2);
}
.toast-success { border-left-color: var(--success); }
.toast-info { border-left-color: var(--primary); }
.toast-warning { border-left-color: var(--warning); }
.toast-error { border-left-color: var(--danger); }
.toast-message {
flex: 1;
}
.toast-sub {
display: block;
font-size: 11px;
color: var(--text-muted);
margin-top: 2px;
}
.toast-dismiss {
background: none;
border: none;
cursor: pointer;
padding: 0 var(--space-1);
font-size: 14px;
color: var(--text-muted);
line-height: 1;
}
.toast-dismiss:hover {
color: var(--text);
}
@keyframes toast-slide-in {
from {
transform: translateX(16px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* ----------------------------------------------------------------------------
Drop-zone empty state (DESIGN.md D13)
---------------------------------------------------------------------------- */
.drop-zone {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-3);
padding: var(--space-16) var(--space-6);
border: 2px dashed var(--border-strong);
border-radius: var(--radius-md);
background-color: var(--surface);
color: var(--text-muted);
text-align: center;
transition: border-color var(--duration-short) var(--easing-out),
background-color var(--duration-short) var(--easing-out);
}
.drop-zone.is-active,
.drop-zone:hover {
border-color: var(--primary);
background-color: var(--primary-soft);
}
.drop-zone-title {
font-family: 'Geist', system-ui, sans-serif;
font-size: 14px;
font-weight: 500;
color: var(--text);
}
.drop-zone-sub {
font-size: 11px;
color: var(--text-muted);
}
/* ----------------------------------------------------------------------------
Spinner — Geist Mono braille cycle (DESIGN.md D8 / PR-CSS)
80ms cycle pe ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏.
---------------------------------------------------------------------------- */
.spinner-mono {
display: inline-block;
width: 1ch;
font-family: 'Geist Mono', ui-monospace, monospace;
font-variant-numeric: tabular-nums;
color: var(--text-muted);
}
.spinner-mono::before {
content: "⠋";
animation: spinner-mono-cycle 800ms steps(1, end) infinite;
}
@keyframes spinner-mono-cycle {
0% { content: "⠋"; }
10% { content: "⠙"; }
20% { content: "⠹"; }
30% { content: "⠸"; }
40% { content: "⠼"; }
50% { content: "⠴"; }
60% { content: "⠦"; }
70% { content: "⠧"; }
80% { content: "⠇"; }
90% { content: "⠏"; }
100% { content: "⠋"; }
}
/* ----------------------------------------------------------------------------
Responsive: ≤720px (DESIGN.md breakpoint)
---------------------------------------------------------------------------- */
@media (max-width: 1200px) {
.vat-inputs {
flex-wrap: wrap;
}
.vat-exemption {
flex-direction: column;
}
.vat-exemption .form-group {
width: 100%;
}
}
@media (max-width: 720px) {
.container {
padding: var(--space-3);
}
.header {
flex-direction: column;
gap: var(--space-3);
text-align: center;
align-items: stretch;
padding: var(--space-3) var(--space-4);
}
.header > div:first-child {
text-align: left;
}
.button-group {
flex-wrap: wrap;
justify-content: flex-start;
}
.vat-inputs {
gap: var(--space-2);
}
.vat-inputs > label {
min-width: 80px;
text-align: left;
}
.vat-inputs > input,
.vat-inputs > select {
width: calc(100% - 90px);
}
.vat-exemption {
flex-direction: column;
width: 100%;
}
.vat-exemption .form-group {
min-width: 0;
}
.identification-content {
grid-template-columns: 1fr auto;
}
.scheme-select {
grid-column: 1 / -1;
}
.app-footer {
flex-direction: column;
gap: var(--space-2);
}
.total-row-final > span:last-child {
font-size: 16px;
}
/* Touch targets minim 44×44 pe primary/danger CTA */
.button:not(.button-small):not(.button-add) {
min-height: 40px;
}
}
/* ----------------------------------------------------------------------------
BR Validation Panel (PR-BR / A2 / D5)
Sticky bottom-right floating container, collapsed by default.
---------------------------------------------------------------------------- */
.br-panel {
position: fixed;
bottom: 16px;
right: 16px;
width: 360px;
max-width: calc(100vw - 32px);
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
z-index: 900;
font-size: 13px;
color: var(--text);
overflow: hidden;
}
.br-panel--hidden {
display: none;
}
.br-panel__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
cursor: pointer;
user-select: none;
border-bottom: 1px solid var(--border);
background: var(--surface-muted);
gap: 8px;
}
.br-panel__header:hover {
background: var(--bg);
}
.br-panel__summary {
font-size: 13px;
font-weight: 500;
color: var(--text);
flex: 1;
}
.br-panel__summary--errors {
color: var(--danger);
}
.br-panel__summary--warnings {
color: var(--warning);
}
.br-panel__summary--ok {
color: var(--success);
}
.br-panel__toggle {
font-size: 11px;
color: var(--text-muted);
white-space: nowrap;
}
.br-panel__body {
max-height: 360px;
overflow-y: auto;
padding: 6px 0;
display: none;
}
.br-panel.is-expanded .br-panel__body {
display: block;
}
.br-panel__item {
display: flex;
gap: 8px;
align-items: flex-start;
padding: 8px 14px;
border-bottom: 1px solid var(--border);
cursor: pointer;
transition: background var(--duration-micro) var(--easing-out);
}
.br-panel__item:last-child {
border-bottom: none;
}
.br-panel__item:hover {
background: var(--surface-muted);
}
.br-panel__item-code {
font-family: 'Geist Mono', monospace;
font-size: 11px;
color: var(--text-muted);
white-space: nowrap;
min-width: 70px;
margin-top: 1px;
}
.br-panel__item-msg {
font-size: 12px;
color: var(--text);
line-height: 1.4;
flex: 1;
}
.br-panel__item--fatal .br-panel__item-code,
.br-panel__item--fatal .br-panel__item-msg {
color: var(--danger);
}
.br-panel__item--error .br-panel__item-code {
color: var(--danger);
}
.br-panel__item--warning .br-panel__item-code {
color: var(--warning);
}
.br-panel__empty {
padding: 12px 14px;
font-size: 13px;
color: var(--success);
}
/* Highlight câmp cu eroare BR — 2s flash */
@keyframes br-field-flash {
0% { background-color: var(--warning-soft); }
80% { background-color: var(--warning-soft); }
100% { background-color: transparent; }
}
.br-field-highlight {
animation: br-field-flash 2s ease-out forwards;
}
/* Mobile ≤720px: bottom-bar fix 44px (D20) */
@media (max-width: 720px) {
.br-panel {
bottom: 0;
right: 0;
left: 0;
width: 100%;
max-width: 100%;
border-radius: 0;
border-left: none;
border-right: none;
border-bottom: none;
}
.br-panel__header {
min-height: 44px;
border-top: 3px solid var(--warning);
background: var(--warning-soft);
}
.br-panel--errors .br-panel__header {
border-top-color: var(--danger);
background: var(--danger-soft);
}
.br-panel__body {
max-height: calc(100vh - 120px);
}
}
/* ----------------------------------------------------------------------------
Pikaday override (datepicker — keep functional, restyle to tokens)
---------------------------------------------------------------------------- */
.pika-single {
font-family: 'Geist', system-ui, sans-serif !important;
border: 1px solid var(--border-strong) !important;
border-radius: var(--radius-md) !important;
box-shadow: var(--shadow-modal) !important;
}
/* ----------------------------------------------------------------------------
PR-A14 — XML Sidebar (bulk mode, only when body.has-xml-sidebar)
D3 spec: 240px left rail, surface-muted bg, border-right.
---------------------------------------------------------------------------- */
#xml-sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 240px;
background: var(--surface-muted);
border-right: 1px solid var(--border);
overflow-y: auto;
z-index: 200;
display: flex;
flex-direction: column;
padding: 16px 14px;
box-sizing: border-box;
}
body.has-xml-sidebar .container {
padding-left: 256px; /* 240px sidebar + 16px gap */
}
.xml-sidebar-header {
font-size: 11px;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.04em;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.xml-sidebar-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.xml-sidebar-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
border-radius: var(--radius-sm);
cursor: pointer;
transition: background 100ms;
min-width: 0;
}
.xml-sidebar-item:hover {
background: var(--bg);
}
.xml-sidebar-item.is-active {
background: var(--primary-soft);
color: var(--primary);
}
.xml-sidebar-item-name {
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
min-width: 0;
}
.xml-sidebar-dirty {
width: 6px;
height: 6px;
border-radius: 50%;
flex-shrink: 0;
margin-left: 6px;
background: transparent;
transition: background 150ms;
}
.xml-sidebar-dirty.is-dirty {
background: var(--warning);
}
/* Mobile: sidebar vertical stack la ≤720px */
@media (max-width: 720px) {
#xml-sidebar {
position: static;
width: 100%;
max-height: 160px;
border-right: none;
border-bottom: 1px solid var(--border);
flex-direction: row;
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
padding: 8px 12px;
align-items: center;
}
.xml-sidebar-list {
flex-direction: row;
gap: 4px;
}
body.has-xml-sidebar .container {
padding-left: 0;
}
.xml-sidebar-header {
display: none;
}
}