commit cd1ff989d008c3ffdd7ec009efaa07e4392e9f92 Author: Sebastian Krüger Date: Wed Apr 8 19:49:15 2026 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05cb710 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +public/ +resources/ +.hugo_build.lock +node_modules/ +.DS_Store +hugo_stats.json +*.local diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2ab0a09 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# Stage 1: Build +FROM node:22-alpine AS builder + +# Install Hugo +RUN apk add --no-cache hugo + +# Install pnpm +RUN corepack enable && corepack prepare pnpm@latest --activate + +WORKDIR /app + +# Copy package files first (for layer caching) +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +# Copy source files +COPY . . + +# Build CSS and Hugo site +RUN pnpm build + +# Stage 2: Production +FROM nginx:alpine + +# Copy built site +COPY --from=builder /app/public /usr/share/nginx/html + +# Copy nginx config +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..0a78fe8 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,595 @@ +@import "tailwindcss"; + +/* ── Content sources ─────────────────────────────────────────── */ +@source "../../layouts/**/*.html"; +@source "../../content/**/*.md"; +@source "../../assets/js/**/*.js"; + +/* ── Design tokens — sneaker drop culture ────────────────────── */ +@theme { + + /* Dark base — deep navy-black */ + --color-void: #050510; + --color-ink: #09091A; + --color-concrete: #0F0F22; + --color-zinc: #1C1C38; + --color-smoke: #383860; + --color-fog: #6868A0; + --color-chalk: #B8B8E0; + --color-paper: #EEEEFF; + + /* Gradient triad — pink → purple → ice */ + --color-heat: #FF1A8C; /* hot pink — primary energy */ + --color-pulse: #9B00FF; /* electric purple — mid */ + --color-frost: #00C8FF; /* ice blue — cool accent */ + --color-ember: #FF4455; /* alert red */ + --color-lime: #AAFF00; /* acid lime — highlight */ + + /* Backward-compat aliases so existing templates still work */ + --color-gold: var(--color-heat); + --color-gold-dim: #CC1570; + --color-hot: var(--color-heat); + --color-volt: var(--color-lime); + --color-ice: var(--color-frost); + --color-mist: var(--color-zinc); + --color-ash: var(--color-smoke); + --color-graphite: var(--color-concrete); + --color-charcoal: var(--color-ink); + + /* ── Typography ─────────────────────────────────────────────── */ + --font-display: "Bebas Neue", "Arial Black", sans-serif; + --font-body: "Barlow", system-ui, sans-serif; + --font-comic: "Unbounded", "Arial Black", sans-serif; + --font-mono: "Share Tech Mono", "Courier New", monospace; + + /* ── Easing ─────────────────────────────────────────────────── */ + --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); + --ease-sharp: cubic-bezier(0.4, 0, 0.6, 1); + --ease-cinematic: cubic-bezier(0.25, 0.46, 0.45, 0.94); + --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); +} + +/* ── Base ─────────────────────────────────────────────────────── */ +@layer base { + *, *::before, *::after { box-sizing: border-box; } + [x-cloak] { display: none !important; } + + html { + background-color: var(--color-void); + color: var(--color-paper); + font-family: var(--font-body); + font-size: 16px; + scroll-behavior: smooth; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; + } + + body { min-height: 100vh; } + + h1, h2, h3, h4, h5, h6 { + font-family: var(--font-display); + font-weight: 400; + letter-spacing: 0.01em; + line-height: 0.92; + text-transform: uppercase; + } + + a { + color: inherit; + text-decoration: none; + transition: color 0.2s var(--ease-sharp); + } + + img, video { max-width: 100%; height: auto; display: block; } + + ::selection { + background-color: var(--color-heat); + color: #fff; + } + + :focus-visible { + outline: 2px solid var(--color-heat); + outline-offset: 3px; + } + + /* Gradient scrollbar */ + ::-webkit-scrollbar { width: 4px; height: 4px; } + ::-webkit-scrollbar-track { background: var(--color-ink); } + ::-webkit-scrollbar-thumb { background: linear-gradient(180deg, var(--color-heat), var(--color-frost)); } +} + +/* ── Components ───────────────────────────────────────────────── */ +@layer components { + + /* ── Gradient text ─────────────────────────────────────────── */ + .text-gradient { + background: linear-gradient(90deg, var(--color-heat) 0%, var(--color-pulse) 50%, var(--color-frost) 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + color: transparent; + } + + .text-gradient-animated { + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), var(--color-frost), var(--color-heat)); + background-size: 300% 100%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + color: transparent; + animation: gradient-shift 5s ease infinite; + } + + /* ── Gradient overlays ─────────────────────────────────────── */ + .overlay-gradient { + background: linear-gradient( + to top, + rgba(5, 5, 16, 0.98) 0%, + rgba(5, 5, 16, 0.65) 40%, + rgba(5, 5, 16, 0.1) 70%, + transparent 100% + ); + } + + .overlay-gradient-hero { + background: linear-gradient( + 155deg, + rgba(5, 5, 16, 0.1) 0%, + rgba(5, 5, 16, 0.5) 45%, + rgba(5, 5, 16, 0.97) 100% + ); + } + + /* ── Label — monospace spec-sheet text ─────────────────────── */ + .label { + font-family: var(--font-mono); + font-size: 0.65rem; + font-weight: 400; + letter-spacing: 0.16em; + text-transform: uppercase; + } + + /* ── Badge — parallelogram sticker ────────────────────────── */ + .badge { + display: inline-flex; + align-items: center; + font-family: var(--font-mono); + font-size: 0.65rem; + font-weight: 400; + letter-spacing: 0.14em; + line-height: 1; + background: var(--color-heat); + color: #fff; + padding: 5px 16px; + text-transform: uppercase; + clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%); + transition: transform 0.15s var(--ease-bounce), filter 0.2s; + } + + .badge:hover { transform: skewX(-4deg) scale(1.06); filter: brightness(1.2); } + a.badge, a > .badge { cursor: pointer; } + + .badge-heat { background: var(--color-heat); color: #fff; } + .badge-pulse { background: var(--color-pulse); color: #fff; } + .badge-frost { background: var(--color-frost); color: var(--color-void); } + .badge-lime { background: var(--color-lime); color: var(--color-void); } + .badge-ember { background: var(--color-ember); color: #fff; } + + /* Semantic aliases kept for template compat */ + .badge-hot { background: var(--color-heat); color: #fff; } + .badge-volt { background: var(--color-lime); color: var(--color-void); } + .badge-ice { background: var(--color-frost); color: var(--color-void); } + + .badge-gradient { + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), var(--color-frost)); + color: #fff; + } + + .badge-outline { + background: transparent; + color: var(--color-heat); + border: 1.5px solid var(--color-heat); + padding: 4px 14px; + clip-path: none; + } + + /* ── Btn — primary CTA with shimmer sweep ──────────────────── */ + .btn { + display: inline-flex; + align-items: center; + gap: 0.5em; + font-family: var(--font-mono); + font-size: 0.7rem; + font-weight: 400; + letter-spacing: 0.18em; + text-transform: uppercase; + padding: 14px 28px; + background: var(--color-heat); + color: #fff; + position: relative; + overflow: hidden; + clip-path: polygon(10px 0, 100% 0, calc(100% - 10px) 100%, 0 100%); + transition: + box-shadow 0.25s var(--ease-sharp), + transform 0.2s var(--ease-bounce); + cursor: pointer; + } + + /* shimmer sweep */ + .btn::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 105deg, + transparent 35%, + rgba(255, 255, 255, 0.28) 50%, + transparent 65% + ); + transform: translateX(-150%); + transition: transform 0.55s var(--ease-out-expo); + pointer-events: none; + } + + .btn:hover { + transform: translateY(-2px); + box-shadow: 0 8px 32px rgba(255, 26, 140, 0.5), + 0 2px 8px rgba(155, 0, 255, 0.2); + } + .btn:hover::before { transform: translateX(200%); } + .btn:active { transform: translateY(0px); } + + .btn-outline { + background: transparent; + border: 2px solid var(--color-heat); + color: var(--color-heat); + clip-path: none; + } + .btn-outline::before { display: none; } + .btn-outline:hover { + background: var(--color-heat); + color: #fff; + box-shadow: 0 8px 28px rgba(255, 26, 140, 0.4); + } + + .btn-frost { + background: var(--color-frost); + color: var(--color-void); + } + .btn-frost:hover { + box-shadow: 0 8px 32px rgba(0, 200, 255, 0.45); + } + + .btn-ghost { + background: transparent; + border: 1px solid var(--color-zinc); + color: var(--color-chalk); + clip-path: none; + } + .btn-ghost::before { display: none; } + .btn-ghost:hover { + border-color: var(--color-heat); + color: var(--color-heat); + box-shadow: none; + } + + /* ── Card media — zoom on hover ────────────────────────────── */ + .card-media { + overflow: hidden; + position: relative; + background-color: var(--color-concrete); + } + + .card-media img, + .card-media video { + transition: transform 0.7s var(--ease-out-expo); + will-change: transform; + } + + .card-media:hover img, + .card-media:hover video { + transform: scale(1.07); + } + + /* ── Card — gradient border + graffiti offset shadow ──────── */ + .card-comic { + position: relative; + border: 1.5px solid var(--color-zinc); + overflow: hidden; + transition: + border-color 0.2s var(--ease-sharp), + box-shadow 0.3s var(--ease-out-expo), + transform 0.25s var(--ease-out-expo); + } + + /* gradient top bar */ + .card-comic::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), var(--color-frost)); + opacity: 0; + transition: opacity 0.3s var(--ease-sharp); + z-index: 2; + } + + .card-comic:hover { + border-color: rgba(255, 26, 140, 0.55); + transform: translateY(-5px) scale(1.005); + box-shadow: + 0 0 0 1.5px rgba(255, 26, 140, 0.4), + 0 20px 60px rgba(255, 26, 140, 0.18), + 0 8px 24px rgba(155, 0, 255, 0.12), + 6px 6px 0 rgba(255, 26, 140, 0.22); + } + + .card-comic:hover::after { opacity: 1; } + + /* ── Isometric triangle grid — 3 sets of lines at 0° / 60° / -60° + Creates an infinite isometric floor-tile illusion. + Colors: heat (horizontal) · frost (60°) · pulse (-60°) + ────────────────────────────────────────────────────────────── */ + .speed-lines { + background-image: + repeating-linear-gradient( + -55deg, + rgba(255, 26, 140, 0.14) 0, rgba(255, 26, 140, 0.14) 1px, + transparent 1px, transparent 22px, + rgba(0, 200, 255, 0.08) 22px, rgba(0, 200, 255, 0.08) 23px, + transparent 23px, transparent 44px + ); + } + + /* ── Diamond crosshatch ──────────────────────────────────── */ + .halftone { + background-image: + repeating-linear-gradient( + 45deg, + rgba(255, 26, 140, 0.07) 0, rgba(255, 26, 140, 0.07) 1px, + transparent 1px, transparent 24px + ), + repeating-linear-gradient( + -45deg, + rgba(0, 200, 255, 0.05) 0, rgba(0, 200, 255, 0.05) 1px, + transparent 1px, transparent 24px + ); + } + + /* ── Spray dot halftone ──────────────────────────────────── */ + .spray-bg { + background-image: + radial-gradient(circle, rgba(255, 26, 140, 0.09) 1px, transparent 1px), + radial-gradient(circle, rgba(0, 200, 255, 0.06) 1px, transparent 1px); + background-size: 18px 18px, 29px 29px; + background-position: 0 0, 9px 9px; + } + + /* ── Noise overlay ──────────────────────────────────────────── */ + .noise::after { + content: ""; + position: absolute; + inset: 0; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E"); + background-size: 200px 200px; + pointer-events: none; + opacity: 0.25; + } + + /* ── Graffiti tag — oversized hollow decorative text ────────── */ + .graffiti-tag { + font-family: var(--font-display); + font-size: clamp(5rem, 14vw, 13rem); + letter-spacing: 0.02em; + line-height: 0.9; + color: transparent; + -webkit-text-stroke: 1px rgba(255, 26, 140, 0.12); + pointer-events: none; + user-select: none; + } + + /* ── Marquee ticker ──────────────────────────────────────────── */ + .marquee-track { + display: flex; + white-space: nowrap; + animation: marquee-scroll 32s linear infinite; + } + .marquee-track:hover { animation-play-state: paused; } + + /* ── Section rules ──────────────────────────────────────────── */ + .section-rule { border: none; border-top: 1px solid var(--color-zinc); } + + .section-rule-electric { + border: none; + height: 1px; + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), var(--color-frost)); + opacity: 0.5; + } + + /* Thin gradient divider */ + .gradient-line { + height: 1px; + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), var(--color-frost)); + opacity: 0.35; + } + + /* ── Neon glow utilities ────────────────────────────────────── */ + .neon-heat { box-shadow: 0 0 24px rgba(255, 26, 140, 0.35), 0 0 60px rgba(255, 26, 140, 0.08); } + .neon-pulse { box-shadow: 0 0 24px rgba(155, 0, 255, 0.35), 0 0 60px rgba(155, 0, 255, 0.08); } + .neon-frost { box-shadow: 0 0 24px rgba( 0, 200, 255, 0.35), 0 0 60px rgba( 0, 200, 255, 0.08); } + + /* ── Prose editorial ────────────────────────────────────────── */ + .prose-editorial { + color: var(--color-chalk); + font-family: var(--font-body); + font-size: 1.0625rem; + line-height: 1.8; + max-width: 72ch; + } + + .prose-editorial > * + * { margin-top: 1.6em; } + + .prose-editorial strong { color: var(--color-paper); font-weight: 600; } + .prose-editorial em { font-style: italic; color: var(--color-paper); } + + .prose-editorial a { + color: var(--color-heat); + border-bottom: 1px solid rgba(255, 26, 140, 0.35); + transition: border-color 0.2s, color 0.2s; + } + .prose-editorial a:hover { + color: var(--color-frost); + border-color: var(--color-frost); + } + + .prose-editorial blockquote { + border-left: 3px solid var(--color-heat); + padding: 0.4em 0 0.4em 1.5rem; + margin: 2.5em 0; + color: var(--color-paper); + font-family: var(--font-display); + font-size: 1.5rem; + letter-spacing: 0.01em; + line-height: 1.1; + } + .prose-editorial blockquote p { margin: 0; } + + .prose-editorial h2 { + font-size: 2.5rem; + color: var(--color-paper); + margin-top: 2.5em; + margin-bottom: 0.3em; + } + .prose-editorial h3 { + font-size: 1.8rem; + color: var(--color-paper); + margin-top: 2em; + margin-bottom: 0.3em; + } + + .prose-editorial hr { + border: none; + height: 2px; + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), transparent); + margin: 3em 0; + width: 8rem; + } + + .prose-editorial code { + font-family: var(--font-mono); + font-size: 0.875em; + background: var(--color-zinc); + padding: 0.1em 0.4em; + color: var(--color-frost); + } + .prose-editorial pre { + background: var(--color-ink); + border: 1px solid var(--color-zinc); + padding: 1.25rem 1.5rem; + overflow-x: auto; + } + .prose-editorial pre code { + background: none; + padding: 0; + font-size: 0.875rem; + color: var(--color-chalk); + } + + /* ── HTMX progress bar ─────────────────────────────────────── */ + #progress-bar { + position: fixed; + top: 0; + left: 0; + height: 4px; + background: linear-gradient(90deg, var(--color-heat), var(--color-pulse), var(--color-frost)); + box-shadow: 0 0 12px rgba(255, 26, 140, 0.6); + z-index: 9999; + transition: width 0.4s var(--ease-out-expo), opacity 0.3s ease; + width: 0; + opacity: 0; + } +} + +/* ── Utilities ────────────────────────────────────────────────── */ +@layer utilities { + + .gutter-x { + padding-left: clamp(1rem, 4vw, 3rem); + padding-right: clamp(1rem, 4vw, 3rem); + } + + /* Aspect ratios */ + .aspect-editorial { aspect-ratio: 3 / 4; } + .aspect-cinema { aspect-ratio: 21 / 9; } + .aspect-portrait { aspect-ratio: 2 / 3; } + + /* Text wrapping */ + .text-balance { text-wrap: balance; } + .text-pretty { text-wrap: pretty; } + + /* Offset shadow */ + .shadow-comic { box-shadow: 5px 5px 0 var(--color-heat); } + .shadow-comic-hot { box-shadow: 5px 5px 0 var(--color-heat); } + .shadow-comic-volt { box-shadow: 5px 5px 0 var(--color-lime); } + .shadow-comic-ice { box-shadow: 5px 5px 0 var(--color-frost); } + + /* Text stroke — hollow headline */ + .text-stroke-gold { -webkit-text-stroke: 1.5px var(--color-heat); color: transparent; } + .text-stroke-paper { -webkit-text-stroke: 1.5px var(--color-paper); color: transparent; } + .text-stroke-heat { -webkit-text-stroke: 1.5px var(--color-heat); color: transparent; } + .text-stroke-frost { -webkit-text-stroke: 1.5px var(--color-frost); color: transparent; } + + /* Scrollbar hide */ + .scrollbar-hide { scrollbar-width: none; -ms-overflow-style: none; } + .scrollbar-hide::-webkit-scrollbar { display: none; } +} + +/* ── Keyframes ────────────────────────────────────────────────── */ +@keyframes gradient-shift { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +@keyframes marquee-scroll { + to { transform: translateX(-50%); } +} + +@keyframes scroll-line { + 0% { transform: translateY(-100%); opacity: 0; } + 20% { opacity: 1; } + 80% { opacity: 1; } + 100% { transform: translateY(100%); opacity: 0; } +} + +/* ── Logo glitch animation ───────────────────────────────────── */ +@keyframes glitch-clip { + 0%, 88%, 100% { transform: translate(0); clip-path: none; } + 90% { transform: translate(-3px, 1px); clip-path: polygon(0 15%, 100% 15%, 100% 40%, 0 40%); } + 92% { transform: translate(3px, -1px); clip-path: polygon(0 60%, 100% 60%, 100% 78%, 0 78%); } + 94% { transform: translate(0); clip-path: none; } +} + +.logo-glitch:hover { + animation: glitch-clip 2.5s steps(1) infinite; +} + +/* ── View Transitions ────────────────────────────────────────── */ +::view-transition-old(main-content) { + animation: 160ms var(--ease-sharp) both page-out; +} + +::view-transition-new(main-content) { + animation: 320ms var(--ease-out-expo) both page-in; +} + +@keyframes page-out { + to { opacity: 0; transform: translateY(-10px); } +} + +@keyframes page-in { + from { opacity: 0; transform: translateY(14px); } +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..7e0efb8 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,79 @@ +// ── Pivoine — main.js ───────────────────────────────────────────── + +// ── HTMX progress bar ───────────────────────────────────────────── +(function () { + const bar = document.getElementById("progress-bar"); + if (!bar) return; + + document.body.addEventListener("htmx:beforeRequest", () => { + bar.style.width = "0"; + bar.style.opacity = "1"; + requestAnimationFrame(() => { + bar.style.width = "55%"; + }); + }); + + document.body.addEventListener("htmx:afterSettle", () => { + bar.style.width = "100%"; + setTimeout(() => { + bar.style.opacity = "0"; + setTimeout(() => { bar.style.width = "0"; }, 350); + }, 150); + }); +})(); + +// ── Lazy-load videos (data-src attribute) ───────────────────────── +function initLazyVideos(root) { + if (!("IntersectionObserver" in window)) return; + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (!entry.isIntersecting) return; + const video = entry.target; + if (video.dataset.src) { + video.src = video.dataset.src; + video.load(); + } + observer.unobserve(video); + }); + }, + { rootMargin: "300px" } + ); + (root || document).querySelectorAll("video[data-src]").forEach((v) => observer.observe(v)); +} + +initLazyVideos(); + +// ── After HTMX partial swap ──────────────────────────────────────── +document.body.addEventListener("htmx:afterSwap", (e) => { + initLazyVideos(e.target); + if (window.Alpine) Alpine.initTree(e.target); + window.scrollTo({ top: 0, behavior: "instant" }); +}); + +// ── After HTMX history restore (back / forward navigation) ──────── +document.body.addEventListener("htmx:historyRestore", () => { + // Sync nav active state to the restored URL + if (window.Alpine) Alpine.store("nav").path = window.location.pathname; + + // Complete the progress bar (htmx:afterSettle never fires on history restore) + const bar = document.getElementById("progress-bar"); + if (bar) { + bar.style.width = "100%"; + setTimeout(() => { + bar.style.opacity = "0"; + setTimeout(() => { bar.style.width = "0"; }, 350); + }, 150); + } + + const main = document.getElementById("main-content"); + if (!main) return; + if (window.Alpine) Alpine.initTree(main); + // Reload and replay autoplay videos (autoplay attr is ignored on restore) + main.querySelectorAll("video[autoplay]").forEach((v) => { + v.load(); + v.play().catch(() => {}); + }); + window.scrollTo({ top: 0, behavior: "instant" }); +}); + diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..f06308f --- /dev/null +++ b/content/_index.md @@ -0,0 +1,4 @@ +--- +title: "Pivoine" +description: "An editorial magazine for AI-generated art and generative aesthetics." +--- diff --git a/content/about/index.md b/content/about/index.md new file mode 100644 index 0000000..60391f1 --- /dev/null +++ b/content/about/index.md @@ -0,0 +1,22 @@ +--- +title: "About Pivoine" +description: "A magazine dedicated to the intersection of artificial intelligence and aesthetic culture." +--- + +*Pivoine* is an independent editorial project exploring how machine intelligence reshapes visual culture. + +We publish editorial features, artist profiles, and critical essays about AI-generated art — approaching this emerging medium with the same rigour and aesthetic seriousness as any other. + +## The Name + +The name comes from the French word for **peony** — a flower that is both extravagant and precise, excessive and structured. That tension feels right for AI art: the overwhelming abundance of generated imagery held against the deliberate choices that make something worth looking at. + +## What We Publish + +We are interested in the **editorial dimension** of AI image-making. Not the tools, not the prompts, not the speed records — but the *work* itself and the questions it raises about authorship, aesthetics, and what it means to make an image in an age when images are free. + +Each feature is a collaboration between a human sensibility and a machine process. The artists and authors we publish treat the generator as a medium, not a shortcut. + +## Submissions + +We accept editorial pitches and artist submissions. Write to us at [valknar@pivoine.art](mailto:valknar@pivoine.art). diff --git a/content/authors/_index.md b/content/authors/_index.md new file mode 100644 index 0000000..af2755d --- /dev/null +++ b/content/authors/_index.md @@ -0,0 +1,4 @@ +--- +title: "Authors" +description: "The artists and writers behind Pivoine's editorial features." +--- diff --git a/content/authors/valknar/avatar.png b/content/authors/valknar/avatar.png new file mode 100644 index 0000000..9625110 Binary files /dev/null and b/content/authors/valknar/avatar.png differ diff --git a/content/authors/valknar/index.md b/content/authors/valknar/index.md new file mode 100644 index 0000000..f908f02 --- /dev/null +++ b/content/authors/valknar/index.md @@ -0,0 +1,14 @@ +--- +title: "Valknar" +name: "Valknar" +bio: "Valknar works with diffusion models as a compositional tool, creating dark surrealist visions that challenge the language of machine vision and disrupt comfortable readings of the generated face." +social: + instagram: "valknarix" + x: "valknar100" +--- + +Valknar approaches AI generation as a negotiation — between the model's statistical memory of human aesthetics and a deliberate effort to pull those aesthetics toward the unfamiliar. The results are portraits and figures that feel simultaneously recognisable and wrong. + +Working primarily with portrait and figure generation, Sable uses seed manipulation, latent space traversal, and post-processing to extract images that resist the smoothness the models default to. + +Based in Stuttgart. diff --git a/content/imprint/index.md b/content/imprint/index.md new file mode 100644 index 0000000..a5dcdf7 --- /dev/null +++ b/content/imprint/index.md @@ -0,0 +1,27 @@ +--- +title: "Imprint" +description: "Legal information and editorial responsibility." +--- + +## Responsible for Content + +**Pivoine Editorial** +[valknar@pivoine.art](mailto:valknar@pivoine.art) + +## Editorial Policy + +*Pivoine* is an independent publication. All AI-generated images and videos published on this site are the creative work of the named authors using various generative AI tools. The editorial team curates, commissions, and publishes this work under the publication's name. + +## Copyright + +Unless otherwise noted, all editorial content, text, and design on this site is © 2026 Pivoine. AI-generated images remain the creative property of their respective named authors. + +Reproduction of any content requires written permission from the editorial team. + +## Privacy + +This site uses [Umami](https://umami.is) for privacy-friendly analytics. Umami is self-hosted at `umami.pivoine.art`, collects no personally identifiable information, sets no cookies, and does not share data with third parties. Standard server logs are retained for operational purposes only. + +## Hosting & Technology + +Built with [Hugo](https://gohugo.io), styled with [Tailwind CSS](https://tailwindcss.com), and deployed as a static site. diff --git a/content/posts/_index.md b/content/posts/_index.md new file mode 100644 index 0000000..f311654 --- /dev/null +++ b/content/posts/_index.md @@ -0,0 +1,4 @@ +--- +title: "Editorials" +description: "All editorial features published in Pivoine magazine." +--- diff --git a/content/posts/hyperloop/01.mp4 b/content/posts/hyperloop/01.mp4 new file mode 100644 index 0000000..aab3a28 Binary files /dev/null and b/content/posts/hyperloop/01.mp4 differ diff --git a/content/posts/hyperloop/01.png b/content/posts/hyperloop/01.png new file mode 100644 index 0000000..29545d0 Binary files /dev/null and b/content/posts/hyperloop/01.png differ diff --git a/content/posts/hyperloop/02.mp4 b/content/posts/hyperloop/02.mp4 new file mode 100644 index 0000000..a45de4c Binary files /dev/null and b/content/posts/hyperloop/02.mp4 differ diff --git a/content/posts/hyperloop/02.png b/content/posts/hyperloop/02.png new file mode 100644 index 0000000..ab0084d Binary files /dev/null and b/content/posts/hyperloop/02.png differ diff --git a/content/posts/hyperloop/03.mp4 b/content/posts/hyperloop/03.mp4 new file mode 100644 index 0000000..9702ff3 Binary files /dev/null and b/content/posts/hyperloop/03.mp4 differ diff --git a/content/posts/hyperloop/03.png b/content/posts/hyperloop/03.png new file mode 100644 index 0000000..d403199 Binary files /dev/null and b/content/posts/hyperloop/03.png differ diff --git a/content/posts/hyperloop/banner.png b/content/posts/hyperloop/banner.png new file mode 100644 index 0000000..b1fd0a5 Binary files /dev/null and b/content/posts/hyperloop/banner.png differ diff --git a/content/posts/hyperloop/index.md b/content/posts/hyperloop/index.md new file mode 100644 index 0000000..8e59545 --- /dev/null +++ b/content/posts/hyperloop/index.md @@ -0,0 +1,15 @@ +--- +title: "Hyperloop" +description: "A sleek train glides through a vibrant, swirling tunnel of neon colors. The camera smoothly tracks alongside the train, capturing the reflective surfaces and mesmerizing patterns of the tunnel as it shifts and undulates." +date: 2025-08-17 +author: "valknar" +featured: true +categories: + - Surreal +tags: + - futuristic + - vibrant + - urban + - technology +--- + diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..fb4c113 --- /dev/null +++ b/hugo.toml @@ -0,0 +1,70 @@ +baseURL = "https://pivoine.art/" +languageCode = "en-us" +title = "Pivoine" +copyright = "© 2026 Pivoine Editorial" + +[pagination] + pagerSize = 12 + +enableRobotsTXT = true +enableGitInfo = true # populates .Lastmod for article:modified_time + +[sitemap] + changefreq = "weekly" + priority = 0.5 + filename = "sitemap.xml" + +[params] + description = "An editorial magazine for AI-generated art and generative aesthetics." + tagline = "Where the machine dreams." + author = "Pivoine Editorial" + ogImage = "/images/og-default.jpg" + logoText = "PIVOINE" + copyrightYear = "2026" + twitterHandle = "pivoineArt" + umamiSrc = "https://umami.pivoine.art/script.js" + umamiId = "9190b814-0480-498a-b5fe-1fe1dc162766" + +[params.social] + instagram = "https://instagram.com/valknarix" + x = "https://x.com/valknar100" + +[taxonomies] + category = "categories" + tag = "tags" + +[[menus.main]] + name = "Posts" + url = "/posts/" + weight = 1 +[[menus.main]] + name = "Authors" + url = "/authors/" + weight = 2 +[[menus.main]] + name = "Categories" + url = "/categories/" + weight = 3 +[[menus.main]] + name = "About" + url = "/about/" + weight = 4 + +[[menus.footer]] + name = "About" + url = "/about/" + weight = 1 +[[menus.footer]] + name = "Imprint" + url = "/imprint/" + weight = 2 + +[markup.goldmark.renderer] + unsafe = true + +[markup.highlight] + style = "dracula" + noClasses = true + +[build] + writeStats = true diff --git a/layouts/404.html b/layouts/404.html new file mode 100644 index 0000000..93e7639 --- /dev/null +++ b/layouts/404.html @@ -0,0 +1,65 @@ +{{- define "main" -}} +
+ + +
+
+ + + + + +
+ + + + Error 404 + + + +

+ PAGE
+ NOT FOUND +

+ + +
+ + +

+ This drop got pulled. The page you're looking for doesn't exist, was moved, or got lost in the grid. +

+ + + + +
+ + + + +
+{{- end -}} diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html new file mode 100644 index 0000000..f9c7742 --- /dev/null +++ b/layouts/_default/baseof.html @@ -0,0 +1,52 @@ + + + + {{- partial "head.html" . -}} + + + + + + + {{- partial "nav.html" . -}} + + {{- block "page-background" . -}}{{- end -}} + +
+ {{- block "main" . }}{{- end }} +
+ + {{- partial "footer.html" . -}} + + + + + + + + + {{- $js := resources.Get "js/main.js" -}} + {{- if eq hugo.Environment "production" -}} + {{- $js = $js | minify | fingerprint "sha256" -}} + {{- end -}} + + + {{- block "scripts" . }}{{- end }} + + {{- if and (eq hugo.Environment "production") .Site.Params.umamiId -}} + + + {{- end -}} + + diff --git a/layouts/_default/list.html b/layouts/_default/list.html new file mode 100644 index 0000000..008723a --- /dev/null +++ b/layouts/_default/list.html @@ -0,0 +1,34 @@ +{{- define "main" -}} + + +
+
+ {{- with .Data.Singular -}} + {{ . | title }} + {{- else -}} + {{ .Kind | title }} + {{- end -}} +

{{ .Title }}

+ {{- with .Description -}} +

{{ . }}

+ {{- end -}} +
+
+ +
+ + +
+ {{- if .Paginator.Pages -}} +
+ {{- range .Paginator.Pages -}} + {{- partial "post-card.html" . -}} + {{- end -}} +
+ {{- partial "pagination.html" . -}} + {{- else -}} +

No posts yet.

+ {{- end -}} +
+ +{{- end -}} diff --git a/layouts/_default/single.html b/layouts/_default/single.html new file mode 100644 index 0000000..d3be843 --- /dev/null +++ b/layouts/_default/single.html @@ -0,0 +1,18 @@ +{{- define "main" -}} + + +
+
+

{{ .Title }}

+ {{- with .Description -}} +

{{ . }}

+ {{- end -}} +
+
+ + +
+ {{ .Content }} +
+ +{{- end -}} diff --git a/layouts/_default/terms.html b/layouts/_default/terms.html new file mode 100644 index 0000000..07799e8 --- /dev/null +++ b/layouts/_default/terms.html @@ -0,0 +1,32 @@ +{{- define "main" -}} + + +
+
+ Browse +

{{ .Title }}

+
+
+ +
+ + +
+ {{- if .Data.Terms -}} +
+ {{- range .Data.Terms.Alphabetical -}} + + {{ .Page.Title }} + {{ .Count }} + + {{- end -}} +
+ {{- else -}} +

No entries yet.

+ {{- end -}} +
+ +{{- end -}} diff --git a/layouts/authors/list.html b/layouts/authors/list.html new file mode 100644 index 0000000..91a5698 --- /dev/null +++ b/layouts/authors/list.html @@ -0,0 +1,54 @@ +{{- define "main" -}} + + +
+ Contributors +

Authors

+
+ +
+ + +
+ +
+ +{{- end -}} diff --git a/layouts/authors/single.html b/layouts/authors/single.html new file mode 100644 index 0000000..2805308 --- /dev/null +++ b/layouts/authors/single.html @@ -0,0 +1,97 @@ +{{- define "main" -}} +{{- $slug := .File.Dir | strings.TrimSuffix "/" | path.Base -}} +{{- $posts := where .Site.RegularPages "Params.author" $slug -}} + + +
+
+
+ + + {{- $avatarRes := .Resources.GetMatch "avatar.*" -}} + {{- $avatarSrc := "" -}} + {{- with $avatarRes }}{{ $avatarSrc = .RelPermalink }}{{ else }}{{ with $.Params.avatar }}{{ $avatarSrc = . }}{{ end }}{{ end -}} + {{- if $avatarSrc -}} +
+ {{ .Params.name | default .Title }} +
+ {{- else -}} +
+ {{ substr (.Params.name | default .Title) 0 1 }} +
+ {{- end -}} + + +
+ Artist +

+ {{ .Params.name | default .Title }} +

+ {{- with .Params.bio -}} +

{{ . }}

+ {{- end -}} + + + {{- with .Params.social -}} + {{- $bases := dict "instagram" "https://instagram.com/" "x" "https://x.com/" "twitter" "https://x.com/" "github" "https://github.com/" "behance" "https://www.behance.net/" "artstation" "https://www.artstation.com/" -}} +
+ {{- range $platform, $handle := . -}} + {{- $href := cond (hasPrefix $handle "http") $handle (printf "%s%s" (index $bases $platform | default "#") $handle) -}} + {{ $platform | upper }} {{ partial "icon.html" "arrow-external" }} + {{- end -}} +
+ {{- end -}} + + + {{- if $posts -}} +

{{ len $posts }} {{ if eq (len $posts) 1 }}editorial{{ else }}editorials{{ end }}

+ {{- end -}} +
+ +
+
+
+ +
+ + +{{- with .Content -}} +
+
{{ . }}
+
+{{- end -}} + + +{{- if $posts -}} +
+
+
+

+ Works by {{ .Params.name | default .Title }} +

+
+
+
+ {{- range $posts.ByDate.Reverse -}} + {{- partial "post-card.html" . -}} + {{- end -}} +
+
+
+{{- else -}} +
+

No editorials published yet.

+
+{{- end -}} + +{{- end -}} diff --git a/layouts/categories/single.html b/layouts/categories/single.html new file mode 100644 index 0000000..a52c2b1 --- /dev/null +++ b/layouts/categories/single.html @@ -0,0 +1,26 @@ +{{- define "main" -}} + + +
+
+ Category +

{{ .Title }}

+

{{ len .Pages }} {{ if eq (len .Pages) 1 }}editorial{{ else }}editorials{{ end }}

+
+
+ + +
+ {{- if .Paginator.Pages -}} +
+ {{- range .Paginator.Pages -}} + {{- partial "post-card.html" . -}} + {{- end -}} +
+ {{- partial "pagination.html" . -}} + {{- else -}} +

No posts in this category yet.

+ {{- end -}} +
+ +{{- end -}} diff --git a/layouts/index.html b/layouts/index.html new file mode 100644 index 0000000..879fc59 --- /dev/null +++ b/layouts/index.html @@ -0,0 +1,144 @@ +{{- define "main" -}} +{{- $posts := where .Site.RegularPages "Section" "posts" -}} +{{- $featured := where $posts "Params.featured" true -}} +{{- $hero := index $featured 0 -}} +{{- $secondary := after 1 $featured | first 3 -}} +{{- $latest := complement $featured $posts -}} + + +{{- with $hero -}} +
+ + + {{- $heroBanner := .Resources.GetMatch "banner.png" -}} + {{- if not $heroBanner -}}{{- $heroBanner = .Resources.GetMatch "banner.*" -}}{{- end -}} + {{- $heroBannerSrc := "" -}} + {{- with $heroBanner }}{{ $heroBannerSrc = .RelPermalink }}{{ else }}{{ with $.Params.background }}{{ $heroBannerSrc = .src }}{{ else }}{{ with $.Params.banner }}{{ $heroBannerSrc = .src }}{{ end }}{{ end }}{{ end -}} + {{- with $heroBannerSrc -}} +
+ +
+ {{- end -}} + + +
+ + +
+
+ + +
+ Featured Drop + {{- with .Params.categories -}} + {{- range first 1 . -}} + {{ . }} + {{- end -}} + {{- end -}} +
+ + +

+ {{- .Title -}} +

+ + +

+ {{- .Description -}} +

+ + +
+ View Editorial {{ partial "icon.html" "arrow-right" }} + {{- with .Params.author -}} + {{- $author := site.GetPage (printf "authors/%s" .) -}} + {{- with $author -}} +
+ {{- $avRes := .Resources.GetMatch "avatar.*" -}} + {{- $avSrc := "" -}} + {{- with $avRes }}{{ $avSrc = .RelPermalink }}{{ else }}{{ with $author.Params.avatar }}{{ $avSrc = . }}{{ end }}{{ end -}} + {{- with $avSrc -}} + {{ $author.Params.name | default $author.Title }} + {{- end -}} + + By {{ .Params.name | default .Title }} + +
+ {{- end -}} + {{- end -}} +
+ +
+
+ + + + +
+{{- end -}} + + +{{- with $secondary -}} +
+
+ Also Featured +
+
+
+ {{- range . -}} + {{- partial "post-card-large.html" . -}} + {{- end -}} +
+
+{{- end -}} + +
+ + +
+ + + + + + +
+ {{- range first 8 $latest -}} + {{- partial "post-card.html" . -}} + {{- end -}} +
+ + {{- if gt (len $latest) 8 -}} + + {{- end -}} + +
+ + +
+
+ About the Magazine +

+ {{ .Site.Params.description }} +

+ Learn more {{ partial "icon.html" "arrow-right" }} +
+
+ +{{- end -}} diff --git a/layouts/partials/author-card.html b/layouts/partials/author-card.html new file mode 100644 index 0000000..330ad37 --- /dev/null +++ b/layouts/partials/author-card.html @@ -0,0 +1,26 @@ +{{- /* Inline author byline for post single pages. + Expects the author page as context (.). +*/ -}} +
+ {{- $avatarRes := .Resources.GetMatch "avatar.*" -}} + {{- $avatarSrc := "" -}} + {{- with $avatarRes }}{{ $avatarSrc = .RelPermalink }}{{ else }}{{ with $.Params.avatar }}{{ $avatarSrc = . }}{{ end }}{{ end -}} + {{- with $avatarSrc -}} + + {{ $.Params.name | default $.Title }} + + {{- end -}} +
+ + {{ .Params.name | default .Title }} + + {{- with .Params.bio -}} +

{{ . }}

+ {{- end -}} +
+
diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html new file mode 100644 index 0000000..97ae9ba --- /dev/null +++ b/layouts/partials/footer.html @@ -0,0 +1,46 @@ + diff --git a/layouts/partials/head.html b/layouts/partials/head.html new file mode 100644 index 0000000..0ebff7a --- /dev/null +++ b/layouts/partials/head.html @@ -0,0 +1,74 @@ + + + + + + + {{- if .IsHome -}} + {{- .Site.Title }} — {{ .Site.Params.tagline -}} + {{- else -}} + {{- .Title }} — {{ .Site.Title -}} + {{- end -}} + + + + +{{- if .Site.Params.robots }}{{ end }} + + + + + + + + +{{- $ogImage := .Site.Params.ogImage -}} +{{- $ogImageAlt := .Site.Title -}} +{{- with .Params.banner -}} + {{- $ogImage = .src -}} + {{- $ogImageAlt = $.Title -}} +{{- end -}} + + + + + +{{- if .IsPage }} + + +{{- with .Params.author }}{{ end }} +{{- range .Params.categories }}{{ end }} +{{- range .Params.tags }}{{ end }} +{{- end }} + + + +{{- with .Site.Params.twitterHandle }} + +{{- end }} + + + + + + + + + +{{- partial "schema.html" . -}} + + + + + + + +{{- $css := resources.Get "css/main.css" | css.PostCSS -}} +{{- if eq hugo.Environment "production" -}} + {{- $css = $css | minify | fingerprint "sha256" -}} +{{- end -}} + + + + + diff --git a/layouts/partials/icon.html b/layouts/partials/icon.html new file mode 100644 index 0000000..92f8988 --- /dev/null +++ b/layouts/partials/icon.html @@ -0,0 +1,11 @@ +{{- /* Inline SVG icon. Usage: {{ partial "icon.html" "arrow-right" }} + Renders at 1em × 1em, inherits currentColor, aria-hidden. +*/ -}} +{{- $name := . -}} +{{- if eq $name "arrow-right" -}} + +{{- else if eq $name "arrow-left" -}} + +{{- else if eq $name "arrow-external" -}} + +{{- end -}} diff --git a/layouts/partials/logo.html b/layouts/partials/logo.html new file mode 100644 index 0000000..2e95231 --- /dev/null +++ b/layouts/partials/logo.html @@ -0,0 +1,31 @@ +{{- /* + Inline SVG logotype with gradient fill. + Usage: {{ partial "logo.html" (dict "id" "nav" "class" "h-9 w-auto") }} + Params: + id — unique suffix for gradient ID (required to avoid conflicts when used twice) + class — CSS classes on the element (default: "h-9 w-auto") +*/ -}} +{{- $id := .id | default "logo" -}} +{{- $class := .class | default "h-9 w-auto" -}} + + + + + + + + + + + + diff --git a/layouts/partials/media.html b/layouts/partials/media.html new file mode 100644 index 0000000..3e4824e --- /dev/null +++ b/layouts/partials/media.html @@ -0,0 +1,36 @@ +{{- /* + Renders an image or video from a front matter map. + + Usage: + {{ partial "media.html" (dict "media" .Params.banner "class" "w-full h-full object-cover") }} + + Parameters: + media — map with keys: type (image|video), src, alt + class — CSS classes applied to the img/video element + lazy — set to false to disable lazy loading (default true) +*/ -}} + +{{- $media := .media -}} +{{- $class := .class | default "" -}} +{{- $lazy := .lazy | default true -}} + +{{- with $media -}} + {{- if eq .type "video" -}} + + {{- else -}} + {{ .alt | default + {{- end -}} +{{- end -}} diff --git a/layouts/partials/nav.html b/layouts/partials/nav.html new file mode 100644 index 0000000..b8b3356 --- /dev/null +++ b/layouts/partials/nav.html @@ -0,0 +1,132 @@ +
+ +
+ + + {{- partial "logo.html" (dict "id" "nav" "class" "h-8 w-auto flex-shrink-0") -}} + + {{- .Site.Params.logoText -}} + + + + + + + + +
+ + + +
+ + diff --git a/layouts/partials/pagination.html b/layouts/partials/pagination.html new file mode 100644 index 0000000..5cb505f --- /dev/null +++ b/layouts/partials/pagination.html @@ -0,0 +1,33 @@ +{{- /* Custom pagination component. + Call as: {{ partial "pagination.html" . }} +*/ -}} +{{- $paginator := .Paginator -}} +{{- if gt $paginator.TotalPages 1 -}} + +{{- end -}} diff --git a/layouts/partials/post-card-large.html b/layouts/partials/post-card-large.html new file mode 100644 index 0000000..290dcc0 --- /dev/null +++ b/layouts/partials/post-card-large.html @@ -0,0 +1,57 @@ +{{- /* Large overlay card for featured/secondary slots. + Expects a post page as context (.). +*/ -}} +{{- $post := . -}} +
+ + + + {{- $thumb := $post.Resources.GetMatch "banner.png" -}} + {{- if not $thumb -}}{{- $thumb = $post.Resources.GetMatch "01.png" -}}{{- end -}} +
+ {{- if $thumb -}} + {{ $post.Title }} + {{- else -}}{{- with $post.Params.banner -}} + {{- partial "media.html" (dict "media" . "class" "w-full h-full object-cover") -}} + {{- else -}} +
+ PIVOINE +
+ {{- end -}}{{- end -}} +
+ + +
+ + +
+ + +
+ {{- with $post.Params.categories -}} +
+ {{- range first 1 . -}} + {{ . }} + {{- end -}} +
+ {{- end -}} +

+ {{- $post.Title -}} +

+
+ {{- with $post.Params.author -}} + {{- $authorPage := site.GetPage (printf "authors/%s" .) -}} + {{- with $authorPage -}} + {{ .Params.name | default .Title }} + + {{- end -}} + {{- end -}} + +
+
+ +
+
diff --git a/layouts/partials/post-card.html b/layouts/partials/post-card.html new file mode 100644 index 0000000..35ef1ba --- /dev/null +++ b/layouts/partials/post-card.html @@ -0,0 +1,63 @@ +{{- /* Compact post card for grids. + Expects a post page as context (.). +*/ -}} +{{- $post := . -}} +
+ + + + {{- $thumb := $post.Resources.GetMatch "banner.png" -}} + {{- if not $thumb -}}{{- $thumb = $post.Resources.GetMatch "01.png" -}}{{- end -}} +
+ {{- if $thumb -}} + {{ $post.Title }} + {{- else -}}{{- with $post.Params.banner -}} + {{- partial "media.html" (dict "media" . "class" "w-full h-full object-cover") -}} + {{- else -}} +
+ PIVOINE +
+ {{- end -}}{{- end -}} +
+ + + {{- with $post.Params.categories -}} +
+ {{- range first 1 . -}} + {{ . }} + {{- end -}} +
+ {{- end -}} + + +

+ {{- $post.Title -}} +

+ + +
+ {{- with $post.Params.author -}} + {{- $authorPage := site.GetPage (printf "authors/%s" .) -}} + {{- with $authorPage -}} + {{- $avRes := .Resources.GetMatch "avatar.*" -}} + {{- $avSrc := "" -}} + {{- with $avRes }}{{ $avSrc = .RelPermalink }}{{ else }}{{ with $.Params.avatar }}{{ $avSrc = . }}{{ end }}{{ end -}} + {{- with $avSrc -}} + {{ $authorPage.Params.name | default $authorPage.Title }} + {{- end -}} + {{ .Params.name | default .Title }} + + {{- end -}} + {{- end -}} + +
+ +
+
diff --git a/layouts/partials/schema.html b/layouts/partials/schema.html new file mode 100644 index 0000000..9858677 --- /dev/null +++ b/layouts/partials/schema.html @@ -0,0 +1,62 @@ +{{- /* JSON-LD structured data — WebSite on home, BlogPosting on posts */ -}} + +{{- if .IsHome -}} + +{{- else if and .IsPage (eq .Section "posts") -}} +{{- $authorPage := "" -}} +{{- with .Params.author -}} + {{- $authorPage = site.GetPage (printf "authors/%s" .) -}} +{{- end -}} + +{{- end -}} diff --git a/layouts/posts/single.html b/layouts/posts/single.html new file mode 100644 index 0000000..5ca942f --- /dev/null +++ b/layouts/posts/single.html @@ -0,0 +1,186 @@ +{{- define "page-background" -}} +{{- with .Params.background -}} + +{{- end -}} +{{- end -}} + +{{- define "main" -}} + + +
+ + + {{- with index .Params.categories 0 -}} + + {{- end -}} + + + {{- with .Params.categories -}} +
+ {{- range . -}} + {{ . }} + {{- end -}} +
+ {{- end -}} + + +

+ {{- .Title -}} +

+ + + {{- with .Description -}} +

+ {{ . }} +

+ {{- end -}} + + + {{- with .Params.author -}} + {{- $authorPage := site.GetPage (printf "authors/%s" .) -}} + {{- with $authorPage -}} + {{- partial "author-card.html" . -}} + {{- end -}} + {{- end -}} + + +
+ + {{- $imgCount := len (.Resources.Match "[0-9]*.png") -}} + {{- $itemCount := $imgCount -}} + {{- if and (eq $imgCount 0) .Params.items -}}{{- $itemCount = len .Params.items -}}{{- end -}} + {{- if gt $itemCount 0 -}} + {{ $itemCount }} {{ if eq $itemCount 1 }}Work{{ else }}Works{{ end }} + {{- end -}} +
+ +
+ + +
+ + +{{- $bannerImg := .Resources.GetMatch "banner.png" -}} +{{- if not $bannerImg -}}{{- $bannerImg = .Resources.GetMatch "01.png" -}}{{- end -}} +{{- if $bannerImg -}} +
+ {{ .Title }} +
+{{- else -}}{{- with .Params.banner -}} +
+ {{- partial "media.html" (dict "media" . "class" "w-full h-full object-cover" "lazy" false) -}} +
+{{- end -}}{{- end -}} + + +{{- with .Content -}} +
+
+
+ {{ . }} +
+
+
+{{- end -}} + + +{{- $bundleImages := .Resources.Match "[0-9]*.png" -}} +{{- $legacyItems := slice -}} +{{- with .Params.items -}}{{- $legacyItems = . -}}{{- end -}} +{{- if or $bundleImages $legacyItems -}} +
+
+ + {{- if $bundleImages -}} +
+ Gallery + {{ len $bundleImages }} {{ if eq (len $bundleImages) 1 }}work{{ else }}works{{ end }} +
+
+ +
+ {{- range $bundleImages -}} + {{- $stem := .Name | strings.TrimSuffix ".png" -}} + {{- $video := $.Resources.GetMatch (printf "%s.mp4" $stem) -}} +
+
+ {{- if $video -}} + + {{- else -}} + + {{- end -}} +
+
+ {{- end -}} +
+ + {{- else -}} + +
+ Gallery + {{ len $legacyItems }} {{ if eq (len $legacyItems) 1 }}work{{ else }}works{{ end }} +
+
+
+ {{- range $i, $item := $legacyItems -}} +
+
+ {{- partial "media.html" (dict "media" $item "class" "w-full") -}} +
+ {{- with $item.description -}} +
{{ . }}
+ {{- end -}} +
+ {{- end -}} +
+ {{- end -}} + +
+
+{{- end -}} + + +{{- with .Params.tags -}} + +{{- end -}} + + +{{- $related := .Site.RegularPages.Related . | first 3 -}} +{{- with $related -}} +
+
+
+

+ More Drops +

+
+
+
+ {{- range . -}} + {{- partial "post-card.html" . -}} + {{- end -}} +
+
+
+{{- end -}} + +{{- end -}} diff --git a/layouts/robots.txt b/layouts/robots.txt new file mode 100644 index 0000000..92f9689 --- /dev/null +++ b/layouts/robots.txt @@ -0,0 +1,7 @@ +User-agent: * +Allow: / + +# Block build artefacts +Disallow: /public/ + +Sitemap: {{ .Site.BaseURL }}sitemap.xml diff --git a/layouts/tags/single.html b/layouts/tags/single.html new file mode 100644 index 0000000..64e6f9c --- /dev/null +++ b/layouts/tags/single.html @@ -0,0 +1,26 @@ +{{- define "main" -}} + + +
+
+ Tag +

# {{ .Title }}

+

{{ len .Pages }} {{ if eq (len .Pages) 1 }}editorial{{ else }}editorials{{ end }}

+
+
+ + +
+ {{- if .Paginator.Pages -}} +
+ {{- range .Paginator.Pages -}} + {{- partial "post-card.html" . -}} + {{- end -}} +
+ {{- partial "pagination.html" . -}} + {{- else -}} +

No posts with this tag yet.

+ {{- end -}} +
+ +{{- end -}} diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..d0243b1 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,51 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml application/json application/rss+xml image/svg+xml; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Static assets with long cache + location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot|webp|mp3|mp4|webm|ogg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # HTML files - no cache for fresh content + location ~* \.html$ { + expires -1; + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + + # Custom 404 page + error_page 404 /404.html; + + # Clean URLs - try files, then directories, then 404 + location / { + try_files $uri $uri/ $uri.html =404; + } + + # RSS feed + location = /index.xml { + types { application/rss+xml xml; } + } + + # Deny access to hidden files + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..022279a --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "pivoine-art", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "hugo server --buildDrafts --disableFastRender", + "build": "NODE_ENV=production hugo --minify" + }, + "devDependencies": { + "tailwindcss": "^4.0.0", + "@tailwindcss/postcss": "^4.0.0", + "autoprefixer": "^10.4.0", + "postcss": "^8.5.0", + "postcss-cli": "^11.0.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..c102491 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,892 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.0.0 + version: 4.2.2 + autoprefixer: + specifier: ^10.4.0 + version: 10.4.27(postcss@8.5.8) + postcss: + specifier: ^8.5.0 + version: 8.5.8 + postcss-cli: + specifier: ^11.0.0 + version: 11.0.1(jiti@2.6.1)(postcss@8.5.8) + tailwindcss: + specifier: ^4.0.0 + version: 4.2.2 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} + + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.2.2': + resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + baseline-browser-mapping@2.10.12: + resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + caniuse-lite@1.0.30001782: + resolution: {integrity: sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + dependency-graph@1.0.0: + resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} + engines: {node: '>=4'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + electron-to-chromium@1.5.329: + resolution: {integrity: sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} + engines: {node: '>=14.14'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + postcss-cli@11.0.1: + resolution: {integrity: sha512-0UnkNPSayHKRe/tc2YGW6XnSqqOA9eqpiRMgRlV1S6HdGi16vwJBx7lviARzbV1HpQHqLLRH3o8vTcB0cLc+5g==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + postcss: ^8.0.0 + + postcss-load-config@5.1.0: + resolution: {integrity: sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + + postcss-reporter@7.1.0: + resolution: {integrity: sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==} + engines: {node: '>=10'} + peerDependencies: + postcss: ^8.1.0 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + + pretty-hrtime@1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} + engines: {node: '>=6'} + + thenby@1.3.4: + resolution: {integrity: sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@tailwindcss/node@4.2.2': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.20.1 + jiti: 2.6.1 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.2 + + '@tailwindcss/oxide-android-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide@4.2.2': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 + + '@tailwindcss/postcss@4.2.2': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + postcss: 8.5.8 + tailwindcss: 4.2.2 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001782 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + baseline-browser-mapping@2.10.12: {} + + binary-extensions@2.3.0: {} + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.12 + caniuse-lite: 1.0.30001782 + electron-to-chromium: 1.5.329 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + caniuse-lite@1.0.30001782: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + dependency-graph@1.0.0: {} + + detect-libc@2.1.2: {} + + electron-to-chromium@1.5.329: {} + + emoji-regex@8.0.0: {} + + enhanced-resolve@5.20.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.2 + + escalade@3.2.0: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + fraction.js@5.3.4: {} + + fs-extra@11.3.4: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fsevents@2.3.3: + optional: true + + get-caller-file@2.0.5: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + graceful-fs@4.2.11: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + jiti@2.6.1: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lilconfig@3.1.3: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + nanoid@3.3.11: {} + + node-releases@2.0.36: {} + + normalize-path@3.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pify@2.3.0: {} + + postcss-cli@11.0.1(jiti@2.6.1)(postcss@8.5.8): + dependencies: + chokidar: 3.6.0 + dependency-graph: 1.0.0 + fs-extra: 11.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-load-config: 5.1.0(jiti@2.6.1)(postcss@8.5.8) + postcss-reporter: 7.1.0(postcss@8.5.8) + pretty-hrtime: 1.0.3 + read-cache: 1.0.0 + slash: 5.1.0 + tinyglobby: 0.2.15 + yargs: 17.7.2 + transitivePeerDependencies: + - jiti + - tsx + + postcss-load-config@5.1.0(jiti@2.6.1)(postcss@8.5.8): + dependencies: + lilconfig: 3.1.3 + yaml: 2.8.3 + optionalDependencies: + jiti: 2.6.1 + postcss: 8.5.8 + + postcss-reporter@7.1.0(postcss@8.5.8): + dependencies: + picocolors: 1.1.1 + postcss: 8.5.8 + thenby: 1.3.4 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-hrtime@1.0.3: {} + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + require-directory@2.1.1: {} + + slash@5.1.0: {} + + source-map-js@1.2.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + tailwindcss@4.2.2: {} + + tapable@2.3.2: {} + + thenby@1.3.4: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + universalify@2.0.1: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + y18n@5.0.8: {} + + yaml@2.8.3: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..de8ec71 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + "@tailwindcss/postcss": {}, + autoprefixer: {}, + }, +}; diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000..c64c112 --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/images/og-default.jpg b/static/images/og-default.jpg new file mode 100644 index 0000000..ace90ad Binary files /dev/null and b/static/images/og-default.jpg differ diff --git a/static/images/og-default.svg b/static/images/og-default.svg new file mode 100644 index 0000000..bcd538d --- /dev/null +++ b/static/images/og-default.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AI ART MAGAZINE + + + + + + PIVOINE + + + Where the machine dreams. + + + PIVOINE.ART + + \ No newline at end of file diff --git a/static/images/og-logo.svg b/static/images/og-logo.svg new file mode 100644 index 0000000..b0d2d29 --- /dev/null +++ b/static/images/og-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 0000000..4c9b3e2 --- /dev/null +++ b/static/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file