From 2a2d9f50f1c5d0a1134d59d5f8b526cfad59fce3 Mon Sep 17 00:00:00 2001 From: ArtemBozhko Date: Mon, 5 Oct 2026 21:12:36 +0300 Subject: [PATCH] Add SCSS --- package-lock.json | 359 +++++++++++ package.json | 1 + src/layouts/AdminLayout.astro | 2 +- src/layouts/BaseLayout.astro | 2 +- src/styles/_admin.scss | 101 +++ src/styles/_auth.scss | 36 ++ src/styles/_base.scss | 67 ++ src/styles/_buttons.scss | 91 +++ src/styles/_cards.scss | 131 ++++ src/styles/_contact.scss | 22 + src/styles/_event-detail.scss | 67 ++ src/styles/_filters.scss | 43 ++ src/styles/_footer.scss | 38 ++ src/styles/_forms.scss | 74 +++ src/styles/_header.scss | 102 +++ src/styles/_hero.scss | 40 ++ src/styles/_layout.scss | 61 ++ src/styles/_map.scss | 23 + src/styles/_misc.scss | 49 ++ src/styles/_responsive.scss | 53 ++ src/styles/_reviews.scss | 59 ++ src/styles/_tokens.scss | 47 ++ src/styles/_utilities.scss | 31 + src/styles/global.css | 1116 --------------------------------- src/styles/global.scss | 23 + 25 files changed, 1520 insertions(+), 1118 deletions(-) create mode 100644 src/styles/_admin.scss create mode 100644 src/styles/_auth.scss create mode 100644 src/styles/_base.scss create mode 100644 src/styles/_buttons.scss create mode 100644 src/styles/_cards.scss create mode 100644 src/styles/_contact.scss create mode 100644 src/styles/_event-detail.scss create mode 100644 src/styles/_filters.scss create mode 100644 src/styles/_footer.scss create mode 100644 src/styles/_forms.scss create mode 100644 src/styles/_header.scss create mode 100644 src/styles/_hero.scss create mode 100644 src/styles/_layout.scss create mode 100644 src/styles/_map.scss create mode 100644 src/styles/_misc.scss create mode 100644 src/styles/_responsive.scss create mode 100644 src/styles/_reviews.scss create mode 100644 src/styles/_tokens.scss create mode 100644 src/styles/_utilities.scss delete mode 100644 src/styles/global.css create mode 100644 src/styles/global.scss diff --git a/package-lock.json b/package-lock.json index 716b75e..ecb5b73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "devDependencies": { "@astrojs/check": "^0.9.10", "@types/leaflet": "^1.9.22", + "sass": "^1.102.0", "typescript": "^6.0.3" }, "engines": { @@ -4173,6 +4174,259 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-wasm": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.6.0.tgz", @@ -4199,6 +4453,46 @@ "inBundle": true, "license": "MIT" }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -8417,6 +8711,13 @@ "node": ">=16.x" } }, + "node_modules/immutable": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", + "devOptional": true, + "license": "MIT" + }, "node_modules/import-in-the-middle": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.3.3.tgz", @@ -10078,6 +10379,13 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -11417,6 +11725,57 @@ "node": ">=10" } }, + "node_modules/sass": { + "version": "1.102.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz", + "integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/satteri": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.9.5.tgz", diff --git a/package.json b/package.json index a78fb9e..2712479 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "devDependencies": { "@astrojs/check": "^0.9.10", "@types/leaflet": "^1.9.22", + "sass": "^1.102.0", "typescript": "^6.0.3" } } diff --git a/src/layouts/AdminLayout.astro b/src/layouts/AdminLayout.astro index f46f586..17d9342 100644 --- a/src/layouts/AdminLayout.astro +++ b/src/layouts/AdminLayout.astro @@ -1,5 +1,5 @@ --- -import '../styles/global.css'; +import '../styles/global.scss'; import { getDict } from '../lib/i18n'; interface Props { diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 47095e2..adadc37 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -1,5 +1,5 @@ --- -import '../styles/global.css'; +import '../styles/global.scss'; import { LOCALES, localizedPath, getAlternateLocales } from '../lib/i18n'; import type { Locale, Dict } from '../lib/i18n'; import Header from '../components/Header.astro'; diff --git a/src/styles/_admin.scss b/src/styles/_admin.scss new file mode 100644 index 0000000..1ac901f --- /dev/null +++ b/src/styles/_admin.scss @@ -0,0 +1,101 @@ +// ============================================================ +// Admin +// ============================================================ + +.table-wrap { + overflow-x: auto; + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--surface); +} + +.table { + width: 100%; + border-collapse: collapse; + font-size: 0.92rem; + + th, + td { + padding: var(--space-3) var(--space-4); + text-align: left; + vertical-align: middle; + } + + th { + background: var(--bg-alt); + font-size: 0.78rem; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--muted); + } + + tr + tr td { + border-top: 1px solid var(--border); + } +} + +.row-actions { + display: flex; + gap: var(--space-2); + flex-wrap: wrap; + align-items: center; + flex-direction: column; + align-items: stretch; + .btn { + width: 100%; + } +} + +.admin-shell { + display: grid; + grid-template-columns: 220px 1fr; + gap: var(--space-6); + padding-block: var(--space-8); + align-items: start; +} + +.admin-nav { + display: grid; + gap: var(--space-1); + position: sticky; + top: calc(var(--header-h) + var(--space-4)); + + a { + padding: 0.6rem 0.9rem; + border-radius: var(--radius-sm); + color: var(--text); + font-weight: 500; + + &:hover { + background: var(--bg-alt); + } + + &[aria-current='page'] { + background: var(--primary); + color: #fff; + } + } +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-4); + margin-bottom: var(--space-8); +} + +.stat-card { + padding: var(--space-5); +} + +.stat-card__value { + font-family: var(--font-serif); + font-size: 2.2rem; + font-weight: 700; + color: var(--ink); +} + +.stat-card__label { + color: var(--muted); + font-size: 0.9rem; +} diff --git a/src/styles/_auth.scss b/src/styles/_auth.scss new file mode 100644 index 0000000..e2047ce --- /dev/null +++ b/src/styles/_auth.scss @@ -0,0 +1,36 @@ +// ============================================================ +// Auth +// ============================================================ + +.auth-wrap { + max-width: 420px; + margin-inline: auto; + padding-block: var(--space-8) var(--space-10); +} + +.auth-card { + padding: var(--space-8); + display: grid; + gap: var(--space-5); +} + +.oauth-buttons { + display: grid; + gap: var(--space-3); +} + +.oauth-divider { + display: flex; + align-items: center; + gap: var(--space-3); + color: var(--muted); + font-size: 0.85rem; + + &::before, + &::after { + content: ''; + flex: 1; + height: 1px; + background: var(--border); + } +} diff --git a/src/styles/_base.scss b/src/styles/_base.scss new file mode 100644 index 0000000..d82cda8 --- /dev/null +++ b/src/styles/_base.scss @@ -0,0 +1,67 @@ +// ============================================================ +// Base & reset +// ============================================================ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + background: var(--bg); + color: var(--text); + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +h1, +h2, +h3, +h4 { + font-family: var(--font-serif); + color: var(--ink); + line-height: 1.2; + margin: 0 0 0.5em; + font-weight: 600; +} + +h1 { + font-size: clamp(2rem, 5vw, 3.25rem); +} +h2 { + font-size: clamp(1.5rem, 3.2vw, 2.1rem); +} +h3 { + font-size: 1.25rem; +} + +p { + margin: 0 0 1em; +} + +a { + color: var(--primary); + text-decoration: none; +} +a:hover { + color: var(--primary-strong); +} + +img { + max-width: 100%; + display: block; +} + +:focus-visible { + outline: 3px solid var(--accent); + outline-offset: 2px; + border-radius: 2px; +} diff --git a/src/styles/_buttons.scss b/src/styles/_buttons.scss new file mode 100644 index 0000000..4acdadb --- /dev/null +++ b/src/styles/_buttons.scss @@ -0,0 +1,91 @@ +// ============================================================ +// Buttons +// ============================================================ + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + font: inherit; + font-weight: 600; + padding: 0.65rem 1.25rem; + border-radius: var(--radius-full); + border: 2px solid transparent; + cursor: pointer; + text-decoration: none; + transition: + background 0.15s ease, + color 0.15s ease, + border-color 0.15s ease, + transform 0.1s ease; + line-height: 1.2; + + &:active { + transform: translateY(1px); + } + + &:disabled { + opacity: 0.55; + cursor: not-allowed; + } +} + +.btn--primary { + background: var(--primary); + color: #fff; + + &:hover { + background: var(--primary-strong); + color: #fff; + } +} + +.btn--accent { + background: var(--accent); + color: #fff; + + &:hover { + background: var(--accent-strong); + color: #fff; + } +} + +.btn--outline { + background: transparent; + border-color: var(--primary); + color: var(--primary); + + &:hover { + background: var(--primary-soft); + color: var(--primary-strong); + } +} + +.btn--ghost { + background: transparent; + color: var(--text); + + &:hover { + background: var(--bg-alt); + } +} + +.btn--danger { + background: var(--danger); + color: #fff; + + &:hover { + filter: brightness(0.92); + color: #fff; + } +} + +.btn--sm { + padding: 0.4rem 0.9rem; + font-size: 0.875rem; +} + +.btn--block { + width: 100%; +} diff --git a/src/styles/_cards.scss b/src/styles/_cards.scss new file mode 100644 index 0000000..207d5ed --- /dev/null +++ b/src/styles/_cards.scss @@ -0,0 +1,131 @@ +// ============================================================ +// Cards & badges +// ============================================================ + +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow-sm); + overflow: hidden; +} + +.event-card { + display: flex; + flex-direction: column; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); + overflow: hidden; + text-decoration: none; + color: inherit; + transition: + transform 0.18s ease, + box-shadow 0.18s ease; + + &:hover { + transform: translateY(-3px); + box-shadow: var(--shadow-lg); + color: inherit; + } +} + +.event-card__media { + position: relative; + aspect-ratio: 16 / 9; + background: var(--bg-alt); + overflow: hidden; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.event-card__media-placeholder { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + font-family: var(--font-serif); + font-size: 2rem; + color: var(--primary); + background: + radial-gradient(circle at 30% 20%, var(--primary-soft), transparent 60%), + var(--bg-alt); +} + +.event-card__date-badge { + position: absolute; + top: var(--space-3); + left: var(--space-3); + background: var(--accent); + color: #fff; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.06em; + padding: 0.35rem 0.7rem; + border-radius: var(--radius-full); + box-shadow: var(--shadow-sm); +} + +.event-card__body { + padding: var(--space-5); + display: flex; + flex-direction: column; + gap: var(--space-2); + flex: 1; +} + +.event-card__title { + font-family: var(--font-serif); + font-size: 1.3rem; + font-weight: 600; + color: var(--ink); + margin: 0; +} + +.event-card__meta { + display: flex; + flex-wrap: wrap; + gap: var(--space-2) var(--space-4); + color: var(--muted); + font-size: 0.875rem; +} + +.event-card__foot { + margin-top: auto; + padding-top: var(--space-3); + display: flex; + justify-content: space-between; + align-items: center; +} + +.badge { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.78rem; + font-weight: 600; + letter-spacing: 0.04em; + padding: 0.28rem 0.7rem; + border-radius: var(--radius-full); +} + +.badge--published { + background: var(--primary-soft); + color: var(--primary-strong); +} + +.badge--draft { + background: var(--accent-soft); + color: var(--accent-strong); +} + +.badge--past { + background: var(--bg-alt); + color: var(--muted); +} diff --git a/src/styles/_contact.scss b/src/styles/_contact.scss new file mode 100644 index 0000000..1b5898c --- /dev/null +++ b/src/styles/_contact.scss @@ -0,0 +1,22 @@ +// ============================================================ +// Contact +// ============================================================ + +.contact-details { + display: grid; + gap: var(--space-4); +} + +.contact-detail { + display: flex; + gap: var(--space-3); + align-items: flex-start; +} + +.contact-detail__label { + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--muted); + font-weight: 600; +} diff --git a/src/styles/_event-detail.scss b/src/styles/_event-detail.scss new file mode 100644 index 0000000..ca78040 --- /dev/null +++ b/src/styles/_event-detail.scss @@ -0,0 +1,67 @@ +// ============================================================ +// Event detail +// ============================================================ + +.event-hero { + position: relative; + padding-block: var(--space-8) var(--space-10); +} + +.event-hero__media { + border-radius: var(--radius-lg); + overflow: hidden; + aspect-ratio: 21 / 9; + background: var(--bg-alt); + box-shadow: var(--shadow); + margin-bottom: var(--space-6); + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.event-hero__body { + display: grid; + grid-template-columns: 1fr 340px; + gap: var(--space-8); + align-items: start; +} + +.event-facts { + display: grid; + gap: var(--space-4); +} + +.event-fact { + display: flex; + gap: var(--space-3); + align-items: flex-start; +} + +.event-fact__icon { + font-size: 1.15rem; + line-height: 1.4; +} + +.event-fact__label { + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--muted); + font-weight: 600; +} + +.event-fact__value { + font-weight: 600; + color: var(--ink); +} + +.prose { + color: var(--text); + + p { + white-space: pre-line; + } +} diff --git a/src/styles/_filters.scss b/src/styles/_filters.scss new file mode 100644 index 0000000..b919def --- /dev/null +++ b/src/styles/_filters.scss @@ -0,0 +1,43 @@ +// ============================================================ +// Filters & tabs +// ============================================================ + +.filter-bar { + display: flex; + gap: var(--space-3); + align-items: center; + flex-wrap: wrap; + margin-bottom: var(--space-6); +} + +.tabs { + display: inline-flex; + background: var(--bg-alt); + border-radius: var(--radius-full); + padding: 3px; + gap: 2px; + + button { + border: none; + background: transparent; + font: inherit; + font-weight: 600; + font-size: 0.9rem; + padding: 0.45rem 1rem; + border-radius: var(--radius-full); + cursor: pointer; + color: var(--text); + + &.is-active { + background: var(--surface); + color: var(--primary-strong); + box-shadow: var(--shadow-sm); + } + } +} + +.search-input { + flex: 1; + min-width: 220px; + max-width: 360px; +} diff --git a/src/styles/_footer.scss b/src/styles/_footer.scss new file mode 100644 index 0000000..8a5a8de --- /dev/null +++ b/src/styles/_footer.scss @@ -0,0 +1,38 @@ +// ============================================================ +// Footer +// ============================================================ + +.footer { + background: var(--ink); + color: rgb(255 255 255 / 0.75); + padding-block: var(--space-8) var(--space-6); + margin-top: var(--space-10); + + a { + color: rgb(255 255 255 / 0.8); + + &:hover { + color: #fff; + } + } +} + +.footer__grid { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + gap: var(--space-8); +} + +.footer__title { + font-family: var(--font-serif); + color: #fff; + font-size: 1.05rem; + margin-bottom: var(--space-3); +} + +.footer__bottom { + margin-top: var(--space-8); + padding-top: var(--space-4); + border-top: 1px solid rgb(255 255 255 / 0.15); + font-size: 0.85rem; +} diff --git a/src/styles/_forms.scss b/src/styles/_forms.scss new file mode 100644 index 0000000..6c4183b --- /dev/null +++ b/src/styles/_forms.scss @@ -0,0 +1,74 @@ +// ============================================================ +// Forms +// ============================================================ + +.form { + display: grid; + gap: var(--space-4); +} + +.form-field { + display: grid; + gap: var(--space-2); +} + +.form-field label, +.form-field__label { + font-weight: 600; + font-size: 0.9rem; + color: var(--ink); +} + +.input, +.textarea, +.select { + font: inherit; + width: 100%; + padding: 0.7rem 0.9rem; + border: 1.5px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--surface); + color: var(--ink); + transition: + border-color 0.15s ease, + box-shadow 0.15s ease; + + &:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px var(--primary-soft); + } +} + +.textarea { + min-height: 130px; + resize: vertical; +} + +.form-error { + background: var(--danger-soft); + color: var(--danger); + padding: var(--space-3) var(--space-4); + border-radius: var(--radius-sm); + font-size: 0.9rem; +} + +.form-success { + background: var(--primary-soft); + color: var(--primary-strong); + padding: var(--space-3) var(--space-4); + border-radius: var(--radius-sm); + font-size: 0.9rem; +} + +.field-error { + color: var(--danger); + font-size: 0.8rem; +} + +.honeypot { + position: absolute; + left: -9999px; + opacity: 0; + pointer-events: none; +} diff --git a/src/styles/_header.scss b/src/styles/_header.scss new file mode 100644 index 0000000..de21916 --- /dev/null +++ b/src/styles/_header.scss @@ -0,0 +1,102 @@ +// ============================================================ +// Header & navigation +// ============================================================ + +.header { + position: sticky; + top: 0; + z-index: 50; + background: rgb(250 246 239 / 0.92); + backdrop-filter: blur(10px); + border-bottom: 1px solid var(--border); +} + +.header__inner { + display: flex; + align-items: center; + gap: var(--space-4); + min-height: var(--header-h); +} + +.logo { + display: flex; + align-items: center; + gap: var(--space-2); + font-family: var(--font-serif); + font-size: 1.35rem; + font-weight: 700; + color: var(--ink); + text-decoration: none; + + &:hover { + color: var(--primary); + } +} + +.logo__mark { + width: 34px; + height: 34px; + border-radius: 50%; + background: var(--primary); + color: #fff; + display: grid; + place-items: center; + font-family: var(--font-serif); + font-size: 0.95rem; + font-weight: 700; +} + +.nav { + display: flex; + align-items: center; + gap: var(--space-1); + margin-left: auto; + flex-wrap: wrap; +} + +.nav__link { + padding: 0.5rem 0.85rem; + border-radius: var(--radius-full); + color: var(--text); + font-weight: 500; + font-size: 0.95rem; + text-decoration: none; + + &:hover { + background: var(--bg-alt); + color: var(--ink); + } + + &[aria-current='page'] { + background: var(--primary-soft); + color: var(--primary-strong); + } +} + +.nav__sep { + width: 1px; + height: 22px; + background: var(--border-strong); + margin-inline: var(--space-1); +} + +.lang-switch { + display: inline-flex; + border: 1px solid var(--border-strong); + border-radius: var(--radius-full); + overflow: hidden; + background: var(--surface); + + a { + padding: 0.35rem 0.75rem; + font-size: 0.8rem; + font-weight: 600; + color: var(--muted); + text-decoration: none; + + &[aria-current='true'] { + background: var(--primary); + color: #fff; + } + } +} diff --git a/src/styles/_hero.scss b/src/styles/_hero.scss new file mode 100644 index 0000000..4df66a7 --- /dev/null +++ b/src/styles/_hero.scss @@ -0,0 +1,40 @@ +// ============================================================ +// Hero +// ============================================================ + +.hero { + position: relative; + padding-block: var(--space-12); + overflow: hidden; + + &::before { + content: ''; + position: absolute; + inset: 0; + background: + radial-gradient(60% 60% at 85% 15%, rgb(217 108 63 / 0.16), transparent 70%), + radial-gradient(50% 50% at 10% 90%, rgb(46 107 79 / 0.18), transparent 70%); + z-index: -1; + } + + h1 { + margin-bottom: var(--space-4); + } + + p { + font-size: 1.15rem; + color: var(--text); + max-width: 60ch; + } +} + +.hero__inner { + max-width: 720px; +} + +.hero__actions { + display: flex; + gap: var(--space-3); + margin-top: var(--space-6); + flex-wrap: wrap; +} diff --git a/src/styles/_layout.scss b/src/styles/_layout.scss new file mode 100644 index 0000000..c3ba178 --- /dev/null +++ b/src/styles/_layout.scss @@ -0,0 +1,61 @@ +// ============================================================ +// Layout +// ============================================================ + +.container { + width: 100%; + max-width: var(--container); + margin-inline: auto; + padding-inline: var(--space-5); +} + +.section { + padding-block: var(--space-10); +} + +.section--alt { + background: var(--bg-alt); +} + +.section-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: var(--space-4); + margin-bottom: var(--space-6); + flex-wrap: wrap; +} + +.section-head p { + color: var(--muted); + margin: 0; +} + +.eyebrow { + display: inline-block; + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--accent-strong); + margin-bottom: var(--space-2); +} + +.split { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-8); + align-items: start; +} + +.grid-3 { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-5); +} + +.grid-2 { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: var(--space-5); +} diff --git a/src/styles/_map.scss b/src/styles/_map.scss new file mode 100644 index 0000000..c4de5b4 --- /dev/null +++ b/src/styles/_map.scss @@ -0,0 +1,23 @@ +// ============================================================ +// Map +// ============================================================ + +.map-wrap { + height: 420px; + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow); + border: 1px solid var(--border); + z-index: 1; +} + +.map-page { + display: grid; + grid-template-columns: 320px 1fr; + gap: var(--space-6); + align-items: stretch; +} + +.leaflet-container { + font: inherit; +} diff --git a/src/styles/_misc.scss b/src/styles/_misc.scss new file mode 100644 index 0000000..b229896 --- /dev/null +++ b/src/styles/_misc.scss @@ -0,0 +1,49 @@ +// ============================================================ +// Misc components +// ============================================================ + +.empty-state { + text-align: center; + padding: var(--space-10) var(--space-6); + color: var(--muted); +} + +.empty-state__icon { + font-size: 2.5rem; + margin-bottom: var(--space-3); +} + +.cta-band { + background: var(--primary); + color: #fff; + border-radius: var(--radius-lg); + padding: var(--space-8); + text-align: center; + + h2 { + color: #fff; + } + + p { + color: rgb(255 255 255 / 0.85); + max-width: 52ch; + margin-inline: auto; + } + + .btn--accent { + background: var(--accent); + } +} + +.avatar { + width: 38px; + height: 38px; + border-radius: 50%; + object-fit: cover; + background: var(--primary-soft); + color: var(--primary-strong); + display: grid; + place-items: center; + font-weight: 700; + text-transform: uppercase; +} diff --git a/src/styles/_responsive.scss b/src/styles/_responsive.scss new file mode 100644 index 0000000..55ea4f4 --- /dev/null +++ b/src/styles/_responsive.scss @@ -0,0 +1,53 @@ +// ============================================================ +// Responsive +// ============================================================ + +@media (max-width: 920px) { + .grid-3 { + grid-template-columns: repeat(2, 1fr); + } + + .event-hero__body, + .split, + .map-page, + .admin-shell { + grid-template-columns: 1fr; + } + + .map-wrap { + height: 320px; + } + + .stats-grid { + grid-template-columns: repeat(2, 1fr); + } + + .footer__grid { + grid-template-columns: 1fr; + gap: var(--space-6); + } +} + +@media (max-width: 620px) { + .grid-3, + .grid-2 { + grid-template-columns: 1fr; + } + + .section { + padding-block: var(--space-8); + } + + .header__inner { + flex-wrap: wrap; + padding-block: var(--space-2); + } + + .nav { + order: 3; + width: 100%; + overflow-x: auto; + margin-left: 0; + padding-bottom: var(--space-1); + } +} diff --git a/src/styles/_reviews.scss b/src/styles/_reviews.scss new file mode 100644 index 0000000..076e1f3 --- /dev/null +++ b/src/styles/_reviews.scss @@ -0,0 +1,59 @@ +// ============================================================ +// Reviews +// ============================================================ + +.review { + padding: var(--space-5); + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--surface); +} + +.review__head { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--space-3); + margin-bottom: var(--space-2); +} + +.review__author { + font-weight: 600; + color: var(--ink); +} + +.review__date { + color: var(--muted); + font-size: 0.85rem; +} + +.stars { + color: var(--accent); + letter-spacing: 0.1em; + font-size: 1.05rem; +} + +.star-rating { + display: inline-flex; + gap: 0.2rem; + + button { + background: none; + border: none; + font-size: 1.6rem; + line-height: 1; + cursor: pointer; + color: var(--border-strong); + transition: color 0.1s ease; + padding: 0.1rem; + + &.is-selected { + color: var(--accent); + } + } +} + +.review-list { + display: grid; + gap: var(--space-4); +} diff --git a/src/styles/_tokens.scss b/src/styles/_tokens.scss new file mode 100644 index 0000000..24c7219 --- /dev/null +++ b/src/styles/_tokens.scss @@ -0,0 +1,47 @@ +// ============================================================ +// Design tokens +// ============================================================ + +:root { + --bg: #faf6ef; + --bg-alt: #f2ead9; + --surface: #ffffff; + --ink: #1d2a24; + --text: #3f4c44; + --muted: #6d766f; + --primary: #2e6b4f; + --primary-strong: #22543d; + --primary-soft: #e4efe8; + --accent: #d96c3f; + --accent-strong: #b8522b; + --accent-soft: #f9e6d8; + --danger: #b3392f; + --danger-soft: #fbe3e0; + --border: #e4d9c5; + --border-strong: #d3c5a9; + + --radius-sm: 6px; + --radius: 12px; + --radius-lg: 20px; + --radius-full: 999px; + + --shadow-sm: 0 1px 2px rgb(29 42 36 / 0.06); + --shadow: 0 4px 16px rgb(29 42 36 / 0.08); + --shadow-lg: 0 12px 40px rgb(29 42 36 / 0.14); + + --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; + --font-serif: 'Fraunces', Georgia, 'Times New Roman', serif; + + --container: 1160px; + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.5rem; + --space-6: 2rem; + --space-8: 3rem; + --space-10: 4rem; + --space-12: 5rem; + + --header-h: 68px; +} diff --git a/src/styles/_utilities.scss b/src/styles/_utilities.scss new file mode 100644 index 0000000..e42b23f --- /dev/null +++ b/src/styles/_utilities.scss @@ -0,0 +1,31 @@ +// ============================================================ +// Utilities +// ============================================================ + +.mt-6 { + margin-top: var(--space-6); +} + +.mb-2 { + margin-bottom: var(--space-2); +} + +.mb-6 { + margin-bottom: var(--space-6); +} + +.text-muted { + color: var(--muted); +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} diff --git a/src/styles/global.css b/src/styles/global.css deleted file mode 100644 index dbbf4d7..0000000 --- a/src/styles/global.css +++ /dev/null @@ -1,1116 +0,0 @@ -/* ============================================================ - Devodytyji — design tokens & base styles - ============================================================ */ - -:root { - --bg: #faf6ef; - --bg-alt: #f2ead9; - --surface: #ffffff; - --ink: #1d2a24; - --text: #3f4c44; - --muted: #6d766f; - --primary: #2e6b4f; - --primary-strong: #22543d; - --primary-soft: #e4efe8; - --accent: #d96c3f; - --accent-strong: #b8522b; - --accent-soft: #f9e6d8; - --danger: #b3392f; - --danger-soft: #fbe3e0; - --border: #e4d9c5; - --border-strong: #d3c5a9; - - --radius-sm: 6px; - --radius: 12px; - --radius-lg: 20px; - --radius-full: 999px; - - --shadow-sm: 0 1px 2px rgb(29 42 36 / 0.06); - --shadow: 0 4px 16px rgb(29 42 36 / 0.08); - --shadow-lg: 0 12px 40px rgb(29 42 36 / 0.14); - - --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; - --font-serif: 'Fraunces', Georgia, 'Times New Roman', serif; - - --container: 1160px; - --space-1: 0.25rem; - --space-2: 0.5rem; - --space-3: 0.75rem; - --space-4: 1rem; - --space-5: 1.5rem; - --space-6: 2rem; - --space-8: 3rem; - --space-10: 4rem; - --space-12: 5rem; - - --header-h: 68px; -} - -*, -*::before, -*::after { - box-sizing: border-box; -} - -html { - scroll-behavior: smooth; -} - -body { - margin: 0; - background: var(--bg); - color: var(--text); - font-family: var(--font-sans); - font-size: 16px; - line-height: 1.6; - -webkit-font-smoothing: antialiased; -} - -h1, -h2, -h3, -h4 { - font-family: var(--font-serif); - color: var(--ink); - line-height: 1.2; - margin: 0 0 0.5em; - font-weight: 600; -} - -h1 { - font-size: clamp(2rem, 5vw, 3.25rem); -} -h2 { - font-size: clamp(1.5rem, 3.2vw, 2.1rem); -} -h3 { - font-size: 1.25rem; -} - -p { - margin: 0 0 1em; -} - -a { - color: var(--primary); - text-decoration: none; -} -a:hover { - color: var(--primary-strong); -} - -img { - max-width: 100%; - display: block; -} - -:focus-visible { - outline: 3px solid var(--accent); - outline-offset: 2px; - border-radius: 2px; -} - -.container { - width: 100%; - max-width: var(--container); - margin-inline: auto; - padding-inline: var(--space-5); -} - -.section { - padding-block: var(--space-10); -} - -.section--alt { - background: var(--bg-alt); -} - -.section-head { - display: flex; - align-items: flex-end; - justify-content: space-between; - gap: var(--space-4); - margin-bottom: var(--space-6); - flex-wrap: wrap; -} - -.section-head p { - color: var(--muted); - margin: 0; -} - -.eyebrow { - display: inline-block; - font-size: 0.8rem; - font-weight: 600; - letter-spacing: 0.12em; - text-transform: uppercase; - color: var(--accent-strong); - margin-bottom: var(--space-2); -} - -/* ---------- Buttons ---------- */ - -.btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: var(--space-2); - font: inherit; - font-weight: 600; - padding: 0.65rem 1.25rem; - border-radius: var(--radius-full); - border: 2px solid transparent; - cursor: pointer; - text-decoration: none; - transition: - background 0.15s ease, - color 0.15s ease, - border-color 0.15s ease, - transform 0.1s ease; - line-height: 1.2; -} - -.btn:active { - transform: translateY(1px); -} - -.btn--primary { - background: var(--primary); - color: #fff; -} -.btn--primary:hover { - background: var(--primary-strong); - color: #fff; -} - -.btn--accent { - background: var(--accent); - color: #fff; -} -.btn--accent:hover { - background: var(--accent-strong); - color: #fff; -} - -.btn--outline { - background: transparent; - border-color: var(--primary); - color: var(--primary); -} -.btn--outline:hover { - background: var(--primary-soft); - color: var(--primary-strong); -} - -.btn--ghost { - background: transparent; - color: var(--text); -} -.btn--ghost:hover { - background: var(--bg-alt); -} - -.btn--danger { - background: var(--danger); - color: #fff; -} -.btn--danger:hover { - filter: brightness(0.92); - color: #fff; -} - -.btn--sm { - padding: 0.4rem 0.9rem; - font-size: 0.875rem; -} - -.btn--block { - width: 100%; -} - -.btn:disabled { - opacity: 0.55; - cursor: not-allowed; -} - -/* ---------- Cards ---------- */ - -.card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); - overflow: hidden; -} - -/* ---------- Event cards ---------- */ - -.event-card { - display: flex; - flex-direction: column; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - overflow: hidden; - text-decoration: none; - color: inherit; - transition: - transform 0.18s ease, - box-shadow 0.18s ease; -} - -.event-card:hover { - transform: translateY(-3px); - box-shadow: var(--shadow-lg); - color: inherit; -} - -.event-card__media { - position: relative; - aspect-ratio: 16 / 9; - background: var(--bg-alt); - overflow: hidden; -} - -.event-card__media img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.event-card__media-placeholder { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - font-family: var(--font-serif); - font-size: 2rem; - color: var(--primary); - background: - radial-gradient(circle at 30% 20%, var(--primary-soft), transparent 60%), - var(--bg-alt); -} - -.event-card__date-badge { - position: absolute; - top: var(--space-3); - left: var(--space-3); - background: var(--accent); - color: #fff; - font-size: 0.75rem; - font-weight: 700; - letter-spacing: 0.06em; - padding: 0.35rem 0.7rem; - border-radius: var(--radius-full); - box-shadow: var(--shadow-sm); -} - -.event-card__body { - padding: var(--space-5); - display: flex; - flex-direction: column; - gap: var(--space-2); - flex: 1; -} - -.event-card__title { - font-family: var(--font-serif); - font-size: 1.3rem; - font-weight: 600; - color: var(--ink); - margin: 0; -} - -.event-card__meta { - display: flex; - flex-wrap: wrap; - gap: var(--space-2) var(--space-4); - color: var(--muted); - font-size: 0.875rem; -} - -.event-card__foot { - margin-top: auto; - padding-top: var(--space-3); - display: flex; - justify-content: space-between; - align-items: center; -} - -.badge { - display: inline-flex; - align-items: center; - gap: 0.35rem; - font-size: 0.78rem; - font-weight: 600; - letter-spacing: 0.04em; - padding: 0.28rem 0.7rem; - border-radius: var(--radius-full); -} - -.badge--published { - background: var(--primary-soft); - color: var(--primary-strong); -} - -.badge--draft { - background: var(--accent-soft); - color: var(--accent-strong); -} - -.badge--past { - background: var(--bg-alt); - color: var(--muted); -} - -/* ---------- Header ---------- */ - -.header { - position: sticky; - top: 0; - z-index: 50; - background: rgb(250 246 239 / 0.92); - backdrop-filter: blur(10px); - border-bottom: 1px solid var(--border); -} - -.header__inner { - display: flex; - align-items: center; - gap: var(--space-4); - min-height: var(--header-h); -} - -.logo { - display: flex; - align-items: center; - gap: var(--space-2); - font-family: var(--font-serif); - font-size: 1.35rem; - font-weight: 700; - color: var(--ink); - text-decoration: none; -} - -.logo:hover { - color: var(--primary); -} - -.logo__mark { - width: 34px; - height: 34px; - border-radius: 50%; - background: var(--primary); - color: #fff; - display: grid; - place-items: center; - font-family: var(--font-serif); - font-size: 0.95rem; - font-weight: 700; -} - -.nav { - display: flex; - align-items: center; - gap: var(--space-1); - margin-left: auto; - flex-wrap: wrap; -} - -.nav__link { - padding: 0.5rem 0.85rem; - border-radius: var(--radius-full); - color: var(--text); - font-weight: 500; - font-size: 0.95rem; - text-decoration: none; -} - -.nav__link:hover { - background: var(--bg-alt); - color: var(--ink); -} - -.nav__link[aria-current='page'] { - background: var(--primary-soft); - color: var(--primary-strong); -} - -.nav__sep { - width: 1px; - height: 22px; - background: var(--border-strong); - margin-inline: var(--space-1); -} - -.lang-switch { - display: inline-flex; - border: 1px solid var(--border-strong); - border-radius: var(--radius-full); - overflow: hidden; - background: var(--surface); -} - -.lang-switch a { - padding: 0.35rem 0.75rem; - font-size: 0.8rem; - font-weight: 600; - color: var(--muted); - text-decoration: none; -} - -.lang-switch a[aria-current='true'] { - background: var(--primary); - color: #fff; -} - -/* ---------- Footer ---------- */ - -.footer { - background: var(--ink); - color: rgb(255 255 255 / 0.75); - padding-block: var(--space-8) var(--space-6); - margin-top: var(--space-10); -} - -.footer__grid { - display: grid; - grid-template-columns: 2fr 1fr 1fr; - gap: var(--space-8); -} - -.footer a { - color: rgb(255 255 255 / 0.8); -} -.footer a:hover { - color: #fff; -} - -.footer__title { - font-family: var(--font-serif); - color: #fff; - font-size: 1.05rem; - margin-bottom: var(--space-3); -} - -.footer__bottom { - margin-top: var(--space-8); - padding-top: var(--space-4); - border-top: 1px solid rgb(255 255 255 / 0.15); - font-size: 0.85rem; -} - -/* ---------- Forms ---------- */ - -.form { - display: grid; - gap: var(--space-4); -} - -.form-field { - display: grid; - gap: var(--space-2); -} - -.form-field label { - font-weight: 600; - font-size: 0.9rem; - color: var(--ink); -} - -.form-field__label { - font-weight: 600; - font-size: 0.9rem; - color: var(--ink); -} - -.input, -.textarea, -.select { - font: inherit; - width: 100%; - padding: 0.7rem 0.9rem; - border: 1.5px solid var(--border-strong); - border-radius: var(--radius-sm); - background: var(--surface); - color: var(--ink); - transition: - border-color 0.15s ease, - box-shadow 0.15s ease; -} - -.input:focus, -.textarea:focus, -.select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px var(--primary-soft); -} - -.textarea { - min-height: 130px; - resize: vertical; -} - -.form-error { - background: var(--danger-soft); - color: var(--danger); - padding: var(--space-3) var(--space-4); - border-radius: var(--radius-sm); - font-size: 0.9rem; -} - -.form-success { - background: var(--primary-soft); - color: var(--primary-strong); - padding: var(--space-3) var(--space-4); - border-radius: var(--radius-sm); - font-size: 0.9rem; -} - -.field-error { - color: var(--danger); - font-size: 0.8rem; -} - -.honeypot { - position: absolute; - left: -9999px; - opacity: 0; - pointer-events: none; -} - -/* ---------- Auth card ---------- */ - -.auth-wrap { - max-width: 420px; - margin-inline: auto; - padding-block: var(--space-8) var(--space-10); -} - -.auth-card { - padding: var(--space-8); - display: grid; - gap: var(--space-5); -} - -.oauth-buttons { - display: grid; - gap: var(--space-3); -} - -.oauth-divider { - display: flex; - align-items: center; - gap: var(--space-3); - color: var(--muted); - font-size: 0.85rem; -} - -.oauth-divider::before, -.oauth-divider::after { - content: ''; - flex: 1; - height: 1px; - background: var(--border); -} - -/* ---------- Reviews ---------- */ - -.review { - padding: var(--space-5); - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--surface); -} - -.review__head { - display: flex; - justify-content: space-between; - align-items: center; - gap: var(--space-3); - margin-bottom: var(--space-2); -} - -.review__author { - font-weight: 600; - color: var(--ink); -} - -.review__date { - color: var(--muted); - font-size: 0.85rem; -} - -.stars { - color: var(--accent); - letter-spacing: 0.1em; - font-size: 1.05rem; -} - -.star-rating { - display: inline-flex; - gap: 0.2rem; -} - -.star-rating button { - background: none; - border: none; - font-size: 1.6rem; - line-height: 1; - cursor: pointer; - color: var(--border-strong); - transition: color 0.1s ease; - padding: 0.1rem; -} - -.star-rating button.is-selected { - color: var(--accent); -} - -.review-list { - display: grid; - gap: var(--space-4); -} - -/* ---------- Event detail ---------- */ - -.event-hero { - position: relative; - padding-block: var(--space-8) var(--space-10); -} - -.event-hero__media { - border-radius: var(--radius-lg); - overflow: hidden; - aspect-ratio: 21 / 9; - background: var(--bg-alt); - box-shadow: var(--shadow); - margin-bottom: var(--space-6); -} - -.event-hero__media img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.event-hero__body { - display: grid; - grid-template-columns: 1fr 340px; - gap: var(--space-8); - align-items: start; -} - -.event-facts { - display: grid; - gap: var(--space-4); -} - -.event-fact { - display: flex; - gap: var(--space-3); - align-items: flex-start; -} - -.event-fact__icon { - font-size: 1.15rem; - line-height: 1.4; -} - -.event-fact__label { - font-size: 0.8rem; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--muted); - font-weight: 600; -} - -.event-fact__value { - font-weight: 600; - color: var(--ink); -} - -.prose { - color: var(--text); -} -.prose p { - white-space: pre-line; -} - -/* ---------- Map ---------- */ - -.map-wrap { - height: 420px; - border-radius: var(--radius-lg); - overflow: hidden; - box-shadow: var(--shadow); - border: 1px solid var(--border); - z-index: 1; -} - -.map-page { - display: grid; - grid-template-columns: 320px 1fr; - gap: var(--space-6); - align-items: stretch; -} - -.leaflet-container { - font: inherit; -} - -/* ---------- Contact / About layouts ---------- */ - -.split { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--space-8); - align-items: start; -} - -.contact-details { - display: grid; - gap: var(--space-4); -} - -.contact-detail { - display: flex; - gap: var(--space-3); - align-items: flex-start; -} - -.contact-detail__label { - font-size: 0.8rem; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--muted); - font-weight: 600; -} - -/* ---------- Tables (admin) ---------- */ - -.table-wrap { - overflow-x: auto; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--surface); -} - -.table { - width: 100%; - border-collapse: collapse; - font-size: 0.92rem; -} - -.table th, -.table td { - padding: var(--space-3) var(--space-4); - text-align: left; - vertical-align: middle; -} - -.table th { - background: var(--bg-alt); - font-size: 0.78rem; - text-transform: uppercase; - letter-spacing: 0.07em; - color: var(--muted); -} - -.table tr + tr td { - border-top: 1px solid var(--border); -} - -.table .row-actions { - display: flex; - gap: var(--space-2); - flex-wrap: wrap; - align-items: center; -} - -/* ---------- Admin layout ---------- */ - -.admin-shell { - display: grid; - grid-template-columns: 220px 1fr; - gap: var(--space-6); - padding-block: var(--space-8); - align-items: start; -} - -.admin-nav { - display: grid; - gap: var(--space-1); - position: sticky; - top: calc(var(--header-h) + var(--space-4)); -} - -.admin-nav a { - padding: 0.6rem 0.9rem; - border-radius: var(--radius-sm); - color: var(--text); - font-weight: 500; -} - -.admin-nav a:hover { - background: var(--bg-alt); -} - -.admin-nav a[aria-current='page'] { - background: var(--primary); - color: #fff; -} - -.stats-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: var(--space-4); - margin-bottom: var(--space-8); -} - -.stat-card { - padding: var(--space-5); -} - -.stat-card__value { - font-family: var(--font-serif); - font-size: 2.2rem; - font-weight: 700; - color: var(--ink); -} - -.stat-card__label { - color: var(--muted); - font-size: 0.9rem; -} - -/* ---------- Hero (home) ---------- */ - -.hero { - position: relative; - padding-block: var(--space-12); - overflow: hidden; -} - -.hero::before { - content: ''; - position: absolute; - inset: 0; - background: - radial-gradient(60% 60% at 85% 15%, rgb(217 108 63 / 0.16), transparent 70%), - radial-gradient(50% 50% at 10% 90%, rgb(46 107 79 / 0.18), transparent 70%); - z-index: -1; -} - -.hero__inner { - max-width: 720px; -} - -.hero h1 { - margin-bottom: var(--space-4); -} - -.hero p { - font-size: 1.15rem; - color: var(--text); - max-width: 60ch; -} - -.hero__actions { - display: flex; - gap: var(--space-3); - margin-top: var(--space-6); - flex-wrap: wrap; -} - -/* ---------- Grids ---------- */ - -.grid-3 { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: var(--space-5); -} - -.grid-2 { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: var(--space-5); -} - -/* ---------- Filter bar ---------- */ - -.filter-bar { - display: flex; - gap: var(--space-3); - align-items: center; - flex-wrap: wrap; - margin-bottom: var(--space-6); -} - -.tabs { - display: inline-flex; - background: var(--bg-alt); - border-radius: var(--radius-full); - padding: 3px; - gap: 2px; -} - -.tabs button { - border: none; - background: transparent; - font: inherit; - font-weight: 600; - font-size: 0.9rem; - padding: 0.45rem 1rem; - border-radius: var(--radius-full); - cursor: pointer; - color: var(--text); -} - -.tabs button.is-active { - background: var(--surface); - color: var(--primary-strong); - box-shadow: var(--shadow-sm); -} - -.search-input { - flex: 1; - min-width: 220px; - max-width: 360px; -} - -/* ---------- Empty state ---------- */ - -.empty-state { - text-align: center; - padding: var(--space-10) var(--space-6); - color: var(--muted); -} - -.empty-state__icon { - font-size: 2.5rem; - margin-bottom: var(--space-3); -} - -/* ---------- CTA band ---------- */ - -.cta-band { - background: var(--primary); - color: #fff; - border-radius: var(--radius-lg); - padding: var(--space-8); - text-align: center; -} - -.cta-band h2 { - color: #fff; -} - -.cta-band p { - color: rgb(255 255 255 / 0.85); - max-width: 52ch; - margin-inline: auto; -} - -.cta-band .btn--accent { - background: var(--accent); -} - -/* ---------- Avatar ---------- */ - -.avatar { - width: 38px; - height: 38px; - border-radius: 50%; - object-fit: cover; - background: var(--primary-soft); - color: var(--primary-strong); - display: grid; - place-items: center; - font-weight: 700; - text-transform: uppercase; -} - -/* ---------- Utilities ---------- */ - -.mt-6 { - margin-top: var(--space-6); -} - -.mb-2 { - margin-bottom: var(--space-2); -} - -.mb-6 { - margin-bottom: var(--space-6); -} - -.text-muted { - color: var(--muted); -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -@media (max-width: 920px) { - .grid-3 { - grid-template-columns: repeat(2, 1fr); - } - - .event-hero__body, - .split, - .map-page, - .admin-shell { - grid-template-columns: 1fr; - } - - .map-wrap { - height: 320px; - } - - .stats-grid { - grid-template-columns: repeat(2, 1fr); - } - - .footer__grid { - grid-template-columns: 1fr; - gap: var(--space-6); - } -} - -@media (max-width: 620px) { - .grid-3, - .grid-2 { - grid-template-columns: 1fr; - } - - .section { - padding-block: var(--space-8); - } - - .header__inner { - flex-wrap: wrap; - padding-block: var(--space-2); - } - - .nav { - order: 3; - width: 100%; - overflow-x: auto; - margin-left: 0; - padding-bottom: var(--space-1); - } -} diff --git a/src/styles/global.scss b/src/styles/global.scss new file mode 100644 index 0000000..d0a0718 --- /dev/null +++ b/src/styles/global.scss @@ -0,0 +1,23 @@ +// ============================================================ +// Devodytyji — global styles entry +// ============================================================ + +@use 'tokens'; +@use 'base'; +@use 'layout'; +@use 'buttons'; +@use 'cards'; +@use 'header'; +@use 'footer'; +@use 'forms'; +@use 'auth'; +@use 'reviews'; +@use 'event-detail'; +@use 'map'; +@use 'contact'; +@use 'admin'; +@use 'hero'; +@use 'filters'; +@use 'misc'; +@use 'utilities'; +@use 'responsive';