feat: reskin public pages to zine direction
This commit is contained in:
parent
8b3daadadd
commit
88caca94c7
8 changed files with 2663 additions and 3577 deletions
|
|
@ -1,503 +1,164 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="pending" class="min-h-screen flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<div
|
||||
class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto mb-4"
|
||||
></div>
|
||||
<p class="text-[--ui-text-muted]">Loading series details...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="pending" class="loading">Loading series details...</div>
|
||||
|
||||
<div
|
||||
v-else-if="error"
|
||||
class="min-h-screen flex items-center justify-center"
|
||||
>
|
||||
<div class="text-center">
|
||||
<h2 class="text-2xl font-bold text-[--ui-text] mb-2">
|
||||
Series Not Found
|
||||
</h2>
|
||||
<p class="text-[--ui-text-muted] mb-6">
|
||||
The event series you're looking for doesn't exist.
|
||||
</p>
|
||||
<NuxtLink to="/series" class="text-primary hover:underline">
|
||||
← Back to Event Series
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div v-else-if="error" class="loading">
|
||||
<h2>Series Not Found</h2>
|
||||
<p>The event series you're looking for doesn't exist.</p>
|
||||
<NuxtLink to="/events">← Back to Events</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<!-- Page Header -->
|
||||
<PageHeader :title="series.title" size="large" />
|
||||
<!-- BACK LINK -->
|
||||
<div class="back-link">
|
||||
<NuxtLink to="/events">← Back to Events</NuxtLink>
|
||||
</div>
|
||||
|
||||
<!-- Series Meta -->
|
||||
<section class="py-20 bg-[--ui-bg]">
|
||||
<UContainer>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- Series Description -->
|
||||
<div v-if="series.description" class="mb-8">
|
||||
<p class="text-lg text-[--ui-text-muted] leading-relaxed">
|
||||
{{ series.description }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- SERIES HEADER -->
|
||||
<div class="series-header">
|
||||
<h1>{{ series.title }}</h1>
|
||||
<div class="series-meta-row">
|
||||
<span v-if="series.type" class="badge all">{{ formatSeriesType(series.type) }}</span>
|
||||
<span class="meta-text">{{ series.events?.length || 0 }} sessions</span>
|
||||
<span v-if="series.startDate" class="meta-text">
|
||||
{{ formatDate(series.startDate) }} – {{ formatDate(series.endDate) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4 mb-8 flex-wrap">
|
||||
<span
|
||||
:class="[
|
||||
'inline-flex items-center px-3 py-1 rounded text-sm font-medium',
|
||||
getSeriesTypeBadgeClass(series.type),
|
||||
]"
|
||||
>
|
||||
{{ formatSeriesType(series.type) }}
|
||||
</span>
|
||||
<span
|
||||
:class="[
|
||||
'inline-flex items-center px-3 py-1 rounded text-sm font-medium',
|
||||
getSeriesStatusClass(),
|
||||
]"
|
||||
>
|
||||
{{ getSeriesStatusText() }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- DESCRIPTION -->
|
||||
<div v-if="series.description" class="section">
|
||||
<p>{{ series.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Series Stats -->
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6 mb-12">
|
||||
<div>
|
||||
<div class="text-3xl font-bold text-[--ui-text] mb-1">
|
||||
{{ series.statistics.totalEvents }}
|
||||
</div>
|
||||
<div class="text-sm text-[--ui-text-muted]">Total Events</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-3xl font-bold text-[--ui-text] mb-1">
|
||||
{{ series.statistics.completedEvents }}
|
||||
</div>
|
||||
<div class="text-sm text-[--ui-text-muted]">Completed</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-3xl font-bold text-[--ui-text] mb-1">
|
||||
{{ series.statistics.upcomingEvents }}
|
||||
</div>
|
||||
<div class="text-sm text-[--ui-text-muted]">Upcoming</div>
|
||||
</div>
|
||||
|
||||
<div v-if="series.statistics.totalRegistrations">
|
||||
<div class="text-3xl font-bold text-[--ui-text] mb-1">
|
||||
{{ series.statistics.totalRegistrations }}
|
||||
</div>
|
||||
<div class="text-sm text-[--ui-text-muted]">Registrations</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Series Date Range -->
|
||||
<div
|
||||
v-if="series.startDate && series.endDate"
|
||||
class="flex items-center gap-2 text-[--ui-text-muted] mb-8"
|
||||
>
|
||||
<Icon name="heroicons:calendar-days" class="w-5 h-5" />
|
||||
<span>
|
||||
Series runs from
|
||||
{{ formatDateRange(series.startDate, series.endDate) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Status Message -->
|
||||
<div
|
||||
v-if="series?.statistics?.isOngoing"
|
||||
class="p-4 bg-candlelight-900/20 border border-candlelight-700/30 rounded mb-8"
|
||||
>
|
||||
<p class="text-candlelight-500 dark:text-candlelight-400 font-semibold mb-1">
|
||||
This series is currently ongoing!
|
||||
</p>
|
||||
<p class="text-sm text-[--ui-text-muted]">
|
||||
Register for upcoming events to join the learning journey.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="series?.statistics?.isUpcoming"
|
||||
class="p-4 bg-guild-500/10 border border-guild-500/30 rounded mb-8"
|
||||
>
|
||||
<p class="text-guild-300 dark:text-guild-300 font-semibold mb-1">
|
||||
This series is starting soon!
|
||||
</p>
|
||||
<p class="text-sm text-[--ui-text-muted]">
|
||||
Mark your calendar and register for the events.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="series?.statistics?.isCompleted"
|
||||
class="p-4 bg-guild-500/10 border border-guild-500/30 rounded mb-8"
|
||||
>
|
||||
<p class="text-[--ui-text] font-semibold mb-1">
|
||||
This series has concluded.
|
||||
</p>
|
||||
<p class="text-sm text-[--ui-text-muted]">
|
||||
Check out our other event series for more opportunities to learn
|
||||
and connect.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</UContainer>
|
||||
</section>
|
||||
|
||||
<!-- Series Pass Purchase (if tickets enabled) -->
|
||||
<section v-if="series?.tickets?.enabled" class="py-20 bg-[--ui-bg]">
|
||||
<UContainer>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<h2 class="text-display-sm font-bold text-[--ui-text] mb-8">
|
||||
Get Your Series Pass
|
||||
</h2>
|
||||
<SeriesPassPurchase
|
||||
:series-id="series.id || series._id"
|
||||
:series-info="{
|
||||
id: series.id,
|
||||
title: series.title,
|
||||
totalEvents: series?.statistics?.totalEvents || 0,
|
||||
type: series.type,
|
||||
}"
|
||||
:series-events="series.events || []"
|
||||
:user-email="user?.email"
|
||||
:user-name="user?.name"
|
||||
@purchase-success="handlePurchaseSuccess"
|
||||
/>
|
||||
</div>
|
||||
</UContainer>
|
||||
</section>
|
||||
|
||||
<!-- Events Timeline -->
|
||||
<section class="py-20 bg-[--ui-bg-elevated]">
|
||||
<UContainer>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<h2 class="text-display-sm font-bold text-[--ui-text] mb-8">
|
||||
Event Schedule
|
||||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div
|
||||
v-for="(event, index) in series?.events || []"
|
||||
:key="event.id"
|
||||
class="group"
|
||||
>
|
||||
<div class="flex items-start gap-4">
|
||||
<!-- Position indicator -->
|
||||
<div class="flex flex-col items-center flex-shrink-0">
|
||||
<div
|
||||
:class="[
|
||||
'w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border',
|
||||
getEventTimelineColor(event),
|
||||
]"
|
||||
>
|
||||
{{ event.series?.position || index + 1 }}
|
||||
</div>
|
||||
<div
|
||||
v-if="index < (series?.events?.length || 0) - 1"
|
||||
class="w-0.5 h-12 bg-[--ui-border]"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- Event Card -->
|
||||
<NuxtLink
|
||||
:to="`/events/${event.slug || event.id}`"
|
||||
class="flex-1 border border-[--ui-border] rounded p-4 hover:border-primary transition-colors"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col md:flex-row md:items-start md:justify-between gap-3"
|
||||
>
|
||||
<!-- Event Info -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start gap-2 mb-2 flex-wrap">
|
||||
<h3
|
||||
class="text-lg font-semibold text-[--ui-text] group-hover:text-primary transition-colors"
|
||||
>
|
||||
{{ event.title }}
|
||||
</h3>
|
||||
<span
|
||||
:class="[
|
||||
'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium flex-shrink-0',
|
||||
getEventStatusClass(event),
|
||||
]"
|
||||
>
|
||||
{{ getEventStatus(event) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p
|
||||
v-if="event.description"
|
||||
class="text-[--ui-text-muted] mb-3 line-clamp-2"
|
||||
>
|
||||
{{ event.description }}
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="flex flex-wrap items-center gap-3 text-sm text-[--ui-text-muted]"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
<Icon
|
||||
name="heroicons:calendar-days"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
{{ formatEventDate(event.startDate) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<Icon name="heroicons:clock" class="w-4 h-4" />
|
||||
{{ formatEventTime(event.startDate) }}
|
||||
</div>
|
||||
<div
|
||||
v-if="event.location"
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
<Icon name="heroicons:map-pin" class="w-4 h-4" />
|
||||
{{ event.location }}
|
||||
</div>
|
||||
<div
|
||||
v-if="event.registeredCount"
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
<Icon name="heroicons:users" class="w-4 h-4" />
|
||||
{{ event.registeredCount }} registered
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Arrow -->
|
||||
<div class="flex items-center md:pt-1">
|
||||
<Icon
|
||||
name="heroicons:arrow-right"
|
||||
class="w-5 h-5 text-[--ui-text-muted] group-hover:text-primary group-hover:translate-x-1 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UContainer>
|
||||
</section>
|
||||
|
||||
<!-- Questions -->
|
||||
<section class="py-20 bg-[--ui-bg]">
|
||||
<UContainer>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<h3 class="text-xl font-bold text-[--ui-text] mb-3">
|
||||
Questions About This Series?
|
||||
</h3>
|
||||
<p class="text-[--ui-text-muted] mb-4">
|
||||
If you have any questions about this event series, please reach
|
||||
out to us.
|
||||
</p>
|
||||
<a
|
||||
href="mailto:events@ghostguild.org"
|
||||
class="text-primary hover:underline"
|
||||
>
|
||||
events@ghostguild.org
|
||||
</a>
|
||||
|
||||
<div class="mt-8">
|
||||
<NuxtLink to="/series" class="text-primary hover:underline">
|
||||
← Back to all event series
|
||||
<!-- EVENT LIST -->
|
||||
<div class="section">
|
||||
<div class="section-label">Sessions</div>
|
||||
<div v-if="series.events?.length">
|
||||
<div v-for="(event, index) in series.events" :key="event._id || index" class="event-row">
|
||||
<span class="event-num">{{ String(index + 1).padStart(2, '0') }}</span>
|
||||
<span class="event-date">{{ formatDate(event.startDate) }}</span>
|
||||
<div class="event-info">
|
||||
<NuxtLink :to="`/events/${event.slug || event._id || event.id}`" class="event-title-link">
|
||||
{{ event.title }}
|
||||
</NuxtLink>
|
||||
<span class="event-status">{{ getEventStatus(event) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</UContainer>
|
||||
</section>
|
||||
</div>
|
||||
<p v-else class="empty">No sessions scheduled yet.</p>
|
||||
</div>
|
||||
|
||||
<!-- PASS PURCHASE -->
|
||||
<div v-if="series.passPrice" class="section">
|
||||
<DashedBox>
|
||||
<div class="section-label">Series Pass</div>
|
||||
<p>Get access to all sessions in this series with a single pass.</p>
|
||||
<div class="pass-price">${{ series.passPrice }}</div>
|
||||
</DashedBox>
|
||||
</div>
|
||||
|
||||
<!-- QUESTIONS -->
|
||||
<div class="section">
|
||||
<div class="section-label">Questions?</div>
|
||||
<p>If you have questions about this series, reach out to us.</p>
|
||||
<a href="mailto:events@ghostguild.org">events@ghostguild.org</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const route = useRoute();
|
||||
const { data: session } = useAuth();
|
||||
const toast = useToast();
|
||||
const route = useRoute()
|
||||
|
||||
// Get user info
|
||||
const user = computed(() => session?.value?.user || null);
|
||||
const { data: series, pending, error } = await useFetch(`/api/series/${route.params.id}`)
|
||||
|
||||
// Fetch series data from API
|
||||
const {
|
||||
data: series,
|
||||
pending,
|
||||
error,
|
||||
refresh: refreshSeries,
|
||||
} = await useFetch(`/api/series/${route.params.id}`);
|
||||
|
||||
// Handle series not found
|
||||
if (error.value?.statusCode === 404) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Event series not found",
|
||||
});
|
||||
throw createError({ statusCode: 404, statusMessage: 'Event series not found' })
|
||||
}
|
||||
|
||||
// Handle successful series pass purchase
|
||||
const handlePurchaseSuccess = async (response) => {
|
||||
// Refresh series data to show updated registration status
|
||||
await refreshSeries();
|
||||
|
||||
// Scroll to top to show success message
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
const formatSeriesType = (type) => {
|
||||
const types = {
|
||||
workshop_series: "Workshop Series",
|
||||
recurring_meetup: "Recurring Meetup",
|
||||
multi_day: "Multi-Day Event",
|
||||
course: "Course",
|
||||
tournament: "Tournament",
|
||||
};
|
||||
return types[type] || type;
|
||||
};
|
||||
const types = { workshop_series: 'Workshop Series', recurring_meetup: 'Recurring Meetup', multi_day: 'Multi-Day Event', course: 'Course', tournament: 'Tournament' }
|
||||
return types[type] || type
|
||||
}
|
||||
|
||||
const getSeriesTypeBadgeClass = (type) => {
|
||||
const classes = {
|
||||
workshop_series:
|
||||
"bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border border-candlelight-700/30",
|
||||
recurring_meetup:
|
||||
"bg-guild-500/10 text-guild-300 dark:text-guild-300 border border-guild-500/30",
|
||||
multi_day:
|
||||
"bg-ember-900/20 text-ember-500 dark:text-ember-400 border border-ember-700/30",
|
||||
course:
|
||||
"bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border border-candlelight-700/30",
|
||||
tournament:
|
||||
"bg-ember-900/20 text-ember-500 dark:text-ember-400 border border-ember-700/30",
|
||||
};
|
||||
return (
|
||||
classes[type] ||
|
||||
"bg-earth-900/20 text-earth-400 dark:text-earth-400 border border-earth-700/30"
|
||||
);
|
||||
};
|
||||
|
||||
const getSeriesStatusText = () => {
|
||||
if (!series.value?.statistics) return "Active";
|
||||
if (series.value.statistics.isOngoing) return "Ongoing";
|
||||
if (series.value.statistics.isUpcoming) return "Starting Soon";
|
||||
if (series.value.statistics.isCompleted) return "Completed";
|
||||
return "Active";
|
||||
};
|
||||
|
||||
const getSeriesStatusClass = () => {
|
||||
if (!series.value?.statistics)
|
||||
return "bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border border-candlelight-700/30";
|
||||
if (series.value.statistics.isOngoing)
|
||||
return "bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border border-candlelight-700/30";
|
||||
if (series.value.statistics.isUpcoming)
|
||||
return "bg-guild-500/10 text-guild-300 dark:text-guild-300 border border-guild-500/30";
|
||||
if (series.value.statistics.isCompleted)
|
||||
return "bg-guild-500/10 text-guild-400 dark:text-guild-400 border border-guild-500/30";
|
||||
return "bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border border-candlelight-700/30";
|
||||
};
|
||||
|
||||
const formatEventDate = (date) => {
|
||||
return new Date(date).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
};
|
||||
|
||||
const formatEventTime = (date) => {
|
||||
return new Date(date).toLocaleTimeString("en-US", {
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
});
|
||||
};
|
||||
|
||||
const formatDateRange = (startDate, endDate) => {
|
||||
const start = new Date(startDate);
|
||||
const end = new Date(endDate);
|
||||
|
||||
const formatter = new Intl.DateTimeFormat("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
return `${formatter.format(start)} to ${formatter.format(end)}`;
|
||||
};
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return ''
|
||||
return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
|
||||
}
|
||||
|
||||
const getEventStatus = (event) => {
|
||||
const now = new Date();
|
||||
const startDate = new Date(event.startDate);
|
||||
const endDate = new Date(event.endDate);
|
||||
const now = new Date()
|
||||
const start = new Date(event.startDate)
|
||||
const end = new Date(event.endDate)
|
||||
if (now < start) return 'Upcoming'
|
||||
if (now >= start && now <= end) return 'Ongoing'
|
||||
return 'Completed'
|
||||
}
|
||||
|
||||
if (now < startDate) return "Upcoming";
|
||||
if (now >= startDate && now <= endDate) return "Ongoing";
|
||||
return "Completed";
|
||||
};
|
||||
|
||||
const getEventStatusClass = (event) => {
|
||||
const status = getEventStatus(event);
|
||||
const classes = {
|
||||
Upcoming:
|
||||
"bg-guild-500/10 text-guild-300 dark:text-guild-300 border border-guild-500/30",
|
||||
Ongoing:
|
||||
"bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border border-candlelight-700/30",
|
||||
Completed:
|
||||
"bg-guild-500/10 text-guild-400 dark:text-guild-400 border border-guild-500/30",
|
||||
};
|
||||
return (
|
||||
classes[status] ||
|
||||
"bg-guild-500/10 text-guild-400 dark:text-guild-400 border border-guild-500/30"
|
||||
);
|
||||
};
|
||||
|
||||
const getEventTimelineColor = (event) => {
|
||||
const status = getEventStatus(event);
|
||||
const classes = {
|
||||
Upcoming:
|
||||
"bg-guild-500/10 text-guild-300 dark:text-guild-300 border-guild-500/30",
|
||||
Ongoing:
|
||||
"bg-candlelight-900/20 text-candlelight-500 dark:text-candlelight-400 border-candlelight-700/30",
|
||||
Completed:
|
||||
"bg-earth-900/20 text-earth-400 dark:text-earth-400 border-earth-700/30",
|
||||
};
|
||||
return (
|
||||
classes[status] ||
|
||||
"bg-guild-500/10 text-guild-400 dark:text-guild-400 border-guild-500/30"
|
||||
);
|
||||
};
|
||||
|
||||
// SEO Meta
|
||||
useHead(() => {
|
||||
if (!series || !series.value) {
|
||||
return {
|
||||
title: "Event Series - Ghost Guild",
|
||||
meta: [
|
||||
{
|
||||
name: "description",
|
||||
content:
|
||||
"Explore our multi-event series designed for learning and growth",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: `${series.value.title} - Event Series - Ghost Guild`,
|
||||
meta: [
|
||||
{
|
||||
name: "description",
|
||||
content:
|
||||
series.value.description ||
|
||||
"Explore our multi-event series designed for learning and growth",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
useHead(() => ({
|
||||
title: series.value ? `${series.value.title} - Event Series - Ghost Guild` : 'Event Series - Ghost Guild',
|
||||
meta: [{ name: 'description', content: series.value?.description || 'Multi-event series' }],
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
.loading { padding: 48px 32px; color: var(--text-dim); }
|
||||
.loading h2 { font-family: 'Brygada 1918', serif; font-size: 22px; color: var(--text-bright); margin-bottom: 8px; }
|
||||
|
||||
.back-link { padding: 12px 32px; border-bottom: 1px dashed var(--border); font-size: 12px; }
|
||||
.back-link a { color: var(--candle); text-decoration: none; }
|
||||
|
||||
.series-header {
|
||||
padding: 28px 32px;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
}
|
||||
.series-header h1 {
|
||||
font-family: 'Brygada 1918', serif;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: var(--text-bright);
|
||||
line-height: 1.15;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.series-meta-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
.meta-text { color: var(--text-faint); }
|
||||
|
||||
.section {
|
||||
padding: 24px 32px;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
}
|
||||
.section p { font-size: 12px; color: var(--text-dim); line-height: 1.7; max-width: 560px; margin-bottom: 8px; }
|
||||
.section a { font-size: 12px; color: var(--candle); }
|
||||
|
||||
.event-row {
|
||||
display: grid;
|
||||
grid-template-columns: 32px 80px 1fr;
|
||||
gap: 12px;
|
||||
align-items: baseline;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
font-size: 12px;
|
||||
}
|
||||
.event-row:last-child { border-bottom: none; }
|
||||
.event-num { color: var(--text-faint); font-size: 11px; }
|
||||
.event-date { color: var(--text-faint); }
|
||||
.event-title-link { color: var(--text); text-decoration: none; font-size: 13px; }
|
||||
.event-title-link:hover { color: var(--candle); }
|
||||
.event-status { font-size: 10px; color: var(--text-faint); margin-left: 8px; }
|
||||
|
||||
.pass-price {
|
||||
font-family: 'Brygada 1918', serif;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
color: var(--candle);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.empty { font-size: 12px; color: var(--text-faint); }
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue