From e2a19db6637dfa2ea1666811427faa8c50953d0b Mon Sep 17 00:00:00 2001 From: qcigano Date: Mon, 3 Aug 2026 14:10:25 +0200 Subject: [PATCH] Konto: Rechnung direkt auf der Seite ansehen statt nur Download-Platzhalter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der bisherige "Rechnung (PDF)"-Knopf war ein toter Link (href="#"). Jetzt öffnet "Rechnung ansehen" pro Bestellung ein natives Dialog-Fenster direkt auf der Seite mit vollständiger Rechnung: Rechnungsnummer/-datum, Verkäufer, Rechnungsempfänger (live mit dem aktuellen Kontonamen befüllt), Artikeltabelle mit Einzel-/Gesamtpreisen und dem §19-UStG-Hinweis — kein Herunterladen nötig, schließbar per Kreuz, Schließen-Knopf oder Klick auf den abgedunkelten Hintergrund. Co-Authored-By: Claude Sonnet 5 --- src/i18n/ui.ts | 24 +++++++-- src/pages/ch/konto/angemeldet.astro | 84 ++++++++++++++++++++++++++++- src/pages/en/konto/angemeldet.astro | 84 ++++++++++++++++++++++++++++- src/pages/fr/konto/angemeldet.astro | 84 ++++++++++++++++++++++++++++- src/pages/konto/angemeldet.astro | 84 ++++++++++++++++++++++++++++- src/styles/global.css | 50 +++++++++++++++++ 6 files changed, 402 insertions(+), 8 deletions(-) diff --git a/src/i18n/ui.ts b/src/i18n/ui.ts index a8f1bb1..6472abb 100644 --- a/src/i18n/ui.ts +++ b/src/i18n/ui.ts @@ -229,7 +229,11 @@ export const ui = { noArrivedOrders: "Noch keine angekommenen Bestellungen — hier erscheinen deine Bestellungen, sobald sie geliefert wurden.", ordersTitle: "📦 Meine Bestellungen", orderNo: "Bestellung", orderDate: "Bestellt am", orderTotal: "Gesamt", orderItems: "Artikel", - trackingLabel: "Sendungsverfolgung", trackingBtn: "Sendung verfolgen →", invoiceBtn: "Rechnung (PDF)", reorderBtn: "Nochmal bestellen", + trackingLabel: "Sendungsverfolgung", trackingBtn: "Sendung verfolgen →", invoiceBtn: "Rechnung ansehen", reorderBtn: "Nochmal bestellen", + invoiceTitle: "Rechnung", invoiceNumberLabel: "Rechnungsnummer", invoiceDateLabel: "Rechnungsdatum", + invoiceSellerLabel: "Verkäufer", invoiceBillToLabel: "Rechnungsempfänger", + invoiceItemLabel: "Artikel", invoiceQtyLabel: "Menge", invoiceUnitPriceLabel: "Einzelpreis", invoiceSumLabel: "Gesamtbetrag", + invoiceCloseBtn: "Schließen", statusBezahlt: "Bezahlt", statusBearbeitung: "In Bearbeitung", statusVersandVorbereitet: "Versand vorbereitet", statusVersendet: "Versendet", statusAbgeschlossen: "Abgeschlossen", wishlistTitle: "🩵 Meine Wunschliste", wishlistEmpty: "Deine Wunschliste ist noch leer — stöbere im Shop und speichere deine Lieblingsstücke mit dem Herz-Symbol.", recentTitle: "🕘 Zuletzt angesehen", @@ -463,7 +467,11 @@ export const ui = { noArrivedOrders: "No delivered orders yet — your orders will appear here once they've arrived.", ordersTitle: "📦 My orders", orderNo: "Order", orderDate: "Ordered on", orderTotal: "Total", orderItems: "Items", - trackingLabel: "Tracking", trackingBtn: "Track shipment →", invoiceBtn: "Invoice (PDF)", reorderBtn: "Order again", + trackingLabel: "Tracking", trackingBtn: "Track shipment →", invoiceBtn: "View invoice", reorderBtn: "Order again", + invoiceTitle: "Invoice", invoiceNumberLabel: "Invoice number", invoiceDateLabel: "Invoice date", + invoiceSellerLabel: "Seller", invoiceBillToLabel: "Billed to", + invoiceItemLabel: "Item", invoiceQtyLabel: "Qty", invoiceUnitPriceLabel: "Unit price", invoiceSumLabel: "Total amount", + invoiceCloseBtn: "Close", statusBezahlt: "Paid", statusBearbeitung: "In progress", statusVersandVorbereitet: "Preparing shipment", statusVersendet: "Shipped", statusAbgeschlossen: "Completed", wishlistTitle: "🩵 My wishlist", wishlistEmpty: "Your wishlist is still empty — browse the shop and save your favourites with the heart icon.", recentTitle: "🕘 Recently viewed", @@ -697,7 +705,11 @@ export const ui = { noArrivedOrders: "No kei aacho Bstellige — da erschine dini Bstellige, sobald sie glifert worde sind.", ordersTitle: "📦 Mini Bstellige", orderNo: "Bstellig", orderDate: "Bstellt am", orderTotal: "Total", orderItems: "Artikel", - trackingLabel: "Sändigsverfolgig", trackingBtn: "Sändig verfolge →", invoiceBtn: "Rächnig (PDF)", reorderBtn: "Nomal bstelle", + trackingLabel: "Sändigsverfolgig", trackingBtn: "Sändig verfolge →", invoiceBtn: "Rächnig aluege", reorderBtn: "Nomal bstelle", + invoiceTitle: "Rächnig", invoiceNumberLabel: "Rächnigsnummere", invoiceDateLabel: "Rächnigsdatum", + invoiceSellerLabel: "Verchöifer", invoiceBillToLabel: "Rächnigsempfänger", + invoiceItemLabel: "Artikel", invoiceQtyLabel: "Mengi", invoiceUnitPriceLabel: "Ystückspreis", invoiceSumLabel: "Gsamtbetrag", + invoiceCloseBtn: "Schlüsse", statusBezahlt: "Zahlt", statusBearbeitung: "I dr Bearbeitig", statusVersandVorbereitet: "Versand vorbereitet", statusVersendet: "Verschickt", statusAbgeschlossen: "Abgschlosse", wishlistTitle: "🩵 Mini Wunschlischte", wishlistEmpty: "Dini Wunschlischte isch no leer — lueg im Shop verbi und spicher dini Lieblingssächeli mit em Härz-Symbol.", recentTitle: "🕘 Zletscht aagluegt", @@ -931,7 +943,11 @@ export const ui = { noArrivedOrders: "Aucune commande livrée pour le moment — vos commandes apparaîtront ici dès qu'elles seront arrivées.", ordersTitle: "📦 Mes commandes", orderNo: "Commande", orderDate: "Commandé le", orderTotal: "Total", orderItems: "Articles", - trackingLabel: "Suivi", trackingBtn: "Suivre l'envoi →", invoiceBtn: "Facture (PDF)", reorderBtn: "Commander à nouveau", + trackingLabel: "Suivi", trackingBtn: "Suivre l'envoi →", invoiceBtn: "Voir la facture", reorderBtn: "Commander à nouveau", + invoiceTitle: "Facture", invoiceNumberLabel: "Numéro de facture", invoiceDateLabel: "Date de facture", + invoiceSellerLabel: "Vendeur", invoiceBillToLabel: "Facturé à", + invoiceItemLabel: "Article", invoiceQtyLabel: "Qté", invoiceUnitPriceLabel: "Prix unitaire", invoiceSumLabel: "Montant total", + invoiceCloseBtn: "Fermer", statusBezahlt: "Payée", statusBearbeitung: "En préparation", statusVersandVorbereitet: "Envoi en préparation", statusVersendet: "Expédiée", statusAbgeschlossen: "Terminée", wishlistTitle: "🩵 Ma liste de souhaits", wishlistEmpty: "Votre liste de souhaits est encore vide — parcourez la boutique et enregistrez vos coups de cœur avec l'icône en forme de cœur.", recentTitle: "🕘 Vus récemment", diff --git a/src/pages/ch/konto/angemeldet.astro b/src/pages/ch/konto/angemeldet.astro index 454cd6c..edf3930 100644 --- a/src/pages/ch/konto/angemeldet.astro +++ b/src/pages/ch/konto/angemeldet.astro @@ -141,13 +141,72 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend {t.accountDash.orderTotal}: {formatPrice(b.summe, lang)} {b.tracking && (

{t.accountDash.trackingLabel}: {b.tracking}

)} + + {/* Rechnung direkt auf der Seite ansehen (natives , siehe Skript unten) — + kein Download nötig. Empfängername wird beim Öffnen live aus dem Konto befüllt + (siehe .invoice-billto-name), Adresse ist bewusst dieselbe Platzhalter-Adresse + wie oben unter "Meine Daten". */} + +
+
+
+

{t.accountDash.invoiceTitle}

+

{t.accountDash.invoiceNumberLabel}: {b.nummer}

+

{t.accountDash.invoiceDateLabel}: {b.datum}

+
+ +
+ +
+
+

{t.accountDash.invoiceSellerLabel}

+

Van's DIY & Bastelbedarf

+
+
+

{t.accountDash.invoiceBillToLabel}

+


Musterstraße 1
10115 Berlin
Deutschland

+
+
+ + + + + + + + + + + + {b.artikel.map((a) => ( + + + + + + + ))} + + + + + +
{t.accountDash.invoiceItemLabel}{t.accountDash.invoiceQtyLabel}{t.accountDash.invoiceUnitPriceLabel}{t.accountDash.invoiceSumLabel}
{a.name}{a.menge}{formatPrice(a.preis, lang)}{formatPrice(a.preis * a.menge, lang)}
{t.accountDash.orderTotal}{formatPrice(b.summe, lang)}
+ +

{t.common.vatNote}

+ +
+ +
+
+
))} @@ -316,6 +375,10 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend el.style.backgroundImage = bg; el.textContent = text; }); + // Empfängername in allen (schon gerenderten) Rechnungs-Dialogen live mit aktualisieren. + document.querySelectorAll(".invoice-billto-name").forEach((el) => { + el.textContent = anzeigeName(a) || fallbackName; + }); } renderProfil(); window.addEventListener("account:changed", renderProfil); @@ -351,6 +414,25 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend window.location.href = loginPath; }); + // Rechnung direkt auf der Seite ansehen: natives pro Bestellung, geöffnet/geschlossen + // per Button — kein Download nötig, kein Verlassen der Seite. + document.querySelectorAll("[data-open-invoice]").forEach((btn) => { + btn.addEventListener("click", () => { + const id = btn.dataset.openInvoice; + const dialog = id ? (document.getElementById(id) as HTMLDialogElement | null) : null; + dialog?.showModal(); + }); + }); + document.querySelectorAll(".invoice-dialog").forEach((dialog) => { + dialog.querySelectorAll("[data-close-invoice]").forEach((btn) => { + btn.addEventListener("click", () => dialog.close()); + }); + // Klick auf den abgedunkelten Hintergrund schließt den Dialog ebenfalls. + dialog.addEventListener("click", (e) => { + if (e.target === dialog) dialog.close(); + }); + }); + // Pro Bestellposition: Button "Rezension schreiben" durch "✓ Bewertet" ersetzen, sobald für // genau diese Bestellung+Produkt schon eine Rezension existiert (siehe scripts/reviews.ts, // wird beim Absenden des Formulars auf der Produktseite markiert). diff --git a/src/pages/en/konto/angemeldet.astro b/src/pages/en/konto/angemeldet.astro index ffdb371..4613205 100644 --- a/src/pages/en/konto/angemeldet.astro +++ b/src/pages/en/konto/angemeldet.astro @@ -141,13 +141,72 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend {t.accountDash.orderTotal}: {formatPrice(b.summe, lang)} {b.tracking && (

{t.accountDash.trackingLabel}: {b.tracking}

)} + + {/* Rechnung direkt auf der Seite ansehen (natives , siehe Skript unten) — + kein Download nötig. Empfängername wird beim Öffnen live aus dem Konto befüllt + (siehe .invoice-billto-name), Adresse ist bewusst dieselbe Platzhalter-Adresse + wie oben unter "Meine Daten". */} + +
+
+
+

{t.accountDash.invoiceTitle}

+

{t.accountDash.invoiceNumberLabel}: {b.nummer}

+

{t.accountDash.invoiceDateLabel}: {b.datum}

+
+ +
+ +
+
+

{t.accountDash.invoiceSellerLabel}

+

Van's DIY & Bastelbedarf

+
+
+

{t.accountDash.invoiceBillToLabel}

+


Musterstraße 1
10115 Berlin
Deutschland

+
+
+ + + + + + + + + + + + {b.artikel.map((a) => ( + + + + + + + ))} + + + + + +
{t.accountDash.invoiceItemLabel}{t.accountDash.invoiceQtyLabel}{t.accountDash.invoiceUnitPriceLabel}{t.accountDash.invoiceSumLabel}
{a.name}{a.menge}{formatPrice(a.preis, lang)}{formatPrice(a.preis * a.menge, lang)}
{t.accountDash.orderTotal}{formatPrice(b.summe, lang)}
+ +

{t.common.vatNote}

+ +
+ +
+
+
))} @@ -316,6 +375,10 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend el.style.backgroundImage = bg; el.textContent = text; }); + // Empfängername in allen (schon gerenderten) Rechnungs-Dialogen live mit aktualisieren. + document.querySelectorAll(".invoice-billto-name").forEach((el) => { + el.textContent = anzeigeName(a) || fallbackName; + }); } renderProfil(); window.addEventListener("account:changed", renderProfil); @@ -351,6 +414,25 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend window.location.href = loginPath; }); + // Rechnung direkt auf der Seite ansehen: natives pro Bestellung, geöffnet/geschlossen + // per Button — kein Download nötig, kein Verlassen der Seite. + document.querySelectorAll("[data-open-invoice]").forEach((btn) => { + btn.addEventListener("click", () => { + const id = btn.dataset.openInvoice; + const dialog = id ? (document.getElementById(id) as HTMLDialogElement | null) : null; + dialog?.showModal(); + }); + }); + document.querySelectorAll(".invoice-dialog").forEach((dialog) => { + dialog.querySelectorAll("[data-close-invoice]").forEach((btn) => { + btn.addEventListener("click", () => dialog.close()); + }); + // Klick auf den abgedunkelten Hintergrund schließt den Dialog ebenfalls. + dialog.addEventListener("click", (e) => { + if (e.target === dialog) dialog.close(); + }); + }); + // Pro Bestellposition: Button "Rezension schreiben" durch "✓ Bewertet" ersetzen, sobald für // genau diese Bestellung+Produkt schon eine Rezension existiert (siehe scripts/reviews.ts, // wird beim Absenden des Formulars auf der Produktseite markiert). diff --git a/src/pages/fr/konto/angemeldet.astro b/src/pages/fr/konto/angemeldet.astro index 2b448ca..544d35c 100644 --- a/src/pages/fr/konto/angemeldet.astro +++ b/src/pages/fr/konto/angemeldet.astro @@ -141,13 +141,72 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend {t.accountDash.orderTotal}: {formatPrice(b.summe, lang)} {b.tracking && (

{t.accountDash.trackingLabel}: {b.tracking}

)} + + {/* Rechnung direkt auf der Seite ansehen (natives , siehe Skript unten) — + kein Download nötig. Empfängername wird beim Öffnen live aus dem Konto befüllt + (siehe .invoice-billto-name), Adresse ist bewusst dieselbe Platzhalter-Adresse + wie oben unter "Meine Daten". */} + +
+
+
+

{t.accountDash.invoiceTitle}

+

{t.accountDash.invoiceNumberLabel}: {b.nummer}

+

{t.accountDash.invoiceDateLabel}: {b.datum}

+
+ +
+ +
+
+

{t.accountDash.invoiceSellerLabel}

+

Van's DIY & Bastelbedarf

+
+
+

{t.accountDash.invoiceBillToLabel}

+


Musterstraße 1
10115 Berlin
Deutschland

+
+
+ + + + + + + + + + + + {b.artikel.map((a) => ( + + + + + + + ))} + + + + + +
{t.accountDash.invoiceItemLabel}{t.accountDash.invoiceQtyLabel}{t.accountDash.invoiceUnitPriceLabel}{t.accountDash.invoiceSumLabel}
{a.name}{a.menge}{formatPrice(a.preis, lang)}{formatPrice(a.preis * a.menge, lang)}
{t.accountDash.orderTotal}{formatPrice(b.summe, lang)}
+ +

{t.common.vatNote}

+ +
+ +
+
+
))} @@ -316,6 +375,10 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend el.style.backgroundImage = bg; el.textContent = text; }); + // Empfängername in allen (schon gerenderten) Rechnungs-Dialogen live mit aktualisieren. + document.querySelectorAll(".invoice-billto-name").forEach((el) => { + el.textContent = anzeigeName(a) || fallbackName; + }); } renderProfil(); window.addEventListener("account:changed", renderProfil); @@ -351,6 +414,25 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend window.location.href = loginPath; }); + // Rechnung direkt auf der Seite ansehen: natives pro Bestellung, geöffnet/geschlossen + // per Button — kein Download nötig, kein Verlassen der Seite. + document.querySelectorAll("[data-open-invoice]").forEach((btn) => { + btn.addEventListener("click", () => { + const id = btn.dataset.openInvoice; + const dialog = id ? (document.getElementById(id) as HTMLDialogElement | null) : null; + dialog?.showModal(); + }); + }); + document.querySelectorAll(".invoice-dialog").forEach((dialog) => { + dialog.querySelectorAll("[data-close-invoice]").forEach((btn) => { + btn.addEventListener("click", () => dialog.close()); + }); + // Klick auf den abgedunkelten Hintergrund schließt den Dialog ebenfalls. + dialog.addEventListener("click", (e) => { + if (e.target === dialog) dialog.close(); + }); + }); + // Pro Bestellposition: Button "Rezension schreiben" durch "✓ Bewertet" ersetzen, sobald für // genau diese Bestellung+Produkt schon eine Rezension existiert (siehe scripts/reviews.ts, // wird beim Absenden des Formulars auf der Produktseite markiert). diff --git a/src/pages/konto/angemeldet.astro b/src/pages/konto/angemeldet.astro index c6fd76e..23df0e2 100644 --- a/src/pages/konto/angemeldet.astro +++ b/src/pages/konto/angemeldet.astro @@ -141,13 +141,72 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend {t.accountDash.orderTotal}: {formatPrice(b.summe, lang)} {b.tracking && (

{t.accountDash.trackingLabel}: {b.tracking}

)} + + {/* Rechnung direkt auf der Seite ansehen (natives , siehe Skript unten) — + kein Download nötig. Empfängername wird beim Öffnen live aus dem Konto befüllt + (siehe .invoice-billto-name), Adresse ist bewusst dieselbe Platzhalter-Adresse + wie oben unter "Meine Daten". */} + +
+
+
+

{t.accountDash.invoiceTitle}

+

{t.accountDash.invoiceNumberLabel}: {b.nummer}

+

{t.accountDash.invoiceDateLabel}: {b.datum}

+
+ +
+ +
+
+

{t.accountDash.invoiceSellerLabel}

+

Van's DIY & Bastelbedarf

+
+
+

{t.accountDash.invoiceBillToLabel}

+


Musterstraße 1
10115 Berlin
Deutschland

+
+
+ + + + + + + + + + + + {b.artikel.map((a) => ( + + + + + + + ))} + + + + + +
{t.accountDash.invoiceItemLabel}{t.accountDash.invoiceQtyLabel}{t.accountDash.invoiceUnitPriceLabel}{t.accountDash.invoiceSumLabel}
{a.name}{a.menge}{formatPrice(a.preis, lang)}{formatPrice(a.preis * a.menge, lang)}
{t.accountDash.orderTotal}{formatPrice(b.summe, lang)}
+ +

{t.common.vatNote}

+ +
+ +
+
+
))} @@ -316,6 +375,10 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend el.style.backgroundImage = bg; el.textContent = text; }); + // Empfängername in allen (schon gerenderten) Rechnungs-Dialogen live mit aktualisieren. + document.querySelectorAll(".invoice-billto-name").forEach((el) => { + el.textContent = anzeigeName(a) || fallbackName; + }); } renderProfil(); window.addEventListener("account:changed", renderProfil); @@ -351,6 +414,25 @@ const offeneSendungen = beispielBestellungen.filter((b) => b.status === "versend window.location.href = loginPath; }); + // Rechnung direkt auf der Seite ansehen: natives pro Bestellung, geöffnet/geschlossen + // per Button — kein Download nötig, kein Verlassen der Seite. + document.querySelectorAll("[data-open-invoice]").forEach((btn) => { + btn.addEventListener("click", () => { + const id = btn.dataset.openInvoice; + const dialog = id ? (document.getElementById(id) as HTMLDialogElement | null) : null; + dialog?.showModal(); + }); + }); + document.querySelectorAll(".invoice-dialog").forEach((dialog) => { + dialog.querySelectorAll("[data-close-invoice]").forEach((btn) => { + btn.addEventListener("click", () => dialog.close()); + }); + // Klick auf den abgedunkelten Hintergrund schließt den Dialog ebenfalls. + dialog.addEventListener("click", (e) => { + if (e.target === dialog) dialog.close(); + }); + }); + // Pro Bestellposition: Button "Rezension schreiben" durch "✓ Bewertet" ersetzen, sobald für // genau diese Bestellung+Produkt schon eine Rezension existiert (siehe scripts/reviews.ts, // wird beim Absenden des Formulars auf der Produktseite markiert). diff --git a/src/styles/global.css b/src/styles/global.css index be12758..e2f4157 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1556,6 +1556,56 @@ a:focus-visible, button:focus-visible { .order-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; } .order-tracking-no { margin: 0; color: var(--c-text-muted); } .order-tracking-no code { font-size: 0.9em; letter-spacing: 0.02em; } + +/* Rechnung direkt auf der Seite ansehen (natives ) — kein Download nötig, öffnet sich + sofort als Overlay über der aktuellen Ansicht. */ +.invoice-dialog { + border: none; + padding: 0; + background: transparent; + color: var(--c-text); + max-width: min(94vw, 580px); + width: 100%; +} +.invoice-dialog::backdrop { background: rgba(6, 5, 10, 0.75); backdrop-filter: blur(3px); } +.invoice-card { + background: linear-gradient(165deg, var(--c-anthracite-light), var(--c-anthracite)); + border: 1.5px solid rgba(244, 241, 247, 0.16); + border-radius: var(--radius-l); + padding: 1.8rem; + max-height: 85vh; + overflow-y: auto; + box-shadow: var(--shadow-card); +} +.invoice-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; margin-bottom: 1rem; } +.invoice-head h3 { margin: 0; } +.invoice-meta { margin: 0.3rem 0 0; font-size: 0.88rem; color: var(--c-text-muted); } +.invoice-close { + background: none; + border: 1px solid rgba(244, 241, 247, 0.2); + border-radius: 50%; + width: 32px; + height: 32px; + color: var(--c-text); + cursor: pointer; + flex-shrink: 0; + font-size: 1.1rem; + line-height: 1; +} +.invoice-close:hover { border-color: var(--c-accent); color: var(--c-accent); } +.invoice-parties { display: grid; grid-template-columns: 1fr 1fr; gap: 1.2rem; margin: 1.3rem 0; } +.invoice-parties h4 { margin: 0 0 0.35em; font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--c-accent); } +.invoice-parties p { margin: 0; font-size: 0.9rem; color: var(--c-text-muted); line-height: 1.55; } +@media (max-width: 480px) { .invoice-parties { grid-template-columns: 1fr; } } +.invoice-table { width: 100%; border-collapse: collapse; margin-top: 0.6rem; } +.invoice-table th, .invoice-table td { text-align: left; padding: 0.55em 0.35em; border-bottom: 1px solid rgba(244, 241, 247, 0.1); font-size: 0.9rem; } +.invoice-table th { color: var(--c-text-muted); font-weight: 600; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; } +.invoice-table th:last-child, .invoice-table td:last-child, +.invoice-table th:nth-child(2), .invoice-table td:nth-child(2), +.invoice-table th:nth-child(3), .invoice-table td:nth-child(3) { text-align: right; } +.invoice-total-row td { font-weight: 700; color: var(--c-accent); border-bottom: none; padding-top: 0.8em; font-size: 1rem; } +.invoice-vat-note { margin: 1.1rem 0 0; font-size: 0.8rem; color: var(--c-text-muted); } +.invoice-foot { display: flex; justify-content: flex-end; margin-top: 1.4rem; } .profile-card { display: flex; flex-direction: column; align-items: stretch; gap: 1.3rem; } .profile-card .specs { margin-top: 0; width: 100%; } .profile-photo-row { display: flex; align-items: center; gap: 1.1rem; }