From e9297cac61d79acce26afb3cbaba7d9ed8446ae3 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Tue, 18 Aug 2026 21:54:44 +0000 Subject: [PATCH] Add the summer theme: illustrated meadow banner, cohesive palette A light, playful theme whose every color is sampled from its banner.svg meadow scene (sky/grass/sun/flower pink): fixed daylit landscape page background with a sun-glow echo, tilted gradient brand, flower bullets, a dense grass strip (grass.svg, served via /_themes) under h1s, rounded shadowed tables with a sunny hover sheen, and a layered-parallax banner (sun rises, clouds drift, nearer hills move less) with idle animations wrapped in prefers-reduced-motion. The /_themes route now serves any theme asset (previously only theme.css/banner.css) so CSS can reference sibling files like grass.svg. --- AGENTS.md | 11 +- pagerite/app.py | 17 +- pagerite/themes/summer/banner.css | 75 ++++++ pagerite/themes/summer/banner.svg | 369 ++++++++++++++++++++++++++++++ pagerite/themes/summer/grass.svg | 143 ++++++++++++ pagerite/themes/summer/theme.css | 262 +++++++++++++++++++++ 6 files changed, 869 insertions(+), 8 deletions(-) create mode 100644 pagerite/themes/summer/banner.css create mode 100644 pagerite/themes/summer/banner.svg create mode 100644 pagerite/themes/summer/grass.svg create mode 100644 pagerite/themes/summer/theme.css diff --git a/AGENTS.md b/AGENTS.md index 438aaa2..eda4943 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,7 +70,8 @@ not for the public pages. See `docs/design-principles.md` for the design. in the site editor via `/_api/settings`; empty = no header link and no `` suffix. `Data.theme` is the active theme name (empty = none/base only); themes are folders in `pagerite/themes/{name}` - containing `theme.css` and/or `banner.css` (+ `banner.svg` artwork), + containing `theme.css` and/or `banner.css` (+ `banner.svg` artwork and + any extra assets the CSS references, like summer's `grass.svg`), served by the backend at `/_themes/{name}/...` — read from disk per request (etag by mtime), never built, so on-disk edits show on the next page load even in prod. The theme selector and banner-design @@ -154,7 +155,13 @@ not for the public pages. See `docs/design-principles.md` for the design. brand; `nitro` = racing/HUD style following `prefers-color-scheme` (warm light-grey page, deep violet in dark), Montserrat/Literata, black as an accent only, a straight orange blade under the banner, and - an orange racing-tab nav clipped with a bezier `shape()`) and the + an orange racing-tab nav clipped with a bezier `shape()`; `summer` = + light playful meadow, one palette sampled from its illustrated + `banner.svg` (sky/grass/sun/flower pink), Fraunces/Literata, a tilted + gradient brand, flower bullets, and a layered-parallax banner (sun + rises, clouds drift, nearer hills move less) with idle animations + (swaying flowers, floating clouds, breathing sun glow) wrapped in + `prefers-reduced-motion: no-preference`) and the companion `banner.css` banner designs are served by the backend. - Vite builds ES-module `.js` outputs; the backend renders `<script type="module">` for them (module scripts defer by default). diff --git a/pagerite/app.py b/pagerite/app.py index 84567b9..3a4d1e6 100644 --- a/pagerite/app.py +++ b/pagerite/app.py @@ -412,14 +412,16 @@ async def delete_file(name: str) -> None: @app.get("/_themes/{name}/{filename}") async def theme_file(name: str, filename: str, request: Request) -> Response: - """Serve a theme/banner-design stylesheet from pagerite/themes/{name}/. + """Serve a theme/banner-design file from pagerite/themes/{name}/. - Read from disk on every request (etag by mtime+size): theme files are - never built or content-hashed, so edits on disk show on the next page - load, in prod as well as dev. + Stylesheets plus any extra assets the CSS references (like summer's + grass.svg). Read from disk on every request (etag by mtime+size): + theme files are never built or content-hashed, so edits on disk show + on the next page load, in prod as well as dev. """ if ( - filename not in {"theme.css", "banner.css"} + "/" in filename + or filename.startswith(".") or "/" in name or name.startswith(".") ): @@ -429,12 +431,15 @@ async def theme_file(name: str, filename: str, request: Request) -> Response: stat = path.stat() except FileNotFoundError: raise HTTPException(404) from None + if not path.is_file(): + raise HTTPException(404) etag = f'"{stat.st_mtime_ns:x}-{stat.st_size:x}"' if request.headers.get("if-none-match") == etag: return Response(status_code=304) + mime = mimetypes.guess_type(filename)[0] or "application/octet-stream" return Response( path.read_bytes(), - media_type="text/css", + media_type=mime, headers={"etag": etag, "cache-control": "no-cache"}, ) diff --git a/pagerite/themes/summer/banner.css b/pagerite/themes/summer/banner.css new file mode 100644 index 0000000..99118c2 --- /dev/null +++ b/pagerite/themes/summer/banner.css @@ -0,0 +1,75 @@ +/* Summer banner design: a bright illustrated meadow (inlined by the + backend into #page-banner) — rolling hills, leafy bushes, swaying + flowers, drifting clouds and a sun that rises as you scroll. */ + +#banner { + min-height: 15rem; +} + +/* The artwork fades into the page background at its bottom edge. */ +.summer-fade { + stop-color: var(--bg); +} + +/* Layered parallax on top of the whole-artwork drift (pagerite.js sets + --pry on <html>): the sun rises fastest, the clouds lag behind, and the + nearer a hill the less it moves — a cheap depth cue while scrolling. */ +#page-banner .sun, +#page-banner .sun-glow { + transform-box: fill-box; + transform: translateY(calc(var(--pry, 0px) * -1.5)); +} + +#page-banner .clouds { + transform: translateY(calc(var(--pry, 0px) * -0.7)); +} + +#page-banner .hills-far { + transform: translateY(calc(var(--pry, 0px) * -0.3)); +} + +#page-banner .hills-near { + transform: translateY(calc(var(--pry, 0px) * -0.15)); +} + +#page-banner .meadow { + transform: translateY(calc(var(--pry, 0px) * -0.05)); +} + +/* Idle animations: the sun breathes, clouds float sideways, flowers sway. + Each animated group is a transform-less wrapper so the CSS transform + never clobbers the placement transforms inside. */ +@media (prefers-reduced-motion: no-preference) { + #page-banner .sun-glow { + animation: summer-sun 9s ease-in-out infinite alternate; + } + + #page-banner .cloud-a { animation: summer-drift 56s ease-in-out infinite alternate; } + #page-banner .cloud-b { animation: summer-drift 73s ease-in-out infinite alternate-reverse; } + #page-banner .cloud-c { animation: summer-drift 64s ease-in-out infinite alternate; } + + #page-banner .flower { + transform-box: fill-box; + transform-origin: 50% 100%; + animation: summer-sway 5s ease-in-out infinite alternate; + } + + /* Stagger the sway so the meadow doesn't move in lockstep. */ + #page-banner .flower:nth-child(3n) { animation-delay: -1.7s; } + #page-banner .flower:nth-child(3n + 1) { animation-delay: -3.1s; animation-duration: 6s; } +} + +@keyframes summer-sun { + from { opacity: 0.22; } + to { opacity: 0.38; } +} + +@keyframes summer-drift { + from { transform: translateX(-1.6%); } + to { transform: translateX(1.6%); } +} + +@keyframes summer-sway { + from { transform: rotate(-2.6deg); } + to { transform: rotate(2.6deg); } +} diff --git a/pagerite/themes/summer/banner.svg b/pagerite/themes/summer/banner.svg new file mode 100644 index 0000000..21d1c95 --- /dev/null +++ b/pagerite/themes/summer/banner.svg @@ -0,0 +1,369 @@ +<svg xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 1600 320" + preserveAspectRatio="xMidYMid slice"> + + <defs> + <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> + <stop offset="0" stop-color="#8ed0ff"/> + <stop offset=".64" stop-color="#d9f1ff"/> + <stop offset="1" stop-color="#eef9ff"/> + </linearGradient> + + <linearGradient id="farHill" x1="0" y1="0" x2="0" y2="1"> + <stop offset="0" stop-color="#b8dca7"/> + <stop offset="1" stop-color="#a4cf90"/> + </linearGradient> + + <linearGradient id="nearHill" x1="0" y1="0" x2="0" y2="1"> + <stop offset="0" stop-color="#91c97c"/> + <stop offset="1" stop-color="#74b65e"/> + </linearGradient> + + <linearGradient id="grass" x1="0" y1="0" x2="0" y2="1"> + <stop offset="0" stop-color="#69ae4b"/> + <stop offset="1" stop-color="#4f913b"/> + </linearGradient> + + <!-- Soft fade into the page background (stop-color from banner.css) --> + <linearGradient id="meadowFade" x1="0" y1="0" x2="0" y2="1"> + <stop offset="0" class="summer-fade" stop-color="#e6f4cf" stop-opacity="0"/> + <stop offset="1" class="summer-fade" stop-color="#e6f4cf"/> + </linearGradient> + + <filter id="soft"> + <feGaussianBlur stdDeviation="16"/> + </filter> + + <filter id="cloudShadow" x="-20%" y="-40%" width="140%" height="180%"> + <feDropShadow dx="0" dy="3" stdDeviation="4" + flood-color="#4f8fb0" flood-opacity=".12"/> + </filter> + </defs> + + <!-- Sky --> + <rect width="1600" height="320" fill="url(#sky)"/> + + <!-- Sun (rises on scroll, glow pulses) --> + <circle class="sun-glow" cx="1330" cy="72" r="82" + fill="#fff0a2" + opacity=".28" + filter="url(#soft)"/> + <circle class="sun" cx="1330" cy="72" r="42" + fill="#fff0a2" + opacity=".82"/> + + <!-- Clouds (drift on scroll, lazily float sideways) --> + <g class="clouds" fill="#fff" opacity=".82" filter="url(#cloudShadow)"> + <g class="cloud cloud-a"> + <g transform="translate(160 72)"> + <ellipse cx="0" cy="12" rx="54" ry="20"/> + <circle cx="-27" cy="4" r="26"/> + <circle cx="7" cy="-6" r="34"/> + <circle cx="40" cy="7" r="25"/> + </g> + </g> + + <g class="cloud cloud-b" opacity=".72"> + <g transform="translate(650 52)"> + <ellipse cx="0" cy="10" rx="45" ry="16"/> + <circle cx="-21" cy="4" r="21"/> + <circle cx="7" cy="-5" r="27"/> + <circle cx="32" cy="6" r="20"/> + </g> + </g> + + <g class="cloud cloud-c" opacity=".58"> + <g transform="translate(1070 110)"> + <ellipse cx="0" cy="8" rx="38" ry="14"/> + <circle cx="-18" cy="3" r="18"/> + <circle cx="6" cy="-4" r="23"/> + <circle cx="28" cy="5" r="17"/> + </g> + </g> + </g> + + <!-- Far rolling hills (slow parallax); drawn past the bottom edge so the + drift never exposes sky underneath --> + <path class="hills-far" d=" + M0 211 + C145 170 263 173 390 211 + C516 249 616 237 730 194 + C846 151 945 168 1065 208 + C1195 251 1334 214 1600 171 + L1600 340 + L0 340 + Z" + fill="url(#farHill)"/> + + <!-- Near rolling hills --> + <path class="hills-near" d=" + M0 248 + C120 217 228 217 342 247 + C454 278 566 269 674 228 + C789 184 901 202 1024 243 + C1143 282 1278 271 1391 229 + C1473 199 1538 196 1600 207 + L1600 340 + L0 340 + Z" + fill="url(#nearHill)"/> + + <!-- Proper leafy bushes (ride with the near hills) --> + <g class="hills-near"> + <g transform="translate(130 236)"> + <path d=" + M-58 28 + C-61 7 -46 -5 -28 0 + C-28 -20 -4 -31 11 -16 + C22 -36 54 -27 53 -5 + C73 -10 90 6 85 27 + Z" + fill="#5e9c4b"/> + <path d=" + M-47 27 + C-48 10 -37 1 -23 5 + C-20 -10 -4 -17 8 -7 + C19 -21 40 -17 43 -1 + C60 -4 70 8 68 26 + Z" + fill="#70ad58"/> + </g> + + <g transform="translate(1240 225) scale(.9)"> + <path d=" + M-58 28 + C-61 7 -46 -5 -28 0 + C-28 -20 -4 -31 11 -16 + C22 -36 54 -27 53 -5 + C73 -10 90 6 85 27 + Z" + fill="#5e9c4b"/> + <path d=" + M-47 27 + C-48 10 -37 1 -23 5 + C-20 -10 -4 -17 8 -7 + C19 -21 40 -17 43 -1 + C60 -4 70 8 68 26 + Z" + fill="#70ad58"/> + </g> + + <g transform="translate(460 250) scale(.58)"> + <path d=" + M-58 28 + C-61 7 -46 -5 -28 0 + C-28 -20 -4 -31 11 -16 + C22 -36 54 -27 53 -5 + C73 -10 90 6 85 27 + Z" + fill="#5a9748"/> + </g> + + <g transform="translate(940 245) scale(.55)"> + <path d=" + M-58 28 + C-61 7 -46 -5 -28 0 + C-28 -20 -4 -31 11 -16 + C22 -36 54 -27 53 -5 + C73 -10 90 6 85 27 + Z" + fill="#5a9748"/> + </g> + </g> + + <!-- Foreground meadow (near-static parallax) --> + <path class="meadow" d=" + M0 270 + C95 260 175 267 260 273 + C347 279 431 265 521 262 + C620 258 705 275 808 272 + C914 269 1004 251 1115 258 + C1229 265 1324 279 1424 270 + C1491 264 1547 258 1600 262 + L1600 340 + L0 340 + Z" + fill="url(#grass)"/> + + <!-- Dense grass blades --> + <g class="meadow" fill="none" + stroke="#4b8937" + stroke-width="2.5" + stroke-linecap="round"> + + <path d="M20 276 q-2 -19 4 -31 M28 276 q8 -18 11 -29"/> + <path d="M65 272 q-5 -18 1 -28 M74 272 q8 -16 11 -25"/> + <path d="M110 271 q-2 -23 5 -36 M121 272 q9 -18 12 -30"/> + <path d="M165 273 q-6 -16 -1 -28 M175 273 q7 -18 11 -27"/> + <path d="M225 274 q-3 -24 4 -37 M236 274 q8 -17 12 -29"/> + <path d="M286 273 q-6 -19 -1 -31 M296 274 q9 -18 12 -28"/> + <path d="M345 270 q-3 -18 3 -31 M355 270 q8 -17 12 -28"/> + <path d="M405 266 q-4 -22 2 -35 M416 266 q9 -17 13 -28"/> + <path d="M472 263 q-3 -18 3 -30 M482 263 q8 -19 13 -29"/> + <path d="M535 263 q-6 -19 -1 -31 M546 264 q9 -19 13 -30"/> + <path d="M598 266 q-3 -24 4 -37 M609 267 q8 -19 12 -31"/> + <path d="M665 271 q-6 -17 -1 -29 M676 271 q9 -17 13 -28"/> + <path d="M735 273 q-4 -22 3 -34 M746 273 q8 -18 12 -29"/> + <path d="M805 272 q-6 -18 -1 -30 M816 271 q9 -17 13 -27"/> + <path d="M875 265 q-3 -23 4 -35 M886 265 q8 -18 12 -28"/> + <path d="M945 258 q-5 -18 1 -30 M955 258 q9 -17 12 -28"/> + <path d="M1018 256 q-3 -22 4 -34 M1029 256 q8 -18 12 -28"/> + <path d="M1090 259 q-5 -20 1 -31 M1101 259 q8 -18 12 -29"/> + <path d="M1162 264 q-3 -24 4 -36 M1173 264 q8 -18 12 -30"/> + <path d="M1234 269 q-5 -19 1 -31 M1245 269 q8 -17 12 -28"/> + <path d="M1304 273 q-3 -23 4 -35 M1315 273 q8 -18 12 -29"/> + <path d="M1374 272 q-5 -18 1 -29 M1385 272 q8 -18 12 -28"/> + <path d="M1445 268 q-3 -22 4 -34 M1456 268 q8 -17 12 -28"/> + <path d="M1515 264 q-5 -20 1 -31 M1526 264 q8 -18 12 -29"/> + <path d="M1570 263 q-3 -21 4 -33 M1581 263 q8 -17 12 -28"/> + </g> + + <!-- Extra foreground tufts --> + <g class="meadow" fill="#579a40"> + <path d="M80 320 l15 -45 3 45 14 -57 0 57 20 -38 -7 38z"/> + <path d="M365 320 l10 -37 5 37 15 -49 -2 49 20 -34 -7 34z"/> + <path d="M710 320 l13 -42 3 42 15 -54 -1 54 20 -38 -8 38z"/> + <path d="M1040 320 l10 -35 5 35 14 -49 0 49 18 -32 -6 32z"/> + <path d="M1360 320 l13 -43 3 43 16 -55 -2 55 20 -37 -7 37z"/> + </g> + + <!-- Flowers (sway gently; each wrapped in a classed group so the CSS + transform doesn't clobber the placement transform) --> + <g class="meadow"> + <g class="flower"> + <g transform="translate(190 270)"> + <path d="M0 8 Q-2 25 -4 42" stroke="#42833a" stroke-width="2" fill="none"/> + <g fill="#ff8aa7"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ffe071"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(310 280) scale(.8)"> + <path d="M0 8 Q2 23 1 37" stroke="#42833a" stroke-width="2" fill="none"/> + <g fill="#fff0a0"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ef7191"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(540 265)"> + <path d="M0 8 Q-2 25 -2 42" stroke="#42833a" stroke-width="2" fill="none"/> + <g fill="#ff8aa7"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ffe071"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(670 279) scale(.7)"> + <g fill="#fff0a0"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ef7191"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(845 272)"> + <path d="M0 8 Q2 25 0 42" stroke="#42833a" stroke-width="2" fill="none"/> + <g fill="#ff8aa7"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ffe071"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(1010 265) scale(.85)"> + <path d="M0 8 Q-2 24 -1 38" stroke="#42833a" stroke-width="2" fill="none"/> + <g fill="#fff0a0"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ef7191"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(1190 275)"> + <g fill="#ff8aa7"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ffe071"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(1410 269)"> + <path d="M0 8 Q2 26 0 42" stroke="#42833a" stroke-width="2" fill="none"/> + <g fill="#fff0a0"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ef7191"/> + </g> + </g> + + <g class="flower"> + <g transform="translate(1510 282) scale(.72)"> + <g fill="#ff8aa7"> + <circle cx="-5" cy="0" r="5"/> + <circle cx="5" cy="0" r="5"/> + <circle cx="0" cy="-5" r="5"/> + <circle cx="0" cy="5" r="5"/> + </g> + <circle r="3" fill="#ffe071"/> + </g> + </g> + </g> + + <!-- Small scattered meadow dots --> + <g class="meadow" fill="#ffe071" opacity=".9"> + <circle cx="250" cy="287" r="2.5"/> + <circle cx="445" cy="281" r="2.5"/> + <circle cx="615" cy="289" r="2.5"/> + <circle cx="760" cy="283" r="2.5"/> + <circle cx="930" cy="279" r="2.5"/> + <circle cx="1125" cy="287" r="2.5"/> + <circle cx="1290" cy="281" r="2.5"/> + </g> + + <g class="meadow" fill="#ff8aa7" opacity=".8"> + <circle cx="120" cy="291" r="2.5"/> + <circle cx="395" cy="291" r="2.5"/> + <circle cx="730" cy="294" r="2.5"/> + <circle cx="1080" cy="294" r="2.5"/> + <circle cx="1460" cy="291" r="2.5"/> + </g> + + <!-- Soft fade into the page background --> + <rect y="252" width="1600" height="68" fill="url(#meadowFade)"/> +</svg> diff --git a/pagerite/themes/summer/grass.svg b/pagerite/themes/summer/grass.svg new file mode 100644 index 0000000..f57ec8a --- /dev/null +++ b/pagerite/themes/summer/grass.svg @@ -0,0 +1,143 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="300" height="9" viewBox="0 0 300 9"> +<g fill="none" stroke-linecap="round"> + <path d="M1.0 9 q2.0 -3.0 1.5 -5.5" stroke="#579a40" stroke-width="1.0"/> + <path d="M3.5 9 q1.7 -4.1 3.0 -7.5" stroke="#579a40" stroke-width="1.6"/> + <path d="M6.3 9 q-2.0 -3.8 -1.8 -6.9" stroke="#63ad4d" stroke-width="0.8"/> + <path d="M8.4 9 q-1.7 -2.3 -3.1 -4.2" stroke="#74b65e" stroke-width="1.2"/> + <path d="M11.0 9 q0.6 -3.5 1.8 -6.3" stroke="#4f913b" stroke-width="1.3"/> + <path d="M12.7 9 q-0.4 -2.6 -1.9 -4.8" stroke="#63ad4d" stroke-width="0.8"/> + <path d="M14.3 9 q-2.3 -2.9 2.5 -5.3" stroke="#4f913b" stroke-width="1.4"/> + <path d="M16.9 9 q1.8 -4.5 -2.9 -8.1" stroke="#74b65e" stroke-width="1.8"/> + <path d="M19.5 9 q0.5 -2.6 2.9 -4.7" stroke="#63ad4d" stroke-width="1.4"/> + <path d="M22.5 9 q2.3 -2.1 -1.7 -3.9" stroke="#579a40" stroke-width="1.7"/> + <path d="M25.2 9 q-2.1 -4.4 -3.8 -7.9" stroke="#42833a" stroke-width="1.0"/> + <path d="M27.7 9 q-1.9 -4.5 -3.8 -8.2" stroke="#74b65e" stroke-width="1.4"/> + <path d="M29.4 9 q-0.3 -3.7 -3.1 -6.7" stroke="#579a40" stroke-width="1.4"/> + <path d="M31.0 9 q-0.9 -3.5 0.1 -6.3" stroke="#579a40" stroke-width="0.9"/> + <path d="M32.6 9 q-0.9 -4.3 1.1 -7.8" stroke="#4f913b" stroke-width="1.4"/> + <path d="M35.7 9 q-1.4 -2.4 2.3 -4.3" stroke="#63ad4d" stroke-width="1.5"/> + <path d="M36.9 9 q-0.4 -3.2 0.0 -5.8" stroke="#63ad4d" stroke-width="1.6"/> + <path d="M38.5 9 q1.1 -4.6 0.6 -8.4" stroke="#63ad4d" stroke-width="1.2"/> + <path d="M41.3 9 q2.3 -2.9 4.0 -5.4" stroke="#63ad4d" stroke-width="1.8"/> + <path d="M43.3 9 q1.6 -2.6 4.5 -4.7" stroke="#4f913b" stroke-width="1.0"/> + <path d="M45.4 9 q-0.3 -2.6 -2.1 -4.8" stroke="#63ad4d" stroke-width="0.8"/> + <path d="M47.0 9 q0.0 -4.3 -3.8 -7.8" stroke="#42833a" stroke-width="1.6"/> + <path d="M49.6 9 q1.6 -3.1 0.3 -5.7" stroke="#4f913b" stroke-width="1.4"/> + <path d="M51.6 9 q-1.2 -2.7 -0.2 -4.9" stroke="#74b65e" stroke-width="1.2"/> + <path d="M53.7 9 q-1.0 -2.4 3.6 -4.3" stroke="#579a40" stroke-width="1.6"/> + <path d="M55.7 9 q1.4 -2.1 3.5 -3.9" stroke="#579a40" stroke-width="1.2"/> + <path d="M58.4 9 q-0.6 -2.6 0.7 -4.8" stroke="#579a40" stroke-width="1.2"/> + <path d="M60.9 9 q-2.3 -2.4 -3.7 -4.4" stroke="#579a40" stroke-width="1.0"/> + <path d="M62.7 9 q1.0 -2.3 -1.3 -4.1" stroke="#579a40" stroke-width="0.8"/> + <path d="M64.9 9 q-0.3 -4.0 -3.5 -7.2" stroke="#42833a" stroke-width="1.3"/> + <path d="M67.6 9 q1.7 -4.2 4.2 -7.6" stroke="#579a40" stroke-width="0.9"/> + <path d="M70.5 9 q-0.9 -2.3 1.3 -4.1" stroke="#42833a" stroke-width="1.7"/> + <path d="M72.8 9 q-0.2 -2.9 -2.9 -5.2" stroke="#42833a" stroke-width="1.0"/> + <path d="M74.3 9 q-0.5 -2.9 4.5 -5.2" stroke="#42833a" stroke-width="1.4"/> + <path d="M76.9 9 q-1.6 -2.3 0.5 -4.1" stroke="#42833a" stroke-width="1.7"/> + <path d="M78.4 9 q1.1 -5.1 -0.4 -9.2" stroke="#579a40" stroke-width="1.0"/> + <path d="M80.6 9 q-1.2 -3.8 2.1 -6.9" stroke="#42833a" stroke-width="1.8"/> + <path d="M81.9 9 q-1.7 -2.7 -2.8 -5.0" stroke="#42833a" stroke-width="1.0"/> + <path d="M83.8 9 q1.8 -3.1 4.5 -5.7" stroke="#74b65e" stroke-width="0.8"/> + <path d="M85.8 9 q-0.7 -4.0 -0.4 -7.3" stroke="#42833a" stroke-width="0.8"/> + <path d="M88.0 9 q-1.6 -5.0 -0.1 -9.2" stroke="#63ad4d" stroke-width="0.8"/> + <path d="M90.9 9 q1.5 -4.4 2.2 -7.9" stroke="#74b65e" stroke-width="1.5"/> + <path d="M92.3 9 q1.5 -3.3 1.5 -6.0" stroke="#579a40" stroke-width="1.2"/> + <path d="M94.7 9 q-0.4 -3.4 0.2 -6.2" stroke="#63ad4d" stroke-width="1.0"/> + <path d="M96.4 9 q-2.1 -4.8 -1.6 -8.7" stroke="#4f913b" stroke-width="1.7"/> + <path d="M99.3 9 q-0.1 -4.9 0.3 -8.9" stroke="#4f913b" stroke-width="1.7"/> + <path d="M101.1 9 q1.0 -4.6 1.4 -8.4" stroke="#4f913b" stroke-width="0.8"/> + <path d="M103.6 9 q-1.6 -4.8 -0.8 -8.8" stroke="#4f913b" stroke-width="1.7"/> + <path d="M105.1 9 q-2.5 -2.1 1.7 -3.9" stroke="#74b65e" stroke-width="1.5"/> + <path d="M108.0 9 q1.2 -2.2 -3.6 -3.9" stroke="#74b65e" stroke-width="1.8"/> + <path d="M110.5 9 q1.0 -4.2 2.3 -7.6" stroke="#579a40" stroke-width="1.6"/> + <path d="M113.6 9 q0.2 -2.4 2.7 -4.4" stroke="#42833a" stroke-width="1.5"/> + <path d="M115.8 9 q-0.7 -4.6 -1.1 -8.3" stroke="#579a40" stroke-width="1.0"/> + <path d="M117.8 9 q-2.0 -3.2 3.7 -5.8" stroke="#579a40" stroke-width="1.1"/> + <path d="M119.2 9 q-1.0 -4.8 1.2 -8.7" stroke="#4f913b" stroke-width="1.6"/> + <path d="M121.9 9 q-0.2 -4.7 -3.9 -8.5" stroke="#4f913b" stroke-width="1.7"/> + <path d="M125.0 9 q0.4 -2.2 -0.7 -3.9" stroke="#42833a" stroke-width="1.6"/> + <path d="M127.3 9 q-1.6 -5.0 -0.4 -9.0" stroke="#74b65e" stroke-width="1.4"/> + <path d="M129.3 9 q-0.2 -4.1 4.2 -7.4" stroke="#42833a" stroke-width="1.1"/> + <path d="M131.7 9 q-1.7 -2.6 -0.4 -4.7" stroke="#42833a" stroke-width="1.2"/> + <path d="M133.0 9 q2.2 -4.9 -0.0 -8.9" stroke="#579a40" stroke-width="1.2"/> + <path d="M134.8 9 q-1.2 -4.4 -0.5 -8.0" stroke="#42833a" stroke-width="1.6"/> + <path d="M137.2 9 q2.3 -4.9 1.1 -8.8" stroke="#42833a" stroke-width="1.3"/> + <path d="M139.4 9 q-2.1 -4.4 2.3 -7.9" stroke="#4f913b" stroke-width="0.9"/> + <path d="M141.6 9 q1.3 -2.4 2.5 -4.4" stroke="#74b65e" stroke-width="1.4"/> + <path d="M143.3 9 q1.8 -3.5 2.7 -6.4" stroke="#74b65e" stroke-width="1.4"/> + <path d="M146.0 9 q0.1 -4.9 0.9 -8.9" stroke="#579a40" stroke-width="0.8"/> + <path d="M147.2 9 q2.3 -3.6 -2.1 -6.5" stroke="#42833a" stroke-width="1.5"/> + <path d="M149.9 9 q0.8 -3.0 4.6 -5.4" stroke="#63ad4d" stroke-width="0.9"/> + <path d="M151.7 9 q2.5 -3.7 2.8 -6.8" stroke="#74b65e" stroke-width="1.7"/> + <path d="M154.4 9 q-1.8 -2.5 2.6 -4.5" stroke="#63ad4d" stroke-width="1.8"/> + <path d="M155.9 9 q2.4 -4.9 3.1 -8.9" stroke="#63ad4d" stroke-width="1.2"/> + <path d="M158.8 9 q2.4 -3.5 2.3 -6.3" stroke="#63ad4d" stroke-width="1.2"/> + <path d="M161.5 9 q-1.5 -4.1 2.1 -7.5" stroke="#63ad4d" stroke-width="1.7"/> + <path d="M164.2 9 q2.4 -3.4 -1.4 -6.1" stroke="#63ad4d" stroke-width="1.1"/> + <path d="M166.1 9 q1.0 -2.4 2.1 -4.3" stroke="#74b65e" stroke-width="1.1"/> + <path d="M167.7 9 q-1.2 -5.2 1.7 -9.4" stroke="#579a40" stroke-width="1.0"/> + <path d="M169.8 9 q0.9 -5.0 1.2 -9.1" stroke="#74b65e" stroke-width="1.7"/> + <path d="M171.9 9 q-2.3 -5.1 0.1 -9.2" stroke="#63ad4d" stroke-width="1.4"/> + <path d="M174.8 9 q-2.3 -4.0 -2.4 -7.4" stroke="#42833a" stroke-width="1.8"/> + <path d="M176.1 9 q2.3 -3.9 3.4 -7.1" stroke="#74b65e" stroke-width="1.6"/> + <path d="M178.2 9 q2.3 -2.2 2.4 -4.1" stroke="#579a40" stroke-width="1.7"/> + <path d="M179.6 9 q-0.5 -3.2 -3.3 -5.8" stroke="#4f913b" stroke-width="1.1"/> + <path d="M181.1 9 q-2.1 -3.9 1.2 -7.0" stroke="#4f913b" stroke-width="1.4"/> + <path d="M183.7 9 q-2.5 -3.2 0.2 -5.8" stroke="#4f913b" stroke-width="1.7"/> + <path d="M186.2 9 q0.9 -4.4 0.1 -8.1" stroke="#42833a" stroke-width="1.3"/> + <path d="M188.7 9 q-1.1 -2.8 1.0 -5.1" stroke="#579a40" stroke-width="1.1"/> + <path d="M190.3 9 q-0.9 -3.0 -3.0 -5.5" stroke="#579a40" stroke-width="1.8"/> + <path d="M193.2 9 q0.2 -5.1 0.9 -9.3" stroke="#4f913b" stroke-width="0.9"/> + <path d="M195.3 9 q-1.0 -2.3 -3.2 -4.2" stroke="#4f913b" stroke-width="1.7"/> + <path d="M196.9 9 q-1.2 -2.7 1.3 -5.0" stroke="#4f913b" stroke-width="0.9"/> + <path d="M199.2 9 q-1.5 -4.5 4.5 -8.1" stroke="#63ad4d" stroke-width="1.1"/> + <path d="M201.6 9 q1.9 -3.7 -0.1 -6.7" stroke="#63ad4d" stroke-width="1.8"/> + <path d="M202.8 9 q-0.3 -2.2 0.4 -3.9" stroke="#42833a" stroke-width="1.6"/> + <path d="M205.5 9 q0.7 -4.2 3.1 -7.6" stroke="#579a40" stroke-width="0.9"/> + <path d="M207.3 9 q0.4 -4.3 -2.1 -7.8" stroke="#63ad4d" stroke-width="0.9"/> + <path d="M209.9 9 q2.0 -3.4 -0.4 -6.3" stroke="#4f913b" stroke-width="1.6"/> + <path d="M211.1 9 q-1.7 -2.1 0.8 -3.8" stroke="#4f913b" stroke-width="1.5"/> + <path d="M214.0 9 q-2.0 -2.5 4.3 -4.6" stroke="#579a40" stroke-width="0.9"/> + <path d="M215.6 9 q-2.2 -2.2 -2.1 -4.0" stroke="#74b65e" stroke-width="1.0"/> + <path d="M217.1 9 q-1.8 -3.1 -0.9 -5.6" stroke="#63ad4d" stroke-width="1.3"/> + <path d="M220.0 9 q1.4 -4.7 -1.8 -8.5" stroke="#42833a" stroke-width="1.8"/> + <path d="M223.1 9 q0.9 -3.4 -1.5 -6.2" stroke="#42833a" stroke-width="1.7"/> + <path d="M225.3 9 q2.4 -3.5 -3.8 -6.3" stroke="#4f913b" stroke-width="0.9"/> + <path d="M227.1 9 q2.2 -3.8 -3.0 -7.0" stroke="#579a40" stroke-width="1.0"/> + <path d="M229.7 9 q2.1 -4.4 4.4 -8.0" stroke="#74b65e" stroke-width="1.3"/> + <path d="M231.0 9 q-1.2 -4.8 2.8 -8.7" stroke="#63ad4d" stroke-width="1.6"/> + <path d="M232.7 9 q-0.9 -3.1 -3.3 -5.6" stroke="#63ad4d" stroke-width="1.5"/> + <path d="M234.8 9 q2.1 -4.6 0.4 -8.4" stroke="#4f913b" stroke-width="1.0"/> + <path d="M237.9 9 q-0.9 -4.6 -0.1 -8.4" stroke="#74b65e" stroke-width="1.4"/> + <path d="M239.4 9 q1.6 -4.7 -1.0 -8.5" stroke="#579a40" stroke-width="1.6"/> + <path d="M241.3 9 q1.9 -5.1 0.9 -9.4" stroke="#579a40" stroke-width="1.4"/> + <path d="M244.3 9 q-2.2 -3.6 -1.9 -6.6" stroke="#42833a" stroke-width="1.1"/> + <path d="M245.6 9 q1.7 -4.2 -1.7 -7.6" stroke="#579a40" stroke-width="1.4"/> + <path d="M247.1 9 q0.1 -3.1 2.0 -5.7" stroke="#42833a" stroke-width="1.5"/> + <path d="M249.5 9 q-2.2 -3.8 -2.2 -6.9" stroke="#42833a" stroke-width="0.9"/> + <path d="M251.5 9 q-2.1 -4.4 3.5 -8.0" stroke="#579a40" stroke-width="0.9"/> + <path d="M253.2 9 q0.8 -4.3 0.7 -7.8" stroke="#4f913b" stroke-width="1.7"/> + <path d="M255.5 9 q1.4 -2.2 -2.9 -4.0" stroke="#4f913b" stroke-width="1.4"/> + <path d="M258.1 9 q1.9 -4.6 1.0 -8.3" stroke="#63ad4d" stroke-width="1.2"/> + <path d="M260.5 9 q-1.9 -4.8 -3.7 -8.6" stroke="#579a40" stroke-width="1.4"/> + <path d="M263.5 9 q1.4 -3.9 -1.3 -7.2" stroke="#4f913b" stroke-width="1.1"/> + <path d="M265.2 9 q-0.9 -4.8 2.7 -8.7" stroke="#42833a" stroke-width="0.9"/> + <path d="M267.4 9 q2.5 -2.2 3.0 -4.1" stroke="#4f913b" stroke-width="1.5"/> + <path d="M269.4 9 q-1.8 -1.9 -3.9 -3.5" stroke="#579a40" stroke-width="1.5"/> + <path d="M272.3 9 q-1.8 -4.5 2.9 -8.2" stroke="#74b65e" stroke-width="1.1"/> + <path d="M274.0 9 q-0.6 -2.2 1.8 -3.9" stroke="#4f913b" stroke-width="1.6"/> + <path d="M276.4 9 q1.2 -2.8 -3.9 -5.1" stroke="#63ad4d" stroke-width="1.5"/> + <path d="M277.7 9 q2.4 -4.2 3.0 -7.7" stroke="#4f913b" stroke-width="1.1"/> + <path d="M279.6 9 q0.6 -5.0 -3.3 -9.2" stroke="#4f913b" stroke-width="1.4"/> + <path d="M282.5 9 q0.6 -3.5 1.2 -6.3" stroke="#4f913b" stroke-width="1.2"/> + <path d="M284.0 9 q-2.4 -3.8 -2.5 -6.8" stroke="#74b65e" stroke-width="1.5"/> + <path d="M285.6 9 q-1.6 -5.2 -2.4 -9.4" stroke="#63ad4d" stroke-width="1.5"/> + <path d="M288.4 9 q1.6 -2.4 3.1 -4.4" stroke="#63ad4d" stroke-width="1.2"/> + <path d="M290.2 9 q-1.9 -3.0 2.9 -5.4" stroke="#63ad4d" stroke-width="0.8"/> + <path d="M291.6 9 q-0.5 -2.7 -2.1 -4.9" stroke="#579a40" stroke-width="1.8"/> + <path d="M294.2 9 q0.8 -3.7 4.4 -6.7" stroke="#63ad4d" stroke-width="0.9"/> + <path d="M296.6 9 q1.2 -3.7 4.2 -6.7" stroke="#74b65e" stroke-width="0.9"/> + <path d="M298.1 9 q1.0 -3.8 3.9 -7.0" stroke="#42833a" stroke-width="0.8"/> +</g> +</svg> diff --git a/pagerite/themes/summer/theme.css b/pagerite/themes/summer/theme.css new file mode 100644 index 0000000..67a425b --- /dev/null +++ b/pagerite/themes/summer/theme.css @@ -0,0 +1,262 @@ +/* Summer theme: the banner's illustrated meadow carried through the whole + page — one palette (sky blue, grass green, sun yellow, flower pink), + soft daylight surfaces, and playful touches like a tilted brand and + flower bullets. */ + +:root { + color-scheme: light; + + /* Every color is sampled (or text-darkened) from banner.svg. */ + --bg: #e6f4cf; + /* pale meadow — the banner fades into this */ + --surface: #f8fbf0; + --text: #2c4a2f; + /* deep leaf */ + --muted: #5c7a5e; + + --accent: #2598d6; + /* sky, darkened for text contrast */ + --accent2: #4f913b; + /* grass */ + --accent3: #e95f83; + /* flower pink, darkened for text contrast */ + --sun: #ffe071; + --line: #4f913b29; + + --link: color-mix(in oklab, var(--text) 38%, var(--accent)); + + --font-body: var(--font-cause); + --font-heading: var(--font-new-rocker); + --font-brand: var(--font-cause); +} + +/* The page is the same landscape the banner paints: hazy sky light up top + (with an echo of the banner's sun in the top-right corner) settling into + a pale meadow below. Fixed, so the banner parallax reads against a + still backdrop. */ +body { + background: + radial-gradient(ellipse 36rem 24rem at 85% -6rem, + #fff0a299 0, + #fff0a63d 45%, + transparent 70%), + radial-gradient(ellipse 42rem 26rem at 6% 2rem, + #8ed0ff4d 0, + transparent 70%), + radial-gradient(ellipse 30rem 22rem at 96% 62%, + #ff8aa726 0, + transparent 70%), + linear-gradient(180deg, + var(--bg) 0, + #d9eebd 24rem, + #c6e5a8 55rem, + #b8dd9c 100%); + background-attachment: fixed; + + color: var(--text); +} + +::selection { + background: var(--sun); + color: #3d5223; +} + +/* The banner frame ties into the meadow beneath it. */ +#banner { + border-bottom-color: #4f913b30; + box-shadow: 0 0.3rem 1rem #4f913b22; +} + +/* Cheerful oversized tilted brand in a sky→grass→flower gradient. */ +#brand { + font-size: clamp(3.2rem, 9vw, 7.5rem); + line-height: 1; + padding-bottom: 0.3em; + margin-bottom: -0.3em; + + transform: rotate(-2deg); + transform-origin: left bottom; + + background: linear-gradient(100deg, + var(--accent) 0 30%, + var(--accent2) 55%, + var(--accent3) 95%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + text-shadow: none; + + filter: + drop-shadow(0 1px 0 #fff) drop-shadow(0 0.15rem 0.15rem #ffffff99) drop-shadow(0 0.3rem 0.4rem #4f913b33); +} + +/* Navigation floats over the artwork: dark leaf text with a daylight halo. */ +#nav { + color: #24452d; + text-shadow: + 0 1px #ffffff, + 0 0 0.2em #ffffff, + 0 0 0.5em #d9f1ff; +} + +#nav a { + color: #2c4a2f; +} + +#nav ul ul a, +#nav span { + color: #527048; +} + +#nav a:hover, +#nav .current { + color: var(--accent); +} + +/* Content sits in a soft wash of sunlit meadow rather than on a white + card. */ +main { + background: linear-gradient(90deg, + transparent, + #f0f8dc80 15%, + #f0f8dc8c 50%, + #f0f8dc80 85%, + transparent); +} + +/* The sidebar is a piece of the same meadow: glassy green with a light + top edge and a grassy shadow. */ +#sidebar { + background: linear-gradient(160deg, #f4faddd9, #d9eec5cf); + border-right: 1px solid #ffffff80; + border-bottom: 1px solid var(--line); + box-shadow: 0 0.3rem 1rem #4f913b1f; +} + +#sidebar a { + color: #527048; +} + +#sidebar a:hover, +#sidebar .current { + color: var(--accent); +} + +/* One accent per heading level: sky h1 growing a dense low strip of grass + right against its baseline (grass.svg, ~140 varied blades per tile, + served by the backend next to this stylesheet), grass h2, flower h3 in + a quieter weight. */ +article h1 { + color: var(--accent); + width: fit-content; + padding-bottom: 0.12em; + text-shadow: 0 1px #ffffffaa; + background: url("grass.svg") bottom left / auto 0.35em repeat-x; +} + +article h2 { + color: var(--accent2); + text-shadow: 0 1px #ffffff88; +} + +article h3 { + color: var(--accent3); + font-weight: 550; +} + +article a { + color: var(--link); +} + +article a:hover { + color: var(--accent); +} + +/* Flower bullets, one accent per nesting level. */ +article ul li::before { + content: "❀"; + color: var(--accent3); + font-size: 0.8em; + vertical-align: 0.1em; +} + +article ul ul li::before { + content: "✿"; + color: var(--accent); +} + +article ul ul ul li::before { + content: "❁"; + color: var(--accent2); +} + +/* Quotes get a grassy edge and a wash of sunlight. */ +blockquote { + color: #4d6849; + border-left-color: var(--accent2); + background: linear-gradient(90deg, #fff0a238, transparent 70%); + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +/* Code rests on a shaded leaf panel, keeping the base light syntax + palette. */ +pre { + --code-bg: #e7f1d6; + + background: linear-gradient(160deg, #f0f7e2, #ddebc9); + border: 1px solid var(--line); + box-shadow: + inset 0 1px #ffffff99, + 0 0.2rem 0.6rem #4f913b1a; +} + +.copy { + background: linear-gradient(180deg, #f6faec, #e2efcf); + border-color: var(--line); +} + +/* Tables: a rounded piece of the landscape. The base's header-gradient + hooks get sky→grass colors and the cell wash tints green; soft corners + and a grassy shadow replace the old hard grid. */ +table { + --table-head-a: #fdfccd88; + --table-head-b: #ece9ba88; + --table-tint: var(--accent2); + + border-collapse: separate; + border-spacing: 0; + border-radius: 0.7rem; + overflow: clip; + box-shadow: 0 0.1rem 0.5rem #4f913b88; +} + +th { + color: #2c4a2f; +} + +/* A sun-kissed sheen on hover, fading in over the cell wash. */ +tbody td { + transition: background-color 0.2s; +} + +tbody tr:hover td { + background-color: #fff0a238; +} + +figcaption, +.dateline, +.footnote { + color: var(--muted); +} + +/* Editor chrome inherits the meadow rather than the base white. */ +.editor-root.overlay { + background: linear-gradient(160deg, #eef7dd, #d9eec5); +} + +/* The page transition exposes summer color around the rotating + snapshots. */ +::view-transition { + background: var(--bg); +}