chore: add project files and setup gitignore

This commit is contained in:
2026-05-08 10:25:14 +01:00
parent ea29a2f3f3
commit 70a62021a2
58 changed files with 13404 additions and 0 deletions

837
mockups/01_dashboard.html Normal file
View File

@@ -0,0 +1,837 @@
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ReservaMesa — Dashboard Mockup</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg-primary: #0F0E0C;
--bg-secondary: #1A1814;
--bg-tertiary: #252219;
--bg-hover: #2E2A22;
--brand: #D4891A;
--brand-light: #E8A832;
--brand-muted: #3D2E0F;
--status-pending: #F59E0B;
--status-confirmed: #10B981;
--status-seated: #3B82F6;
--status-cancelled: #EF4444;
--status-noshow: #8B5CF6;
--text-primary: #F5F0E8;
--text-secondary: #A09880;
--text-muted: #6B6355;
--border: #2A261E;
--border-strong: #3D3828;
--font-display: 'Playfair Display', serif;
--font-body: 'DM Sans', sans-serif;
--font-mono: 'DM Mono', monospace;
}
body {
font-family: var(--font-body);
background: var(--bg-primary);
color: var(--text-primary);
display: flex;
height: 100vh;
overflow: hidden;
font-size: 14px;
}
/* SIDEBAR */
.sidebar {
width: 220px;
flex-shrink: 0;
background: var(--bg-secondary);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
padding: 0;
}
.sidebar-logo {
padding: 20px 20px 16px;
border-bottom: 1px solid var(--border);
}
.sidebar-logo .logo-mark {
font-family: var(--font-display);
font-size: 18px;
font-weight: 700;
color: var(--brand-light);
letter-spacing: -0.3px;
}
.sidebar-logo .logo-sub {
font-size: 10px;
color: var(--text-muted);
letter-spacing: 1.5px;
text-transform: uppercase;
margin-top: 1px;
}
.sidebar-restaurant {
padding: 12px 16px;
margin: 10px;
background: var(--bg-tertiary);
border-radius: 8px;
border: 1px solid var(--border);
}
.restaurant-name {
font-weight: 600;
font-size: 12px;
color: var(--text-primary);
}
.restaurant-status {
font-size: 10px;
color: var(--status-confirmed);
display: flex;
align-items: center;
gap: 4px;
margin-top: 2px;
}
.dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.nav-section {
padding: 6px 10px 0;
flex: 1;
}
.nav-label {
font-size: 9px;
color: var(--text-muted);
letter-spacing: 1.5px;
text-transform: uppercase;
padding: 8px 8px 4px;
}
.nav-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 7px;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.15s;
font-size: 13px;
font-weight: 500;
margin-bottom: 1px;
}
.nav-item:hover { background: var(--bg-hover); color: var(--text-primary); }
.nav-item.active {
background: var(--brand-muted);
color: var(--brand-light);
}
.nav-icon { width: 16px; height: 16px; opacity: 0.9; }
.nav-badge {
margin-left: auto;
background: var(--brand);
color: #000;
font-size: 10px;
font-weight: 600;
padding: 1px 6px;
border-radius: 10px;
}
.sidebar-footer {
padding: 12px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
}
.avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--brand-muted);
border: 2px solid var(--brand);
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
color: var(--brand-light);
flex-shrink: 0;
}
.footer-info { flex: 1; min-width: 0; }
.footer-name { font-size: 12px; font-weight: 600; }
.footer-role { font-size: 10px; color: var(--text-muted); }
/* MAIN */
.main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
height: 56px;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 24px;
gap: 16px;
flex-shrink: 0;
}
.topbar-title {
font-family: var(--font-display);
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
flex: 1;
}
.topbar-date {
font-size: 12px;
color: var(--text-muted);
font-family: var(--font-mono);
}
.topbar-actions { display: flex; gap: 8px; }
.btn {
display: flex;
align-items: center;
gap: 6px;
padding: 7px 14px;
border-radius: 7px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
border: none;
font-family: var(--font-body);
transition: all 0.15s;
}
.btn-primary {
background: var(--brand);
color: #000;
}
.btn-ghost {
background: transparent;
color: var(--text-secondary);
border: 1px solid var(--border-strong);
}
.notif-btn {
width: 36px;
height: 36px;
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
}
.notif-badge {
position: absolute;
top: -3px;
right: -3px;
width: 14px;
height: 14px;
background: var(--brand);
border-radius: 50%;
font-size: 8px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
color: #000;
}
/* CONTENT */
.content {
flex: 1;
overflow-y: auto;
padding: 24px;
display: flex;
flex-direction: column;
gap: 20px;
}
/* STATS ROW */
.stats-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
}
.stat-card {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px;
}
.stat-label {
font-size: 11px;
color: var(--text-muted);
letter-spacing: 0.5px;
font-weight: 500;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 6px;
}
.stat-icon {
width: 14px;
height: 14px;
color: var(--brand);
}
.stat-value {
font-family: var(--font-display);
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
line-height: 1;
}
.stat-trend {
font-size: 11px;
margin-top: 6px;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 4px;
}
.trend-up { color: var(--status-confirmed); }
.trend-down { color: var(--status-cancelled); }
/* MAIN GRID */
.main-grid {
display: grid;
grid-template-columns: 1fr 320px;
gap: 16px;
flex: 1;
}
.panel {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
}
.panel-header {
padding: 14px 18px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
}
.panel-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
flex: 1;
}
.panel-action {
font-size: 11px;
color: var(--brand);
cursor: pointer;
}
/* TIMELINE */
.timeline {
padding: 4px 0;
overflow-y: auto;
max-height: 340px;
}
.time-slot {
display: flex;
gap: 12px;
padding: 0 18px;
}
.time-label {
font-family: var(--font-mono);
font-size: 11px;
color: var(--text-muted);
width: 40px;
flex-shrink: 0;
padding-top: 14px;
}
.slot-events {
flex: 1;
padding: 8px 0;
border-left: 1px solid var(--border);
padding-left: 12px;
display: flex;
flex-direction: column;
gap: 4px;
}
.event-chip {
padding: 6px 10px;
border-radius: 6px;
font-size: 12px;
display: flex;
align-items: center;
gap: 8px;
border-left: 3px solid transparent;
}
.event-chip.confirmed { background: rgba(16,185,129,0.1); border-color: var(--status-confirmed); }
.event-chip.pending { background: rgba(245,158,11,0.1); border-color: var(--status-pending); }
.event-chip.seated { background: rgba(59,130,246,0.1); border-color: var(--status-seated); }
.event-name { font-weight: 600; color: var(--text-primary); }
.event-meta { font-size: 11px; color: var(--text-secondary); margin-left: auto; }
/* STATUS DOTS */
.status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
flex-shrink: 0;
}
.status-dot.confirmed { background: var(--status-confirmed); }
.status-dot.pending { background: var(--status-pending); }
.status-dot.seated { background: var(--status-seated); }
/* SIDEBAR PANEL - UPCOMING */
.upcoming-list { padding: 0; }
.upcoming-item {
padding: 12px 18px;
border-bottom: 1px solid var(--border);
display: flex;
gap: 12px;
align-items: flex-start;
}
.upcoming-time {
font-family: var(--font-mono);
font-size: 12px;
font-weight: 500;
color: var(--brand);
width: 40px;
flex-shrink: 0;
}
.upcoming-info { flex: 1; }
.upcoming-name { font-size: 13px; font-weight: 600; }
.upcoming-sub { font-size: 11px; color: var(--text-muted); margin-top: 2px; }
.upcoming-badge {
font-size: 10px;
padding: 2px 8px;
border-radius: 10px;
font-weight: 600;
flex-shrink: 0;
}
.badge-confirmed { background: rgba(16,185,129,0.15); color: var(--status-confirmed); }
.badge-pending { background: rgba(245,158,11,0.15); color: var(--status-pending); }
/* MESAS ROW */
.mesas-grid {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 8px;
padding: 14px 18px;
}
.mesa-chip {
aspect-ratio: 1;
border-radius: 7px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 600;
border: 1px solid transparent;
cursor: pointer;
}
.mesa-chip.free {
background: rgba(16,185,129,0.1);
border-color: rgba(16,185,129,0.3);
color: var(--status-confirmed);
}
.mesa-chip.reserved {
background: rgba(245,158,11,0.1);
border-color: rgba(245,158,11,0.3);
color: var(--status-pending);
}
.mesa-chip.occupied {
background: rgba(59,130,246,0.1);
border-color: rgba(59,130,246,0.3);
color: var(--status-seated);
}
.mesa-num { font-size: 14px; }
.mesa-pax { font-size: 9px; opacity: 0.7; }
/* SCROLLBAR */
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
/* WATERMARK */
.mockup-label {
position: fixed;
bottom: 12px;
right: 16px;
font-size: 10px;
color: var(--text-muted);
font-family: var(--font-mono);
letter-spacing: 1px;
opacity: 0.5;
}
svg { display: block; }
</style>
</head>
<body>
<!-- SIDEBAR -->
<aside class="sidebar">
<div class="sidebar-logo">
<div class="logo-mark">ReservaMesa</div>
<div class="logo-sub">Dashboard</div>
</div>
<div style="padding: 10px;">
<div class="sidebar-restaurant">
<div class="restaurant-name">Restaurante Solar</div>
<div class="restaurant-status"><span class="dot"></span> Aberto agora</div>
</div>
</div>
<nav class="nav-section">
<div class="nav-label">Principal</div>
<div class="nav-item active">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
Dashboard
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m9 16 2 2 4-4"/></svg>
Reservas
<span class="nav-badge">12</span>
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/></svg>
Mesas
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
Calendário
</div>
<div class="nav-label" style="margin-top: 8px;">Análise</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg>
Analytics
</div>
<div class="nav-label" style="margin-top: 8px;">Gestão</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
Staff
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 0-14.14 0M4.93 19.07a10 10 0 0 0 14.14 0"/><path d="M12 2v4M12 18v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M2 12h4M18 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
Configurações
</div>
</nav>
<div class="sidebar-footer">
<div class="avatar">JS</div>
<div class="footer-info">
<div class="footer-name">João Silva</div>
<div class="footer-role">Gestor</div>
</div>
</div>
</aside>
<!-- MAIN CONTENT -->
<main class="main">
<!-- TOPBAR -->
<div class="topbar">
<div class="topbar-title">Dashboard</div>
<div class="topbar-date">Quarta, 6 Mai 2026</div>
<div class="topbar-actions">
<div class="notif-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#A09880" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
<div class="notif-badge">3</div>
</div>
<button class="btn btn-primary">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nova Reserva
</button>
</div>
</div>
<!-- CONTENT -->
<div class="content">
<!-- STATS -->
<div class="stats-row">
<div class="stat-card">
<div class="stat-label">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/></svg>
Reservas Hoje
</div>
<div class="stat-value">24</div>
<div class="stat-trend"><span class="trend-up">↑ 8</span> vs ontem</div>
</div>
<div class="stat-card">
<div class="stat-label">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
Ocupação Atual
</div>
<div class="stat-value">73<span style="font-size:18px;color:var(--text-secondary)">%</span></div>
<div class="stat-trend">11 de 16 mesas</div>
</div>
<div class="stat-card">
<div class="stat-label">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
Próximas Chegadas
</div>
<div class="stat-value">6</div>
<div class="stat-trend">nas próximas 2h</div>
</div>
<div class="stat-card">
<div class="stat-label">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="var(--status-cancelled)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
Cancelamentos
</div>
<div class="stat-value" style="color: var(--status-cancelled)">2</div>
<div class="stat-trend"><span class="trend-down">↓ 1</span> vs ontem</div>
</div>
</div>
<!-- MAIN GRID -->
<div class="main-grid">
<!-- LEFT: Timeline + Mesas -->
<div style="display: flex; flex-direction: column; gap: 16px;">
<!-- Timeline -->
<div class="panel">
<div class="panel-header">
<div class="panel-title">Timeline de Hoje</div>
<div class="panel-action">Ver todas →</div>
</div>
<div class="timeline">
<div class="time-slot">
<div class="time-label">18:00</div>
<div class="slot-events">
<div class="event-chip seated">
<span class="status-dot seated"></span>
<span class="event-name">Família Rodrigues</span>
<span class="event-meta">Mesa 4 · 5 pax</span>
</div>
<div class="event-chip seated">
<span class="status-dot seated"></span>
<span class="event-name">Pereira & Costa</span>
<span class="event-meta">Mesa 7 · 2 pax</span>
</div>
</div>
</div>
<div class="time-slot">
<div class="time-label">19:00</div>
<div class="slot-events">
<div class="event-chip confirmed">
<span class="status-dot confirmed"></span>
<span class="event-name">Ana Ferreira</span>
<span class="event-meta">Mesa 2 · 4 pax</span>
</div>
<div class="event-chip confirmed">
<span class="status-dot confirmed"></span>
<span class="event-name">Grupo Empresa XY</span>
<span class="event-meta">Mesa 12 · 8 pax</span>
</div>
<div class="event-chip pending">
<span class="status-dot pending"></span>
<span class="event-name">M. Santos</span>
<span class="event-meta">Mesa 6 · 3 pax</span>
</div>
</div>
</div>
<div class="time-slot">
<div class="time-label">20:30</div>
<div class="slot-events">
<div class="event-chip confirmed">
<span class="status-dot confirmed"></span>
<span class="event-name">Ricardo Nunes</span>
<span class="event-meta">Mesa 1 · 2 pax</span>
</div>
<div class="event-chip pending">
<span class="status-dot pending"></span>
<span class="event-name">Alves Family</span>
<span class="event-meta">Mesa 9 · 6 pax</span>
</div>
</div>
</div>
<div class="time-slot">
<div class="time-label">21:30</div>
<div class="slot-events">
<div class="event-chip confirmed">
<span class="status-dot confirmed"></span>
<span class="event-name">Sofia Lopes</span>
<span class="event-meta">Mesa 3 · 2 pax</span>
</div>
</div>
</div>
</div>
</div>
<!-- Mesas -->
<div class="panel">
<div class="panel-header">
<div class="panel-title">Mapa de Mesas</div>
<div style="display:flex;gap:12px;align-items:center;margin-right:8px">
<span style="font-size:10px;color:var(--status-confirmed);display:flex;align-items:center;gap:4px"><span class="dot" style="background:var(--status-confirmed)"></span>Livre</span>
<span style="font-size:10px;color:var(--status-pending);display:flex;align-items:center;gap:4px"><span class="dot" style="background:var(--status-pending)"></span>Reservada</span>
<span style="font-size:10px;color:var(--status-seated);display:flex;align-items:center;gap:4px"><span class="dot" style="background:var(--status-seated)"></span>Ocupada</span>
</div>
<div class="panel-action">Gerir →</div>
</div>
<div class="mesas-grid">
<div class="mesa-chip occupied"><span class="mesa-num">1</span><span class="mesa-pax">2p</span></div>
<div class="mesa-chip free"><span class="mesa-num">2</span><span class="mesa-pax">4p</span></div>
<div class="mesa-chip reserved"><span class="mesa-num">3</span><span class="mesa-pax">2p</span></div>
<div class="mesa-chip occupied"><span class="mesa-num">4</span><span class="mesa-pax">6p</span></div>
<div class="mesa-chip free"><span class="mesa-num">5</span><span class="mesa-pax">4p</span></div>
<div class="mesa-chip reserved"><span class="mesa-num">6</span><span class="mesa-pax">3p</span></div>
<div class="mesa-chip occupied"><span class="mesa-num">7</span><span class="mesa-pax">2p</span></div>
<div class="mesa-chip free"><span class="mesa-num">8</span><span class="mesa-pax">4p</span></div>
<div class="mesa-chip reserved"><span class="mesa-num">9</span><span class="mesa-pax">6p</span></div>
<div class="mesa-chip occupied"><span class="mesa-num">10</span><span class="mesa-pax">4p</span></div>
<div class="mesa-chip free"><span class="mesa-num">11</span><span class="mesa-pax">2p</span></div>
<div class="mesa-chip occupied"><span class="mesa-num">12</span><span class="mesa-pax">8p</span></div>
<div class="mesa-chip free"><span class="mesa-num">13</span><span class="mesa-pax">4p</span></div>
<div class="mesa-chip occupied"><span class="mesa-num">14</span><span class="mesa-pax">2p</span></div>
<div class="mesa-chip free"><span class="mesa-num">15</span><span class="mesa-pax">4p</span></div>
<div class="mesa-chip occupied"><span class="mesa-num">16</span><span class="mesa-pax">6p</span></div>
</div>
</div>
</div>
<!-- RIGHT: Upcoming -->
<div class="panel">
<div class="panel-header">
<div class="panel-title">Próximas Chegadas</div>
</div>
<div class="upcoming-list">
<div class="upcoming-item">
<div class="upcoming-time">19:00</div>
<div class="upcoming-info">
<div class="upcoming-name">Ana Ferreira</div>
<div class="upcoming-sub">Mesa 2 · 4 pessoas</div>
</div>
<div class="upcoming-badge badge-confirmed">Confirmada</div>
</div>
<div class="upcoming-item">
<div class="upcoming-time">19:00</div>
<div class="upcoming-info">
<div class="upcoming-name">Grupo Empresa XY</div>
<div class="upcoming-sub">Mesa 12 · 8 pessoas</div>
</div>
<div class="upcoming-badge badge-confirmed">Confirmada</div>
</div>
<div class="upcoming-item">
<div class="upcoming-time">19:00</div>
<div class="upcoming-info">
<div class="upcoming-name">M. Santos</div>
<div class="upcoming-sub">Mesa 6 · 3 pessoas</div>
</div>
<div class="upcoming-badge badge-pending">Pendente</div>
</div>
<div class="upcoming-item">
<div class="upcoming-time">20:30</div>
<div class="upcoming-info">
<div class="upcoming-name">Ricardo Nunes</div>
<div class="upcoming-sub">Mesa 1 · 2 pessoas</div>
</div>
<div class="upcoming-badge badge-confirmed">Confirmada</div>
</div>
<div class="upcoming-item">
<div class="upcoming-time">20:30</div>
<div class="upcoming-info">
<div class="upcoming-name">Alves Family</div>
<div class="upcoming-sub">Mesa 9 · 6 pessoas</div>
</div>
<div class="upcoming-badge badge-pending">Pendente</div>
</div>
<div class="upcoming-item">
<div class="upcoming-time">21:30</div>
<div class="upcoming-info">
<div class="upcoming-name">Sofia Lopes</div>
<div class="upcoming-sub">Mesa 3 · 2 pessoas</div>
</div>
<div class="upcoming-badge badge-confirmed">Confirmada</div>
</div>
<div style="padding: 14px 18px; border-top: 1px solid var(--border); margin-top: 4px;">
<div style="font-size:11px;color:var(--text-muted);margin-bottom:8px;font-weight:500">Ações Rápidas</div>
<div style="display:flex;flex-direction:column;gap:6px">
<button class="btn btn-primary" style="width:100%;justify-content:center;padding:9px 14px;font-size:12px">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nova Reserva Manual
</button>
<button class="btn btn-ghost" style="width:100%;justify-content:center;padding:9px 14px;font-size:12px">
Check-in Rápido
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<div class="mockup-label">MOCKUP v1.0 — RESERVAMESA DASHBOARD</div>
</body>
</html>

590
mockups/02_reservas.html Normal file
View File

@@ -0,0 +1,590 @@
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ReservaMesa — Gestão de Reservas Mockup</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg-primary: #0F0E0C;
--bg-secondary: #1A1814;
--bg-tertiary: #252219;
--bg-hover: #2E2A22;
--brand: #D4891A;
--brand-light: #E8A832;
--brand-muted: #3D2E0F;
--status-pending: #F59E0B;
--status-confirmed: #10B981;
--status-seated: #3B82F6;
--status-completed: #6B7280;
--status-cancelled: #EF4444;
--status-noshow: #8B5CF6;
--text-primary: #F5F0E8;
--text-secondary: #A09880;
--text-muted: #6B6355;
--border: #2A261E;
--border-strong: #3D3828;
--font-display: 'Playfair Display', serif;
--font-body: 'DM Sans', sans-serif;
--font-mono: 'DM Mono', monospace;
}
body {
font-family: var(--font-body);
background: var(--bg-primary);
color: var(--text-primary);
display: flex;
height: 100vh;
overflow: hidden;
font-size: 14px;
}
.sidebar {
width: 220px;
flex-shrink: 0;
background: var(--bg-secondary);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
}
.sidebar-logo {
padding: 20px 20px 16px;
border-bottom: 1px solid var(--border);
}
.logo-mark {
font-family: var(--font-display);
font-size: 18px;
font-weight: 700;
color: var(--brand-light);
}
.logo-sub {
font-size: 10px;
color: var(--text-muted);
letter-spacing: 1.5px;
text-transform: uppercase;
}
.sidebar-restaurant {
padding: 12px 16px;
margin: 10px;
background: var(--bg-tertiary);
border-radius: 8px;
border: 1px solid var(--border);
}
.restaurant-name { font-weight: 600; font-size: 12px; }
.restaurant-status { font-size: 10px; color: var(--status-confirmed); display: flex; align-items: center; gap: 4px; margin-top: 2px; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.nav-section { padding: 6px 10px 0; flex: 1; }
.nav-label { font-size: 9px; color: var(--text-muted); letter-spacing: 1.5px; text-transform: uppercase; padding: 8px 8px 4px; }
.nav-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 7px;
color: var(--text-secondary);
cursor: pointer;
font-size: 13px;
font-weight: 500;
margin-bottom: 1px;
}
.nav-item.active { background: var(--brand-muted); color: var(--brand-light); }
.nav-icon { width: 16px; height: 16px; }
.nav-badge { margin-left: auto; background: var(--brand); color: #000; font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: 10px; }
.sidebar-footer { padding: 12px; border-top: 1px solid var(--border); display: flex; align-items: center; gap: 10px; }
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--brand-muted); border: 2px solid var(--brand); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: var(--brand-light); }
.footer-info { flex: 1; }
.footer-name { font-size: 12px; font-weight: 600; }
.footer-role { font-size: 10px; color: var(--text-muted); }
.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.topbar {
height: 56px;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 24px;
gap: 16px;
flex-shrink: 0;
}
.topbar-title { font-family: var(--font-display); font-size: 18px; font-weight: 600; flex: 1; }
.topbar-date { font-size: 12px; color: var(--text-muted); font-family: var(--font-mono); }
.btn {
display: flex;
align-items: center;
gap: 6px;
padding: 7px 14px;
border-radius: 7px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
border: none;
font-family: var(--font-body);
}
.btn-primary { background: var(--brand); color: #000; }
.btn-ghost { background: transparent; color: var(--text-secondary); border: 1px solid var(--border-strong); }
.content { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 16px; }
/* FILTERS BAR */
.filters-bar {
display: flex;
gap: 10px;
align-items: center;
}
.search-box {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 8px 12px;
max-width: 280px;
}
.search-box input {
background: transparent;
border: none;
outline: none;
color: var(--text-primary);
font-family: var(--font-body);
font-size: 13px;
flex: 1;
}
.search-box input::placeholder { color: var(--text-muted); }
.filter-select {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 8px 12px;
color: var(--text-secondary);
font-family: var(--font-body);
font-size: 12px;
cursor: pointer;
outline: none;
}
.date-chip {
display: flex;
align-items: center;
gap: 6px;
background: var(--brand-muted);
border: 1px solid var(--brand);
border-radius: 8px;
padding: 8px 12px;
font-size: 12px;
color: var(--brand-light);
font-weight: 600;
cursor: pointer;
}
/* STATUS TABS */
.status-tabs {
display: flex;
gap: 2px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 9px;
padding: 4px;
width: fit-content;
}
.status-tab {
padding: 5px 14px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 5px;
}
.status-tab.active {
background: var(--bg-tertiary);
color: var(--text-primary);
}
.tab-count {
font-size: 10px;
padding: 1px 5px;
border-radius: 8px;
background: var(--bg-hover);
color: var(--text-secondary);
}
.status-tab.active .tab-count { background: var(--brand-muted); color: var(--brand); }
/* TABLE */
.reservations-panel {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
flex: 1;
}
.table-header {
display: grid;
grid-template-columns: 180px 1fr 90px 80px 120px 130px 160px;
padding: 10px 18px;
border-bottom: 1px solid var(--border);
background: var(--bg-tertiary);
gap: 12px;
}
.th {
font-size: 10px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.8px;
font-weight: 600;
}
.table-body { overflow-y: auto; }
.table-row {
display: grid;
grid-template-columns: 180px 1fr 90px 80px 120px 130px 160px;
padding: 13px 18px;
border-bottom: 1px solid var(--border);
gap: 12px;
align-items: center;
transition: background 0.12s;
}
.table-row:hover { background: var(--bg-hover); }
.table-row:last-child { border-bottom: none; }
.client-info {}
.client-name { font-size: 13px; font-weight: 600; }
.client-phone { font-size: 11px; color: var(--text-muted); margin-top: 1px; font-family: var(--font-mono); }
.time-cell { font-family: var(--font-mono); font-size: 13px; font-weight: 500; color: var(--brand-light); }
.pax-cell { font-size: 13px; color: var(--text-secondary); }
.mesa-cell { font-size: 13px; font-weight: 600; }
.status-badge {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 10px;
border-radius: 20px;
font-size: 11px;
font-weight: 600;
}
.status-badge.confirmed { background: rgba(16,185,129,0.12); color: var(--status-confirmed); }
.status-badge.pending { background: rgba(245,158,11,0.12); color: var(--status-pending); }
.status-badge.seated { background: rgba(59,130,246,0.12); color: var(--status-seated); }
.status-badge.completed { background: rgba(107,114,128,0.12); color: var(--status-completed); }
.status-badge.cancelled { background: rgba(239,68,68,0.12); color: var(--status-cancelled); }
.status-badge.noshow { background: rgba(139,92,246,0.12); color: var(--status-noshow); }
.status-dot-sm { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.actions-cell { display: flex; gap: 4px; }
.action-btn {
padding: 5px 8px;
border-radius: 6px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
border: 1px solid var(--border-strong);
background: transparent;
color: var(--text-secondary);
font-family: var(--font-body);
transition: all 0.1s;
}
.action-btn:hover { background: var(--bg-hover); color: var(--text-primary); }
.action-btn.confirm { color: var(--status-confirmed); border-color: rgba(16,185,129,0.3); }
.action-btn.seat { color: var(--status-seated); border-color: rgba(59,130,246,0.3); }
.action-btn.cancel { color: var(--status-cancelled); border-color: rgba(239,68,68,0.3); }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
.mockup-label {
position: fixed;
bottom: 12px;
right: 16px;
font-size: 10px;
color: var(--text-muted);
font-family: var(--font-mono);
letter-spacing: 1px;
opacity: 0.5;
}
svg { display: block; }
</style>
</head>
<body>
<aside class="sidebar">
<div class="sidebar-logo">
<div class="logo-mark">ReservaMesa</div>
<div class="logo-sub">Dashboard</div>
</div>
<div style="padding: 10px;">
<div class="sidebar-restaurant">
<div class="restaurant-name">Restaurante Solar</div>
<div class="restaurant-status"><span class="dot"></span> Aberto agora</div>
</div>
</div>
<nav class="nav-section">
<div class="nav-label">Principal</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
Dashboard
</div>
<div class="nav-item active">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m9 16 2 2 4-4"/></svg>
Reservas
<span class="nav-badge">12</span>
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/></svg>
Mesas
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
Calendário
</div>
<div class="nav-label" style="margin-top: 8px;">Análise</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg>
Analytics
</div>
<div class="nav-label" style="margin-top: 8px;">Gestão</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 0-14.14 0M4.93 19.07a10 10 0 0 0 14.14 0"/></svg>
Configurações
</div>
</nav>
<div class="sidebar-footer">
<div class="avatar">JS</div>
<div class="footer-info">
<div class="footer-name">João Silva</div>
<div class="footer-role">Gestor</div>
</div>
</div>
</aside>
<main class="main">
<div class="topbar">
<div class="topbar-title">Reservas</div>
<div class="topbar-date">Quarta, 6 Mai 2026</div>
<button class="btn btn-primary">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nova Reserva
</button>
</div>
<div class="content">
<!-- FILTERS -->
<div class="filters-bar">
<div class="search-box">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6B6355" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input placeholder="Pesquisar por nome ou telefone…">
</div>
<div class="date-chip">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
6 Mai 2026
</div>
<select class="filter-select">
<option>Zona: Todas</option>
<option>Interior</option>
<option>Exterior</option>
<option>VIP</option>
</select>
<select class="filter-select">
<option>Grupo: Todos</option>
<option>1-2 pessoas</option>
<option>3-4 pessoas</option>
<option>5+ pessoas</option>
</select>
<div style="margin-left: auto; display: flex; gap: 8px;">
<button class="btn btn-ghost">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Exportar CSV
</button>
</div>
</div>
<!-- STATUS TABS -->
<div class="status-tabs">
<div class="status-tab">Todas <span class="tab-count">24</span></div>
<div class="status-tab active">Pendentes <span class="tab-count">5</span></div>
<div class="status-tab">Confirmadas <span class="tab-count">12</span></div>
<div class="status-tab">Sentados <span class="tab-count">4</span></div>
<div class="status-tab">Concluídas <span class="tab-count">1</span></div>
<div class="status-tab">Canceladas <span class="tab-count">2</span></div>
</div>
<!-- TABLE -->
<div class="reservations-panel">
<div class="table-header">
<div class="th">Cliente</div>
<div class="th">Notas</div>
<div class="th">Hora</div>
<div class="th">Pax</div>
<div class="th">Mesa</div>
<div class="th">Estado</div>
<div class="th">Ações</div>
</div>
<div class="table-body">
<!-- ROW 1 - Pending -->
<div class="table-row">
<div class="client-info">
<div class="client-name">M. Santos</div>
<div class="client-phone">+351 912 345 678</div>
</div>
<div style="font-size:12px;color:var(--text-muted)">Alergia a frutos do mar</div>
<div class="time-cell">19:00</div>
<div class="pax-cell">3 pax</div>
<div class="mesa-cell">Mesa 6</div>
<div><span class="status-badge pending"><span class="status-dot-sm"></span>Pendente</span></div>
<div class="actions-cell">
<button class="action-btn confirm">Confirmar</button>
<button class="action-btn cancel"></button>
</div>
</div>
<!-- ROW 2 - Pending -->
<div class="table-row">
<div class="client-info">
<div class="client-name">Alves Family</div>
<div class="client-phone">+351 961 234 567</div>
</div>
<div style="font-size:12px;color:var(--text-muted)">Aniversário — bolo surpresa</div>
<div class="time-cell">20:30</div>
<div class="pax-cell">6 pax</div>
<div class="mesa-cell">Mesa 9</div>
<div><span class="status-badge pending"><span class="status-dot-sm"></span>Pendente</span></div>
<div class="actions-cell">
<button class="action-btn confirm">Confirmar</button>
<button class="action-btn cancel"></button>
</div>
</div>
<!-- ROW 3 - Pending -->
<div class="table-row">
<div class="client-info">
<div class="client-name">T. Barbosa</div>
<div class="client-phone">+351 934 567 890</div>
</div>
<div style="font-size:12px;color:var(--text-muted)"></div>
<div class="time-cell">19:30</div>
<div class="pax-cell">2 pax</div>
<div class="mesa-cell">Mesa 11</div>
<div><span class="status-badge pending"><span class="status-dot-sm"></span>Pendente</span></div>
<div class="actions-cell">
<button class="action-btn confirm">Confirmar</button>
<button class="action-btn cancel"></button>
</div>
</div>
<!-- ROW 4 - Confirmed -->
<div class="table-row">
<div class="client-info">
<div class="client-name">Ana Ferreira</div>
<div class="client-phone">+351 926 789 012</div>
</div>
<div style="font-size:12px;color:var(--text-muted)">Preferência zona silenciosa</div>
<div class="time-cell">19:00</div>
<div class="pax-cell">4 pax</div>
<div class="mesa-cell">Mesa 2</div>
<div><span class="status-badge confirmed"><span class="status-dot-sm"></span>Confirmada</span></div>
<div class="actions-cell">
<button class="action-btn seat">Sentar</button>
<button class="action-btn cancel"></button>
</div>
</div>
<!-- ROW 5 - Confirmed -->
<div class="table-row">
<div class="client-info">
<div class="client-name">Grupo Empresa XY</div>
<div class="client-phone">+351 213 456 789</div>
</div>
<div style="font-size:12px;color:var(--text-muted)">Jantar de negócios</div>
<div class="time-cell">19:00</div>
<div class="pax-cell">8 pax</div>
<div class="mesa-cell">Mesa 12</div>
<div><span class="status-badge confirmed"><span class="status-dot-sm"></span>Confirmada</span></div>
<div class="actions-cell">
<button class="action-btn seat">Sentar</button>
<button class="action-btn cancel"></button>
</div>
</div>
<!-- ROW 6 - Seated -->
<div class="table-row">
<div class="client-info">
<div class="client-name">Família Rodrigues</div>
<div class="client-phone">+351 917 654 321</div>
</div>
<div style="font-size:12px;color:var(--text-muted)">Cadeira de bebé necessária</div>
<div class="time-cell">18:00</div>
<div class="pax-cell">5 pax</div>
<div class="mesa-cell">Mesa 4</div>
<div><span class="status-badge seated"><span class="status-dot-sm"></span>Sentados</span></div>
<div class="actions-cell">
<button class="action-btn" style="color:var(--text-muted)">Concluir</button>
<button class="action-btn" style="color:var(--status-noshow)">No-show</button>
</div>
</div>
<!-- ROW 7 - Cancelled -->
<div class="table-row" style="opacity: 0.5;">
<div class="client-info">
<div class="client-name">C. Marques</div>
<div class="client-phone">+351 963 258 741</div>
</div>
<div style="font-size:12px;color:var(--text-muted)">Cancelou 2h antes</div>
<div class="time-cell">20:00</div>
<div class="pax-cell">2 pax</div>
<div class="mesa-cell">Mesa 5</div>
<div><span class="status-badge cancelled"><span class="status-dot-sm"></span>Cancelada</span></div>
<div class="actions-cell">
<button class="action-btn">Ver</button>
</div>
</div>
</div>
</div>
</div>
</main>
<div class="mockup-label">MOCKUP v1.0 — RESERVAMESA RESERVAS</div>
</body>
</html>

554
mockups/03_mesas.html Normal file
View File

@@ -0,0 +1,554 @@
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ReservaMesa — Mapa de Mesas Mockup</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg-primary: #0F0E0C;
--bg-secondary: #1A1814;
--bg-tertiary: #252219;
--bg-hover: #2E2A22;
--brand: #D4891A;
--brand-light: #E8A832;
--brand-muted: #3D2E0F;
--status-confirmed: #10B981;
--status-pending: #F59E0B;
--status-seated: #3B82F6;
--status-cancelled: #EF4444;
--text-primary: #F5F0E8;
--text-secondary: #A09880;
--text-muted: #6B6355;
--border: #2A261E;
--border-strong: #3D3828;
--font-display: 'Playfair Display', serif;
--font-body: 'DM Sans', sans-serif;
--font-mono: 'DM Mono', monospace;
}
body { font-family: var(--font-body); background: var(--bg-primary); color: var(--text-primary); display: flex; height: 100vh; overflow: hidden; font-size: 14px; }
.sidebar { width: 220px; flex-shrink: 0; background: var(--bg-secondary); border-right: 1px solid var(--border); display: flex; flex-direction: column; }
.sidebar-logo { padding: 20px 20px 16px; border-bottom: 1px solid var(--border); }
.logo-mark { font-family: var(--font-display); font-size: 18px; font-weight: 700; color: var(--brand-light); }
.logo-sub { font-size: 10px; color: var(--text-muted); letter-spacing: 1.5px; text-transform: uppercase; }
.sidebar-restaurant { padding: 12px 16px; margin: 10px; background: var(--bg-tertiary); border-radius: 8px; border: 1px solid var(--border); }
.restaurant-name { font-weight: 600; font-size: 12px; }
.restaurant-status { font-size: 10px; color: var(--status-confirmed); display: flex; align-items: center; gap: 4px; margin-top: 2px; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.nav-section { padding: 6px 10px 0; flex: 1; }
.nav-label { font-size: 9px; color: var(--text-muted); letter-spacing: 1.5px; text-transform: uppercase; padding: 8px 8px 4px; }
.nav-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 7px; color: var(--text-secondary); cursor: pointer; font-size: 13px; font-weight: 500; margin-bottom: 1px; }
.nav-item.active { background: var(--brand-muted); color: var(--brand-light); }
.nav-icon { width: 16px; height: 16px; }
.nav-badge { margin-left: auto; background: var(--brand); color: #000; font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: 10px; }
.sidebar-footer { padding: 12px; border-top: 1px solid var(--border); display: flex; align-items: center; gap: 10px; }
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--brand-muted); border: 2px solid var(--brand); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: var(--brand-light); }
.footer-name { font-size: 12px; font-weight: 600; }
.footer-role { font-size: 10px; color: var(--text-muted); }
.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.topbar { height: 56px; background: var(--bg-secondary); border-bottom: 1px solid var(--border); display: flex; align-items: center; padding: 0 24px; gap: 16px; flex-shrink: 0; }
.topbar-title { font-family: var(--font-display); font-size: 18px; font-weight: 600; flex: 1; }
.topbar-date { font-size: 12px; color: var(--text-muted); font-family: var(--font-mono); }
.btn { display: flex; align-items: center; gap: 6px; padding: 7px 14px; border-radius: 7px; font-size: 12px; font-weight: 600; cursor: pointer; border: none; font-family: var(--font-body); }
.btn-primary { background: var(--brand); color: #000; }
.btn-ghost { background: transparent; color: var(--text-secondary); border: 1px solid var(--border-strong); }
/* CONTENT */
.content { flex: 1; display: flex; overflow: hidden; }
/* FLOOR PLAN AREA */
.floorplan-area { flex: 1; padding: 20px; overflow: auto; position: relative; }
.zone-label {
font-size: 10px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1.5px;
font-weight: 600;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
}
.zone-label::after {
content: '';
flex: 1;
height: 1px;
background: var(--border);
}
.floor-section {
margin-bottom: 24px;
}
.tables-layout {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
/* TABLE SHAPES */
.table-item {
position: relative;
cursor: pointer;
transition: transform 0.15s;
}
.table-item:hover { transform: scale(1.04); }
.table-rect {
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 2px solid transparent;
position: relative;
}
.table-rect.free {
background: rgba(16,185,129,0.08);
border-color: rgba(16,185,129,0.4);
}
.table-rect.reserved {
background: rgba(245,158,11,0.08);
border-color: rgba(245,158,11,0.4);
}
.table-rect.occupied {
background: rgba(59,130,246,0.08);
border-color: rgba(59,130,246,0.4);
}
.table-rect.selected {
box-shadow: 0 0 0 3px var(--brand);
border-color: var(--brand);
background: var(--brand-muted);
}
.table-num {
font-family: var(--font-display);
font-size: 18px;
font-weight: 700;
}
.table-rect.free .table-num { color: var(--status-confirmed); }
.table-rect.reserved .table-num { color: var(--status-pending); }
.table-rect.occupied .table-num { color: var(--status-seated); }
.table-rect.selected .table-num { color: var(--brand-light); }
.table-pax {
font-size: 10px;
margin-top: 2px;
opacity: 0.7;
}
.table-rect.free .table-pax { color: var(--status-confirmed); }
.table-rect.reserved .table-pax { color: var(--status-pending); }
.table-rect.occupied .table-pax { color: var(--status-seated); }
/* Chairs decoration */
.chair {
position: absolute;
width: 10px;
height: 10px;
border-radius: 3px;
background: currentColor;
opacity: 0.25;
}
/* LEGEND */
.legend {
display: flex;
gap: 16px;
align-items: center;
padding: 12px 20px;
border-bottom: 1px solid var(--border);
background: var(--bg-secondary);
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: var(--text-secondary);
}
.legend-dot { width: 10px; height: 10px; border-radius: 3px; }
.legend-dot.free { background: rgba(16,185,129,0.3); border: 1.5px solid var(--status-confirmed); }
.legend-dot.reserved { background: rgba(245,158,11,0.3); border: 1.5px solid var(--status-pending); }
.legend-dot.occupied { background: rgba(59,130,246,0.3); border: 1.5px solid var(--status-seated); }
/* DETAIL PANEL */
.detail-panel {
width: 280px;
background: var(--bg-secondary);
border-left: 1px solid var(--border);
display: flex;
flex-direction: column;
overflow: hidden;
}
.detail-header {
padding: 16px 18px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
}
.detail-title {
font-family: var(--font-display);
font-size: 16px;
font-weight: 600;
flex: 1;
}
.mesa-status-indicator {
padding: 4px 10px;
border-radius: 20px;
font-size: 11px;
font-weight: 600;
}
.mesa-status-indicator.reserved { background: rgba(245,158,11,0.15); color: var(--status-pending); }
.detail-body { padding: 16px 18px; flex: 1; display: flex; flex-direction: column; gap: 14px; }
.detail-row {
display: flex;
flex-direction: column;
gap: 3px;
}
.detail-label { font-size: 10px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.8px; }
.detail-value { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.detail-value.mono { font-family: var(--font-mono); color: var(--brand-light); }
.detail-divider { height: 1px; background: var(--border); margin: 4px 0; }
.client-card {
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px;
}
.client-card-name { font-size: 14px; font-weight: 700; }
.client-card-phone { font-size: 12px; color: var(--text-muted); font-family: var(--font-mono); margin-top: 2px; }
.client-card-note { font-size: 11px; color: var(--brand); margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.detail-actions { padding: 14px 18px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 6px; }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
.mockup-label { position: fixed; bottom: 12px; right: 16px; font-size: 10px; color: var(--text-muted); font-family: var(--font-mono); letter-spacing: 1px; opacity: 0.5; }
svg { display: block; }
</style>
</head>
<body>
<aside class="sidebar">
<div class="sidebar-logo">
<div class="logo-mark">ReservaMesa</div>
<div class="logo-sub">Dashboard</div>
</div>
<div style="padding: 10px;">
<div class="sidebar-restaurant">
<div class="restaurant-name">Restaurante Solar</div>
<div class="restaurant-status"><span class="dot"></span> Aberto agora</div>
</div>
</div>
<nav class="nav-section">
<div class="nav-label">Principal</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
Dashboard
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m9 16 2 2 4-4"/></svg>
Reservas
<span class="nav-badge">12</span>
</div>
<div class="nav-item active">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/></svg>
Mesas
</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
Calendário
</div>
<div class="nav-label" style="margin-top:8px">Análise</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg>
Analytics
</div>
<div class="nav-label" style="margin-top:8px">Gestão</div>
<div class="nav-item">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 0-14.14 0"/></svg>
Configurações
</div>
</nav>
<div class="sidebar-footer">
<div class="avatar">JS</div>
<div style="flex:1"><div class="footer-name">João Silva</div><div class="footer-role">Gestor</div></div>
</div>
</aside>
<main class="main">
<div class="topbar">
<div class="topbar-title">Mapa de Mesas</div>
<div class="topbar-date">Quarta, 6 Mai 2026 · 19:00</div>
<div style="display:flex;gap:8px">
<button class="btn btn-ghost">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
Editar Layout
</button>
<button class="btn btn-primary">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Adicionar Mesa
</button>
</div>
</div>
<!-- LEGEND -->
<div class="legend">
<span style="font-size:11px;color:var(--text-muted);font-weight:600;margin-right:4px">Estado das Mesas:</span>
<div class="legend-item"><div class="legend-dot free"></div>Livre (5)</div>
<div class="legend-item"><div class="legend-dot reserved"></div>Reservada (6)</div>
<div class="legend-item"><div class="legend-dot occupied"></div>Ocupada (5)</div>
<div style="margin-left:auto;font-size:11px;color:var(--text-muted)">Clique numa mesa para ver detalhes</div>
</div>
<div class="content">
<!-- FLOOR PLAN -->
<div class="floorplan-area">
<!-- Interior Zone -->
<div class="floor-section">
<div class="zone-label">Interior</div>
<div class="tables-layout">
<!-- Table 1 - Occupied (2p) -->
<div class="table-item">
<div class="table-rect occupied" style="width:72px;height:72px">
<div class="table-num">1</div>
<div class="table-pax">2 pax</div>
</div>
</div>
<!-- Table 2 - Free (4p) -->
<div class="table-item">
<div class="table-rect free" style="width:88px;height:72px">
<div class="table-num">2</div>
<div class="table-pax">4 pax</div>
</div>
</div>
<!-- Table 3 - Reserved (selected) -->
<div class="table-item">
<div class="table-rect selected" style="width:72px;height:72px">
<div class="table-num" style="color:var(--brand-light)">3</div>
<div class="table-pax" style="color:var(--brand)">2 pax</div>
</div>
</div>
<!-- Table 4 - Occupied (6p) - long table -->
<div class="table-item">
<div class="table-rect occupied" style="width:140px;height:72px">
<div class="table-num">4</div>
<div class="table-pax">6 pax</div>
</div>
</div>
<!-- Table 5 - Free (4p) -->
<div class="table-item">
<div class="table-rect free" style="width:88px;height:72px">
<div class="table-num">5</div>
<div class="table-pax">4 pax</div>
</div>
</div>
<!-- Table 6 - Reserved (3p) -->
<div class="table-item">
<div class="table-rect reserved" style="width:80px;height:72px">
<div class="table-num">6</div>
<div class="table-pax">3 pax</div>
</div>
</div>
<!-- Table 7 - Occupied (2p) -->
<div class="table-item">
<div class="table-rect occupied" style="width:72px;height:72px">
<div class="table-num">7</div>
<div class="table-pax">2 pax</div>
</div>
</div>
<!-- Table 8 - Free (4p) -->
<div class="table-item">
<div class="table-rect free" style="width:88px;height:72px">
<div class="table-num">8</div>
<div class="table-pax">4 pax</div>
</div>
</div>
</div>
</div>
<!-- Exterior Zone -->
<div class="floor-section">
<div class="zone-label">Exterior / Esplanada</div>
<div class="tables-layout">
<!-- Table 9 - Reserved (6p) -->
<div class="table-item">
<div class="table-rect reserved" style="width:120px;height:72px">
<div class="table-num">9</div>
<div class="table-pax">6 pax</div>
</div>
</div>
<!-- Table 10 - Occupied (4p) -->
<div class="table-item">
<div class="table-rect occupied" style="width:88px;height:72px">
<div class="table-num">10</div>
<div class="table-pax">4 pax</div>
</div>
</div>
<!-- Table 11 - Reserved (2p) -->
<div class="table-item">
<div class="table-rect reserved" style="width:72px;height:72px">
<div class="table-num">11</div>
<div class="table-pax">2 pax</div>
</div>
</div>
<!-- Table 12 - Occupied (8p) - banquet -->
<div class="table-item">
<div class="table-rect occupied" style="width:180px;height:80px">
<div class="table-num">12</div>
<div class="table-pax">8 pax · Grupo Empresa XY</div>
</div>
</div>
</div>
</div>
<!-- VIP Zone -->
<div class="floor-section">
<div class="zone-label">VIP / Privado</div>
<div class="tables-layout">
<!-- Table 13 - Free (4p) -->
<div class="table-item">
<div class="table-rect free" style="width:88px;height:72px; border-style: dashed;">
<div class="table-num">13</div>
<div class="table-pax">4 pax</div>
</div>
</div>
<!-- Table 14 - Reserved (4p) -->
<div class="table-item">
<div class="table-rect reserved" style="width:88px;height:72px; border-style: dashed;">
<div class="table-num">14</div>
<div class="table-pax">4 pax</div>
</div>
</div>
<!-- Table 15 - Free (2p) -->
<div class="table-item">
<div class="table-rect free" style="width:72px;height:72px; border-style: dashed;">
<div class="table-num">15</div>
<div class="table-pax">2 pax</div>
</div>
</div>
<!-- Table 16 - Occupied (6p) -->
<div class="table-item">
<div class="table-rect occupied" style="width:120px;height:72px; border-style: dashed;">
<div class="table-num">16</div>
<div class="table-pax">6 pax</div>
</div>
</div>
</div>
</div>
</div>
<!-- DETAIL PANEL - shown when table selected -->
<div class="detail-panel">
<div class="detail-header">
<div class="detail-title">Mesa 3</div>
<div class="mesa-status-indicator reserved">Reservada</div>
</div>
<div class="detail-body">
<div class="detail-row">
<div class="detail-label">Zona</div>
<div class="detail-value">Interior</div>
</div>
<div class="detail-row">
<div class="detail-label">Capacidade</div>
<div class="detail-value">2 pessoas</div>
</div>
<div class="detail-divider"></div>
<div class="detail-label" style="margin-bottom: 6px;">Reserva Atual</div>
<div class="detail-row">
<div class="detail-label">Hora</div>
<div class="detail-value mono">21:30</div>
</div>
<div class="client-card">
<div class="client-card-name">Sofia Lopes</div>
<div class="client-card-phone">+351 925 147 369</div>
<div class="client-card-note">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline;margin-right:4px"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
Jantar especial — aniversário
</div>
</div>
<div class="detail-row">
<div class="detail-label">Grupo</div>
<div class="detail-value">2 pessoas</div>
</div>
</div>
<div class="detail-actions">
<button class="btn btn-primary" style="width:100%;justify-content:center;font-size:12px;padding:9px">
Confirmar Reserva
</button>
<button class="btn btn-ghost" style="width:100%;justify-content:center;font-size:12px;padding:9px">
Ver Detalhe Completo
</button>
<button class="btn" style="width:100%;justify-content:center;font-size:12px;padding:9px;color:var(--status-cancelled);border:1px solid rgba(239,68,68,0.3);">
Cancelar Reserva
</button>
</div>
</div>
</div>
</main>
<div class="mockup-label">MOCKUP v1.0 — RESERVAMESA MESAS</div>
</body>
</html>