feat(frontend): mockup-uri realiste ale aplicației în landing
- logo Romfast mărit; iconița aplicației (indigo) lângă „ROA Space" - „ROA Space" în culoarea reală a aplicației (#6366f1) - înlocuit secțiunile benefit cu screenshot-uri fidele: Dashboard, Spaces, calendar - cardul din hero adus la același stil de screenshot al aplicației - spațiere mai strânsă și curățat CSS-ul nefolosit Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
<div class="brand">
|
||||
<img src="/romfast_logo.png" alt="Romfast" class="brand-logo" />
|
||||
<span class="brand-divider"></span>
|
||||
<span class="brand-app-icon"><LayoutDashboard :size="26" /></span>
|
||||
<span class="brand-text">
|
||||
<span class="brand-word">ROA Space</span>
|
||||
<span class="brand-sub">Rezervări de spații</span>
|
||||
@@ -49,106 +50,183 @@
|
||||
<p class="hero-note">Cont gratuit, gata în câteva secunde.</p>
|
||||
</div>
|
||||
|
||||
<!-- Interactive booking card -->
|
||||
<div class="demo-card">
|
||||
<div class="demo-head">
|
||||
<div class="demo-head-title">
|
||||
<span class="demo-room">Sala Aurora</span>
|
||||
<span class="demo-meta">azi · 6 locuri</span>
|
||||
<!-- Interactive booking card (same app style as the mockups below) -->
|
||||
<div class="app-window demo-window">
|
||||
<div class="app-bar">
|
||||
<span class="app-dot"></span><span class="app-dot"></span><span class="app-dot"></span>
|
||||
<span class="app-url">roa.space/spaces/aurora-room</span>
|
||||
</div>
|
||||
<span class="badge badge-success"><span class="badge-live-dot"></span>Live</span>
|
||||
<div class="demo-app">
|
||||
<div class="demo-head">
|
||||
<div>
|
||||
<h4>Aurora Room</h4>
|
||||
<p class="app-subtitle">Today · 6 seats</p>
|
||||
</div>
|
||||
<span class="demo-live"><span class="demo-live-dot"></span>Live</span>
|
||||
</div>
|
||||
<div class="demo-slots">
|
||||
<button
|
||||
v-for="(slot, i) in slots"
|
||||
:key="i"
|
||||
type="button"
|
||||
class="slot"
|
||||
class="demo-slot"
|
||||
:class="{ selected: i === selected }"
|
||||
@click="selected = i"
|
||||
>
|
||||
<span class="slot-time">{{ slot.time }}</span>
|
||||
<span class="slot-title" :class="{ free: !slot.booked }">{{ slot.title }}</span>
|
||||
<span class="badge" :class="slot.booked ? 'badge-success' : 'badge-neutral'">
|
||||
<span class="badge-dot"></span>{{ slot.statusText }}
|
||||
</span>
|
||||
<span class="demo-slot-time">{{ slot.time }}</span>
|
||||
<span class="demo-slot-title" :class="{ free: !slot.booked }">{{ slot.title }}</span>
|
||||
<span class="demo-slot-badge" :class="slot.booked ? 'booked' : 'free'">{{ slot.statusText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="demo-foot">
|
||||
<span class="demo-selected">{{ selectedLabel }}</span>
|
||||
<button type="button" class="btn btn-primary btn-sm">Rezervă</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- BENEFIT 1 -->
|
||||
<section class="band">
|
||||
<div class="split">
|
||||
<div class="mini-card">
|
||||
<div class="mini-card-head">
|
||||
<span class="dot-red"></span>
|
||||
<span class="mini-card-title">Sala Aurora — 10:00</span>
|
||||
<span class="mini-card-meta">deja rezervată</span>
|
||||
</div>
|
||||
<div class="conflict">
|
||||
<span class="conflict-x">✕</span>
|
||||
<span>Nu poți rezerva — se suprapune cu ședința lui Andrei.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Nicio sală rezervată de două ori.</h2>
|
||||
<p>
|
||||
Dacă un interval e prins, ROA Space pur și simplu nu te lasă să treci peste.
|
||||
Fără suprapuneri, fără discuții „dar eu credeam că e liberă".
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- BENEFIT 2 -->
|
||||
<section id="cum" class="split split-steps">
|
||||
<div>
|
||||
<h2>Trei pași, și ai sala.</h2>
|
||||
<p>
|
||||
Nimeni nu are timp de formulare. Alegi, pui ora, gata — durează mai puțin decât
|
||||
să scrii mesajul pe grup.
|
||||
</p>
|
||||
</div>
|
||||
<div class="steps">
|
||||
<div v-for="step in steps" :key="step.n" class="step">
|
||||
<span class="step-n">{{ step.n }}</span>
|
||||
<div>
|
||||
<h4>{{ step.title }}</h4>
|
||||
<p>{{ step.body }}</p>
|
||||
<span class="app-btn">Reserve</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- BENEFIT 3 -->
|
||||
<section class="band">
|
||||
<div class="split">
|
||||
<!-- PRODUCT SHOWCASE -->
|
||||
<section id="cum" class="showcase">
|
||||
<!-- Screen 1 — Dashboard -->
|
||||
<div class="app-window">
|
||||
<div class="app-bar">
|
||||
<span class="app-dot"></span><span class="app-dot"></span><span class="app-dot"></span>
|
||||
<span class="app-url">roa.space/dashboard</span>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<aside class="app-side">
|
||||
<div class="app-brand"><LayoutDashboard :size="20" /><span>ROA Space</span></div>
|
||||
<div class="app-nav-label">Main</div>
|
||||
<nav class="app-nav">
|
||||
<span
|
||||
v-for="item in appNav"
|
||||
:key="item.label"
|
||||
class="app-nav-link"
|
||||
:class="{ active: item.label === 'Dashboard' }"
|
||||
>
|
||||
<component :is="item.icon" :size="18" />
|
||||
<span>{{ item.label }}</span>
|
||||
</span>
|
||||
</nav>
|
||||
</aside>
|
||||
<div class="app-content">
|
||||
<div class="app-head">
|
||||
<h3>Dashboard</h3>
|
||||
<span class="app-btn"><Plus :size="15" />Book a Space</span>
|
||||
</div>
|
||||
<div class="app-pills">
|
||||
<span v-for="p in dashPills" :key="p.label" class="app-pill" :class="p.tone">
|
||||
<span class="app-pill-num">{{ p.num }}</span>{{ p.label }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="app-group">Today</div>
|
||||
<div class="app-rows">
|
||||
<div v-for="b in dashRows" :key="b.title" class="app-row" :class="b.st">
|
||||
<span class="app-row-time">{{ b.time }}</span>
|
||||
<span class="app-row-space">{{ b.space }}</span>
|
||||
<span class="app-row-title">{{ b.title }}</span>
|
||||
<span class="app-row-badge" :class="b.st">{{ b.status }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Screen 2 — Spaces -->
|
||||
<div class="app-window">
|
||||
<div class="app-bar">
|
||||
<span class="app-dot"></span><span class="app-dot"></span><span class="app-dot"></span>
|
||||
<span class="app-url">roa.space/spaces</span>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<aside class="app-side">
|
||||
<div class="app-brand"><LayoutDashboard :size="20" /><span>ROA Space</span></div>
|
||||
<div class="app-nav-label">Main</div>
|
||||
<nav class="app-nav">
|
||||
<span
|
||||
v-for="item in appNav"
|
||||
:key="item.label"
|
||||
class="app-nav-link"
|
||||
:class="{ active: item.label === 'Spaces' }"
|
||||
>
|
||||
<component :is="item.icon" :size="18" />
|
||||
<span>{{ item.label }}</span>
|
||||
</span>
|
||||
</nav>
|
||||
</aside>
|
||||
<div class="app-content">
|
||||
<div class="app-head app-head-col">
|
||||
<div>
|
||||
<h2>Spațiile publice, fără înregistrare obligatorie.</h2>
|
||||
<p>
|
||||
Marchezi un spațiu ca public și poate fi rezervat și fără cont — cu nume, e-mail
|
||||
și ora dorită. Cine vrea își face cont, cine nu, rezervă direct. Tu păstrezi
|
||||
controlul: fiecare cerere ajunge tot la tine spre aprobare.
|
||||
</p>
|
||||
<router-link to="/register" class="text-link">Deschide un spațiu public →</router-link>
|
||||
<h3>Available Spaces</h3>
|
||||
<p class="app-subtitle">Browse and reserve meeting rooms and desk spaces</p>
|
||||
</div>
|
||||
<div class="app-search"><Search :size="15" /><span>Search spaces…</span></div>
|
||||
</div>
|
||||
<div class="app-grid">
|
||||
<div v-for="s in spaceCards" :key="s.name" class="app-card">
|
||||
<div class="app-card-head">
|
||||
<h4>{{ s.name }}</h4>
|
||||
<span class="app-card-badge" :class="s.active ? 'ok' : 'off'">
|
||||
{{ s.active ? 'Active' : 'Inactive' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="app-card-info"><Tag :size="15" /><span class="app-lbl">Type:</span><span>{{ s.type }}</span></div>
|
||||
<div class="app-card-info"><Users :size="15" /><span class="app-lbl">Capacity:</span><span>{{ s.cap }}</span></div>
|
||||
<div class="app-card-info"><MapPin :size="15" /><span class="app-lbl">Location:</span><span>{{ s.loc }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Screen 3 — Space calendar -->
|
||||
<div class="app-window">
|
||||
<div class="app-bar">
|
||||
<span class="app-dot"></span><span class="app-dot"></span><span class="app-dot"></span>
|
||||
<span class="app-url">roa.space/spaces/aurora-room</span>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<aside class="app-side">
|
||||
<div class="app-brand"><LayoutDashboard :size="20" /><span>ROA Space</span></div>
|
||||
<div class="app-nav-label">Main</div>
|
||||
<nav class="app-nav">
|
||||
<span
|
||||
v-for="item in appNav"
|
||||
:key="item.label"
|
||||
class="app-nav-link"
|
||||
:class="{ active: item.label === 'Spaces' }"
|
||||
>
|
||||
<component :is="item.icon" :size="18" />
|
||||
<span>{{ item.label }}</span>
|
||||
</span>
|
||||
</nav>
|
||||
</aside>
|
||||
<div class="app-content">
|
||||
<div class="app-head">
|
||||
<div>
|
||||
<h3>Aurora Room</h3>
|
||||
<p class="app-subtitle">Meeting Room · 8 people · Floor 2</p>
|
||||
</div>
|
||||
<span class="app-week">‹ Jul 6 – 10 ›</span>
|
||||
</div>
|
||||
<div class="app-cal">
|
||||
<div class="app-cal-times">
|
||||
<span v-for="t in calTimes" :key="t">{{ t }}</span>
|
||||
</div>
|
||||
<div v-for="day in calDays" :key="day.name" class="app-cal-col">
|
||||
<div class="app-cal-day">{{ day.name }}</div>
|
||||
<div class="app-cal-track">
|
||||
<div
|
||||
v-for="(ev, i) in day.events"
|
||||
:key="i"
|
||||
class="app-ev"
|
||||
:class="ev.type"
|
||||
:style="{ top: ev.top, height: ev.h }"
|
||||
>{{ ev.label }}</div>
|
||||
</div>
|
||||
<div class="mini-card">
|
||||
<span class="eyebrow">Rezervare oaspete</span>
|
||||
<div class="guest-form">
|
||||
<div class="field">
|
||||
<span class="field-label">Nume</span>
|
||||
<div class="field-box strong">Maria Ionescu</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="field-label">E-mail</span>
|
||||
<div class="field-box muted">maria@exemplu.ro</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary btn-md btn-block">Trimite cererea</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -186,6 +264,17 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useLandingTheme } from '@/composables/useLandingTheme'
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Building2,
|
||||
CalendarDays,
|
||||
User,
|
||||
Tag,
|
||||
Users,
|
||||
MapPin,
|
||||
Plus,
|
||||
Search
|
||||
} from 'lucide-vue-next'
|
||||
|
||||
const ctaText = 'Creează cont gratuit'
|
||||
|
||||
@@ -199,24 +288,67 @@ interface Slot {
|
||||
}
|
||||
|
||||
const slots: Slot[] = [
|
||||
{ time: '09:00 — 10:00', title: 'Standup echipă', statusText: 'Ocupat', booked: true },
|
||||
{ time: '11:30 — 12:30', title: 'Interviu', statusText: 'Ocupat', booked: true },
|
||||
{ time: '13:00 — 14:00', title: 'Liber', statusText: 'Liber', booked: false },
|
||||
{ time: '14:00 — 15:30', title: 'Liber', statusText: 'Liber', booked: false },
|
||||
{ time: '16:00 — 17:00', title: 'Demo client', statusText: 'Ocupat', booked: true }
|
||||
{ time: '9:00 – 10:00 AM', title: 'Team standup', statusText: 'Booked', booked: true },
|
||||
{ time: '11:30 – 12:30', title: 'Interview', statusText: 'Booked', booked: true },
|
||||
{ time: '1:00 – 2:00 PM', title: 'Free', statusText: 'Free', booked: false },
|
||||
{ time: '2:00 – 3:30 PM', title: 'Free', statusText: 'Free', booked: false },
|
||||
{ time: '4:00 – 5:00 PM', title: 'Client demo', statusText: 'Booked', booked: true }
|
||||
]
|
||||
|
||||
const steps = [
|
||||
{ n: '01', title: 'Alegi spațiul', body: 'Birou sau sală de ședință, din orice sediu.' },
|
||||
{ n: '02', title: 'Pui ora', body: 'Vezi pe loc ce e liber. Se repetă săptămânal? O bifă.' },
|
||||
{ n: '03', title: 'Ești pe listă', body: 'Confirmare pe loc, sincronizată în Google Calendar.' }
|
||||
/* ── Mockup data (faithful to the real app) ── */
|
||||
const appNav = [
|
||||
{ label: 'Dashboard', icon: LayoutDashboard },
|
||||
{ label: 'Spaces', icon: Building2 },
|
||||
{ label: 'History', icon: CalendarDays },
|
||||
{ label: 'Profile', icon: User }
|
||||
]
|
||||
|
||||
const dashPills = [
|
||||
{ num: '12', label: 'Total', tone: 'primary' },
|
||||
{ num: '3', label: 'My Pending', tone: 'warning' },
|
||||
{ num: '9', label: 'Approved', tone: 'success' },
|
||||
{ num: '5', label: 'Needs Approval', tone: 'danger' }
|
||||
]
|
||||
|
||||
const dashRows = [
|
||||
{ time: '9:00 AM – 10:00 AM', space: 'Aurora Room', title: 'Team standup', status: 'Approved', st: 'approved' },
|
||||
{ time: '11:00 AM – 1:00 PM', space: 'Desk 12', title: 'Design review', status: 'Pending', st: 'pending' },
|
||||
{ time: '2:30 PM – 3:30 PM', space: 'North Hall', title: 'Client demo', status: 'Approved', st: 'approved' }
|
||||
]
|
||||
|
||||
const spaceCards = [
|
||||
{ name: 'Aurora Room', type: 'Meeting Room', cap: '8 people', loc: 'Floor 2 · East wing', active: true },
|
||||
{ name: 'North Hall', type: 'Conference Room', cap: '20 people', loc: 'Floor 1 · Main', active: true },
|
||||
{ name: 'Desk 12', type: 'Desk', cap: '1 person', loc: 'Open space A', active: true },
|
||||
{ name: 'Studio B', type: 'Meeting Room', cap: '6 people', loc: 'Floor 3', active: false }
|
||||
]
|
||||
|
||||
const calTimes = ['9 AM', '11 AM', '1 PM', '3 PM', '5 PM']
|
||||
const calDays = [
|
||||
{ name: 'Mon', events: [
|
||||
{ label: 'Standup', type: 'busy', top: '3%', h: '13%' },
|
||||
{ label: 'Interview', type: 'busy', top: '44%', h: '19%' }
|
||||
] },
|
||||
{ name: 'Tue', events: [
|
||||
{ label: 'Design review', type: 'busy', top: '28%', h: '18%' }
|
||||
] },
|
||||
{ name: 'Wed', events: [
|
||||
{ label: 'Planning', type: 'busy', top: '6%', h: '21%' },
|
||||
{ label: 'Your booking', type: 'mine', top: '58%', h: '24%' }
|
||||
] },
|
||||
{ name: 'Thu', events: [
|
||||
{ label: 'Client demo', type: 'busy', top: '50%', h: '19%' }
|
||||
] },
|
||||
{ name: 'Fri', events: [
|
||||
{ label: 'Retro', type: 'mine', top: '18%', h: '17%' }
|
||||
] }
|
||||
]
|
||||
|
||||
const selected = ref(3)
|
||||
|
||||
const selectedLabel = computed(() => {
|
||||
const s = slots[selected.value]
|
||||
return s.booked ? `Ocupat · ${s.time}` : `Ai ales · ${s.time}`
|
||||
return s.booked ? `Booked · ${s.time}` : `Selected · ${s.time}`
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -354,22 +486,24 @@ const selectedLabel = computed(() => {
|
||||
.nav-inner {
|
||||
max-width: var(--container);
|
||||
margin: 0 auto;
|
||||
height: 64px;
|
||||
height: 80px;
|
||||
padding: 0 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 28px;
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 12px; }
|
||||
.brand-logo { height: 42px; width: auto; display: block; }
|
||||
.brand-divider { width: 1px; height: 30px; background: var(--border-default); }
|
||||
.brand { display: flex; align-items: center; gap: 14px; }
|
||||
.brand-logo { height: 60px; width: auto; display: block; }
|
||||
.brand-divider { width: 1px; height: 38px; background: var(--border-default); }
|
||||
/* App brand color — the real accent used inside the ROA app (indigo). */
|
||||
.brand-app-icon { display: flex; align-items: center; color: #6366f1; flex: none; }
|
||||
.brand-text { display: flex; flex-direction: column; gap: 1px; line-height: 1.1; }
|
||||
.brand-word {
|
||||
font-family: var(--font-mark);
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--brand);
|
||||
color: #6366f1;
|
||||
}
|
||||
.brand-sub {
|
||||
font-size: 0.6875rem;
|
||||
@@ -403,7 +537,7 @@ const selectedLabel = computed(() => {
|
||||
.hero {
|
||||
max-width: var(--container);
|
||||
margin: 0 auto;
|
||||
padding: 96px 32px 72px;
|
||||
padding: 72px 32px 56px;
|
||||
display: grid;
|
||||
grid-template-columns: 1.05fr 0.95fr;
|
||||
gap: 64px;
|
||||
@@ -425,173 +559,85 @@ const selectedLabel = computed(() => {
|
||||
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
|
||||
.hero-note { font-size: 0.875rem; color: var(--text-subtle); margin: 20px 0 0; }
|
||||
|
||||
/* ── Demo booking card ── */
|
||||
.demo-card {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
overflow: hidden;
|
||||
}
|
||||
/* ── Hero booking card (same app style as the mockups below) ── */
|
||||
.demo-window { margin-bottom: 0; }
|
||||
.demo-app { background: var(--sf); padding: 4px 0 0; }
|
||||
.demo-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
padding: 16px 20px 14px;
|
||||
border-bottom: 1px solid var(--bd);
|
||||
}
|
||||
.demo-head-title { display: flex; flex-direction: column; gap: 2px; }
|
||||
.demo-room { font-size: 0.875rem; font-weight: 700; color: var(--text-strong); letter-spacing: -0.01em; }
|
||||
.demo-meta { font-size: 0.75rem; color: var(--text-muted); }
|
||||
.demo-slots { display: flex; flex-direction: column; gap: 8px; padding: 16px 20px 12px; }
|
||||
.slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 11px 12px;
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--border-subtle);
|
||||
text-align: left;
|
||||
font-family: inherit;
|
||||
transition: background 180ms ease, border-color 180ms ease;
|
||||
}
|
||||
.slot:hover { border-color: var(--brand); }
|
||||
.slot.selected { background: var(--brand-tint); border-color: var(--brand); }
|
||||
.slot-time {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
width: 96px;
|
||||
flex: none;
|
||||
}
|
||||
.slot-title { flex: 1; font-size: 0.875rem; font-weight: 500; color: var(--text-strong); }
|
||||
.slot-title.free { color: var(--text-subtle); }
|
||||
.demo-foot {
|
||||
padding: 14px 20px;
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
background: var(--surface-page);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.demo-selected { font-size: 0.875rem; color: var(--text-body); }
|
||||
|
||||
/* ── Badges ── */
|
||||
.badge {
|
||||
.demo-head h4 { font-size: 1.0625rem; font-weight: 700; color: var(--tp); margin: 0; }
|
||||
.demo-head .app-subtitle { margin-top: 3px; }
|
||||
.demo-live {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
padding: 3px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
border-radius: 10px;
|
||||
background: color-mix(in srgb, var(--ok) 12%, transparent);
|
||||
color: var(--ok);
|
||||
}
|
||||
.badge-dot, .badge-live-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
.demo-live-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: pulse 1.6s ease-in-out infinite; }
|
||||
.demo-slots { display: flex; flex-direction: column; gap: 6px; padding: 14px 18px 10px; }
|
||||
.demo-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 7px;
|
||||
cursor: pointer;
|
||||
background: var(--bg2);
|
||||
border: 1px solid transparent;
|
||||
text-align: left;
|
||||
font-family: inherit;
|
||||
transition: background 150ms ease, border-color 150ms ease;
|
||||
}
|
||||
.demo-slot:hover { border-color: var(--a); }
|
||||
.demo-slot.selected { background: var(--a-light); border-color: var(--a); }
|
||||
.demo-slot-time {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
color: var(--ts);
|
||||
width: 108px;
|
||||
flex: none;
|
||||
}
|
||||
.badge-live-dot { animation: pulse 1.6s ease-in-out infinite; }
|
||||
.badge-success { background: var(--ok-tint); color: var(--okt); }
|
||||
.badge-neutral { background: color-mix(in srgb, var(--sub) 15%, var(--card)); color: var(--text-muted); }
|
||||
.demo-slot-title { flex: 1; font-size: 0.8125rem; font-weight: 500; color: var(--tp); }
|
||||
.demo-slot-title.free { color: var(--tm); }
|
||||
.demo-slot-badge {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
flex: none;
|
||||
}
|
||||
.demo-slot-badge.booked { background: var(--bg3); color: var(--ts); }
|
||||
.demo-slot-badge.free { background: color-mix(in srgb, var(--ok) 15%, transparent); color: var(--ok); }
|
||||
.demo-foot {
|
||||
padding: 14px 18px;
|
||||
border-top: 1px solid var(--bd);
|
||||
background: var(--bg2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.demo-selected { font-size: 0.8125rem; color: var(--ts); font-weight: 500; }
|
||||
|
||||
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
|
||||
|
||||
/* ── Sections / splits ── */
|
||||
.band { border-top: 1px solid var(--border-subtle); background: var(--surface-card); }
|
||||
.split {
|
||||
max-width: var(--container);
|
||||
margin: 0 auto;
|
||||
padding: 88px 32px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 72px;
|
||||
align-items: center;
|
||||
}
|
||||
.split-steps { grid-template-columns: 0.85fr 1.15fr; }
|
||||
.split h2, .cta-band h2 { font-size: 1.875rem; letter-spacing: -0.02em; margin-bottom: 16px; }
|
||||
.split p { font-size: 1rem; line-height: 1.55; color: var(--text-muted); margin: 0; max-width: 440px; }
|
||||
.text-link { display: inline-block; margin-top: 20px; font-size: 1rem; font-weight: 600; color: var(--brand); }
|
||||
.text-link:hover { color: var(--brand-hover); }
|
||||
|
||||
/* ── Mini cards (benefit visuals) ── */
|
||||
.mini-card {
|
||||
background: var(--surface-page);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-md);
|
||||
padding: 28px;
|
||||
}
|
||||
.band .mini-card { background: var(--surface-page); }
|
||||
.mini-card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
|
||||
.dot-red { width: 10px; height: 10px; border-radius: 50%; background: var(--errt); flex: none; }
|
||||
.mini-card-title { font-size: 0.875rem; font-weight: 600; color: var(--text-strong); }
|
||||
.mini-card-meta { font-size: 0.75rem; color: var(--text-muted); margin-left: auto; }
|
||||
.conflict {
|
||||
padding: 14px 16px;
|
||||
border: 1px dashed var(--err-border);
|
||||
background: var(--err-tint);
|
||||
border-radius: var(--radius-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.conflict-x { color: var(--errt); font-size: 18px; flex: none; }
|
||||
.conflict span:last-child { font-size: 0.875rem; color: var(--errt); }
|
||||
|
||||
.eyebrow {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-subtle);
|
||||
}
|
||||
.guest-form { display: flex; flex-direction: column; gap: 12px; margin-top: 16px; }
|
||||
.field { display: flex; flex-direction: column; gap: 5px; }
|
||||
.field-label { font-size: 0.75rem; color: var(--text-muted); }
|
||||
.field-box {
|
||||
padding: 11px 14px;
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.field-box.strong { color: var(--text-strong); }
|
||||
.field-box.muted { color: var(--text-muted); }
|
||||
|
||||
/* ── Steps ── */
|
||||
.steps { display: flex; flex-direction: column; }
|
||||
.step {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.step:last-child { border-bottom: none; }
|
||||
.step-n {
|
||||
font-family: var(--font-mark);
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--brand);
|
||||
flex: none;
|
||||
width: 40px;
|
||||
}
|
||||
.step h4 { font-size: 1.125rem; font-weight: 600; margin-bottom: 4px; }
|
||||
.step p { font-size: 0.875rem; line-height: 1.55; color: var(--text-muted); margin: 0; }
|
||||
|
||||
/* ── CTA band (subtle accent-tinted surface — accent stays on the button) ── */
|
||||
.cta-band {
|
||||
background: color-mix(in srgb, var(--accent) 7%, var(--card));
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.cta-inner { max-width: var(--container-narrow); margin: 0 auto; padding: 88px 32px; text-align: center; }
|
||||
.cta-band h2 { color: var(--text-strong); margin-bottom: 14px; }
|
||||
.cta-inner { max-width: var(--container-narrow); margin: 0 auto; padding: 72px 32px; text-align: center; }
|
||||
.cta-band h2 { font-size: 1.875rem; letter-spacing: -0.02em; color: var(--text-strong); margin-bottom: 14px; }
|
||||
.cta-inner p { font-size: 1.125rem; line-height: 1.55; color: var(--text-muted); margin: 0 auto 30px; max-width: 440px; }
|
||||
.cta-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
|
||||
|
||||
@@ -612,16 +658,267 @@ const selectedLabel = computed(() => {
|
||||
.footer-links a:hover { color: var(--brand); }
|
||||
.footer-copy { font-size: 0.8125rem; color: var(--text-subtle); }
|
||||
|
||||
/* ── Product showcase (faithful app screenshots) ── */
|
||||
.showcase {
|
||||
max-width: 1040px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 32px 64px;
|
||||
}
|
||||
|
||||
/* App tokens — fixed to the real app's light theme so the mockups read as
|
||||
genuine screenshots regardless of the landing theme. */
|
||||
.app-window {
|
||||
--a: #6366f1; --a-light: #eef2ff;
|
||||
--ok: #10b981; --warn: #f59e0b; --dan: #ef4444;
|
||||
--sf: #ffffff; --bg2: #f8f9fa; --bg3: #f1f3f5;
|
||||
--tp: #1a1a2e; --ts: #6b7280; --tm: #9ca3af;
|
||||
--bd: #e5e7eb; --bdl: #f3f4f6;
|
||||
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
overflow: hidden;
|
||||
background: var(--sf);
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.app-window:last-child { margin-bottom: 0; }
|
||||
|
||||
.app-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
padding: 10px 14px;
|
||||
background: var(--bg3);
|
||||
border-bottom: 1px solid var(--bd);
|
||||
}
|
||||
.app-dot { width: 10px; height: 10px; border-radius: 50%; background: #cfd3da; flex: none; }
|
||||
.app-url {
|
||||
margin-left: 10px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
color: var(--ts);
|
||||
background: var(--sf);
|
||||
border: 1px solid var(--bd);
|
||||
border-radius: 6px;
|
||||
padding: 3px 12px;
|
||||
}
|
||||
|
||||
.app-body { display: flex; background: var(--bg2); min-height: 340px; }
|
||||
|
||||
/* Sidebar */
|
||||
.app-side {
|
||||
width: 180px;
|
||||
flex: none;
|
||||
background: var(--sf);
|
||||
border-right: 1px solid var(--bd);
|
||||
padding: 14px 12px;
|
||||
}
|
||||
.app-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
color: var(--a);
|
||||
padding: 6px 8px 14px;
|
||||
border-bottom: 1px solid var(--bdl);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.app-nav-label {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--tm);
|
||||
padding: 4px 8px 6px;
|
||||
}
|
||||
.app-nav { display: flex; flex-direction: column; gap: 2px; }
|
||||
.app-nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 7px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
color: var(--ts);
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
.app-nav-link.active {
|
||||
background: var(--bg3);
|
||||
color: var(--tp);
|
||||
border-left-color: var(--a);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.app-content { flex: 1; padding: 20px 22px; min-width: 0; }
|
||||
.app-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.app-head-col { align-items: flex-start; }
|
||||
.app-content h3 { font-size: 1.25rem; font-weight: 700; color: var(--tp); margin: 0; }
|
||||
.app-subtitle { font-size: 0.8125rem; color: var(--ts); margin: 4px 0 0; }
|
||||
.app-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: var(--a);
|
||||
color: #fff;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
padding: 8px 14px;
|
||||
border-radius: 7px;
|
||||
white-space: nowrap;
|
||||
flex: none;
|
||||
}
|
||||
.app-search {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
color: var(--tm);
|
||||
font-size: 0.8125rem;
|
||||
background: var(--sf);
|
||||
border: 1px solid var(--bd);
|
||||
border-radius: 7px;
|
||||
padding: 8px 12px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* Dashboard — stat pills */
|
||||
.app-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }
|
||||
.app-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
padding: 5px 11px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.app-pill-num { font-size: 0.875rem; font-weight: 700; }
|
||||
.app-pill.primary { background: var(--a-light); color: var(--a); border-color: color-mix(in srgb, var(--a) 20%, transparent); }
|
||||
.app-pill.warning { background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
|
||||
.app-pill.success { background: color-mix(in srgb, var(--ok) 12%, transparent); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
|
||||
.app-pill.danger { background: color-mix(in srgb, var(--dan) 12%, transparent); color: var(--dan); border-color: color-mix(in srgb, var(--dan) 22%, transparent); }
|
||||
|
||||
/* Dashboard — grouped rows */
|
||||
.app-group {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--ts);
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid var(--bdl);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.app-rows { display: flex; flex-direction: column; gap: 5px; }
|
||||
.app-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 14px;
|
||||
min-height: 44px;
|
||||
background: var(--bg2);
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
.app-row.approved { border-left-color: var(--ok); }
|
||||
.app-row.pending { border-left-color: var(--warn); }
|
||||
.app-row-time { font-size: 0.8125rem; font-weight: 600; color: var(--tp); white-space: nowrap; }
|
||||
.app-row-space { font-size: 0.8125rem; font-weight: 500; color: var(--a); white-space: nowrap; }
|
||||
.app-row-title { flex: 1; font-size: 0.8125rem; color: var(--tp); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.app-row-badge {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
flex: none;
|
||||
}
|
||||
.app-row-badge.approved { background: color-mix(in srgb, var(--ok) 15%, transparent); color: var(--ok); }
|
||||
.app-row-badge.pending { background: color-mix(in srgb, var(--warn) 15%, transparent); color: var(--warn); }
|
||||
|
||||
/* Spaces — cards */
|
||||
.app-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
|
||||
.app-card {
|
||||
background: var(--sf);
|
||||
border: 1px solid var(--bd);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
padding: 16px 18px;
|
||||
}
|
||||
.app-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
|
||||
.app-card-head h4 { font-size: 1.0625rem; font-weight: 700; color: var(--tp); margin: 0; }
|
||||
.app-card-badge { font-size: 0.6875rem; font-weight: 600; padding: 3px 10px; border-radius: 10px; white-space: nowrap; }
|
||||
.app-card-badge.ok { background: color-mix(in srgb, var(--ok) 15%, transparent); color: var(--ok); }
|
||||
.app-card-badge.off { background: color-mix(in srgb, var(--dan) 15%, transparent); color: var(--dan); }
|
||||
.app-card-info { display: flex; align-items: center; gap: 8px; font-size: 0.8125rem; color: var(--tp); padding: 4px 0; }
|
||||
.app-card-info svg { color: var(--tm); flex: none; }
|
||||
.app-lbl { color: var(--ts); font-weight: 500; }
|
||||
|
||||
/* Space calendar — week grid */
|
||||
.app-week { font-size: 0.8125rem; font-weight: 600; color: var(--ts); background: var(--sf); border: 1px solid var(--bd); border-radius: 7px; padding: 7px 12px; white-space: nowrap; flex: none; }
|
||||
.app-cal { display: grid; grid-template-columns: 40px repeat(5, 1fr); gap: 6px; }
|
||||
.app-cal-times {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-top: 30px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.625rem;
|
||||
color: var(--tm);
|
||||
}
|
||||
.app-cal-col { display: flex; flex-direction: column; }
|
||||
.app-cal-day { font-size: 0.75rem; font-weight: 600; color: var(--ts); text-align: center; margin-bottom: 8px; }
|
||||
.app-cal-track {
|
||||
position: relative;
|
||||
height: 240px;
|
||||
border: 1px solid var(--bd);
|
||||
border-radius: 8px;
|
||||
background: var(--sf);
|
||||
background-image: repeating-linear-gradient(
|
||||
to bottom, transparent, transparent 47px,
|
||||
var(--bdl) 47px, var(--bdl) 48px
|
||||
);
|
||||
}
|
||||
.app-ev {
|
||||
position: absolute;
|
||||
left: 4px; right: 4px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
padding: 4px 7px;
|
||||
overflow: hidden;
|
||||
line-height: 1.25;
|
||||
}
|
||||
.app-ev.busy { background: var(--bg3); color: var(--ts); border-left: 3px solid var(--tm); }
|
||||
.app-ev.mine { background: var(--a-light); color: var(--a); border-left: 3px solid var(--a); }
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 900px) {
|
||||
.hero, .split, .split-steps { grid-template-columns: 1fr; gap: 40px; }
|
||||
.hero { grid-template-columns: 1fr; gap: 40px; }
|
||||
.hero { padding: 56px 24px 48px; }
|
||||
.hero-copy h1 { font-size: 2.5rem; }
|
||||
.split { padding: 56px 24px; }
|
||||
.nav-inner { padding: 0 20px; gap: 16px; }
|
||||
.nav-links { display: none; }
|
||||
.cta-inner { padding: 64px 24px; }
|
||||
.footer-inner { padding: 32px 24px; }
|
||||
.showcase { padding: 32px 20px 48px; }
|
||||
}
|
||||
@media (max-width: 620px) {
|
||||
.app-side { display: none; }
|
||||
.app-grid { grid-template-columns: 1fr; }
|
||||
.app-row-title { display: none; }
|
||||
.app-cal { grid-template-columns: 32px repeat(5, 1fr); gap: 4px; }
|
||||
.app-cal-track { height: 180px; }
|
||||
.app-search { display: none; }
|
||||
}
|
||||
@media (max-width: 560px) {
|
||||
.theme-label { display: none; }
|
||||
@@ -631,5 +928,6 @@ const selectedLabel = computed(() => {
|
||||
.hero-copy h1 { font-size: 2rem; }
|
||||
.btn-lg { padding: 12px 20px; font-size: 0.9375rem; }
|
||||
.nav-login { display: none; }
|
||||
.app-pills { gap: 6px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user