Files
promo_steakhouse/src/styles.css
T
lukas ecbc42846b
CI / test (push) Successful in 5m16s
CI / deploy (push) Successful in 32s
CI / build (push) Successful in 4m2s
✨ first version
2026-08-28 10:24:15 +02:00

1916 lines
35 KiB
CSS

@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600&display=swap');
:root {
--bg: #17120f;
--bg-raised: #1e1712;
--line: #3a2f26;
--text: #f3ead9;
--text-muted: #c9baa3;
--gold: #c9a15a;
--gold-bright: #e0bb78;
--ember: #a8402c;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
/* `clip`, not `hidden` — `hidden` on both axes-owners forces the browser to also
compute `overflow-y: auto` on each, which creates two nested scroll containers
and breaks `position: sticky` for everything on the page. */
html,
body {
overflow-x: clip;
}
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: 'Inter', system-ui, sans-serif;
line-height: 1.5;
}
h1,
h2,
h3 {
font-family: 'Fraunces', Georgia, serif;
font-weight: 600;
letter-spacing: 0.01em;
margin: 0;
}
a {
color: var(--text);
}
.page {
max-width: 68rem;
margin: 0 auto;
padding: 0 1.5rem;
}
/* Header */
.site-header {
position: sticky;
top: 0;
z-index: 50;
background: var(--bg);
border-bottom: 1px solid var(--line);
display: flex;
align-content: center;
justify-content: center;
}
.site-header-inner {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
row-gap: 0.5rem;
gap: 1rem;
padding: 1.25rem 1.5rem;
min-height: 5rem;
width: 100%;
max-width: 120rem
}
.wordmark {
font-family: 'Fraunces', Georgia, serif;
font-size: 1.15rem;
letter-spacing: 0.03em;
color: var(--text);
text-decoration: none;
}
.wordmark span {
color: var(--gold-bright);
}
.site-nav {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.75rem 1.25rem;
list-style: none;
margin: 0;
padding: 0;
font-size: 0.9rem;
}
.site-nav a {
color: var(--text-muted);
text-decoration: none;
}
.site-nav a:hover {
color: var(--text);
}
.staff-login-link {
color: var(--text-muted);
font-size: 0.8rem;
text-decoration: none;
opacity: 0.75;
}
.staff-login-link:hover {
color: var(--text);
opacity: 1;
}
/* Hero */
.hero {
position: relative;
padding: 4.5rem 1.5rem 5rem;
text-align: center;
background:
radial-gradient(ellipse at top, rgba(200, 90, 50, 0.2), transparent 60%),
linear-gradient(rgba(23, 18, 15, 0.55), rgba(23, 18, 15, 0.93)),
url('/hero-interior.jpg');
background-size: auto, auto, cover;
background-position: center, center, center 55%;
background-repeat: no-repeat;
border-bottom: 1px solid var(--line);
overflow: hidden;
}
.hero-flame {
width: 4rem;
height: 4rem;
margin: 0 auto 1.5rem;
color: var(--ember);
}
.hero h1 {
font-size: clamp(2.25rem, 5vw, 3.5rem);
color: var(--text);
}
.hero h1 span {
color: var(--text);
}
.hero p {
max-width: 34rem;
margin: 1rem auto 0;
color: var(--text-muted);
font-size: 1.05rem;
}
.hero-actions {
margin-top: 2rem;
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.btn {
display: inline-block;
font: inherit;
font-weight: 600;
padding: 0.75rem 1.5rem;
border-radius: 0.25rem;
text-decoration: none;
cursor: pointer;
border: 1px solid transparent;
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-primary {
background: var(--gold);
color: #201709;
}
.btn-primary:hover {
background: var(--gold-bright);
}
.btn-secondary {
background: transparent;
border-color: var(--line);
color: var(--text);
}
.btn-secondary:hover {
border-color: var(--text-muted);
color: var(--text);
}
.btn-ghost {
background: none;
border-color: transparent;
color: var(--text-muted);
}
.btn-ghost:hover {
color: var(--text);
background: rgba(243, 234, 217, 0.06);
}
/* Sections */
.section {
padding: 4rem 0;
border-bottom: 1px solid var(--line);
}
.section:last-of-type {
border-bottom: none;
}
.section-heading {
font-size: 1.75rem;
margin-bottom: 0.5rem;
}
.section-kicker {
display: block;
font-size: 0.8rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 0.75rem;
}
.section-grid {
display: grid;
grid-template-columns: 1fr 1.3fr;
gap: 3rem;
}
.section-grid > * {
min-width: 0;
}
@media (max-width: 46rem) {
.section-grid {
grid-template-columns: 1fr;
}
}
/* Opening hours */
.hours-list {
list-style: none;
margin: 1.5rem 0 0;
padding: 0;
border-top: 1px solid var(--line);
}
.hours-list li {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: 0.65rem 0;
border-bottom: 1px solid var(--line);
color: var(--text-muted);
}
.hours-list li.today {
color: var(--text);
font-weight: 600;
}
.hours-list .day {
font-family: 'Fraunces', Georgia, serif;
}
.hours-closed {
font-style: italic;
}
/* Reservation form */
.reservation-form {
display: flex;
flex-direction: column;
gap: 1.1rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.5rem;
padding: 1.75rem;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.1rem;
}
.form-row > * {
min-width: 0;
}
@media (max-width: 30rem) {
.form-row {
grid-template-columns: 1fr;
}
}
.reservation-form label {
display: flex;
flex-direction: column;
gap: 0.35rem;
min-width: 0;
font-weight: 500;
font-size: 0.9rem;
color: var(--text-muted);
}
.datetime-field {
display: flex;
flex-wrap: wrap;
gap: 0.6rem
}
.date-input-group {
position: relative;
flex: 1 1 10rem;
min-width: 10rem;
}
.date-input-group input[type='text'] {
width: 100%;
padding-right: 2.5rem;
}
.datetime-field select {
flex: 1 1 6.5rem;
min-width: 6.5rem;
}
.datetime-field select:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.date-picker-trigger {
position: absolute;
top: 50%;
right: 0.3rem;
transform: translateY(-50%);
display: flex;
align-items: center;
justify-content: center;
width: 1.9rem;
height: 1.9rem;
padding: 0;
border: none;
border-radius: 0.25rem;
background: transparent;
cursor: pointer;
}
.date-picker-trigger svg {
flex-shrink: 0;
width: 18px;
height: 18px;
color: var(--text);
}
.date-picker-trigger:hover,
.date-picker-trigger[aria-expanded='true'] {
anchor-name: --anchor-date-time;
}
.password-field {
position: relative;
}
.password-field input {
padding-right: 2.5rem;
}
.password-toggle {
position: absolute;
top: 50%;
right: 0.3rem;
transform: translateY(-50%);
display: flex;
align-items: center;
justify-content: center;
width: 1.9rem;
height: 1.9rem;
padding: 0;
border: none;
border-radius: 0.25rem;
background: transparent;
color: var(--text-muted);
cursor: pointer;
}
.password-toggle:hover {
color: var(--text);
}
.password-toggle svg {
flex-shrink: 0;
width: 18px;
height: 18px;
}
.date-popover-backdrop {
display: contents;
}
.date-popover {
position: absolute;
position-anchor: --anchor-date-time;
left: calc(anchor(center) - 100%);
z-index: 20;
padding: 0.6rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.4rem;
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
overflow: hidden;
}
@media (max-width: 30rem) {
.date-popover-backdrop {
display: flex;
position: fixed;
inset: 0;
z-index: 100;
align-items: center;
justify-content: center;
padding: 1rem;
background: rgba(0, 0, 0, 0.6);
}
.date-popover {
position: static;
width: 100%;
padding: 1rem;
box-shadow: 0 20px 45px rgba(0, 0, 0, 0.45);
animation: confirm-dialog-fade-in 0.15s ease-out;
}
.date-popover-header {
margin-bottom: 0.6rem;
font-size: 1rem;
}
.date-popover-header button {
width: 3rem;
height: 3rem;
font-size: 1.8rem;
}
.date-popover-weekdays span,
.date-popover-grid button {
font-size: 0.95rem;
display: flex;
align-items: center;
justify-content: center;
width: 100% !important;
}
.date-popover-grid button {
aspect-ratio: unset;
padding: 0.5rem 0;
}
}
.date-popover-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.4rem;
color: var(--text);
font-size: 0.8rem;
font-weight: 500;
}
.date-popover-header button {
width: 1.5rem;
height: 1.5rem;
padding: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 0.25rem;
background: transparent;
color: var(--text-muted);
font: inherit;
font-size: 1.2rem;
cursor: pointer;
}
.date-popover-header button:hover:not(:disabled) {
color: var(--text);
}
.date-popover-header button:disabled {
opacity: 0.35;
cursor: not-allowed;
}
.date-popover-weekdays,
.date-popover-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 0.1rem;
span {
width: 1.8rem;
}
button {
display: flex;
align-items: center;
justify-content: center;
}
}
.date-popover-weekdays {
margin-bottom: 0.15rem;
font-size: 0.68rem;
color: var(--text-muted);
text-align: center;
}
.date-popover-grid button {
aspect-ratio: 1;
min-width: 0;
min-height: 0;
padding: 0;
margin: 0;
align-self: auto;
border: none;
border-radius: 50%;
background: transparent;
color: var(--text);
font: inherit;
font-size: 0.78rem;
cursor: pointer;
}
.date-popover-grid button:hover:not(:disabled) {
background: var(--line);
}
.date-popover-grid button:disabled {
color: var(--text-muted);
opacity: 0.35;
cursor: not-allowed;
}
.date-popover-grid button.is-selected {
background: var(--text);
color: var(--bg);
font-weight: 600;
}
.reservation-form input,
.reservation-form select,
.reservation-form textarea {
width: 100%;
min-width: 0;
font-family: inherit;
font-size: 1rem;
padding: 0.6rem 0.7rem;
border: 1px solid var(--line);
border-radius: 0.3rem;
background: var(--bg);
color: var(--text);
}
.reservation-form textarea {
resize: vertical;
min-height: 4.5rem;
}
.reservation-form input:focus,
.reservation-form select:focus,
.reservation-form textarea:focus {
outline: none;
border-color: var(--gold);
box-shadow: 0 0 0 2px rgba(201, 161, 90, 0.25);
}
/* Overrides the generic `.reservation-form input` box styling above — that rule
assumes text-like inputs and would otherwise stretch radios/checkboxes into
full-width bordered rectangles instead of native controls. */
.reservation-form input[type='radio'],
.reservation-form input[type='checkbox'] {
width: 1rem;
height: 1rem;
padding: 0;
border: none;
background: none;
accent-color: var(--gold);
}
.table-display-fieldset {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 0;
padding: 0;
border: none;
}
.table-display-fieldset legend {
padding: 0;
margin-bottom: 0.35rem;
font-weight: 500;
font-size: 0.9rem;
color: var(--text-muted);
}
.reservation-form .radio-option {
flex-direction: row;
align-items: center;
gap: 0.5rem;
font-weight: 400;
font-size: 0.95rem;
color: var(--text);
}
/* `.radio-option` centers its input against a single-line label, which breaks
down for the consent checkbox's multi-line sentence — the checkbox needs to
sit at the top of the text instead of drifting to its vertical center. */
.reservation-form .consent-option {
align-items: flex-start;
}
.reservation-form .consent-option input {
margin-top: 0.2rem;
flex-shrink: 0;
}
/* `:not(.btn)` keeps this scoped to the plain submit buttons — anything already
using the `.btn` component (Abbrechen, Bearbeiten, Löschen, …) styles itself
and shouldn't be overridden here (a previous version of this rule beat
`.btn-secondary` on specificity and left its hover text unreadable).
`:not(.date-popover *):not(.date-picker-trigger):not(.table-marker):not(.password-toggle)`
keeps it off the calendar's own buttons, the overview-photo markers, and the
show-password toggle — they live inside this form too, and without this
exclusion this rule's specificity beats their own button styles. */
.reservation-form
button:not(.btn):not(.date-popover *):not(.date-picker-trigger):not(.table-marker):not(.password-toggle) {
align-self: flex-start;
font: inherit;
font-weight: 600;
padding: 0.7rem 1.5rem;
border: none;
border-radius: 0.3rem;
background: var(--gold);
color: #201709;
cursor: pointer;
}
.reservation-form
button:not(.btn):not(.date-popover *):not(.date-picker-trigger):not(.table-marker):not(.password-toggle):hover:not(
:disabled
) {
background: var(--gold-bright);
}
.reservation-form
button:not(.btn):not(.date-popover *):not(.date-picker-trigger):not(.table-marker):not(.password-toggle):disabled {
opacity: 0.6;
cursor: not-allowed;
}
.field-hint {
margin: -0.4rem 0 0;
font-size: 0.82rem;
color: var(--text-muted);
}
.field-hint a {
color: inherit;
text-decoration: underline;
}
.message {
margin: 0;
padding: 0.65rem 0.9rem;
border-radius: 0.3rem;
font-size: 0.9rem;
}
.message-error {
background: #3a1414;
color: #f3a9a9;
border: 1px solid #5c1f1f;
}
.message-success {
background: #17301c;
color: #a9d9b4;
border: 1px solid #23502c;
}
.staff-page-messages {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 1.25rem 0 0;
}
/* Contact */
.contact-list {
list-style: none;
margin: 1.5rem 0 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.9rem;
}
.contact-list li {
display: flex;
gap: 0.75rem;
color: var(--text-muted);
}
.contact-list .label {
color: var(--text-muted);
min-width: 6rem;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.06em;
padding-top: 0.15rem;
}
/* Footer */
.site-footer {
padding: 2.5rem 1.5rem;
text-align: center;
color: var(--text-muted);
font-size: 0.85rem;
}
.site-footer .wordmark {
display: block;
margin-bottom: 0.5rem;
}
.footer-nav {
display: flex;
gap: 1.25rem;
justify-content: center;
margin-top: 0.75rem;
}
.footer-nav a {
color: var(--text-muted);
text-decoration: none;
}
.footer-nav a:hover {
color: var(--text);
}
/* Staff dashboard */
.staff-page {
min-height: 100vh;
}
/* Sticks the topbar and the tabs below it together as one unit — sticking them
separately would need the tabs' `top` hardcoded to the topbar's height, which
shifts whenever the topbar wraps onto two lines on narrow screens. */
.staff-nav {
position: sticky;
top: 0;
z-index: 50;
background: var(--bg);
}
.staff-topbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 1rem;
padding: 1.25rem 1.5rem;
/* Matches `.site-header-inner`'s floor so both bars read as the same height —
this bar's own content is already taller, so the min-height is a no-op here
and never shrinks it. */
min-height: 5rem;
border-bottom: 1px solid var(--line);
}
.staff-topbar-right {
display: flex;
align-items: center;
gap: 1rem;
color: var(--text-muted);
font-size: 0.9rem;
}
.staff-topbar-right .btn {
padding: 0.5rem 1rem;
}
.staff-tabs-bar {
border-bottom: 1px solid var(--line);
}
.staff-tabs {
display: flex;
gap: 1.5rem;
max-width: 68rem;
margin: 0 auto;
padding: 0 1.5rem;
overflow: scroll hidden;
&::-webkit-scrollbar {
display: none;
}
}
.staff-tab {
display: inline-flex;
align-items: center;
padding: 0.9rem 0.1rem;
margin-bottom: -1px;
color: var(--text-muted);
font-size: 0.9rem;
font-weight: 500;
text-decoration: none;
border-bottom: 2px solid transparent;
}
.staff-tab:hover {
color: var(--text);
}
.staff-tab.is-active {
color: var(--gold-bright);
border-bottom-color: var(--gold-bright);
view-transition-name: staff-tab-active;
}
::view-transition-group(staff-tab-active) {
animation-duration: 0.22s;
animation-timing-function: ease;
}
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
.bar-chart-bar {
transition: none;
}
.confirm-dialog {
animation: none;
}
.reservation-confirmed-flame {
animation: none;
}
}
.staff-main {
padding: 3rem 1.5rem 4rem;
}
.staff-subheading {
font-size: 1.35rem;
margin: 2.5rem 0 1.25rem;
}
.staff-stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
margin-top: 1.5rem;
}
@media (max-width: 40rem) {
.staff-stats {
grid-template-columns: repeat(2, 1fr);
}
}
.stat-card {
display: flex;
flex-direction: column;
gap: 0.35rem;
padding: 1.25rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.5rem;
}
.stat-value {
font-family: 'Fraunces', Georgia, serif;
font-size: 1.75rem;
color: var(--text);
}
.stat-label {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
}
.charts-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1.5rem;
margin-top: 1.5rem;
}
@media (max-width: 48rem) {
.charts-grid {
grid-template-columns: 1fr;
}
}
.chart-card {
padding: 1.25rem 1.25rem 1rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.5rem;
}
.chart-card-header {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 0.75rem;
margin-bottom: 1.25rem;
}
.chart-title {
font-family: 'Inter', system-ui, sans-serif;
font-size: 0.9rem;
font-weight: 600;
margin: 0;
}
.chart-toggle {
display: inline-flex;
gap: 0.15rem;
padding: 0.15rem;
background: var(--bg);
border: 1px solid var(--line);
border-radius: 0.4rem;
}
.chart-toggle button {
padding: 0.3rem 0.65rem;
border: none;
border-radius: 0.3rem;
background: transparent;
color: var(--text-muted);
font: inherit;
font-size: 0.8rem;
cursor: pointer;
}
.chart-toggle button:hover {
color: var(--text);
}
.chart-toggle button.is-active {
background: var(--gold);
color: var(--bg);
}
.bar-chart-plot {
position: relative;
height: 10rem;
}
.bar-chart-gridline {
position: absolute;
left: 0;
right: 0;
border-top: 1px solid var(--line);
}
.bar-chart-tick {
position: absolute;
left: 0;
bottom: 0;
transform: translateY(50%);
font-size: 0.7rem;
color: var(--text-muted);
}
.bar-chart-bars {
position: absolute;
inset: 0;
display: flex;
align-items: flex-end;
gap: 0.4rem;
padding-left: 1.5rem;
}
.bar-chart-col {
position: relative;
flex: 1 1 0;
height: 100%;
min-width: 0;
display: flex;
align-items: flex-end;
justify-content: center;
outline: none;
}
.bar-chart-bar {
position: relative;
width: 100%;
max-width: 1.5rem;
margin-top: auto;
min-height: 2px;
background: var(--gold);
border-radius: 4px 4px 0 0;
transition: background-color 0.15s ease, height 0.2s ease;
}
.bar-chart-col:hover .bar-chart-bar,
.bar-chart-col:focus-visible .bar-chart-bar {
background: var(--gold-bright);
}
.bar-chart-col:focus-visible .bar-chart-bar {
outline: 2px solid var(--gold-bright);
outline-offset: 2px;
}
.bar-chart-value {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 0.3rem;
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
}
.bar-chart-tooltip {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%) translateY(-0.4rem);
margin-bottom: 0.5rem;
padding: 0.4rem 0.6rem;
background: var(--bg);
border: 1px solid var(--line);
border-radius: 0.35rem;
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
color: var(--text);
font-size: 0.75rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.12s ease;
z-index: 1;
}
.bar-chart-col:hover .bar-chart-tooltip,
.bar-chart-col:focus-visible .bar-chart-tooltip {
opacity: 1;
}
.bar-chart-axis {
display: flex;
gap: 0.4rem;
padding-left: 1.5rem;
margin-top: 0.5rem;
}
.bar-chart-axis-label {
flex: 1 1 0;
min-width: 0;
text-align: center;
font-size: 0.7rem;
color: var(--text-muted);
}
.staff-form-section {
max-width: 36rem;
}
.form-actions {
display: flex;
gap: 0.75rem;
align-items: center;
}
.form-actions .btn {
font: inherit;
padding: 0.7rem 1.5rem;
}
.staff-table-section {
margin-top: 2.5rem;
}
.table-toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-bottom: 1.25rem;
}
.table-toolbar .staff-subheading {
margin: 0;
}
.table-filters {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-bottom: 1.25rem;
}
.table-filters input,
.table-filters select {
font-family: inherit;
font-size: 0.9rem;
padding: 0.55rem 0.7rem;
border: 1px solid var(--line);
border-radius: 0.3rem;
background: var(--bg);
color: var(--text);
}
.table-filters input:focus,
.table-filters select:focus {
outline: none;
border-color: var(--gold);
box-shadow: 0 0 0 2px rgba(201, 161, 90, 0.25);
}
.table-search {
flex: 1 1 16rem;
min-width: 0;
}
.table-scroll {
overflow-x: auto;
border: 1px solid var(--line);
border-radius: 0.5rem;
&::-webkit-scrollbar {
display: none;
}
}
.reservations-table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
.reservations-table th,
.reservations-table td {
padding: 0.85rem 1rem;
text-align: left;
white-space: nowrap;
border-bottom: 1px solid var(--line);
}
.reservations-table th {
color: var(--text-muted);
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.06em;
background: var(--bg-raised);
}
.reservations-table tbody tr:last-child td {
border-bottom: none;
}
.reservations-table tr.is-editing {
background: rgba(243, 234, 217, 0.06);
}
.reservations-table-clickable tbody tr:hover {
background: rgba(243, 234, 217, 0.05);
cursor: pointer;
}
.reservations-table .muted {
color: var(--text-muted);
font-size: 0.8rem;
}
.reservations-table .message-cell {
max-width: 16rem;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 40rem) {
/* On mobile the column headers are hidden and each row becomes a card laid
out on a 2-column grid — related fields (table nr/name, party/status)
sit side by side, while date/time, customer and message span full width. */
.reservations-table thead {
display: none;
}
.reservations-table,
.reservations-table tbody {
display: block;
width: 100%;
}
.reservations-table tbody {
padding: 0.75rem;
}
.reservations-table tbody tr {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: 1rem;
row-gap: 0.6rem;
padding: 0.9rem 1rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.5rem;
}
.reservations-table tbody tr + tr {
margin-top: 0.75rem;
}
.reservations-table td {
display: block;
max-width: none;
padding: 0;
white-space: normal;
word-break: break-word;
border-bottom: none;
}
.reservations-table td[data-label]::before {
content: attr(data-label);
display: block;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
margin-bottom: 0.15rem;
}
.reservations-table .cell-datetime,
.reservations-table .cell-customer,
.reservations-table .message-cell {
grid-column: 1 / -1;
}
.reservations-table .message-cell {
max-width: none;
overflow: visible;
text-overflow: unset;
}
}
.status-badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 9.5rem;
padding: 0.2rem 0.6rem;
border-radius: 999px;
font: inherit;
font-size: 0.75rem;
font-weight: 600;
white-space: nowrap;
}
.status-badge.status-confirmed {
background: rgba(201, 161, 90, 0.15);
color: var(--gold-bright);
border: 1px solid rgba(201, 161, 90, 0.35);
}
.status-badge.status-no_show {
background: #3a1414;
color: #f3a9a9;
border: 1px solid #5c1f1f;
}
.status-badge.status-completed {
background: #17301c;
color: #a9d9b4;
border: 1px solid #23502c;
}
/* A single grouped 3-way toggle track, not three loose floating pills — the
active segment gets a solid fill, the other two stay flat text until hovered. */
.status-options {
display: flex;
gap: 0.25rem;
margin: 0 0 1.5rem;
padding: 0.25rem;
background: var(--bg);
border: 1px solid var(--line);
border-radius: 999px;
}
.status-option {
flex: 1;
cursor: pointer;
padding: 0.45rem 0.75rem;
transition:
background-color 0.15s ease,
color 0.15s ease;
}
/* `.status-badge.status-option` — matches `.status-badge.status-confirmed` (etc.)
on specificity so this actually wins and overrides their fixed `width`/`border`,
rather than losing to them by cascade order. */
.status-badge.status-option {
width: auto;
border: none;
}
.status-option:disabled {
cursor: not-allowed;
}
.status-option:hover:not(:disabled):not(.is-active) {
color: var(--text);
background: rgba(243, 234, 217, 0.06);
}
.status-option.is-active.status-confirmed {
background: var(--gold);
color: #201709;
}
.status-option.is-active.status-no_show {
background: var(--ember);
color: #fdeceb;
}
.status-option.is-active.status-completed {
background: #2f7a3c;
color: #eafcee;
}
.table-actions {
display: flex;
gap: 0.5rem;
}
.table-actions .btn {
font: inherit;
padding: 0.4rem 0.85rem;
font-size: 0.8rem;
}
.action-menu-trigger {
display: flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
padding: 0;
border: none;
border-radius: 0.3rem;
background: transparent;
color: var(--text-muted);
cursor: pointer;
}
.action-menu-trigger:hover,
.action-menu-trigger[aria-expanded='true'] {
background: var(--line);
color: var(--text);
}
/* `top`/`right` are set inline per instance (src/components/action-menu.tsx) —
the panel is portaled to <body> and positioned from a measured rect so it
isn't clipped by `.table-scroll`'s (forced) `overflow-y: auto`. `z-index` is
above `.confirm-dialog-backdrop` (100) since the menu can now be opened from
inside the reservation detail modal, not just from a table row. */
.action-menu-panel {
position: fixed;
z-index: 110;
display: flex;
flex-direction: column;
gap: 0.35rem;
min-width: 11rem;
padding: 0.5rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.4rem;
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
}
.action-menu-panel .btn {
display: block;
width: 100%;
text-align: left;
font: inherit;
padding: 0.5rem 0.7rem;
font-size: 0.85rem;
}
.table-thumb {
width: 3rem;
height: 3rem;
border-radius: 0.3rem;
object-fit: cover;
display: block;
}
.table-thumb-empty {
background: var(--bg);
border: 1px dashed var(--line);
}
.table-image-field {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
}
.table-image-field input[type='file'] {
flex: 1 1 12rem;
min-width: 0;
padding: 0.4rem;
font-size: 0.85rem;
}
.table-image-preview {
width: 4.5rem;
height: 4.5rem;
border-radius: 0.3rem;
object-fit: cover;
flex-shrink: 0;
}
.table-preview {
width: 100%;
max-height: 14rem;
object-fit: cover;
border-radius: 0.4rem;
border: 1px solid var(--line);
}
/* A fixed aspect ratio (rather than sizing to the photo's own dimensions) so a
marker's percentage position lines up with the same spot on the image whether
it's rendered here, in the admin editor, or at a different screen width —
`object-fit: contain` (not `cover`) keeps the whole photo, and thus every
marker coordinate, on-screen instead of letting some get cropped away. */
.table-overview-wrap {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
border-radius: 0.4rem;
border: 1px solid var(--line);
background: var(--bg);
overflow: hidden;
cursor: pointer;
}
.table-overview-wrap.is-busy {
cursor: wait;
opacity: 0.7;
}
.table-overview-image {
display: block;
width: 100%;
height: 100%;
object-fit: contain;
pointer-events: none;
}
/* A classic map-pin: a square with three rounded corners (50% 50% 50% 0 leaves
the bottom-left one sharp), rotated -45deg around that exact sharp corner so
the corner itself — not the box center — lands on the `left`/`top` coordinate
and becomes the pin's tip, with the round "head" swinging up above it. */
.table-marker {
position: absolute;
width: 1.6rem;
height: 1.6rem;
transform: translate(0, -100%) rotate(-45deg);
transform-origin: 0 100%;
border: none;
border-radius: 50% 50% 50% 0;
padding: 0;
background: var(--bg-raised);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.45), inset 0 0 0 1.5px var(--gold);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.table-marker-label {
transform: rotate(45deg);
font: inherit;
font-size: 0.62rem;
font-weight: 700;
color: var(--text);
}
.table-marker.is-selected,
.table-marker.is-active {
background: var(--gold);
transform: translate(0, -100%) rotate(-45deg) scale(1.2);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
}
.table-marker.is-selected .table-marker-label,
.table-marker.is-active .table-marker-label {
color: #201709;
}
.btn-danger {
background: transparent;
border-color: #5c1f1f;
color: #f3a9a9;
}
.btn-danger:hover:not(:disabled) {
background: #3a1414;
}
.btn-danger:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.confirm-dialog-backdrop {
position: fixed;
inset: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
padding: 1.5rem;
background: rgba(0, 0, 0, 0.6);
}
.confirm-dialog {
width: 100%;
max-width: 24rem;
padding: 1.5rem;
background: var(--bg-raised);
border: 1px solid var(--line);
border-radius: 0.5rem;
box-shadow: 0 20px 45px rgba(0, 0, 0, 0.45);
animation: confirm-dialog-fade-in 0.15s ease-out;
}
@keyframes confirm-dialog-fade-in {
from {
opacity: 0;
transform: translateY(-8px) scale(0.98);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.confirm-dialog-title {
font-size: 1.15rem;
margin: 0 0 0.75rem;
}
.confirm-dialog-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
margin-bottom: 0.75rem;
}
.confirm-dialog-header .confirm-dialog-title {
margin: 0;
}
.confirm-dialog-header-actions {
display: flex;
align-items: center;
gap: 0.4rem;
flex-shrink: 0;
}
.confirm-dialog-header-actions .btn {
padding: 0.45rem 0.9rem;
font-size: 0.85rem;
}
.confirm-dialog-message {
margin: 0 0 1.25rem;
color: var(--text-muted);
}
.confirm-dialog-message strong {
color: var(--text);
font-weight: 700;
}
.confirm-dialog-warning {
display: flex;
align-items: flex-start;
gap: 0.6rem;
margin: 0 0 1.5rem;
padding: 0.75rem 0.9rem;
border: 1px solid #5c1f1f;
border-radius: 0.4rem;
background: rgba(168, 64, 44, 0.14);
color: #f3a9a9;
}
.confirm-dialog-warning svg {
flex-shrink: 0;
margin-top: 0.1rem;
color: #f3a9a9;
}
.confirm-dialog-warning span {
font-size: 0.85rem;
font-weight: 600;
line-height: 1.4;
}
.confirm-dialog-actions {
display: flex;
justify-content: flex-end;
gap: 0.75rem;
}
/* Puts "Bearbeiten" and "Schließen" on opposite ends of the row instead of the
usual right-aligned button cluster, since they aren't a confirm/cancel pair. */
.confirm-dialog-actions-split {
justify-content: space-between;
}
.confirm-dialog-actions .btn {
padding: 0.6rem 1.25rem;
font-size: 0.9rem;
}
/* Beats the rule above on source order (same specificity), so it reads as a
plain text action instead of a button-shaped one. */
.confirm-dialog-actions .btn-ghost {
padding: 0;
font-size: 0.8rem;
text-decoration: underline;
}
.reservation-confirmed-dialog {
max-width: 26rem;
text-align: center;
}
.reservation-confirmed-flame {
width: 3.25rem;
height: 3.25rem;
margin: 0 auto 1rem;
color: var(--ember);
animation: reservation-confirmed-flicker 2.2s ease-in-out infinite;
}
@keyframes reservation-confirmed-flicker {
0%,
100% {
transform: rotate(0deg) scale(1);
color: var(--ember);
}
25% {
transform: rotate(-3deg) scale(1.05);
}
50% {
transform: rotate(2deg) scale(0.97);
color: var(--gold-bright);
}
75% {
transform: rotate(-2deg) scale(1.03);
}
}
.reservation-confirmed-title {
margin: 0 0 0.5rem;
font-size: 1.5rem;
color: var(--gold-bright);
}
.reservation-confirmed-message {
margin: 0 0 1.5rem;
color: var(--text-muted);
}
.reservation-confirmed-dialog .detail-list {
text-align: left;
}
.reservation-confirmed-footnote {
margin: 0 0 1.5rem;
font-size: 0.82rem;
color: var(--text-muted);
}
.reservation-confirmed-footnote strong {
color: var(--text);
font-weight: 600;
}
.reservation-confirmed-dialog .confirm-dialog-actions {
justify-content: center;
}
.success-modal {
max-width: 22rem;
text-align: center;
}
.success-modal-icon {
display: flex;
align-items: center;
justify-content: center;
width: 2.75rem;
height: 2.75rem;
margin: 0 auto 1rem;
border: 1px solid var(--gold);
border-radius: 50%;
color: var(--gold-bright);
}
.success-modal .confirm-dialog-title {
margin-bottom: 0.5rem;
}
.success-modal .confirm-dialog-message {
margin-bottom: 1.5rem;
}
.success-modal .confirm-dialog-actions {
justify-content: center;
}
.reservation-detail-dialog {
max-width: 28rem;
}
.reservation-detail-dialog .table-preview {
margin-bottom: 1.25rem;
}
.reservation-dialog-editing {
max-width: 34rem;
}
/* The dialog card already provides the background/border/padding — strip
`.reservation-form`'s own so the form doesn't render as a card-in-a-card. */
.reservation-form-dialog {
background: none;
border: none;
padding: 0;
}
.detail-list {
display: flex;
flex-direction: column;
gap: 0.6rem;
margin: 0 0 1.25rem;
}
.detail-list > div {
display: flex;
justify-content: space-between;
gap: 1rem;
padding-bottom: 0.6rem;
border-bottom: 1px solid var(--line);
}
.detail-list dt {
color: var(--text-muted);
font-size: 0.8rem;
}
.detail-list dd {
margin: 0;
text-align: right;
font-weight: 500;
}
.detail-message {
margin: 0 0 1.5rem;
padding-top: 0.6rem;
border-top: 1px solid var(--line);
}
.detail-message-label {
display: block;
margin-bottom: 0.35rem;
color: var(--text-muted);
font-size: 0.8rem;
}
.detail-message p {
margin: 0;
white-space: pre-wrap;
}
.empty-state {
color: var(--text-muted);
font-style: italic;
}
.staff-login-page {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 1.5rem;
}
.staff-login-form {
width: 100%;
max-width: 24rem;
}
.staff-login-heading {
text-align: center;
}
.staff-login-heading .section-heading {
font-size: 1.5rem;
}
.back-link {
display: inline-flex;
align-items: center;
gap: 0.4rem;
margin-bottom: 1.75rem;
color: var(--text-muted);
font-size: 0.85rem;
text-decoration: none;
}
.back-link svg {
transition: transform 0.15s ease;
}
.back-link:hover {
color: var(--text);
}
.back-link:hover svg {
transform: translateX(-3px);
}
/* Legal page */
.legal-page {
padding: 3.5rem 0 4rem;
}
.legal-page h1 {
font-size: 2.25rem;
margin-bottom: 2rem;
}
.legal-page h2 {
font-size: 1.25rem;
color: var(--text);
margin: 2.25rem 0 0.75rem;
}
.legal-page h3 {
font-size: 1rem;
margin: 1.5rem 0 0.5rem;
}
.legal-page p {
color: var(--text-muted);
max-width: 42rem;
}