From 3957987b0753f8d4c54bad6bde14e48cd5e515ae Mon Sep 17 00:00:00 2001
From: bisco
Date: Tue, 5 May 2026 10:26:03 +0200
Subject: [PATCH] feat: refresh frontend visual design
---
frontend/src/app/app.component.ts | 198 ++++++++++---
.../booking-placeholder-page.component.ts | 86 ++++--
.../check-in-placeholder-page.component.ts | 89 ++++--
frontend/src/app/pages/home-page.component.ts | 278 +++++++++++++++---
.../reservation-confirm-page.component.ts | 71 +++--
.../show-detail-placeholder-page.component.ts | 84 +++---
.../src/app/pages/show-list-page.component.ts | 84 ++++--
frontend/src/styles.css | 117 ++++++--
8 files changed, 760 insertions(+), 247 deletions(-)
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts
index 9355b39..19be632 100644
--- a/frontend/src/app/app.component.ts
+++ b/frontend/src/app/app.component.ts
@@ -1,8 +1,6 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
-import { MatIconModule } from '@angular/material/icon';
-import { MatToolbarModule } from '@angular/material/toolbar';
@Component({
selector: 'app-root',
@@ -11,56 +9,108 @@ import { MatToolbarModule } from '@angular/material/toolbar';
RouterOutlet,
RouterLink,
RouterLinkActive,
- MatToolbarModule,
MatButtonModule,
- MatIconModule,
],
template: `
`,
styles: [`
.app-shell {
min-height: 100vh;
+ display: flex;
+ flex-direction: column;
}
- .app-toolbar {
- position: sticky;
- top: 0;
- z-index: 10;
+ .topline {
+ background: var(--azionelab-surface-dark);
+ color: rgba(255, 247, 239, 0.84);
+ font-size: 0.85rem;
+ }
+
+ .topline-inner,
+ .header-inner,
+ .footer-inner {
+ width: min(100%, var(--azionelab-shell-width));
+ margin: 0 auto;
+ }
+
+ .topline-inner {
display: flex;
justify-content: space-between;
gap: 16px;
- min-height: 72px;
- padding: 0 24px;
- background: rgba(251, 247, 242, 0.88);
- backdrop-filter: blur(18px);
+ padding: 10px 20px;
+ flex-wrap: wrap;
+ }
+
+ .site-header {
+ position: sticky;
+ top: 0;
+ z-index: 20;
+ backdrop-filter: blur(16px);
+ background: rgba(250, 245, 238, 0.9);
border-bottom: 1px solid var(--azionelab-border);
}
+ .header-inner {
+ display: grid;
+ grid-template-columns: auto 1fr auto;
+ align-items: center;
+ gap: 18px;
+ min-height: 82px;
+ padding: 0 20px;
+ }
+
.brand {
display: inline-flex;
align-items: center;
- gap: 12px;
+ gap: 14px;
color: inherit;
text-decoration: none;
}
@@ -68,49 +118,117 @@ import { MatToolbarModule } from '@angular/material/toolbar';
.brand-mark {
display: inline-grid;
place-items: center;
- width: 42px;
- height: 42px;
- border-radius: 10px;
- background: linear-gradient(135deg, var(--azionelab-accent), #ca6d3b);
- color: white;
+ width: 48px;
+ height: 48px;
+ border-radius: 14px;
+ background: linear-gradient(145deg, var(--azionelab-accent), var(--azionelab-accent-soft));
+ color: #fff8f2;
font-weight: 700;
+ box-shadow: 0 14px 30px rgba(111, 40, 33, 0.18);
}
.brand-text {
display: flex;
flex-direction: column;
- line-height: 1.1;
+ line-height: 1.05;
+ }
+
+ .brand-text strong {
+ font-family: var(--azionelab-serif);
+ font-size: 1.4rem;
+ font-weight: 700;
}
.brand-text small {
color: var(--azionelab-muted);
- font-size: 0.74rem;
+ font-size: 0.78rem;
}
.main-nav {
display: flex;
align-items: center;
- gap: 4px;
+ justify-content: center;
+ gap: 6px;
flex-wrap: wrap;
}
.main-nav .active {
- background: rgba(159, 47, 40, 0.08);
+ background: rgba(143, 51, 45, 0.1);
+ }
+
+ .header-actions {
+ display: flex;
+ justify-content: flex-end;
}
.page-shell {
- padding: 32px 20px 56px;
+ flex: 1;
+ padding: 40px 20px 72px;
+ }
+
+ .site-footer {
+ border-top: 1px solid var(--azionelab-border);
+ background:
+ linear-gradient(180deg, rgba(255, 251, 246, 0.86), rgba(244, 235, 223, 0.92));
+ }
+
+ .footer-inner {
+ display: grid;
+ grid-template-columns: minmax(0, 1.5fr) auto;
+ gap: 24px;
+ align-items: start;
+ padding: 28px 20px 34px;
+ }
+
+ .footer-title {
+ margin: 0 0 8px;
+ font-family: var(--azionelab-serif);
+ font-size: 1.15rem;
+ font-weight: 700;
+ color: var(--azionelab-ink);
+ }
+
+ .footer-copy {
+ margin: 0;
+ max-width: 52ch;
+ color: var(--azionelab-muted);
+ line-height: 1.6;
+ }
+
+ .footer-nav {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 14px;
+ }
+
+ .footer-nav a {
+ color: var(--azionelab-ink-soft);
+ text-decoration: none;
}
@media (max-width: 800px) {
- .app-toolbar {
+ .header-inner {
+ grid-template-columns: 1fr;
align-items: flex-start;
- flex-direction: column;
- padding: 16px 16px 14px;
+ padding: 16px;
}
.main-nav {
width: 100%;
+ justify-content: flex-start;
+ }
+
+ .header-actions {
+ width: 100%;
+ }
+
+ .footer-inner {
+ grid-template-columns: 1fr;
+ padding: 24px 16px 28px;
+ }
+
+ .page-shell {
+ padding: 28px 16px 52px;
}
}
`],
diff --git a/frontend/src/app/pages/booking-placeholder-page.component.ts b/frontend/src/app/pages/booking-placeholder-page.component.ts
index 763bbfa..ac99a7b 100644
--- a/frontend/src/app/pages/booking-placeholder-page.component.ts
+++ b/frontend/src/app/pages/booking-placeholder-page.component.ts
@@ -36,8 +36,21 @@ type ApiValidationErrors = Record;
-
-
+
+
+
+ Before you submit
+ Reservations are activated only after email confirmation.
+
+ - Your confirmation link arrives at the email address you provide.
+ - Seat availability is checked on the server before confirmation.
+ - The QR code is generated only after the reservation becomes confirmed.
+
+
+
+
+
+
@if (isSuccess()) {
@@ -131,52 +144,69 @@ type ApiValidationErrors = Record;
}
-
-
+
+
+
`,
styles: [`
- .page {
- max-width: 760px;
- margin: 0 auto;
- }
-
.page-header {
- margin-bottom: 24px;
- }
-
- .eyebrow {
- margin: 0 0 10px;
- color: var(--azionelab-accent);
- text-transform: uppercase;
- font-size: 0.78rem;
- font-weight: 700;
- }
-
- h1 {
- margin: 0;
- font-size: clamp(2rem, 4vw, 3rem);
+ margin-bottom: 26px;
}
.supporting {
- color: var(--azionelab-muted);
- line-height: 1.6;
max-width: 56ch;
margin: 14px 0 0;
}
+ .booking-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
+ gap: 20px;
+ align-items: start;
+ }
+
+ .summary-card,
.content-card {
- border-radius: 20px;
+ border-radius: var(--azionelab-radius-lg);
border: 1px solid var(--azionelab-border);
background: var(--azionelab-surface-strong);
box-shadow: var(--azionelab-shadow);
overflow: hidden;
}
+ .summary-card {
+ background:
+ linear-gradient(180deg, rgba(255, 252, 248, 0.98), rgba(247, 238, 227, 0.94));
+ }
+
mat-card-content {
padding: 28px !important;
}
+ .summary-label {
+ margin: 0 0 10px;
+ font-size: 0.78rem;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ color: var(--azionelab-accent);
+ }
+
+ .summary-card h2 {
+ margin: 0;
+ max-width: 14ch;
+ }
+
+ .summary-list {
+ display: grid;
+ gap: 12px;
+ margin: 18px 0 0;
+ padding-left: 18px;
+ color: var(--azionelab-ink-soft);
+ line-height: 1.6;
+ }
+
.intro-note {
display: flex;
align-items: flex-start;
@@ -317,6 +347,10 @@ type ApiValidationErrors = Record;
}
@media (max-width: 640px) {
+ .booking-grid {
+ grid-template-columns: 1fr;
+ }
+
mat-card-content {
padding: 22px !important;
}
diff --git a/frontend/src/app/pages/check-in-placeholder-page.component.ts b/frontend/src/app/pages/check-in-placeholder-page.component.ts
index af5e587..b608896 100644
--- a/frontend/src/app/pages/check-in-placeholder-page.component.ts
+++ b/frontend/src/app/pages/check-in-placeholder-page.component.ts
@@ -68,8 +68,21 @@ type BarcodeDetectorConstructor = new (options?: { formats?: string[] }) => Barc
Enter a token manually or scan a QR code to preview admission data and confirm entrance.
-
-
+
+
+
+ Front of house
+ Designed for quick, low-friction arrivals.
+
+ - Scan a QR code when a device camera is available.
+ - Enter the token manually if scanning is not possible.
+ - Confirm admission only after the preview data matches the guest.
+
+
+
+
+
+
Camera scan
@@ -175,46 +188,62 @@ type BarcodeDetectorConstructor = new (options?: { formats?: string[] }) => Barc
@if (state() === 'error') {
Something went wrong. Please try again.
}
-
-
+
+
+
`,
styles: [`
- .page {
- max-width: 760px;
- margin: 0 auto;
- }
-
.page-header {
- margin-bottom: 22px;
- }
-
- .eyebrow {
- margin: 0 0 10px;
- color: var(--azionelab-accent);
- text-transform: uppercase;
- font-size: 0.78rem;
- font-weight: 700;
- }
-
- h1 {
- margin: 0;
- font-size: clamp(2rem, 4vw, 3rem);
+ margin-bottom: 24px;
}
.supporting {
- color: var(--azionelab-muted);
- line-height: 1.6;
max-width: 50ch;
}
+ .checkin-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
+ gap: 20px;
+ align-items: start;
+ }
+
+ .side-card,
.content-card {
- border-radius: 8px;
+ border-radius: var(--azionelab-radius-lg);
border: 1px solid var(--azionelab-border);
- background: var(--azionelab-surface);
+ background: var(--azionelab-surface-strong);
box-shadow: var(--azionelab-shadow);
}
+ .side-card {
+ background:
+ linear-gradient(180deg, rgba(255, 252, 248, 0.98), rgba(247, 238, 227, 0.94));
+ }
+
+ .side-label {
+ margin: 0 0 10px;
+ font-size: 0.78rem;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ color: var(--azionelab-accent);
+ }
+
+ .side-card h2 {
+ margin: 0;
+ }
+
+ .side-list {
+ display: grid;
+ gap: 12px;
+ margin: 18px 0 0;
+ padding-left: 18px;
+ color: var(--azionelab-ink-soft);
+ line-height: 1.6;
+ }
+
.scanner-panel {
display: grid;
gap: 14px;
@@ -320,6 +349,12 @@ type BarcodeDetectorConstructor = new (options?: { formats?: string[] }) => Barc
color: #b3261e;
font-weight: 500;
}
+
+ @media (max-width: 760px) {
+ .checkin-grid {
+ grid-template-columns: 1fr;
+ }
+ }
`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
diff --git a/frontend/src/app/pages/home-page.component.ts b/frontend/src/app/pages/home-page.component.ts
index 3911ddd..65610cd 100644
--- a/frontend/src/app/pages/home-page.component.ts
+++ b/frontend/src/app/pages/home-page.component.ts
@@ -9,66 +9,103 @@ import { API_BASE_URL } from '../services/api-config.token';
standalone: true,
imports: [RouterLink, MatButtonModule, MatCardModule],
template: `
-
+
AzioneLab Theatre Company
-
Public website and booking UI foundations.
+
Small-stage evenings, thoughtful performances, simple reservations.
- This Angular shell is wired for the existing Django APIs and ready for the next booking-focused iterations.
+ AzioneLab brings contemporary theatre into intimate venues. This public frontend is shaped around clear show discovery, lightweight booking, and a calm arrival experience at the door.
-
-
- Frontend wiring
+
+
+
+
+ Tonight at AzioneLab
+ Doors open 30 minutes before the performance
+
+
+
+
+
+
+
+
At a glance
+
Built for a small company, not a sprawling ticketing empire
+
+
The public experience stays simple: browse a show, reserve seats, confirm by email, arrive with a QR code.
+
+
+
+
+ Find the right performance
- API base URL
- {{ apiBaseUrl }}
- Placeholders are in place for public content, booking, and staff check-in flows.
+ Show listings and detail pages keep venue, schedule, and availability visible without noise.
+
+
+
+ Confirm by email
+
+ Reservations stay pending until the audience member confirms, which keeps capacity trustworthy and easy to manage.
+
+
+
+ Check in quickly
+
+ Front-of-house staff can preview a token, validate it server-side, and record entry in one compact flow.
+
+
+
+
Audience journey
+
From interest to entrance in a few quiet steps
+
+ - Browse the public programme and open a show page.
+ - Reserve seats for a performance and confirm by email.
+ - Keep the QR code ready on your phone or on paper for entry.
+
+
+
+
+ Runtime wiring
+
+ API base URL
+ {{ apiBaseUrl }}
+ The frontend remains aligned with the existing Django API surface without changing backend contracts.
+
+
+
`,
styles: [`
.hero {
display: grid;
- grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.9fr);
+ grid-template-columns: minmax(0, 1.3fr) minmax(280px, 0.9fr);
gap: 28px;
align-items: stretch;
- max-width: 1180px;
- margin: 0 auto;
+ padding: 12px 0 24px;
}
.hero-copy {
- padding: 36px 0;
- }
-
- .eyebrow {
- margin: 0 0 12px;
- color: var(--azionelab-accent);
- text-transform: uppercase;
- font-size: 0.78rem;
- font-weight: 700;
+ padding: 34px 0 20px;
}
h1 {
margin: 0;
- max-width: 10ch;
- font-size: clamp(2.5rem, 5vw, 4.75rem);
- line-height: 0.95;
+ max-width: 11ch;
+ font-size: 3.85rem;
}
.supporting {
- max-width: 52ch;
- color: var(--azionelab-muted);
- font-size: 1.08rem;
- line-height: 1.65;
margin: 20px 0 0;
+ font-size: 1.06rem;
}
.hero-actions {
@@ -78,32 +115,189 @@ import { API_BASE_URL } from '../services/api-config.token';
margin-top: 28px;
}
- .hero-panel mat-card {
- height: 100%;
- border-radius: 8px;
+ .hero-stage {
+ position: relative;
+ overflow: hidden;
+ min-height: 420px;
+ border-radius: var(--azionelab-radius-lg);
+ border: 1px solid rgba(255, 250, 245, 0.16);
+ background:
+ linear-gradient(180deg, rgba(31, 18, 18, 0.1), rgba(27, 18, 14, 0.62)),
+ linear-gradient(135deg, #b04b40 0%, #7f251f 24%, #43261f 56%, #211b1a 100%);
+ box-shadow: var(--azionelab-shadow-strong);
+ }
+
+ .curtain {
+ position: absolute;
+ inset: 0;
+ background:
+ linear-gradient(90deg, rgba(255, 255, 255, 0.08) 0, rgba(255, 255, 255, 0) 22%, rgba(255, 255, 255, 0.08) 48%, rgba(255, 255, 255, 0) 74%, rgba(255, 255, 255, 0.08) 100%),
+ repeating-linear-gradient(90deg, rgba(75, 18, 14, 0.2) 0 18px, rgba(160, 60, 52, 0.08) 18px 36px);
+ opacity: 0.9;
+ }
+
+ .stage-glow {
+ position: absolute;
+ left: 50%;
+ bottom: -80px;
+ width: 340px;
+ height: 340px;
+ transform: translateX(-50%);
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(245, 214, 150, 0.9) 0, rgba(245, 214, 150, 0.22) 44%, rgba(245, 214, 150, 0) 72%);
+ }
+
+ .stage-copy {
+ position: absolute;
+ left: 24px;
+ right: 24px;
+ bottom: 24px;
+ display: grid;
+ gap: 8px;
+ padding: 18px 20px;
+ border-radius: 18px;
+ background: rgba(24, 17, 15, 0.52);
+ backdrop-filter: blur(8px);
+ color: rgba(255, 247, 239, 0.94);
+ border: 1px solid rgba(255, 247, 239, 0.12);
+ }
+
+ .stage-copy span {
+ text-transform: uppercase;
+ font-size: 0.76rem;
+ letter-spacing: 0.08em;
+ color: rgba(255, 227, 192, 0.84);
+ }
+
+ .stage-copy strong {
+ font-family: var(--azionelab-serif);
+ font-size: 1.4rem;
+ font-weight: 700;
+ line-height: 1.15;
+ }
+
+ .overview,
+ .journey-grid {
+ margin-top: 34px;
+ }
+
+ .section-heading {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(260px, 420px);
+ gap: 24px;
+ align-items: end;
+ margin-bottom: 20px;
+ }
+
+ .section-heading h2,
+ .journey-copy h2 {
+ margin: 0;
+ max-width: 18ch;
+ }
+
+ .feature-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 18px;
+ }
+
+ .feature-card,
+ .meta-card {
+ border-radius: var(--azionelab-radius-md);
border: 1px solid var(--azionelab-border);
- background: var(--azionelab-surface);
+ background: linear-gradient(180deg, rgba(255, 253, 250, 0.98), rgba(251, 245, 236, 0.94));
box-shadow: var(--azionelab-shadow);
}
+ .feature-card {
+ min-height: 210px;
+ }
+
+ .feature-card mat-card-title,
+ .meta-card mat-card-title {
+ margin-bottom: 12px;
+ font-family: var(--azionelab-serif);
+ font-size: 1.18rem;
+ font-weight: 700;
+ }
+
+ .feature-card p,
+ .meta-card p {
+ margin: 0;
+ color: var(--azionelab-muted);
+ line-height: 1.6;
+ }
+
+ .journey-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.9fr);
+ gap: 24px;
+ align-items: start;
+ }
+
+ .journey-copy {
+ padding: 10px 0;
+ }
+
+ ol {
+ display: grid;
+ gap: 12px;
+ margin: 20px 0 0;
+ padding-left: 22px;
+ color: var(--azionelab-ink-soft);
+ line-height: 1.65;
+ }
+
+ .meta-label {
+ margin: 0 0 10px;
+ font-size: 0.8rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ color: var(--azionelab-muted);
+ letter-spacing: 0.08em;
+ }
+
code {
display: inline-block;
- margin-top: 8px;
padding: 10px 12px;
- border-radius: 8px;
- background: rgba(30, 27, 24, 0.06);
+ border-radius: 12px;
+ background: rgba(34, 28, 24, 0.06);
+ color: var(--azionelab-ink-soft);
+ word-break: break-word;
}
- .panel-note {
- margin-top: 20px;
- color: var(--azionelab-muted);
- line-height: 1.5;
+ .meta-note {
+ margin: 18px 0 0;
}
@media (max-width: 900px) {
- .hero {
+ .hero,
+ .section-heading,
+ .journey-grid,
+ .feature-grid {
grid-template-columns: 1fr;
}
+
+ h1 {
+ font-size: 2.9rem;
+ }
+ }
+
+ @media (max-width: 640px) {
+ h1 {
+ font-size: 2.25rem;
+ }
+
+ .hero-stage {
+ min-height: 320px;
+ }
+
+ .stage-copy {
+ left: 16px;
+ right: 16px;
+ bottom: 16px;
+ padding: 16px;
+ }
}
`],
changeDetection: ChangeDetectionStrategy.OnPush,
diff --git a/frontend/src/app/pages/reservation-confirm-page.component.ts b/frontend/src/app/pages/reservation-confirm-page.component.ts
index cdd26c0..110d195 100644
--- a/frontend/src/app/pages/reservation-confirm-page.component.ts
+++ b/frontend/src/app/pages/reservation-confirm-page.component.ts
@@ -68,6 +68,17 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
Check-in URL: {{ confirmation()!.qr_code_url }}
}
+
+
+
+
What to do next
+
Keep the QR code on your phone or print it. Staff can scan it directly at the entrance.
+
+
+
Need the link later?
+
Save the confirmation email so you can reopen the check-in page if the QR needs to be shown again.
+
+
}
@if (state() === 'invalid') {
@@ -115,37 +126,17 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
`,
styles: [`
- .page {
- max-width: 760px;
- margin: 0 auto;
- }
-
.page-header {
margin-bottom: 24px;
}
- .eyebrow {
- margin: 0 0 10px;
- color: var(--azionelab-accent);
- text-transform: uppercase;
- font-size: 0.78rem;
- font-weight: 700;
- }
-
- h1 {
- margin: 0;
- font-size: clamp(2rem, 4vw, 3rem);
- }
-
.supporting {
- color: var(--azionelab-muted);
- line-height: 1.6;
max-width: 58ch;
margin: 14px 0 0;
}
.status-card {
- border-radius: 20px;
+ border-radius: var(--azionelab-radius-lg);
border: 1px solid var(--azionelab-border);
background: var(--azionelab-surface-strong);
box-shadow: var(--azionelab-shadow);
@@ -172,7 +163,6 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
.status-panel h2 {
margin: 0 0 6px;
- font-size: 1.2rem;
}
.status-panel p {
@@ -262,7 +252,7 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
.qr-panel {
margin-top: 18px;
padding: 16px;
- border-radius: 18px;
+ border-radius: var(--azionelab-radius-md);
border: 1px solid var(--azionelab-border);
display: inline-block;
background: white;
@@ -289,7 +279,7 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
gap: 10px;
margin-top: 16px;
padding: 14px 16px;
- border-radius: 16px;
+ border-radius: var(--azionelab-radius-md);
background: rgba(159, 47, 40, 0.05);
color: var(--azionelab-muted);
}
@@ -303,6 +293,35 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
color: var(--azionelab-accent-strong);
}
+ .next-steps {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 14px;
+ margin-top: 18px;
+ }
+
+ .next-steps > div {
+ padding: 16px;
+ border-radius: var(--azionelab-radius-md);
+ background: rgba(34, 28, 24, 0.035);
+ border: 1px solid var(--azionelab-border);
+ }
+
+ .step-label {
+ margin: 0 0 6px !important;
+ font-size: 0.8rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--azionelab-accent);
+ }
+
+ .next-steps p {
+ margin: 0;
+ line-height: 1.55;
+ color: var(--azionelab-muted);
+ }
+
@media (max-width: 640px) {
mat-card-content {
padding: 22px !important;
@@ -325,6 +344,10 @@ type ConfirmationState = 'loading' | 'success' | 'invalid' | 'expired' | 'error'
width: min(100%, 280px);
margin: 0 auto;
}
+
+ .next-steps {
+ grid-template-columns: 1fr;
+ }
}
`],
changeDetection: ChangeDetectionStrategy.OnPush,
diff --git a/frontend/src/app/pages/show-detail-placeholder-page.component.ts b/frontend/src/app/pages/show-detail-placeholder-page.component.ts
index fe32853..a74e4fc 100644
--- a/frontend/src/app/pages/show-detail-placeholder-page.component.ts
+++ b/frontend/src/app/pages/show-detail-placeholder-page.component.ts
@@ -49,6 +49,10 @@ import { ShowDetail, ShowPerformance, ShowsApiService } from '../services/shows-
Show detail
{{ show()!.title }}
{{ show()!.description || show()!.summary }}
+
+ Published programme
+ Choose a performance below to continue
+
@if (show()!.image_url) {
@@ -116,52 +120,51 @@ import { ShowDetail, ShowPerformance, ShowsApiService } from '../services/shows-
`,
styles: [`
- .page {
- max-width: 1080px;
- margin: 0 auto;
- }
-
.page-header {
display: grid;
grid-template-columns: minmax(0, 1.2fr) minmax(280px, 420px);
- gap: 24px;
+ gap: 28px;
align-items: start;
- margin-bottom: 28px;
+ margin-bottom: 32px;
}
.hero-copy {
min-width: 0;
- }
-
- .eyebrow {
- margin: 0 0 10px;
- color: var(--azionelab-accent);
- text-transform: uppercase;
- font-size: 0.78rem;
- font-weight: 700;
- }
-
- h1 {
- margin: 0;
- font-size: clamp(2rem, 4vw, 3.2rem);
+ padding: 8px 0;
}
.supporting {
margin: 14px 0 0;
- color: var(--azionelab-muted);
- line-height: 1.6;
- max-width: 64ch;
+ }
+
+ .hero-note {
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+ margin-top: 18px;
+ }
+
+ .hero-note span {
+ display: inline-flex;
+ align-items: center;
+ min-height: 32px;
+ padding: 0 14px;
+ border-radius: 999px;
+ background: rgba(143, 51, 45, 0.08);
+ color: var(--azionelab-accent-strong);
+ font-size: 0.85rem;
+ font-weight: 700;
}
.hero-image-wrap {
overflow: hidden;
- border-radius: 12px;
+ border-radius: var(--azionelab-radius-lg);
border: 1px solid var(--azionelab-border);
background:
linear-gradient(135deg, rgba(207, 71, 51, 0.16), rgba(15, 22, 36, 0.08)),
#f8f1ea;
- box-shadow: var(--azionelab-shadow);
- aspect-ratio: 4 / 5;
+ box-shadow: var(--azionelab-shadow-strong);
+ aspect-ratio: 4 / 4.8;
}
.hero-image {
@@ -185,30 +188,39 @@ import { ShowDetail, ShowPerformance, ShowsApiService } from '../services/shows-
.section-heading h2 {
margin: 0 0 6px;
- font-size: 1.4rem;
- }
-
- .section-heading p {
- margin: 0;
- color: var(--azionelab-muted);
}
.performance-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- gap: 20px;
+ gap: 22px;
}
.performance-card,
.status-card {
- border-radius: 8px;
+ border-radius: var(--azionelab-radius-md);
border: 1px solid var(--azionelab-border);
- background: var(--azionelab-surface);
+ background: linear-gradient(180deg, rgba(255, 253, 249, 0.98), rgba(250, 243, 233, 0.94));
box-shadow: var(--azionelab-shadow);
}
.performance-card {
- min-height: 260px;
+ min-height: 280px;
+ }
+
+ .performance-card mat-card-title,
+ .performance-card mat-card-subtitle,
+ .performance-card mat-card-content,
+ .performance-card mat-card-actions {
+ padding-left: 18px;
+ padding-right: 18px;
+ }
+
+ .performance-card mat-card-title {
+ margin-top: 14px;
+ font-family: var(--azionelab-serif);
+ font-size: 1.28rem;
+ line-height: 1.15;
}
.performance-meta {
diff --git a/frontend/src/app/pages/show-list-page.component.ts b/frontend/src/app/pages/show-list-page.component.ts
index c0fe47e..1825463 100644
--- a/frontend/src/app/pages/show-list-page.component.ts
+++ b/frontend/src/app/pages/show-list-page.component.ts
@@ -19,7 +19,7 @@ import { ShowListItem, ShowsApiService } from '../services/shows-api.service';
Shows
- Browse current productions published from the AzioneLab backend.
+ Browse current productions, open a show page, and move toward booking without friction.
@@ -64,6 +64,9 @@ import { ShowListItem, ShowsApiService } from '../services/shows-api.service';
}
+
+ Published show
+
{{ show.title }}
{{ show.summary }}
@@ -78,42 +81,23 @@ import { ShowListItem, ShowsApiService } from '../services/shows-api.service';
`,
styles: [`
- .page {
- max-width: 1180px;
- margin: 0 auto;
- }
-
.page-header {
display: grid;
- grid-template-columns: minmax(0, 1fr) minmax(260px, 380px);
+ grid-template-columns: minmax(0, 1fr) minmax(260px, 410px);
gap: 24px;
align-items: end;
- margin-bottom: 24px;
- }
-
- .eyebrow {
- margin: 0 0 10px;
- color: var(--azionelab-accent);
- text-transform: uppercase;
- font-size: 0.78rem;
- font-weight: 700;
- }
-
- h1 {
- margin: 0;
- font-size: clamp(2rem, 4vw, 3rem);
+ margin-bottom: 28px;
}
.supporting {
margin: 0;
- color: var(--azionelab-muted);
- line-height: 1.6;
+ max-width: 34ch;
}
.show-grid {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
- gap: 20px;
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+ gap: 22px;
}
.status-panel,
@@ -131,9 +115,9 @@ import { ShowListItem, ShowsApiService } from '../services/shows-api.service';
.status-card {
max-width: 680px;
- border-radius: 8px;
+ border-radius: var(--azionelab-radius-md);
border: 1px solid var(--azionelab-border);
- background: var(--azionelab-surface);
+ background: var(--azionelab-surface-strong);
box-shadow: var(--azionelab-shadow);
}
@@ -155,15 +139,16 @@ import { ShowListItem, ShowsApiService } from '../services/shows-api.service';
.show-card {
display: flex;
flex-direction: column;
- min-height: 220px;
- border-radius: 8px;
+ min-height: 360px;
+ overflow: hidden;
+ border-radius: var(--azionelab-radius-md);
border: 1px solid var(--azionelab-border);
- background: var(--azionelab-surface);
+ background: linear-gradient(180deg, rgba(255, 253, 249, 0.98), rgba(250, 243, 233, 0.94));
box-shadow: var(--azionelab-shadow);
}
.show-image-wrap {
- aspect-ratio: 16 / 10;
+ aspect-ratio: 15 / 10;
overflow: hidden;
border-bottom: 1px solid var(--azionelab-border);
background:
@@ -176,15 +161,52 @@ import { ShowListItem, ShowsApiService } from '../services/shows-api.service';
height: 100%;
display: block;
object-fit: cover;
+ transition: transform 180ms ease;
+ }
+
+ .show-card:hover .show-image {
+ transform: scale(1.03);
+ }
+
+ .card-topline {
+ padding: 18px 18px 0;
+ }
+
+ .card-label {
+ display: inline-flex;
+ align-items: center;
+ min-height: 28px;
+ padding: 0 12px;
+ border-radius: 999px;
+ background: rgba(143, 51, 45, 0.08);
+ color: var(--azionelab-accent-strong);
+ font-size: 0.78rem;
+ font-weight: 700;
}
.show-card mat-card-content {
flex: 1;
}
+ .show-card mat-card-title,
+ .show-card mat-card-content,
+ .show-card mat-card-actions {
+ padding-left: 18px;
+ padding-right: 18px;
+ }
+
+ .show-card mat-card-title {
+ margin-top: 10px;
+ font-family: var(--azionelab-serif);
+ font-size: 1.45rem;
+ font-weight: 700;
+ line-height: 1.12;
+ }
+
.show-card p {
color: var(--azionelab-muted);
line-height: 1.6;
+ margin: 0;
}
@media (max-width: 860px) {
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 6e568db..3a10e0a 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -1,13 +1,28 @@
:root {
- --azionelab-bg: #f3eee6;
- --azionelab-surface: rgba(255, 255, 255, 0.78);
- --azionelab-surface-strong: rgba(255, 255, 255, 0.92);
- --azionelab-ink: #1e1b18;
- --azionelab-muted: #645b53;
- --azionelab-accent: #9f2f28;
- --azionelab-accent-strong: #7f211c;
- --azionelab-border: rgba(30, 27, 24, 0.12);
- --azionelab-shadow: 0 18px 48px rgba(46, 28, 18, 0.12);
+ --azionelab-bg: #f5efe6;
+ --azionelab-bg-strong: #efe4d4;
+ --azionelab-surface: rgba(255, 251, 246, 0.84);
+ --azionelab-surface-strong: rgba(255, 252, 248, 0.96);
+ --azionelab-surface-dark: #342924;
+ --azionelab-ink: #221c18;
+ --azionelab-ink-soft: #3a302a;
+ --azionelab-muted: #6f6258;
+ --azionelab-accent: #8f332d;
+ --azionelab-accent-strong: #6e251f;
+ --azionelab-accent-soft: #c88f64;
+ --azionelab-highlight: #c6a768;
+ --azionelab-border: rgba(34, 28, 24, 0.11);
+ --azionelab-border-strong: rgba(34, 28, 24, 0.18);
+ --azionelab-shadow: 0 18px 48px rgba(46, 28, 18, 0.10);
+ --azionelab-shadow-strong: 0 26px 64px rgba(46, 28, 18, 0.16);
+ --azionelab-radius-sm: 10px;
+ --azionelab-radius-md: 16px;
+ --azionelab-radius-lg: 24px;
+ --azionelab-shell-width: 1180px;
+ --azionelab-copy-width: 64ch;
+ --azionelab-section-gap: 28px;
+ --azionelab-sans: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
+ --azionelab-serif: Georgia, "Times New Roman", serif;
--azionelab-success-bg: #edf7ef;
--azionelab-success-ink: #1f5f2b;
--azionelab-success-border: rgba(46, 125, 50, 0.18);
@@ -23,12 +38,11 @@
html, body {
margin: 0;
min-height: 100%;
- font-family: "Manrope", "Segoe UI", sans-serif;
+ font-family: var(--azionelab-sans);
color: var(--azionelab-ink);
background:
- radial-gradient(circle at top right, rgba(159, 47, 40, 0.12), transparent 28%),
- radial-gradient(circle at left center, rgba(140, 116, 86, 0.14), transparent 35%),
- linear-gradient(180deg, #fbf7f2 0%, var(--azionelab-bg) 100%);
+ linear-gradient(180deg, rgba(143, 51, 45, 0.06), transparent 140px),
+ linear-gradient(180deg, #faf5ee 0%, var(--azionelab-bg) 52%, #efe4d6 100%);
}
body {
@@ -36,18 +50,79 @@ body {
}
h1, h2, h3 {
- font-family: "Fraunces", "Times New Roman", serif;
- letter-spacing: -0.02em;
+ font-family: var(--azionelab-serif);
+ font-weight: 700;
+ letter-spacing: 0;
+ color: var(--azionelab-ink);
+}
+
+h1 {
+ font-size: 2.5rem;
+ line-height: 1.02;
+}
+
+h2 {
+ font-size: 1.65rem;
+ line-height: 1.12;
+}
+
+h3 {
+ font-size: 1.15rem;
+ line-height: 1.2;
}
button, input, textarea {
font: inherit;
}
-.material-symbols-outlined {
- font-variation-settings:
- 'FILL' 0,
- 'wght' 500,
- 'GRAD' 0,
- 'opsz' 24;
+a {
+ color: var(--azionelab-accent-strong);
+}
+
+img {
+ max-width: 100%;
+}
+
+code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
+}
+
+.page {
+ width: min(100%, var(--azionelab-shell-width));
+ margin: 0 auto;
+}
+
+.eyebrow {
+ margin: 0 0 12px;
+ color: var(--azionelab-accent);
+ text-transform: uppercase;
+ font-size: 0.78rem;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+}
+
+.supporting {
+ color: var(--azionelab-muted);
+ line-height: 1.65;
+ max-width: var(--azionelab-copy-width);
+}
+
+@media (max-width: 900px) {
+ h1 {
+ font-size: 2.15rem;
+ }
+
+ h2 {
+ font-size: 1.45rem;
+ }
+}
+
+@media (max-width: 640px) {
+ h1 {
+ font-size: 1.9rem;
+ }
+
+ h2 {
+ font-size: 1.3rem;
+ }
}