Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec4ff5dfa2 | ||
|
|
2e6d374b4b | ||
|
|
c4d21b59be | ||
|
|
cec8018c18 | ||
|
|
c64528a1d3 | ||
|
|
746b015e85 | ||
|
|
a74eef0e47 | ||
|
|
c6de06f017 | ||
|
|
bbbb090cce | ||
|
|
54de9d3ee9 | ||
|
|
f6340a89b3 | ||
|
|
93712a1481 | ||
|
|
71b9808a11 | ||
|
|
c0edb2033d | ||
|
|
145490fe60 | ||
|
|
48fa17c351 | ||
|
|
ba629e2a96 | ||
|
|
d06c2cf0c0 | ||
|
|
c0d06f4a17 | ||
|
|
99f5601456 | ||
|
|
29385a5ca7 | ||
|
|
5744c16a1c | ||
|
|
bc0201252d | ||
|
|
46ec5e2e3c | ||
|
|
80d886c0cb | ||
|
|
ed7a9c01e7 | ||
|
|
4102974927 | ||
|
|
beb585e5dc | ||
|
|
47902f7278 | ||
|
|
0bb378e0cc | ||
|
|
694b7d2003 | ||
|
|
61f5d8444f | ||
|
|
affa3262ef | ||
|
|
1ef2cab89e | ||
|
|
c9161af655 | ||
|
|
d0eeedb62b | ||
|
|
185380ffa5 | ||
|
|
e7c804c9da | ||
|
|
075d44dce3 | ||
|
|
6e3f8e23b6 | ||
|
|
95f8f7b1a6 | ||
|
|
4082be0c37 | ||
|
|
97d1a0aa43 | ||
|
|
3362b214c3 | ||
|
|
ffe54bc766 | ||
|
|
4fa35e5317 | ||
|
|
eaf511a976 | ||
|
|
3202b853a7 | ||
|
|
d564f840e8 | ||
|
|
0516cae5b2 | ||
|
|
d014445248 | ||
|
|
419e9a2dd1 | ||
|
|
a8833ce736 | ||
|
|
4ace039233 | ||
|
|
2de0cf148e | ||
|
|
3b736af25e | ||
|
|
ea4ebd2d70 | ||
|
|
a8c0e802e2 | ||
|
|
cf35739a64 | ||
|
|
11e7eb484f | ||
|
|
009a6ae52a | ||
|
|
7c949bbb3c | ||
|
|
02f30af010 | ||
|
|
778ab25063 | ||
|
|
7286121f71 | ||
|
|
366c95aa86 | ||
|
|
f8181396b1 | ||
|
|
757752d91f | ||
|
|
45c5e3c407 | ||
|
|
228ad5b60b | ||
|
|
ed45ff6d54 | ||
|
|
8a2bf69576 | ||
|
|
4180882065 | ||
|
|
c2016e723f | ||
|
|
a1c85d73c7 |
@@ -1,4 +0,0 @@
|
||||
*.sh text eol=lf
|
||||
*.service text eol=lf
|
||||
*.timer text eol=lf
|
||||
*.container text eol=lf
|
||||
@@ -2,16 +2,3 @@ node_modules/
|
||||
dist/
|
||||
.astro/
|
||||
.DS_Store
|
||||
|
||||
# Content lives in the ctao/content repo (deploy copies it in; npm run content:link links ../content locally)
|
||||
src/content/news/
|
||||
src/content/pages/
|
||||
public/uploads/
|
||||
|
||||
# Session scratch
|
||||
.tmp/
|
||||
|
||||
# Local secrets and editor state
|
||||
.env*
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<!-- Screenshot probe: headless Chrome clamps --window-size below ~500px, so a
|
||||
fixed-width iframe gives a true narrow layout viewport. Copied into dist/
|
||||
by shoot.sh; not part of the site. -->
|
||||
<meta charset="utf-8">
|
||||
<title>probe</title>
|
||||
<style>html,body{margin:0;background:#b0b4c0}iframe{border:0;display:block}</style>
|
||||
<script>
|
||||
var q = new URLSearchParams(location.search);
|
||||
var f = document.createElement('iframe');
|
||||
f.src = q.get('p') || '/';
|
||||
f.style.width = (q.get('w') || 390) + 'px';
|
||||
f.style.height = (q.get('h') || 2000) + 'px';
|
||||
f.onload = function () {
|
||||
var s = +(q.get('s') || 0);
|
||||
// behavior:instant — the site sets scroll-behavior:smooth, which would
|
||||
// leave the screenshot mid-animation
|
||||
if (s) f.contentWindow.scrollTo({ top: s, behavior: 'instant' });
|
||||
};
|
||||
document.addEventListener('DOMContentLoaded', function () { document.body.appendChild(f); });
|
||||
</script>
|
||||
|
After Width: | Height: | Size: 675 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 609 KiB |
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 750 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 317 KiB |
|
After Width: | Height: | Size: 400 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 594 KiB |
|
After Width: | Height: | Size: 669 KiB |
|
After Width: | Height: | Size: 317 KiB |
|
After Width: | Height: | Size: 453 KiB |
|
After Width: | Height: | Size: 495 KiB |
|
After Width: | Height: | Size: 595 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 420 KiB |
|
After Width: | Height: | Size: 669 KiB |
|
After Width: | Height: | Size: 600 KiB |
|
After Width: | Height: | Size: 535 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 424 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 675 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 609 KiB |
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 750 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 396 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 424 KiB |
|
After Width: | Height: | Size: 535 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 361 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,45 @@
|
||||
#!/bin/zsh
|
||||
# Screenshot helper for the CSS polish pass. $1 = output dir (before|after)
|
||||
# Narrow widths go through dist/__probe.html (a fixed-width iframe): headless
|
||||
# Chrome clamps --window-size below ~500px, so 360/390/480 shots would silently
|
||||
# be 500px-wide renders cropped to the window.
|
||||
set -e
|
||||
CH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
OUT="$(cd "$(dirname "$0")" && pwd)/$1"
|
||||
mkdir -p "$OUT"
|
||||
cp "$(dirname "$0")/__probe.html" "$ROOT/dist/__probe.html"
|
||||
shot() { # name url w h
|
||||
"$CH" --headless=new --disable-gpu --hide-scrollbars --window-size=$3,$4 \
|
||||
--screenshot="$OUT/$1.png" "$2" >/dev/null 2>&1
|
||||
}
|
||||
wide() { shot "$1" "http://localhost:4330$2" $3 $4; } # name path w h
|
||||
narrow() { # name path w h (h = iframe height)
|
||||
shot "$1" "http://localhost:4330/__probe.html?w=$3&h=$4&p=$2" $(($3 + 20)) $(($4 + 10))
|
||||
}
|
||||
W='/news/ctao-and-cabildo-of-la-palma-organise-women-of-ctao-2026'
|
||||
wide home "/" 1440 2600
|
||||
narrow home-390 "/" 390 2200
|
||||
wide news "/news" 1440 2600
|
||||
narrow news-390 "/news" 390 2400
|
||||
wide news-768 "/news" 768 2200
|
||||
wide art6 "/news/6" 1440 2600
|
||||
narrow art6-390 "/news/6" 390 2600
|
||||
wide artwomen "$W" 1440 2600
|
||||
narrow artwomen-390 "$W" 390 2600
|
||||
wide artwomen-1280 "$W" 1280 2000
|
||||
wide search "/search?q=lst" 1440 2000
|
||||
narrow search-390 "/search?q=lst" 390 1800
|
||||
wide support "/support" 1440 1800
|
||||
narrow support-360 "/support" 360 1500
|
||||
wide privacy "/pages/privacy" 1440 1400
|
||||
narrow privacy-390 "/pages/privacy" 390 1500
|
||||
wide nf "/404-nonexistent" 1440 1200
|
||||
narrow nf-390 "/404-nonexistent" 390 1300
|
||||
wide proposals "/proposals" 1440 1600
|
||||
narrow proposals-390 "/proposals" 390 1700
|
||||
wide dashboard "/dashboard" 1440 1600
|
||||
narrow dashboard-480 "/dashboard" 480 1900
|
||||
wide login "/login" 1440 1200
|
||||
narrow login-390 "/login" 390 1100
|
||||
echo "shots in $OUT"
|
||||
@@ -0,0 +1,32 @@
|
||||
# Design handoff
|
||||
|
||||
All styling lives in **`src/styles/global.css`** — design tokens in `:root`
|
||||
(colors, type scale, spacing, radius, shadows, `--header-h`) + plain-CSS
|
||||
components below them. No frameworks, no preprocessors, no runtime JS for
|
||||
presentation. Pages are `.astro` templates (plain HTML).
|
||||
|
||||
## Brand (official: CTAO Brand Guidelines, April 2024 — PDF in the project docs)
|
||||
|
||||
- Colors: Galaxy Blue `#00004A`, Cherenkov Blue `#00E4D8`, Moon Gray
|
||||
`#F5F5F5`, Cosmic Azure `#007AFF` (links/focus), Interstellar Indigo
|
||||
`#00009C`. Cherenkov is an ACCENT (brand book rations it — currently:
|
||||
primary CTA, hero subtitle, logo flash); it fails AA as text on white.
|
||||
- Type: **Inter** for everything, **Space Grotesk** (weight 500) only for
|
||||
communicative headlines (h1/h2). Sizes come from the `--fs-*` scale.
|
||||
- Logo files in `public/brand/`; always "CTAO", min 100px wide, no effects.
|
||||
|
||||
## Practical notes (the non-obvious ones)
|
||||
|
||||
- **`public/admin/preview.css` mirrors the `.prose` styles** so the CMS
|
||||
editor preview matches articles 1:1 — when you touch `.prose` or its
|
||||
tokens, update the mirror (both files carry a KEEP IN SYNC comment).
|
||||
- Fonts ship **inlined as data: URIs** in global.css (no font requests, no
|
||||
swap flash). The woff2 files in `public/fonts/` look unused but feed the
|
||||
CMS preview — keep them.
|
||||
- All `animation`/`transition` rules sit in the single
|
||||
`prefers-reduced-motion: no-preference` block at the end of global.css.
|
||||
- Scroll-driven effects need `vite.build.cssMinify: 'esbuild'`
|
||||
(astro.config.mjs) — the default minifier breaks `animation-timeline`.
|
||||
- `--header-h` drives the sticky-header offsets (anchors, TOC rail, reading
|
||||
progress); change the header height only through the token.
|
||||
- Deterministic gate before pushing: `npm run check` (build + link check).
|
||||
@@ -1,54 +1,78 @@
|
||||
# CTAO Science Portal
|
||||
# CTAO Science Portal — static site + git-based CMS
|
||||
|
||||
Static Astro site with a git-based CMS (Sveltia). Code lives here; editorial
|
||||
content lives in the separate [`ctao/content`](https://astro-git.isl-dev.grid.cyfronet.pl/ctao/content)
|
||||
repository. The Home page and four Example pages are editable; the rest are placeholders.
|
||||
Public portal for CTAO news, built as a fully static site. Editors get a
|
||||
browser WYSIWYG editor (Sveltia CMS) that commits Markdown to a Gitea repo;
|
||||
a build job turns commits into static HTML. No application or database runs
|
||||
on the public path.
|
||||
|
||||
- Live demo: https://astro.isl-dev.grid.cyfronet.pl
|
||||
- Editor: https://astro.isl-dev.grid.cyfronet.pl/admin/ (Gitea sign-in)
|
||||
Live demo: <https://astro.isl-dev.grid.cyfronet.pl> ·
|
||||
Gitea on the demo machine: <https://astro-git.isl-dev.grid.cyfronet.pl>
|
||||
|
||||
## Run locally
|
||||
## Repository layout & deployment
|
||||
|
||||
Node 22.19 or newer. Clone the content repository next to this one:
|
||||
Code and content are SEPARATE repositories, so editorial commits never mix
|
||||
with development:
|
||||
|
||||
```sh
|
||||
git clone https://astro-git.isl-dev.grid.cyfronet.pl/ctao/content.git ../content
|
||||
| Repo | Holds | Source of truth | Who commits |
|
||||
|---|---|---|---|
|
||||
| `ctao-portal` (this one, Bitbucket) | Templates, CSS, deploy | development | the team |
|
||||
| `ctao/content` (Gitea on the demo machine) | `news/`, `pages/`, `uploads/` | editorial | Sveltia CMS / editors |
|
||||
|
||||
The demo machine polls ITS Gitea (`ctao/portal` mirror + `ctao/content`) and
|
||||
republishes on a push to either — so a push to Bitbucket does NOT deploy;
|
||||
deploying code = pushing it to the machine's Gitea (a deliberate step). The
|
||||
build overlays content onto code (`deploy/build.sh`); the content paths are
|
||||
gitignored here.
|
||||
|
||||
## Stack
|
||||
|
||||
- **Astro** (static output). Pages are `.astro` templates (plain HTML with a
|
||||
JS frontmatter block). No React/Vue/Svelte components, no client-side
|
||||
framework.
|
||||
- **Plain CSS** — everything lives in `src/styles/global.css` as design
|
||||
tokens (custom properties) + rules. No Tailwind, no preprocessor.
|
||||
The design system (tokens, type scale, spacing, motion policy) is
|
||||
documented in `DESIGN.md` — read it before touching styles.
|
||||
- **Sveltia CMS** — a single prebuilt JS bundle, vendored in
|
||||
`public/vendor/sveltia-cms.js` and loaded on `/admin/`
|
||||
(`src/pages/admin/index.astro`), configured by `public/admin/config.yml`.
|
||||
It runs entirely in the editor's browser and talks to the Gitea API
|
||||
(OAuth PKCE). There is no CMS server. To update it:
|
||||
`curl -sL https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js -o public/vendor/sveltia-cms.js`
|
||||
- Runtime dependencies: none beyond Astro. This is deliberate — keep it
|
||||
that way.
|
||||
|
||||
## Develop
|
||||
|
||||
```
|
||||
npm ci
|
||||
git clone https://astro-git.isl-dev.grid.cyfronet.pl/ctao/content.git ../ctao-content
|
||||
./scripts/link-content.sh # copies news/pages/uploads into the dev tree
|
||||
npm run dev # http://localhost:4321
|
||||
npm run build # static output in dist/
|
||||
npm run check # deterministic gate: build + internal-link check
|
||||
```
|
||||
|
||||
The site reads `../content` directly through links, so pull that repository
|
||||
for the latest content. To use a checkout elsewhere:
|
||||
`npm run content:link -- <path>`.
|
||||
## Layout
|
||||
|
||||
Before pushing code, run `npm run check` (types, build, internal links).
|
||||
|
||||
## Edit content locally
|
||||
|
||||
With `npm run dev` running, open `http://localhost:4321/admin/` in Chrome or
|
||||
Edge, choose **Work with Local Repository** and select the `../content` folder.
|
||||
Saves write the Markdown files and show up on the local site on reload. They
|
||||
are not committed: commit and push in `../content` to publish.
|
||||
|
||||
## Publishing
|
||||
|
||||
Pushing to `main` of `ctao/portal` (code) or `ctao/content` (content) on
|
||||
Gitea rebuilds and publishes the live demo automatically; the online editor
|
||||
commits to `ctao/content` directly. Pushing to Bitbucket does not deploy.
|
||||
Server setup is in [deploy/README.md](deploy/README.md).
|
||||
|
||||
## Where things live
|
||||
|
||||
| Path | Purpose |
|
||||
| Path | What |
|
||||
|---|---|
|
||||
| `src/layouts/Base.astro` | Header, navigation, footer, page shell |
|
||||
| `src/layouts/ContentPage.astro` | Layout of the editable pages (Home and Examples) |
|
||||
| `src/data/examples.json` | Example pages: menu labels, order, slugs |
|
||||
| `src/data/placeholders.json` | Placeholder pages |
|
||||
| `src/styles/global.css` | All site styles |
|
||||
| `public/admin/config.yml` | CMS fields and Gitea connection |
|
||||
| `scripts/preview-styles.mjs` | Builds the CMS preview styles from `global.css` |
|
||||
| `scripts/content.mjs` | Links the content checkout into the site |
|
||||
| `src/pages/` | Routes (`.astro` templates), incl. `news/`, `search`, RSS/sitemap |
|
||||
| `src/layouts/Base.astro` | HTML shell: head, header/nav, footer |
|
||||
| `src/content/news/*.md` | Articles (from the content repo — gitignored here; schema in `src/content.config.ts`) |
|
||||
| `src/styles/global.css` | All CSS: tokens + components + prose |
|
||||
| `DESIGN.md` | Design handoff: where the tokens live, brand basics, practical notes |
|
||||
| `public/admin/` | CMS config (`config.yml`) + editor preview styles (`preview.css`) |
|
||||
| `public/uploads/` | Editor-uploaded media (from the content repo — gitignored here) |
|
||||
| `deploy/` | Runbook + container/systemd units for the demo machine — see `deploy/README.md` |
|
||||
|
||||
To add an Example page, add it to `src/data/examples.json` and
|
||||
`public/admin/config.yml`, and commit its Markdown file to `ctao/content`.
|
||||
## Editing content
|
||||
|
||||
Editors use `/admin/` (link in the footer) and sign in with a Gitea account.
|
||||
Saving commits to `main`; the machine polls and republishes automatically
|
||||
(seconds). Full history/rollback = git history in Gitea. Articles with
|
||||
`draft: true` are excluded from the build.
|
||||
|
||||
Note for styling work: `public/admin/preview.css` mirrors the `.prose` rules
|
||||
from `global.css` so the editor preview matches the site 1:1 — keep them in
|
||||
sync (both files carry a KEEP IN SYNC comment).
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
// Static output (zero runtime) — the whole point of the git-based approach.
|
||||
export default defineConfig({
|
||||
output: 'static',
|
||||
// Public origin — used to build absolute URLs (canonical, og:*, RSS,
|
||||
// sitemap). Change when the portal moves to its production domain.
|
||||
site: 'https://astro.isl-dev.grid.cyfronet.pl',
|
||||
trailingSlash: 'always',
|
||||
build: { format: 'directory' },
|
||||
compressHTML: true,
|
||||
// Built-in prefetch on every internal link (no per-link attributes needed).
|
||||
// Default 'hover' strategy: near-instant navigation without the bandwidth
|
||||
// cost of 'viewport' on a 24-card grid; auto-falls back to 'tap' on
|
||||
// data-saver / slow connections (Astro handles that).
|
||||
prefetch: { prefetchAll: true },
|
||||
server: { port: 4321, host: true },
|
||||
vite: {
|
||||
build: {
|
||||
// Lightning CSS (the default minifier) illegally folds animation-timeline
|
||||
// INTO the `animation` shorthand (`animation: ... view()`), which browsers
|
||||
// reject — silently killing every scroll-driven effect in production.
|
||||
// esbuild minifies without property merging.
|
||||
cssMinify: 'esbuild',
|
||||
},
|
||||
server: {
|
||||
// Vite blocks unknown Host headers by default; the demo is viewed through an
|
||||
// ephemeral cloudflared quick tunnel, so allow any *.trycloudflare.com host.
|
||||
allowedHosts: ['.trycloudflare.com'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
# Deployment log — CTAO portal demo on strapi-experimental.cyfronet
|
||||
|
||||
Living document: what was done, what broke, what is left. Update it as work
|
||||
proceeds so any agent (or human) can resume without the chat history.
|
||||
Started 2026-07-28.
|
||||
|
||||
## Goal
|
||||
|
||||
Run the git-based CMS demo (Gitea + Sveltia + Astro static build) on the
|
||||
Cyfronet test machine so the SUSS-PORT team can click through it. Shape must
|
||||
be production-viable, not throwaway. Machine footprint: one directory
|
||||
(`~/ctao-portal-demo/`) + 4 unit files, fully removable (README "Uninstall").
|
||||
|
||||
## Ground rules (from the user, non-negotiable)
|
||||
|
||||
- **Write every command out in chat, marked read-only / write, BEFORE running
|
||||
it** — the user reviews on a phone and cannot see truncated tool calls.
|
||||
- Non-invasive verification first, debugging second: confirm each precondition
|
||||
instead of fixing after the fact.
|
||||
- Never read secrets (`~/.ssh/*`, tokens). Mask token URLs in any output
|
||||
(`sed 's|://[^@]*@|://***@|g'`). Secrets stay in 0600 files on the machine.
|
||||
- No sudo, nothing outside `$HOME` on the machine, no traces for the admin.
|
||||
- Temp/working files under `.tmp/<date>-<topic>/` in the repo, never `/tmp`.
|
||||
- Commit messages: **no "Co-Authored-By: Claude"**, no session links.
|
||||
|
||||
## Architecture (decided, see also README.md in this dir)
|
||||
|
||||
```
|
||||
editor → Sveltia (/admin, static) → commit → Gitea :3000 (container, SQLite)
|
||||
│ polled every 10 s
|
||||
build.sh (systemd user timer)
|
||||
└─ podman run node+git, --network=container:ctao-demo-gitea
|
||||
npm ci (only if lockfile changed) → astro build
|
||||
→ releases/<sha>/ → atomic symlink flip
|
||||
│
|
||||
nginx :8080 serves releases/current
|
||||
│ (TODO) ingress vhost → team access
|
||||
```
|
||||
|
||||
## Machine facts (verified 2026-07-28, read-only)
|
||||
|
||||
- Rocky Linux 9.7, host `outline.openstacklocal`, IP 192.168.10.15, 2 vCPU,
|
||||
3.6 GB RAM, no swap. User `strapi`, no sudo, `Linger=yes`, user systemd running.
|
||||
- Podman 5.6.0 rootless. Host has node 24.17, npm, curl, jq, rsync — **no git**,
|
||||
**no nginx** (hence the build container / nginx container).
|
||||
- Neighbours: pod-strapi (`:1337`), Outline (`:9091`), code-server (`127.0.0.1:41787`).
|
||||
- **VPN does NOT route to machine ports** (`curl 192.168.10.15:1337` times out);
|
||||
only the admin-managed HTTPS ingress reaches the machine
|
||||
(`https://strapi.isl-dev.grid.cyfronet.pl` → 204). Hence ports 3000/8080 are
|
||||
reachable for us only via `ssh -L`, and the team needs vhosts from Hubert.
|
||||
|
||||
## DONE
|
||||
|
||||
### 1. Local: files authored + reviewed + tested (before touching the machine)
|
||||
- Wrote quadlets, `build.sh`, systemd service/timer, `nginx.conf`,
|
||||
`Containerfile.build`, `README.md` (runbook incl. uninstall).
|
||||
- **Opus security review** — 8 findings, every one verified personally:
|
||||
BLOCKER `--network=host` (build code could reach host loopback: code-server
|
||||
= RCE, Strapi) → replaced; `OnUnitActiveSec` is start-relative, not
|
||||
end-relative (agent corrected me) → `OnUnitInactiveSec`; missing `mkdir` for
|
||||
`~/.config/*`; nginx-before-first-build race; prune `pipefail` landmine;
|
||||
noisy unit failure when Gitea is down; CORS `SCHEME` note; RAM headroom.
|
||||
All fixed. No hallucinated findings.
|
||||
- **Local end-to-end test** against the local Gitea (`:3010`), sandbox
|
||||
`.tmp/2026-07-28-deploy-test/`: cold build 23 s · no-op poll 45 ms ·
|
||||
incremental rebuild 4 s · prune ✓ · Gitea-down grace ✓ · anonymous clone
|
||||
(no token in `.git/config`) ✓.
|
||||
- Commits (local Gitea repo `ctao/portal`): `ed7a9c0`, `80d886c`.
|
||||
|
||||
### 2. Machine: install steps 1–7 of README
|
||||
- Created `~/ctao-portal-demo/{gitea-data,gitea-config,releases,state,bin,config}`
|
||||
and `~/.config/{containers/systemd,systemd/user}`.
|
||||
- Copied unit files, `build.sh`, `nginx.conf`, `Containerfile.build`.
|
||||
- Pulled + **pinned by digest**: gitea 1.27-rootless, nginx stable-alpine,
|
||||
node:24-alpine; built `localhost/ctao-portal-build:1`.
|
||||
- Gitea running (`:3000`, API version 1.27.1), admin `ctao` created with
|
||||
`--random-password` → `~/ctao-portal-demo/state/initial-admin.txt` (0600),
|
||||
push token → `state/push-token.txt` (0600). **Never printed in chat.**
|
||||
- Content pushed via git bundle (78 MB, one-off bootstrap): repo `ctao/portal`
|
||||
at `80d886c`, public, anonymously clonable. Bundle deleted afterwards.
|
||||
- **First build on the machine: 44 s** (`npm ci` ~35 s + astro build 6.5 s),
|
||||
225 pages. Incremental rebuilds should be ~10 s (measure to confirm).
|
||||
- nginx container running, `http://localhost:8080/` → **200, `<title>CTAO
|
||||
Science Portal</title>`**.
|
||||
- Poll timer enabled (`ctao-portal-build.timer`), ticking every ~10 s, journal
|
||||
clean.
|
||||
|
||||
### 3. Problems hit on the machine (and the fixes)
|
||||
1. **Rootless bridge network impossible**: `netavark: modprobe ip_tables:
|
||||
Operation not permitted` → quadlet restart loop. Root cause: kernel module
|
||||
not loaded, rootless cannot modprobe, no sudo. **Fix:** dropped
|
||||
`ctao-demo.network`; build joins Gitea's netns
|
||||
(`--network=container:ctao-demo-gitea`), so it reaches Gitea on
|
||||
`localhost:3000` while the host loopback stays unreachable (pasta).
|
||||
Same security property as the bridge, zero privileges. Lesson written to
|
||||
`.skills/podman-quadlet/SKILL.md`.
|
||||
2. **Push rejected**: admin was created with `--must-change-password` →
|
||||
`remote: Update your password`. **Fix:** `gitea admin user
|
||||
must-change-password --unset ctao`.
|
||||
3. **My rc-chain bug**: `... | sed` made `$?` the sed's status, so a failed
|
||||
push printed "push-ok" and the bundle was deleted prematurely → had to
|
||||
re-upload 78 MB. **Fix:** capture output in a var, check rc of the real
|
||||
command. (Also why the upload "took so long" — it ran twice.)
|
||||
4. **Push-created repo was private** despite `DEFAULT_PRIVATE=public` —
|
||||
push-to-create has its own key. **Fix:** PATCH via API to public +
|
||||
`GITEA__repository__DEFAULT_PUSH_CREATE_PRIVATE=false` in the quadlet.
|
||||
5. **`npm ci` failed: `ETXTBSY` spawning `esbuild`** (postinstall race in a
|
||||
rootless container, ~5 min wasted). **Fix:** `npm ci --ignore-scripts`
|
||||
(also removes the malicious-postinstall vector) + persistent npm cache
|
||||
volume `~/ctao-portal-demo/npm-cache`. Validated locally, then on machine.
|
||||
|
||||
### 4. Left on the machine (known, not cleaned — user asked to be told, not tidied)
|
||||
- Orphan systemd entry `ctao-demo-network.service` (not-found/active-exited),
|
||||
ghost of the removed network quadlet. Harmless; clears with
|
||||
`systemctl --user stop ctao-demo-network.service`.
|
||||
- `/tmp/storage-run-1003/` (~136 KB) — podman runroot from ssh calls without
|
||||
`XDG_RUNTIME_DIR`. Disappears on reboot. (`storage-run-1001` is NOT ours.)
|
||||
- Red journal entries from the netavark restart loop (history, not a live fault).
|
||||
- Disk: 11 G → 9.6 G free (images ~590 MB + repo/content). RAM available ~1.3 G.
|
||||
|
||||
### 5. Pipeline proven end-to-end on the machine (2026-07-28)
|
||||
- Pushed `46ec5e2` to the machine's Gitea (incremental bundle, 6 KB — this is
|
||||
what ongoing syncs cost, vs the 78 MB one-off bootstrap).
|
||||
- **The poller published it automatically in 26 s end-to-end** (push →
|
||||
visible), of which the build itself was 21 s. That is the demo's publish
|
||||
latency: **~30 s worst case** on 2 vCPU (vs 44 s for the very first build
|
||||
which included `npm ci`). Cold-cache builds only happen when the lockfile
|
||||
changes.
|
||||
- Verified after publish: `/` 200, `/admin/` 200 (Sveltia), an article page
|
||||
200; neighbours untouched (Strapi 204, Outline 200); RAM available 1.2 G,
|
||||
disk free 9.0 G.
|
||||
|
||||
### 6. Sveltia wired to the machine + editor cycle proven (2026-07-28)
|
||||
- **OAuth app created via API, no UI clicking**: temp `write:user` token from
|
||||
`gitea admin user generate-access-token` (CLI in container) → POST
|
||||
`/user/applications/oauth2` → temp token deleted (needed basic auth from
|
||||
`initial-admin.txt`; token-auth DELETE returns 401). App: "Sveltia CMS
|
||||
(demo)", `client_id cf1c44ac-ebe6-4a97-bf2f-f7f26ef1126c`, PKCE
|
||||
(`confidential_client=false`), redirect_uris: `http://localhost:18080/admin/`
|
||||
and `http://localhost:8080/admin/`.
|
||||
- **Found & fixed**: `public/admin/config.yml` still pointed at the MAC's Gitea
|
||||
(`localhost:3010` + old app_id) — CMS login on the machine could never work.
|
||||
Switched to `localhost:3000` + machine app_id (`bc02012`). localhost:3000 is
|
||||
valid both on the machine and through the tunnel (same-port trick).
|
||||
- **Editor cycle simulated exactly like Sveltia does it** (Gitea contents API):
|
||||
create article via API → **live on the portal in 12 s**; delete via API →
|
||||
**gone in 21 s**. Repo left clean (`29385a5`). Earlier full-push rebuild:
|
||||
16 s build. Publish latency ≈ **10–30 s** depending on poll-tick alignment.
|
||||
- Tunnel run from the Mac with keepalive (`-o ServerAliveInterval=30`), portal
|
||||
mapped to **18080** locally (user request: non-default port), Gitea kept at
|
||||
**3000** (must match ROOT_URL). First tunnel died after idle — keepalive fixed.
|
||||
- Push token scope confirmed minimal (`write:repository` only) — cannot manage
|
||||
users/apps; file format is `<name>:<40-hex>` (grep the hex out).
|
||||
|
||||
## TODO (next agent starts here)
|
||||
|
||||
1. ~~Commit the `--ignore-scripts` fix and mirror to the machine~~ — DONE
|
||||
(`46ec5e2`, and it doubled as the live pipeline test above).
|
||||
2. ~~Measure incremental publish latency on the machine~~ — DONE: **26 s
|
||||
end-to-end**, build 21 s.
|
||||
3. ~~Verify the loop through `ssh -L`~~ — mostly DONE: tunnel
|
||||
`-L 18080:localhost:8080 -L 3000:localhost:3000` (with ServerAlive
|
||||
keepalive) verified with real content. **Remaining: the user clicks
|
||||
"Sign in with Gitea" at `http://localhost:18080/admin/`** and edits an
|
||||
article in the browser — the only step that needs a human + browser
|
||||
(PKCE login). Credentials: `initial-admin.txt` on the machine.
|
||||
4. ~~Sveltia OAuth app~~ — DONE via API (see §6). Config committed and
|
||||
auto-published. Only the browser login test remains (see 3).
|
||||
5. **Message to Hubert** (only after we have seen it working):
|
||||
- two ingress vhosts → `192.168.10.15:8080` (portal) and `:3000` (gitea),
|
||||
same mechanism as `strapi.isl-dev…:1337`;
|
||||
- are vhosts public-internet or VPN-scopable? (Gitea preferably VPN-only);
|
||||
- does Cyfronet offer static-file hosting on the ingress itself? If yes we
|
||||
drop our nginx container and just rsync builds there.
|
||||
6. **After vhosts arrive**: replace both `TODO(vhost)` in
|
||||
`ctao-demo-gitea.container` (ROOT_URL, CORS origin + `GITEA__cors__SCHEME=https`),
|
||||
`daemon-reload` + restart, update Sveltia config, re-test login.
|
||||
7. **Backup**: nightly `tar` of `~/ctao-portal-demo/gitea-data` (the only
|
||||
stateful thing; everything else is rebuildable). Not yet written.
|
||||
8. **Decided but not implemented — split into two repos** (`portal` = code,
|
||||
`portal-content` = markdown + uploads). Rationale: editors get write access
|
||||
ONLY to content, so repo-push cannot alter `package.json`/templates that the
|
||||
build executes; also keeps code history clean. Cost: `build.sh` clones two
|
||||
repos and overlays content (~10 lines), polls two SHAs. Do this for the
|
||||
production version, not mid-demo.
|
||||
9. Demo choreography: the test article is `draft: true`; the user creates one
|
||||
live during the demo. With the poller running, a Sveltia save publishes
|
||||
automatically — no manual rebuild needed (unlike the Mac preview setup).
|
||||
|
||||
## Command cheat-sheet (machine)
|
||||
|
||||
```
|
||||
export XDG_RUNTIME_DIR=/run/user/$(id -u) # needed for systemctl --user over ssh
|
||||
systemctl --user status ctao-demo-gitea ctao-demo-web ctao-portal-build.timer
|
||||
journalctl --user -u ctao-portal-build -n 20 --no-pager # build times land here
|
||||
~/ctao-portal-demo/bin/build.sh # manual build
|
||||
readlink ~/ctao-portal-demo/releases/current # which sha is live
|
||||
curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/
|
||||
```
|
||||
@@ -1,10 +1,10 @@
|
||||
# Deploy: CTAO portal demo on strapi-experimental.cyfronet
|
||||
# Deploy — CTAO portal demo on strapi-experimental.cyfronet
|
||||
|
||||
Everything runs rootless as user `strapi`. Footprint on the machine:
|
||||
ONE directory (`~/ctao-portal-demo/`) + 4 unit files in `~/.config/`.
|
||||
Uninstall restores the machine exactly (see bottom). No secrets in any file.
|
||||
|
||||
Two Gitea repos by design: `ctao/portal` (code, developed by the team) and
|
||||
Two Gitea repos by design — `ctao/portal` (code, developed by the team) and
|
||||
`ctao/content` (Markdown + uploads, committed by the CMS). The build overlays
|
||||
content onto code; a push to EITHER republishes the site.
|
||||
|
||||
@@ -29,44 +29,9 @@ missing). Everything else runs inside containers.
|
||||
| 3000 | Gitea | https://astro-git.isl-dev.grid.cyfronet.pl (ingress vhost) |
|
||||
| 8080 | portal (nginx, static) | https://astro.isl-dev.grid.cyfronet.pl (ingress vhost) |
|
||||
|
||||
## Publish the simplified portal from `main`
|
||||
|
||||
1. Check that `ctao/content:main` contains the four Example files in `pages/`
|
||||
(listed in `src/data/examples.json`) and the uploads they reference. They
|
||||
are already committed there (`a3452d7`, "demo lorem ipsum pages"). News and
|
||||
other page files can remain in the content repository; this portal loads
|
||||
only the four Example files.
|
||||
2. Push the content branch to Gitea as `ctao/content:main`, and the code
|
||||
branch as `ctao/portal:main`. These are separate pushes; Bitbucket is
|
||||
not the deployment remote.
|
||||
3. Copy the updated `build.sh` to `~/ctao-portal-demo/bin/build.sh` and the
|
||||
updated `ctao-portal-build.service` to `~/.config/systemd/user/`. Reload
|
||||
systemd with `systemctl --user daemon-reload`. The service explicitly sets
|
||||
`CODE_BRANCH=main` and `CONTENT_BRANCH=main`; the script defaults agree.
|
||||
4. Start the build service or let its timer run. It overlays `pages/` and
|
||||
`uploads/`, clears the previous news overlay, and runs `npm run check`
|
||||
before the atomic release switch. Missing Example pages fail the build.
|
||||
5. Verify the four `/example/…/` pages and empty `/news/`. Sign in at `/admin/`,
|
||||
save an Example title, and check that a commit appears on
|
||||
`ctao/content:main` and the rebuilt page reflects it.
|
||||
|
||||
The OAuth client and public portal origin stay the same. Sveltia's
|
||||
`backend.branch` in `public/admin/config.yml` must always match
|
||||
`CONTENT_BRANCH`. Branches are selected independently; a single `BRANCH`
|
||||
environment variable is no longer used. For a separate preview hostname,
|
||||
update the site origin, OAuth redirect, and Gitea CORS together.
|
||||
|
||||
To undo the simplification in shared code history, use
|
||||
`git revert -m 1 <simplification-merge-commit>` on `main` and publish the
|
||||
resulting commit. The previous portal code is also preserved at `0772462`.
|
||||
For an immediate deployment rollback, restore the previous release and worker
|
||||
script/service configuration. Content has its own history: reverting a code
|
||||
commit does not revert CMS edits. Keep the old content files available if
|
||||
the previous portal may be restored.
|
||||
|
||||
## Install (each step reviewed before running; [W] = writes to the machine)
|
||||
|
||||
1. **[W]** `loginctl enable-linger $USER`. Without lingering every user unit
|
||||
1. **[W]** `loginctl enable-linger $USER` — without lingering every user unit
|
||||
dies at logout and nothing starts after a reboot. Verify:
|
||||
`loginctl show-user $USER -p Linger` → `Linger=yes`.
|
||||
2. **[W]** `mkdir -p ~/ctao-portal-demo/{gitea-data,gitea-config,releases,state,bin,config} ~/.config/containers/systemd ~/.config/systemd/user`
|
||||
@@ -84,16 +49,15 @@ the previous portal may be restored.
|
||||
(Upgrading later = pick new digests deliberately, update the pins in the
|
||||
`.container` files / `Containerfile.build`, re-pull, re-build.)
|
||||
5. **[W]** `systemctl --user daemon-reload && systemctl --user start ctao-demo-gitea`
|
||||
6. **[W]** Create the Gitea admin. Run it interactively in a terminal so the
|
||||
6. **[W]** Create the Gitea admin — run interactively in a terminal so the
|
||||
password never lands in a file or shell history:
|
||||
`podman exec -it ctao-demo-gitea gitea admin user create --admin --username <you> --email <you@…> --random-password`
|
||||
7. **[W]** In the Gitea UI: create org `ctao` with repos `portal` and
|
||||
`content` (both public read). The content `main` branch needs the four
|
||||
Example pages described above. Then, from your workstation, push both over
|
||||
`content` (both public read). Then, from your workstation, push both over
|
||||
the vhost with a repo-scoped token:
|
||||
`git push https://<user>:<token>@astro-git.isl-dev.grid.cyfronet.pl/ctao/portal.git main`
|
||||
`git push https://<user>:<token>@astro-git.isl-dev.grid.cyfronet.pl/ctao/content.git main`
|
||||
8. **[W]** `systemctl --user enable --now ctao-portal-build.timer`. The first run
|
||||
8. **[W]** `systemctl --user enable --now ctao-portal-build.timer` — first run
|
||||
clones + `npm ci` + builds (minutes); later runs are seconds. Wait until
|
||||
`journalctl --user -u ctao-portal-build -n 5` shows `published <sha>`
|
||||
(starting nginx earlier just serves 404s until the first build lands).
|
||||
@@ -101,10 +65,6 @@ the previous portal may be restored.
|
||||
10. **[R]** Verify: `curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/`
|
||||
and `journalctl --user -u ctao-portal-build -n 20` (shows measured build times).
|
||||
|
||||
Editor accounts need WRITE access to `ctao/content` (Gitea → repo →
|
||||
Collaborators, or a team); public read alone lets them sign in but every
|
||||
save fails.
|
||||
|
||||
## CMS sign-in (Sveltia ↔ Gitea OAuth)
|
||||
|
||||
- Gitea OAuth2 app (PKCE, `confidential_client=false`, no secret) with
|
||||
@@ -134,11 +94,6 @@ loginctl disable-linger $USER # only if nothing else of yours should survive l
|
||||
|
||||
## Notes
|
||||
|
||||
- A release that fails to build is not retried until either repo gets a new
|
||||
commit (`state/last-failed` guards against a 10 s rebuild loop). To force a
|
||||
retry of the SAME release (e.g. after fixing `bin/build.sh` itself):
|
||||
`rm ~/ctao-portal-demo/state/last-failed`.
|
||||
|
||||
- **Only pushes to the machine's Gitea auto-deploy** (code and content repos
|
||||
alike). Changes to `deploy/*` need a manual
|
||||
re-copy: `build.sh` → `bin/`, `nginx.conf` → `config/` +
|
||||
@@ -152,12 +107,12 @@ loginctl disable-linger $USER # only if nothing else of yours should survive l
|
||||
lockfile changes. Routine rebuilds are fully offline.
|
||||
- Memory caps (`MemoryHigh`) keep us polite next to Outline + Strapi;
|
||||
the build container is capped at 1 GB via `podman run --memory`. Watch the
|
||||
first `npm ci` + build in the journal; if it OOMs inside its cgroup
|
||||
first `npm ci` + build in the journal — if it OOMs inside its cgroup
|
||||
(contained, just retries), raise the cap.
|
||||
- Build isolation: build containers join the Gitea container's network
|
||||
namespace (`--network=container:ctao-demo-gitea`): repo/npm code sees
|
||||
namespace (`--network=container:ctao-demo-gitea`) — repo/npm code sees
|
||||
Gitea on localhost:3000 but cannot reach host loopback services. (Rootless
|
||||
netavark bridges don't work here: no `ip_tables` kernel module, no sudo.)
|
||||
- Secrets inventory: Gitea admin password (typed interactively, lives only
|
||||
in Gitea's DB) and repo-scoped push tokens (managed in Gitea); that's the
|
||||
in Gitea's DB) and repo-scoped push tokens (managed in Gitea) — that's the
|
||||
complete list. Build/poll/serve use none.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Two repositories by design: code (templates/CSS, developed by the team) and
|
||||
# content (Markdown + uploads, committed by the CMS). The build overlays
|
||||
# content onto code, so an editor publishing a page and a developer
|
||||
# content onto code, so an editor publishing an article and a developer
|
||||
# shipping CSS never mix histories — either change republishes the site.
|
||||
set -euo pipefail
|
||||
|
||||
@@ -17,8 +17,7 @@ BASE="${BASE:-$HOME/ctao-portal-demo}"
|
||||
GITEA_URL="${GITEA_URL:-http://localhost:3000}" # published by ctao-demo-gitea
|
||||
CODE_REPO="${CODE_REPO:-ctao/portal}" # owner/repo in Gitea
|
||||
CONTENT_REPO="${CONTENT_REPO:-ctao/content}"
|
||||
CODE_BRANCH="${CODE_BRANCH:-main}"
|
||||
CONTENT_BRANCH="${CONTENT_BRANCH:-main}"
|
||||
BRANCH="${BRANCH:-main}"
|
||||
BUILD_IMAGE="${BUILD_IMAGE:-localhost/ctao-portal-build:1}"
|
||||
# The build joins the Gitea container's network namespace: localhost inside
|
||||
# the build = Gitea's loopback (port 3000), host loopback stays unreachable.
|
||||
@@ -27,7 +26,7 @@ BUILD_IMAGE="${BUILD_IMAGE:-localhost/ctao-portal-build:1}"
|
||||
BUILD_NETNS="${BUILD_NETNS:-container:ctao-demo-gitea}"
|
||||
CODE_URL="${CODE_URL:-http://localhost:3000/$CODE_REPO.git}"
|
||||
CONTENT_URL="${CONTENT_URL:-http://localhost:3000/$CONTENT_REPO.git}"
|
||||
KEEP="${KEEP:-3}" # previous releases kept besides `current` (rollback targets)
|
||||
KEEP="${KEEP:-3}" # released builds to retain
|
||||
mkdir -p "$BASE/repo" "$BASE/content" "$BASE/releases" "$BASE/state" "$BASE/npm-cache"
|
||||
|
||||
# Host prerequisites (everything else runs inside containers). Fail loud —
|
||||
@@ -38,28 +37,24 @@ done
|
||||
|
||||
# --- 1. Cheap poll: both branch heads via the local Gitea API ---
|
||||
head_of() {
|
||||
curl -fsS --max-time 5 "$GITEA_URL/api/v1/repos/$1/branches/$2" \
|
||||
curl -fsS --max-time 5 "$GITEA_URL/api/v1/repos/$1/branches/$BRANCH" \
|
||||
| jq -r '.commit.id' || true
|
||||
}
|
||||
code_sha=$(head_of "$CODE_REPO" "$CODE_BRANCH")
|
||||
content_sha=$(head_of "$CONTENT_REPO" "$CONTENT_BRANCH")
|
||||
code_sha=$(head_of "$CODE_REPO")
|
||||
content_sha=$(head_of "$CONTENT_REPO")
|
||||
# Gitea down/unreachable is a transient, not a unit failure — exit 0 quietly
|
||||
# instead of painting the journal red every 10 s. Name the repo: a 404 here
|
||||
# also means "repo/branch missing or renamed", not just "Gitea down".
|
||||
[[ "$code_sha" =~ ^[0-9a-f]{40}$ ]] || { echo "poll failed for $CODE_REPO@$CODE_BRANCH (gitea down, or repo/branch missing) — skipping"; exit 0; }
|
||||
[[ "$content_sha" =~ ^[0-9a-f]{40}$ ]] || { echo "poll failed for $CONTENT_REPO@$CONTENT_BRANCH (gitea down, or repo/branch missing) — skipping"; exit 0; }
|
||||
# instead of painting the journal red every 10 s.
|
||||
for sha in "$code_sha" "$content_sha"; do
|
||||
if [[ ! "$sha" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "poll failed (gitea unreachable?) — skipping this tick"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
release="${code_sha:0:12}-${content_sha:0:12}" # code+content pin the release
|
||||
# Skip only if this pair is both recorded AND still present in releases/
|
||||
# (a deleted release dir must trigger a rebuild, not an eternal skip).
|
||||
[[ "$release" == "$(cat "$BASE/state/last-built" 2>/dev/null)" \
|
||||
&& -d "$BASE/releases/$release" ]] && exit 0
|
||||
# A release that already failed is not retried until either repo moves —
|
||||
# otherwise one bad commit (e.g. broken frontmatter) turns into a full
|
||||
# rebuild every 10 s on a shared VM. The failure is loud once, then quiet.
|
||||
if [[ "$release" == "$(cat "$BASE/state/last-failed" 2>/dev/null)" ]]; then
|
||||
echo "skipping $release — build failed before; push a fix to retry"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "building code=$code_sha content=$content_sha"
|
||||
t0=$(date +%s)
|
||||
@@ -74,7 +69,7 @@ podman run --rm --network="$BUILD_NETNS" --memory=1g \
|
||||
-e ASTRO_TELEMETRY_DISABLED=1 \
|
||||
-e CODE_SHA="$code_sha" -e CODE_URL="$CODE_URL" \
|
||||
-e CONTENT_SHA="$content_sha" -e CONTENT_URL="$CONTENT_URL" \
|
||||
-e RELEASE="$release" -e CODE_BRANCH="$CODE_BRANCH" -e CONTENT_BRANCH="$CONTENT_BRANCH" \
|
||||
-e RELEASE="$release" -e BRANCH="$BRANCH" \
|
||||
-v "$BASE/repo:/work/repo:z" \
|
||||
-v "$BASE/content:/work/content:z" \
|
||||
-v "$BASE/releases:/work/releases:z" \
|
||||
@@ -82,20 +77,19 @@ podman run --rm --network="$BUILD_NETNS" --memory=1g \
|
||||
-w /work "$BUILD_IMAGE" sh -ec '
|
||||
git config --global safe.directory "/work/repo"
|
||||
git config --global --add safe.directory "/work/content"
|
||||
sync_clone() { # $1 dir $2 url $3 sha $4 branch
|
||||
[ -d "$1/.git" ] || git clone --branch "$4" "$2" "$1"
|
||||
sync_clone() { # $1 dir $2 url $3 sha
|
||||
[ -d "$1/.git" ] || git clone --branch "$BRANCH" "$2" "$1"
|
||||
git -C "$1" remote set-url origin "$2" # self-heal if the URL changes
|
||||
git -C "$1" fetch --quiet origin "$4"
|
||||
git -C "$1" fetch --quiet origin "$BRANCH"
|
||||
# --force: the working copy is disposable; a stray tracked-file edit
|
||||
# must not wedge every future build.
|
||||
git -C "$1" checkout --quiet --force "$3"
|
||||
}
|
||||
sync_clone repo "$CODE_URL" "$CODE_SHA" "$CODE_BRANCH"
|
||||
sync_clone content "$CONTENT_URL" "$CONTENT_SHA" "$CONTENT_BRANCH"
|
||||
# Overlay content onto code (these paths are gitignored in the code repo).
|
||||
# mkdir -p: checkout prunes the emptied parent dirs, cp needs them back.
|
||||
sync_clone repo "$CODE_URL" "$CODE_SHA"
|
||||
sync_clone content "$CONTENT_URL" "$CONTENT_SHA"
|
||||
# Overlay content onto code (these paths are gitignored in the code repo)
|
||||
rm -rf repo/src/content/news repo/src/content/pages repo/public/uploads
|
||||
mkdir -p repo/src/content repo/public
|
||||
cp -a content/news repo/src/content/news
|
||||
cp -a content/pages repo/src/content/pages
|
||||
cp -a content/uploads repo/public/uploads
|
||||
cd repo
|
||||
@@ -109,13 +103,10 @@ podman run --rm --network="$BUILD_NETNS" --memory=1g \
|
||||
npm ci --ignore-scripts --no-audit --no-fund
|
||||
echo "$lock" > .deps-hash
|
||||
fi
|
||||
# Validate the overlay and links before publishing; never seed demo content
|
||||
# in place of an incomplete content branch.
|
||||
npm run check
|
||||
npm run build
|
||||
rm -rf "../releases/$RELEASE"
|
||||
cp -a dist "../releases/$RELEASE"
|
||||
' || { echo "$release" > "$BASE/state/last-failed"; echo "BUILD FAILED for $release (see above) — will not retry until a new commit"; exit 1; }
|
||||
rm -f "$BASE/state/last-failed"
|
||||
'
|
||||
|
||||
# --- 3. Atomic publish: symlink flip via rename(2) — no half-published moment.
|
||||
# mv -T is GNU (the target host is Rocky); when testing on macOS put a
|
||||
|
||||
@@ -40,7 +40,7 @@ Environment=GITEA__service__DISABLE_REGISTRATION=true
|
||||
Environment=GITEA__mailer__ENABLED=false
|
||||
# Repos default to public so the build pipeline can clone anonymously —
|
||||
# content is the public site anyway. The `ctao/portal` repo itself is
|
||||
# created in the UI (README step 7).
|
||||
# created in the UI (README step 6).
|
||||
Environment=GITEA__repository__DEFAULT_PRIVATE=public
|
||||
# Sveltia is served from the portal vhost and calls the Gitea API cross-origin
|
||||
# — CORS locked to exactly that origin. ALLOW_DOMAIN takes FULL origins with
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
# activate a service that is still running.
|
||||
|
||||
[Unit]
|
||||
Description=CTAO portal demo — rebuild if the code or content repo has new commits
|
||||
Description=CTAO portal demo — rebuild if the content repo has new commits
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=CODE_BRANCH=main
|
||||
Environment=CONTENT_BRANCH=main
|
||||
ExecStart=%h/ctao-portal-demo/bin/build.sh
|
||||
# Polite neighbour on the shared VM:
|
||||
Nice=10
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# OnBootSec covers reboot. Enable: systemctl --user enable --now ctao-portal-build.timer
|
||||
|
||||
[Unit]
|
||||
Description=CTAO portal demo — poll the code and content repos every 10 s
|
||||
Description=CTAO portal demo — poll the content repo every 10 s
|
||||
|
||||
[Timer]
|
||||
OnActiveSec=5
|
||||
|
||||
@@ -8,14 +8,11 @@
|
||||
"name": "ctao-portal",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"astro": "7.2.10"
|
||||
"astro": "^7.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "0.9.10",
|
||||
"typescript": "6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
"@astrojs/check": "^0.9.10",
|
||||
"typescript": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/check": {
|
||||
@@ -3594,9 +3591,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.18",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
|
||||
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
|
||||
"version": "3.3.16",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -3794,9 +3791,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.28",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
|
||||
"integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==",
|
||||
"version": "8.5.22",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz",
|
||||
"integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -3813,7 +3810,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.18",
|
||||
"nanoid": "^3.3.16",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
|
||||
@@ -4,23 +4,16 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"content:link": "node scripts/content.mjs --relink",
|
||||
"predev": "node scripts/content.mjs && node scripts/preview-styles.mjs",
|
||||
"dev": "astro dev",
|
||||
"prebuild": "node scripts/content.mjs && node scripts/preview-styles.mjs",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"precheck": "node scripts/content.mjs && node scripts/preview-styles.mjs",
|
||||
"check": "astro check && astro build && node scripts/check-links.mjs"
|
||||
"check": "astro build && node scripts/check-links.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "7.2.10"
|
||||
"astro": "^7.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "0.9.10",
|
||||
"typescript": "6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
"@astrojs/check": "^0.9.10",
|
||||
"typescript": "^6.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Sveltia CMS config — backend: Gitea behind the Cyfronet ingress (HTTPS
|
||||
# vhost). Editors log in via Gitea OAuth (PKCE, no client secret); edits are
|
||||
# committed to the ctao/content repo. Gitea's ROOT_URL and CORS are pinned to
|
||||
# committed to the ctao/portal repo. Gitea's ROOT_URL and CORS are pinned to
|
||||
# these origins in deploy/ctao-demo-gitea.container.
|
||||
backend:
|
||||
name: gitea
|
||||
# Keep this branch in sync with CONTENT_BRANCH in deploy/build.sh.
|
||||
# Content lives in its OWN repo (editorial history separate from code —
|
||||
# the build overlays it onto the portal code, see deploy/build.sh).
|
||||
repo: ctao/content
|
||||
branch: main
|
||||
base_url: https://astro-git.isl-dev.grid.cyfronet.pl
|
||||
@@ -44,82 +45,36 @@ media_libraries:
|
||||
optimize: true
|
||||
|
||||
collections:
|
||||
- name: home
|
||||
label: "Home page"
|
||||
files:
|
||||
- name: home
|
||||
label: "Home page"
|
||||
file: "pages/home.md"
|
||||
format: frontmatter
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: introduction, label: "Introduction", widget: text, required: false }
|
||||
- name: images
|
||||
label: "Images"
|
||||
label_singular: "image"
|
||||
widget: list
|
||||
required: false
|
||||
max: 2
|
||||
hint: "Up to two images, shown side by side."
|
||||
fields:
|
||||
- { name: image, label: "Image", widget: image }
|
||||
- { name: alt, label: "Alternative text", widget: string, required: false, hint: "Describe the image; leave empty only for decorative images." }
|
||||
- { name: caption, label: "Caption", widget: string, required: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
- { name: buttonLabel, label: "Button label", widget: string, required: false }
|
||||
- { name: buttonUrl, label: "Button destination", widget: string, required: false, hint: "A site path such as /example/lorem-ipsum/, or an https:// URL." }
|
||||
- name: examples
|
||||
label: "Example pages"
|
||||
files:
|
||||
- name: lorem-ipsum
|
||||
label: "Lorem ipsum"
|
||||
file: "pages/lorem-ipsum.md"
|
||||
format: frontmatter
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: introduction, label: "Introduction", widget: text, required: false }
|
||||
- { name: image, label: "Image", widget: image, required: false }
|
||||
- { name: imageAlt, label: "Image alternative text", widget: string, required: false, hint: "Describe the image; leave empty only for decorative images." }
|
||||
- { name: imageCaption, label: "Image caption", widget: string, required: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
- { name: buttonLabel, label: "Button label", widget: string, required: false }
|
||||
- { name: buttonUrl, label: "Button destination", widget: string, required: false, hint: "A site path such as /example/lorem-ipsum/, or an https:// URL." }
|
||||
- name: dolor-sit-amet
|
||||
label: "Dolor sit amet"
|
||||
file: "pages/dolor-sit-amet.md"
|
||||
format: frontmatter
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: introduction, label: "Introduction", widget: text, required: false }
|
||||
- { name: image, label: "Image", widget: image, required: false }
|
||||
- { name: imageAlt, label: "Image alternative text", widget: string, required: false, hint: "Describe the image; leave empty only for decorative images." }
|
||||
- { name: imageCaption, label: "Image caption", widget: string, required: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
- { name: buttonLabel, label: "Button label", widget: string, required: false }
|
||||
- { name: buttonUrl, label: "Button destination", widget: string, required: false, hint: "A site path such as /example/lorem-ipsum/, or an https:// URL." }
|
||||
- name: consectetur-adipiscing
|
||||
label: "Consectetur adipiscing"
|
||||
file: "pages/consectetur-adipiscing.md"
|
||||
format: frontmatter
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: introduction, label: "Introduction", widget: text, required: false }
|
||||
- { name: image, label: "Image", widget: image, required: false }
|
||||
- { name: imageAlt, label: "Image alternative text", widget: string, required: false, hint: "Describe the image; leave empty only for decorative images." }
|
||||
- { name: imageCaption, label: "Image caption", widget: string, required: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
- { name: buttonLabel, label: "Button label", widget: string, required: false }
|
||||
- { name: buttonUrl, label: "Button destination", widget: string, required: false, hint: "A site path such as /example/lorem-ipsum/, or an https:// URL." }
|
||||
- name: sed-do-eiusmod
|
||||
label: "Sed do eiusmod"
|
||||
file: "pages/sed-do-eiusmod.md"
|
||||
format: frontmatter
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: introduction, label: "Introduction", widget: text, required: false }
|
||||
- { name: image, label: "Image", widget: image, required: false }
|
||||
- { name: imageAlt, label: "Image alternative text", widget: string, required: false, hint: "Describe the image; leave empty only for decorative images." }
|
||||
- { name: imageCaption, label: "Image caption", widget: string, required: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
- { name: buttonLabel, label: "Button label", widget: string, required: false }
|
||||
- { name: buttonUrl, label: "Button destination", widget: string, required: false, hint: "A site path such as /example/lorem-ipsum/, or an https:// URL." }
|
||||
- name: news
|
||||
label: "News"
|
||||
label_singular: "Article"
|
||||
folder: "news"
|
||||
create: true
|
||||
slug: "{{slug}}"
|
||||
extension: md
|
||||
format: frontmatter
|
||||
summary: "{{title}} · {{date}}"
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: description, label: "Short description", widget: text }
|
||||
- { name: date, label: "Date", widget: datetime, date_format: "YYYY-MM-DD", time_format: false }
|
||||
- { name: category, label: "Category", widget: string, default: "news" }
|
||||
- { name: author, label: "Author", widget: string, default: "CTAO" }
|
||||
- { name: cover, label: "Cover image", widget: image, required: false }
|
||||
- { name: lang, label: "Language (if not English, e.g. pl)", widget: string, required: false }
|
||||
- { name: draft, label: "Draft (unpublished)", widget: boolean, default: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
|
||||
- name: pages
|
||||
label: "Pages"
|
||||
label_singular: "Page"
|
||||
folder: "pages"
|
||||
create: true
|
||||
slug: "{{slug}}"
|
||||
extension: md
|
||||
format: frontmatter
|
||||
summary: "{{title}}"
|
||||
fields:
|
||||
- { name: title, label: "Title", widget: string }
|
||||
- { name: description, label: "Description", widget: text, required: false }
|
||||
- { name: body, label: "Body", widget: markdown }
|
||||
|
||||
@@ -1,470 +1,71 @@
|
||||
/* Generated by scripts/preview-styles.mjs; edit src/styles/global.css. */
|
||||
|
||||
/* ==========================================================================
|
||||
CTAO Science Portal: content page mockup
|
||||
Colours and type follow the CTAO Brand Guidelines (April 2024).
|
||||
The editor preview (public/admin/preview.css) is generated from the
|
||||
hero, prose and button sections below by scripts/preview-styles.mjs.
|
||||
========================================================================== */
|
||||
|
||||
/* Fonts
|
||||
========================================================================== */
|
||||
|
||||
/* Entry-preview styles for the Sveltia editor, registered via the documented
|
||||
CMS.registerPreviewStyle API (bare element selectors, per the official docs
|
||||
example). This file MIRRORS the article styles 1:1 — the design tokens from
|
||||
:root and the `.prose` block in src/styles/global.css — with `.prose`
|
||||
dropped from selectors (the preview pane has no such wrapper).
|
||||
KEEP IN SYNC: when you touch `.prose` or the tokens in global.css, update
|
||||
the corresponding value here (a matching reminder sits next to `.prose`).
|
||||
Fonts: same self-hosted woff2 files the site uses, same origin. (The
|
||||
Sveltia bundle still loads its own UI fonts from jsDelivr — only the
|
||||
PREVIEW pane is CDN-free.) */
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-weight: 400 700;
|
||||
font-display: swap;
|
||||
src: url("/assets/fonts/inter-latin.woff2") format("woff2");
|
||||
font-family: "Inter"; font-weight: 400 700; font-display: swap;
|
||||
src: url("/fonts/inter-latin.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Space Grotesk";
|
||||
font-weight: 500 700;
|
||||
font-display: swap;
|
||||
src: url("/assets/fonts/space-grotesk-latin.woff2") format("woff2");
|
||||
font-family: "Space Grotesk"; font-weight: 500 700; font-display: swap;
|
||||
src: url("/fonts/space-grotesk-latin.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* Tokens
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* Brand main colours (D.2.1) */
|
||||
--galaxy-blue: #00004a;
|
||||
--cherenkov-blue: #00e4d8;
|
||||
--moon-gray: #f5f5f5;
|
||||
|
||||
/* Brand secondary colours (D.2.2) */
|
||||
--white: #ffffff;
|
||||
--cosmic-azure: #007aff;
|
||||
--interstellar-indigo: #00009c;
|
||||
|
||||
/* Text */
|
||||
--text: #111111;
|
||||
--text-muted: #555555;
|
||||
/* Cosmic Azure at 84% brightness: 5.4:1 on white, 3.5:1 against body text */
|
||||
--link: #0066d6;
|
||||
|
||||
/* Type: Inter for everything, Space Grotesk for headlines (D.3) */
|
||||
--font-body: "Inter", Arial, sans-serif;
|
||||
--font-head: "Space Grotesk", Arial, sans-serif;
|
||||
|
||||
/* Layout */
|
||||
--content-width: 85rem;
|
||||
--gutter: clamp(1rem, 4vw, 2.5rem);
|
||||
--header-height: 7rem;
|
||||
--header-height-scrolled: 5rem;
|
||||
/* Large decorative corners (hero, header, search panel): grows with the
|
||||
viewport instead of switching at breakpoints */
|
||||
--radius-lg: min(15vw, 180px);
|
||||
--radius-sm: 15px;
|
||||
/* How far photos are pulled up into the hero */
|
||||
--hero-overlap: clamp(6rem, 11.25vw, 9rem);
|
||||
/* Dropdown submenus (Example, language) */
|
||||
--radius-menu: 8px;
|
||||
--transition: 0.3s ease-in-out;
|
||||
|
||||
/* Film grain tile over the hero background, also hides gradient banding */
|
||||
--grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.05'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* Base
|
||||
========================================================================== */
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-padding-top: var(--header-height-scrolled);
|
||||
/* tokens copied from global.css :root */
|
||||
--galaxy: #00004a;
|
||||
--moon: #f5f5f5;
|
||||
--text: #101228;
|
||||
--muted: #46536a;
|
||||
--border: #e2e5ee;
|
||||
--link: #0057c2;
|
||||
--font-body: "Inter", Arial, system-ui, sans-serif;
|
||||
--font-display: "Space Grotesk", var(--font-body);
|
||||
--fs-s: 0.9rem;
|
||||
--fs-l: 1.125rem;
|
||||
--fs-xl: 1.5rem;
|
||||
--fs-h2: clamp(1.75rem, 3.5vw, 2.5rem);
|
||||
--radius: 16px;
|
||||
}
|
||||
|
||||
/* preview shell ≈ article column */
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-body);
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
color: var(--text);
|
||||
background: var(--white);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body.no-scroll {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus-visible {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.15em;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
background: none;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Focus ring: Link blue on light backgrounds, Cherenkov Blue on dark ones */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--link);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.site-header :focus-visible,
|
||||
.page-hero :focus-visible,
|
||||
.site-footer :focus-visible {
|
||||
outline-color: var(--cherenkov-blue);
|
||||
}
|
||||
|
||||
/* Utilities
|
||||
========================================================================== */
|
||||
|
||||
.container {
|
||||
width: min(100% - 2 * var(--gutter), var(--content-width));
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip-path: inset(50%);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: -4rem;
|
||||
left: 1rem;
|
||||
z-index: 100;
|
||||
padding: 0.5rem 1rem;
|
||||
color: var(--galaxy-blue);
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: inline-block;
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
|
||||
a:hover .arrow,
|
||||
button:hover .arrow {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
@keyframes panel-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Page hero
|
||||
========================================================================== */
|
||||
|
||||
.page-hero {
|
||||
margin-top: calc(-1 * var(--header-height));
|
||||
padding: calc(var(--header-height) + 3rem) 0 calc(var(--hero-overlap) + 3rem);
|
||||
color: var(--white);
|
||||
background: var(--grain), var(--galaxy-blue);
|
||||
border-bottom-right-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
/* Pages without a photo: no room needed for the figure to overlap */
|
||||
.page-hero--compact {
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
.breadcrumb ol {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
margin: 0 0 1rem;
|
||||
padding: 0;
|
||||
font-size: 0.875rem;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.breadcrumb li + li::before {
|
||||
content: "›";
|
||||
margin-right: 0.5rem;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.breadcrumb a:hover {
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.breadcrumb [aria-current] {
|
||||
font-weight: 500;
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
/* Headline: Space Grotesk medium, white on dark (D.3.4) */
|
||||
.page-hero__title {
|
||||
max-width: 24ch;
|
||||
margin: 0 0 1.25rem;
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(2rem, 5vw, 3.75rem);
|
||||
font-weight: 500;
|
||||
line-height: 1.05;
|
||||
letter-spacing: -0.02em;
|
||||
text-wrap: balance;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.page-hero__lead {
|
||||
max-width: 70ch;
|
||||
margin: 0;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
margin: 0 auto;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
/* Photo pulled up over the hero; flat, no shadow */
|
||||
.page-figure {
|
||||
margin: calc(-1 * var(--hero-overlap)) 0 4rem;
|
||||
}
|
||||
|
||||
.page-figure img {
|
||||
width: 100%;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.page-figure figcaption {
|
||||
margin-top: 0.75rem;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Two photos side by side (Home), pulled up over the hero together; they
|
||||
stack by themselves once each would be narrower than 18rem */
|
||||
.page-figures {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
|
||||
gap: 1.5rem;
|
||||
margin: calc(-1 * var(--hero-overlap)) 0 4rem;
|
||||
}
|
||||
|
||||
.page-figures .page-figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Same shape for both photos, whatever the uploads' proportions */
|
||||
.page-figures img {
|
||||
aspect-ratio: 3 / 2;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* Prose
|
||||
========================================================================== */
|
||||
|
||||
.prose {
|
||||
padding-bottom: 5rem;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.prose--no-image {
|
||||
padding-top: 4rem;
|
||||
}
|
||||
|
||||
.prose > * {
|
||||
max-width: 64rem;
|
||||
}
|
||||
|
||||
/* Galaxy Blue headline on light background (D.3.4) */
|
||||
.prose h2 {
|
||||
margin: 3rem 0 1rem;
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(1.75rem, 3vw, 2.375rem);
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--galaxy-blue);
|
||||
}
|
||||
|
||||
.prose h2:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
margin: 0 0 1.25rem;
|
||||
font-size: 1.0625rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Text links: colour only at rest, underline on hover and focus */
|
||||
.prose a:not(.btn):hover,
|
||||
.prose a:not(.btn):focus-visible {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.15em;
|
||||
}
|
||||
|
||||
/* Cherenkov Blue fails contrast as text on white, so it is the accent bar */
|
||||
.prose .highlight,
|
||||
.prose blockquote {
|
||||
margin: 2.5rem 0;
|
||||
padding-left: 1.5rem;
|
||||
font-size: 1.375rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.35;
|
||||
color: var(--galaxy-blue);
|
||||
border-left: 4px solid var(--cherenkov-blue);
|
||||
}
|
||||
|
||||
.prose blockquote p {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.prose h3,
|
||||
.prose h4,
|
||||
.prose h5,
|
||||
.prose h6 {
|
||||
font-family: var(--font-head);
|
||||
color: var(--galaxy-blue);
|
||||
}
|
||||
|
||||
.prose li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.prose img {
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.prose pre {
|
||||
padding: 1rem;
|
||||
overflow-x: auto;
|
||||
background: var(--moon-gray);
|
||||
}
|
||||
|
||||
.prose code {
|
||||
overflow-wrap: normal;
|
||||
}
|
||||
|
||||
.prose table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.prose th,
|
||||
.prose td {
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.prose hr {
|
||||
margin: 2rem 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* Placeholder pages: empty body until their content exists */
|
||||
.placeholder-body {
|
||||
min-height: 12rem;
|
||||
}
|
||||
|
||||
/* Buttons
|
||||
========================================================================== */
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
height: 2.75rem;
|
||||
padding: 0 1.5rem;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
/* Underline the label only: a flex container would pass it on to the arrow */
|
||||
.btn:hover,
|
||||
.btn:focus-visible {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn:hover .btn__label,
|
||||
.btn:focus-visible .btn__label {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.15em;
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
color: var(--white);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--galaxy-blue) 0%,
|
||||
var(--cosmic-azure) 70%,
|
||||
var(--cherenkov-blue) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.btn--primary:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
/* Preferences
|
||||
========================================================================== */
|
||||
|
||||
/* Windows High Contrast: drop the decorative hero background behind system text */
|
||||
@media (forced-colors: active) {
|
||||
.page-hero {
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Preview frame
|
||||
========================================================================== */
|
||||
|
||||
/* There is no site header above the hero */
|
||||
.page-hero {
|
||||
margin-top: 0;
|
||||
padding-top: 3rem;
|
||||
/* = global.css base heading/link rules = */
|
||||
h1, h2 { font-family: var(--font-display); font-weight: 500; letter-spacing: -0.025em; line-height: 1.1; }
|
||||
h3 { font-weight: 600; }
|
||||
h1, h2, h3 { overflow-wrap: break-word; text-wrap: balance; }
|
||||
a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
|
||||
|
||||
/* = global.css `.prose` rules, selectors unwrapped = */
|
||||
body { line-height: 1.65; overflow-wrap: break-word; }
|
||||
a { overflow-wrap: anywhere; }
|
||||
h1 { color: var(--galaxy); font-size: var(--fs-h2); } /* mirrors `.article h1` */
|
||||
h2 { color: var(--galaxy); margin: 44px 0 12px; font-size: var(--fs-xl); }
|
||||
h3 { color: var(--galaxy); margin: 30px 0 8px; font-size: var(--fs-l); }
|
||||
p { margin: 0 0 16px; text-wrap: pretty; }
|
||||
ul, ol { margin: 0 0 16px; padding-left: 22px; }
|
||||
li { margin: 6px 0; }
|
||||
blockquote {
|
||||
margin: 22px 0; padding: 12px 20px; border-left: 3px solid var(--galaxy);
|
||||
background: var(--moon); color: var(--text);
|
||||
}
|
||||
img { display: block; max-width: 100%; height: auto; border: 1px solid var(--border); border-radius: var(--radius); }
|
||||
img + em, p > em:only-child { color: var(--muted); font-size: var(--fs-s); }
|
||||
hr { border: 0; border-top: 1px solid var(--border); margin: 32px 0; }
|
||||
table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; margin: 0 0 16px; font-size: var(--fs-s); }
|
||||
th { text-align: left; font-weight: 600; color: var(--galaxy); }
|
||||
th, td { padding: 10px 12px; border-bottom: 1px solid var(--border); }
|
||||
thead th { border-bottom: 2px solid var(--galaxy); }
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 153 32" style="enable-background:new 0 0 153 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{display:inline;}
|
||||
.st2{display:inline;clip-path:url(#SVGID_00000049184525615463858320000015264053225314800771_);}
|
||||
.st3{fill:#FFFFFF;}
|
||||
.st4{fill:#00E5D9;}
|
||||
.st5{fill:#00E4D8;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
<defs>
|
||||
<rect id="SVGID_1_" x="0.9" width="151.4" height="32"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_00000109021271204444604050000000952066022526769593_" class="st1">
|
||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
||||
</clipPath>
|
||||
<g style="display:inline;clip-path:url(#SVGID_00000109021271204444604050000000952066022526769593_);">
|
||||
<path class="st3" d="M19.3,0c10.9,0,17.1,4.8,18,12.6h-9.1c-0.6-2.8-3.4-5.1-8.8-5.1c-6.3,0-9.4,3.2-9.4,8.5
|
||||
c0,5.3,3.1,8.6,9.4,8.6c5.5,0,8.3-2.4,8.8-5.2h9.1c-0.9,7.9-7,12.7-18,12.7C7.4,32,0.9,26.4,0.9,16C0.9,5.6,7.4,0,19.3,0z"/>
|
||||
<path class="st3" d="M62.3,8.4c0.2-0.1,0.4-0.1,0.6-0.1c4,0,8,0,12.1,0c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3-0.1c0-0.1,0-0.2,0-0.3
|
||||
c0-2.3,0-4.6,0-6.9c0-0.1,0-0.2,0-0.3c-0.2,0-0.5,0-0.7,0c-11.4,0-22.8,0-34.3,0c-0.2,0-0.3,0-0.4,0c-0.1,0-0.2,0-0.3,0.1
|
||||
c0,0.2,0,0.4,0,0.5c0,0.8,0,1.6,0,2.4c0,1.3,0,2.6,0,3.9c0,0.2,0,0.4,0.1,0.5c0.2,0.1,0.4,0.1,0.6,0.1c4,0,8.1,0,12.1,0
|
||||
c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3,0.1c0,0.2,0,0.5,0,0.7c0,6.6,0,13.1,0,19.7c0,0.2,0,0.4,0,0.5c0,0.1,0,0.2,0,0.3
|
||||
c0.1,0,0.1,0,0.1,0c2.7-0.5,5.4-1.1,8.1-1.6c0.1,0,0.2-0.1,0.3-0.1c0-0.2,0-0.4,0-0.6c0-6,0-12,0-18.1c0-0.2,0-0.4,0-0.5
|
||||
C62.2,8.6,62.3,8.5,62.3,8.4L62.3,8.4z M53.7,30.2c0,0.3-0.1,0.6,0,0.8c0.4,0.1,6.6,0.1,8.2,0c0.1,0,0.2,0,0.3,0
|
||||
c0-0.1,0.1-0.1,0.1-0.2c0-0.6,0-1.3,0-1.9c0,0,0-0.1-0.1-0.2C59.4,29.2,56.5,29.7,53.7,30.2L53.7,30.2z"/>
|
||||
<path class="st3" d="M151.5,11.4c0.1,0,0.2,0,0.2,0c0.1,0.1,0.1,0.2,0.1,0.3c0.1,0.6,0.2,1.3,0.3,1.9c0.2,1.3,0.2,2.6,0.1,3.8
|
||||
c-0.1,2-0.6,4-1.5,5.9c-1,2.2-2.6,3.9-4.5,5.3c-1.2,0.8-2.5,1.5-3.9,2c-1.1,0.4-2.3,0.7-3.4,0.9c-0.5,0.1-1.1,0.2-1.6,0.3
|
||||
c-0.5,0.1-0.9,0.1-1.4,0.1c-0.1,0-0.1,0-0.2,0c-0.7,0.1-1.5,0.1-2.2,0.1c-0.7,0-1.5,0-2.2,0c-0.3,0-0.5,0-0.8-0.1
|
||||
c-0.1,0-0.3,0-0.4,0c-2.2-0.2-4.3-0.6-6.4-1.3c-1.4-0.5-2.7-1.2-4-2c-2.7-1.9-4.5-4.5-5.4-7.7c-0.1-0.5-0.3-1.1-0.3-1.6
|
||||
c0-0.1,0-0.1,0-0.2c0.1-0.1,0.2-0.1,0.4-0.2c0.5-0.1,1.1-0.2,1.6-0.3c0.9-0.2,1.8-0.4,2.7-0.5c0.9-0.2,1.8-0.4,2.7-0.6
|
||||
c0.3-0.1,0.5-0.1,0.8-0.2c0.2,0,0.3-0.1,0.5-0.1c0.1,0,0.1,0.1,0.2,0.2c0,0.4,0.1,0.8,0.2,1.2c0.2,0.9,0.6,1.8,1.2,2.6
|
||||
c0.6,0.8,1.3,1.4,2.2,1.9c0.7,0.4,1.5,0.7,2.4,0.9c0.6,0.1,1.2,0.3,1.8,0.3c0.8,0.1,1.7,0.2,2.5,0.2c0.4,0,0.7,0,1.1,0
|
||||
c0.1,0,0.3,0,0.4,0c1.3-0.1,2.5-0.3,3.7-0.7c0.5-0.2,1-0.4,1.5-0.7c1.6-0.9,2.7-2.3,3.2-4.1c0.2-0.6,0.3-1.2,0.3-1.8
|
||||
c0-0.5,0.1-1,0.1-1.4c0-0.7-0.1-1.4-0.2-2.1c0-0.1,0-0.2,0-0.3c0,0,0-0.1,0-0.1c0,0,0.1,0,0.1-0.1c0.1,0,0.3-0.1,0.4-0.1
|
||||
c1.5-0.3,2.9-0.6,4.4-0.9c0.7-0.1,1.5-0.3,2.2-0.4c0.2,0,0.4-0.1,0.6-0.1c0.1,0,0.1-0.1,0.2-0.1c0,0,0,0,0-0.1
|
||||
C151.2,11.3,151.3,11.3,151.5,11.4C151.5,11.4,151.5,11.4,151.5,11.4L151.5,11.4z"/>
|
||||
<path class="st3" d="M151.1,11.5c-0.4,0-0.7,0.1-1.1,0.1c-0.7,0.1-1.4,0.2-2.1,0.4c-0.7,0.1-1.3,0.2-2,0.4c-0.7,0.1-1.3,0.2-2,0.3
|
||||
c-0.1,0-0.3,0.1-0.4,0.1c-0.1,0-0.3,0-0.4,0c-0.1-0.2-0.2-0.3-0.2-0.5c-0.5-1.4-1.4-2.4-2.6-3.2c-0.5-0.3-1-0.6-1.5-0.8
|
||||
c-0.7-0.3-1.5-0.5-2.3-0.6c-1.3-0.2-2.6-0.3-3.8-0.3c-0.7,0-1.4,0.1-2.1,0.2c-0.8,0.1-1.6,0.3-2.4,0.5c-0.5,0.2-1,0.4-1.4,0.6
|
||||
c-1.8,1-3,2.5-3.5,4.5c-0.2,0.7-0.3,1.5-0.3,2.2c0,0.2,0,0.4,0,0.7c0,0.1,0,0.2-0.1,0.2c-0.1,0.1-0.3,0.1-0.4,0.1
|
||||
c-0.6,0.1-1.3,0.2-1.9,0.3c-0.6,0.1-1.3,0.2-1.9,0.3c-0.7,0.1-1.4,0.2-2.1,0.4c-0.7,0.1-1.3,0.2-2,0.4c-0.1,0-0.3,0.1-0.4,0
|
||||
c-0.1,0-0.1-0.1-0.1-0.2c0-0.1,0-0.3,0-0.4c0-0.9-0.1-1.8,0-2.7c0.1-2.3,0.7-4.5,1.8-6.6c1.1-2,2.6-3.6,4.4-4.8
|
||||
c1.3-0.9,2.7-1.5,4.2-2c1.1-0.4,2.3-0.6,3.4-0.8c0.6-0.1,1.3-0.2,1.9-0.3c0.6-0.1,1.3-0.1,1.9-0.1c1.2,0,2.4,0,3.6,0
|
||||
c0.2,0,0.4,0,0.5,0c0.1,0,0.2,0,0.3,0c0.8,0,1.6,0.2,2.5,0.3c1.3,0.2,2.5,0.5,3.7,0.9c1.4,0.5,2.8,1.1,4.1,2
|
||||
c1.9,1.3,3.4,2.9,4.5,5c0.4,0.8,0.8,1.7,1,2.6c0,0.1,0,0.2,0.1,0.2c0,0,0,0.1,0,0.1c-0.1,0-0.1,0.1-0.2,0.1l0,0
|
||||
C151.4,11.5,151.2,11.4,151.1,11.5L151.1,11.5L151.1,11.5z"/>
|
||||
<path class="st3" d="M151,11.5c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.2,0,0.3,0C151.4,11.5,151.2,11.5,151,11.5L151,11.5z"/>
|
||||
<path class="st3" d="M84.5,23.5C84.5,23.4,84.6,23.4,84.5,23.5c2.7-5.4,5.3-10.8,8-16.1c0,0,0-0.1,0.1-0.1c0,0,0-0.1,0.1-0.1
|
||||
c0,0,0,0,0,0c0,0,0,0,0.1,0c0.1,0.1,0.2,0.3,0.2,0.4c0.9,1.8,1.7,3.5,2.6,5.3c1.2,2.4,2.4,4.8,3.6,7.2c0.1,0.2,0.1,0.3,0.3,0.5
|
||||
c0.6-0.1,1.2-0.2,1.8-0.3c1.1-0.2,2.1-0.4,3.2-0.5c1-0.2,2-0.3,3-0.5c0.1,0,0.2-0.1,0.3-0.1c-0.1-0.2-0.2-0.3-0.2-0.5
|
||||
c-1.4-2.8-2.8-5.6-4.2-8.4c-1.5-2.9-2.9-5.8-4.4-8.7c-0.1-0.2-0.1-0.4-0.3-0.5c-0.1,0-0.1,0-0.2,0c-3.8,0-7.6,0-11.4,0
|
||||
c-0.1,0-0.1,0-0.2,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0C82.6,9,78.5,17.2,74.4,25.3c0,0,0,0.1,0,0.1c0,0,0.1,0.1,0.1,0
|
||||
C77.8,24.8,81.2,24.1,84.5,23.5z M100,21.8c0.3,0.7,4.4,9,4.6,9.3c0.1,0,0.2,0,0.3,0c2.9,0,5.8,0,8.7,0c0,0,0,0,0.1,0
|
||||
c0,0,0,0,0.1-0.1c0-0.1-0.1-0.2-0.1-0.2c-0.1-0.2-0.3-0.5-0.4-0.8c-1.6-3.1-3.2-6.3-4.7-9.4c-0.1-0.2-0.1-0.3-0.3-0.5
|
||||
C105.5,20.7,102.8,21.2,100,21.8L100,21.8z M73.7,26.8c-0.7,1.4-1.4,2.7-2,4.1c0,0.1,0,0.2-0.1,0.3h9.1c0.2-0.3,2.6-5,2.9-5.8
|
||||
c0-0.1,0-0.1,0.1-0.2c-0.1,0-0.2,0-0.3,0C80.2,25.6,76.9,26.2,73.7,26.8L73.7,26.8z M93.8,29C93.8,29,93.8,29,93.8,29
|
||||
c0.1-0.5,0.1-1,0-1.5c0-0.5-0.1-1.1,0-1.6c0-0.3,0.1-0.7,0.2-1c0.3-1.2,1.1-2,2.1-2.4c0.5-0.2,1.1-0.4,1.6-0.6
|
||||
c0.4-0.2,0.9-0.3,1.3-0.5c-0.1-0.1-0.2-0.1-0.3-0.1c-1,0-1.9,0-2.9,0c-0.9,0-1.7-0.4-2.4-1c-0.4-0.4-0.8-0.9-1-1.5
|
||||
c-0.3-0.8-0.6-1.6-0.8-2.4c0-0.1,0-0.1-0.2-0.1c0,0.2,0,0.3,0,0.5c0,0.8,0,1.7,0,2.5c0,0.8-0.2,1.5-0.7,2.1
|
||||
c-0.5,0.7-1.1,1.1-1.8,1.3c-0.8,0.3-1.6,0.6-2.4,0.9c-0.1,0-0.1,0.1-0.2,0.1c0.1,0.1,0.3,0.1,0.4,0.1c0.9,0,1.8,0,2.8,0
|
||||
c0.2,0,0.4,0,0.6,0.1c1.3,0.3,2.1,1.1,2.6,2.3c0.1,0.2,0.2,0.5,0.3,0.7C93.3,27.6,93.5,28.3,93.8,29L93.8,29z"/>
|
||||
<path class="st4" d="M93.8,29C93.8,29,93.8,29,93.8,29c0.1-0.5,0.1-1,0-1.5c0-0.5-0.1-1.1,0-1.6c0-0.3,0.1-0.7,0.2-1
|
||||
c0.3-1.2,1.1-2,2.1-2.4c0.5-0.2,1.1-0.4,1.6-0.6c0.4-0.2,0.8-0.3,1.3-0.5c-0.1-0.1-0.2-0.1-0.3-0.1c-1,0-1.9,0-2.9,0
|
||||
c-0.9,0-1.7-0.4-2.4-1c-0.4-0.4-0.8-0.9-1-1.5c-0.3-0.8-0.6-1.6-0.8-2.4c0-0.1,0-0.1-0.2-0.1c0,0.2,0,0.3,0,0.5c0,0.8,0,1.7,0,2.5
|
||||
c0,0.8-0.2,1.5-0.7,2.1c-0.5,0.7-1.1,1.1-1.8,1.3c-0.8,0.3-1.6,0.6-2.4,0.9c-0.1,0-0.1,0.1-0.2,0.1c0.1,0.1,0.3,0.1,0.4,0.1
|
||||
c0.9,0,1.8,0,2.8,0c0.2,0,0.4,0,0.6,0.1c1.3,0.3,2.1,1.1,2.6,2.3c0.1,0.2,0.2,0.5,0.3,0.7C93.3,27.6,93.5,28.3,93.8,29L93.8,29z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Logotype">
|
||||
<g>
|
||||
<g>
|
||||
<polygon class="st3" points="100.4,22.3 104.7,30.8 113.9,30.8 108.6,20.6 "/>
|
||||
<g>
|
||||
<path class="st3" d="M122.9,16.1c0,0,0-0.1,0-0.1c0-5.2,2.9-8.3,10.2-8.3c5.7,0,8.8,1.9,9.8,5.2l8.9-1.4
|
||||
c-1.9-7-8.3-11.1-18.7-11.1c-12.5,0-19.3,5.8-19.3,15.6c0,0.5,0,1.1,0.1,1.6L122.9,16.1L122.9,16.1z"/>
|
||||
<path class="st3" d="M143.1,13.3c0.2,0.8,0.3,1.7,0.3,2.6c0,5.2-3,8.4-10.3,8.4c-6.5,0-9.6-2.5-10.1-6.8l-8.8,1.8
|
||||
c1.4,7.8,8,12.2,18.9,12.2c12.4,0,19.3-5.9,19.3-15.7c0-1.6-0.2-3.1-0.5-4.5L143.1,13.3L143.1,13.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st3" points="73.5,27 71.5,30.8 80.8,30.8 83.5,25.4 "/>
|
||||
<polygon class="st3" points="98.6,1.2 86.8,1.2 74.6,24.7 84.9,22.6 92.7,7.2 99.2,19.9 107.6,18.6 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon class="st3" points="53.6,30.2 53.6,30.8 62.2,30.8 62.2,28.8 "/>
|
||||
<polygon class="st3" points="53.6,29.1 62.2,27.3 62.2,8.5 75.7,8.5 75.7,1.2 40.1,1.2 40.1,8.5 53.6,8.5 "/>
|
||||
</g>
|
||||
<path class="st3" d="M19.3,0.4c10.9,0,17.1,4.7,18,12.3h-9.1c-0.6-2.7-3.4-5-8.8-5c-6.3,0-9.4,3.1-9.4,8.3
|
||||
c0,5.2,3.1,8.4,9.4,8.4c5.5,0,8.3-2.3,8.8-5.1h9.1c-0.9,7.7-7.1,12.4-18,12.4C7.4,31.6,0.9,26.1,0.9,16S7.4,0.4,19.3,0.4
|
||||
L19.3,0.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st5" d="M94.7,23.8c1-1.4,3.3-2.1,5.2-2.7c-2,0.1-4.4,0.3-5.8-0.6c-1.4-1-2.1-3.3-2.7-5.2c0.1,2,0.3,4.4-0.6,5.8
|
||||
c-1,1.4-3.3,2.1-5.2,2.7c2-0.1,4.4-0.3,5.8,0.6c1.4,1,2.1,3.3,2.7,5.2C93.9,27.6,93.7,25.2,94.7,23.8z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.1 KiB |
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 153 32" style="enable-background:new 0 0 153 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{display:inline;}
|
||||
.st2{display:inline;clip-path:url(#SVGID_00000021077498389242353310000002629454631782585475_);}
|
||||
.st3{fill:#00004A;}
|
||||
.st4{fill:#00E5D9;}
|
||||
.st5{fill:#00E4D8;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
<defs>
|
||||
<rect id="SVGID_1_" x="0.9" width="151.4" height="32"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_00000068637063279286702420000005043763006986931103_" class="st1">
|
||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
||||
</clipPath>
|
||||
<g style="display:inline;clip-path:url(#SVGID_00000068637063279286702420000005043763006986931103_);">
|
||||
<path class="st3" d="M19.3,0c10.9,0,17.1,4.8,18,12.6h-9.1c-0.6-2.8-3.4-5.1-8.8-5.1c-6.3,0-9.4,3.2-9.4,8.5
|
||||
c0,5.3,3.1,8.6,9.4,8.6c5.5,0,8.3-2.4,8.8-5.2h9.1c-0.9,7.9-7,12.7-18,12.7C7.4,32,0.9,26.4,0.9,16C0.9,5.6,7.4,0,19.3,0z"/>
|
||||
<path class="st3" d="M62.3,8.4c0.2-0.1,0.4-0.1,0.6-0.1c4,0,8,0,12.1,0c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3-0.1c0-0.1,0-0.2,0-0.3
|
||||
c0-2.3,0-4.6,0-6.9c0-0.1,0-0.2,0-0.3c-0.2,0-0.5,0-0.7,0c-11.4,0-22.8,0-34.3,0c-0.2,0-0.3,0-0.4,0c-0.1,0-0.2,0-0.3,0.1
|
||||
c0,0.2,0,0.4,0,0.5c0,0.8,0,1.6,0,2.4c0,1.3,0,2.6,0,3.9c0,0.2,0,0.4,0.1,0.5c0.2,0.1,0.4,0.1,0.6,0.1c4,0,8.1,0,12.1,0
|
||||
c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3,0.1c0,0.2,0,0.5,0,0.7c0,6.6,0,13.1,0,19.7c0,0.2,0,0.4,0,0.5c0,0.1,0,0.2,0,0.3
|
||||
c0.1,0,0.1,0,0.1,0c2.7-0.5,5.4-1.1,8.1-1.6c0.1,0,0.2-0.1,0.3-0.1c0-0.2,0-0.4,0-0.6c0-6,0-12,0-18.1c0-0.2,0-0.4,0-0.5
|
||||
C62.2,8.6,62.3,8.5,62.3,8.4L62.3,8.4z M53.7,30.2c0,0.3-0.1,0.6,0,0.8c0.4,0.1,6.6,0.1,8.2,0c0.1,0,0.2,0,0.3,0
|
||||
c0-0.1,0.1-0.1,0.1-0.2c0-0.6,0-1.3,0-1.9c0,0,0-0.1-0.1-0.2C59.4,29.2,56.5,29.7,53.7,30.2L53.7,30.2z"/>
|
||||
<path class="st3" d="M151.5,11.4c0.1,0,0.2,0,0.2,0c0.1,0.1,0.1,0.2,0.1,0.3c0.1,0.6,0.2,1.3,0.3,1.9c0.2,1.3,0.2,2.6,0.1,3.8
|
||||
c-0.1,2-0.6,4-1.5,5.9c-1,2.2-2.6,3.9-4.5,5.3c-1.2,0.8-2.5,1.5-3.9,2c-1.1,0.4-2.3,0.7-3.4,0.9c-0.5,0.1-1.1,0.2-1.6,0.3
|
||||
c-0.5,0.1-0.9,0.1-1.4,0.1c-0.1,0-0.1,0-0.2,0c-0.7,0.1-1.5,0.1-2.2,0.1c-0.7,0-1.5,0-2.2,0c-0.3,0-0.5,0-0.8-0.1
|
||||
c-0.1,0-0.3,0-0.4,0c-2.2-0.2-4.3-0.6-6.4-1.3c-1.4-0.5-2.7-1.2-4-2c-2.7-1.9-4.5-4.5-5.4-7.7c-0.1-0.5-0.3-1.1-0.3-1.6
|
||||
c0-0.1,0-0.1,0-0.2c0.1-0.1,0.2-0.1,0.4-0.2c0.5-0.1,1.1-0.2,1.6-0.3c0.9-0.2,1.8-0.4,2.7-0.5c0.9-0.2,1.8-0.4,2.7-0.6
|
||||
c0.3-0.1,0.5-0.1,0.8-0.2c0.2,0,0.3-0.1,0.5-0.1c0.1,0,0.1,0.1,0.2,0.2c0,0.4,0.1,0.8,0.2,1.2c0.2,0.9,0.6,1.8,1.2,2.6
|
||||
c0.6,0.8,1.3,1.4,2.2,1.9c0.7,0.4,1.5,0.7,2.4,0.9c0.6,0.1,1.2,0.3,1.8,0.3c0.8,0.1,1.7,0.2,2.5,0.2c0.4,0,0.7,0,1.1,0
|
||||
c0.1,0,0.3,0,0.4,0c1.3-0.1,2.5-0.3,3.7-0.7c0.5-0.2,1-0.4,1.5-0.7c1.6-0.9,2.7-2.3,3.2-4.1c0.2-0.6,0.3-1.2,0.3-1.8
|
||||
c0-0.5,0.1-1,0.1-1.4c0-0.7-0.1-1.4-0.2-2.1c0-0.1,0-0.2,0-0.3c0,0,0-0.1,0-0.1c0,0,0.1,0,0.1-0.1c0.1,0,0.3-0.1,0.4-0.1
|
||||
c1.5-0.3,2.9-0.6,4.4-0.9c0.7-0.1,1.5-0.3,2.2-0.4c0.2,0,0.4-0.1,0.6-0.1c0.1,0,0.1-0.1,0.2-0.1c0,0,0,0,0-0.1
|
||||
C151.2,11.3,151.3,11.3,151.5,11.4C151.5,11.4,151.5,11.4,151.5,11.4L151.5,11.4z"/>
|
||||
<path class="st3" d="M151.1,11.5c-0.4,0-0.7,0.1-1.1,0.1c-0.7,0.1-1.4,0.2-2.1,0.4c-0.7,0.1-1.3,0.2-2,0.4c-0.7,0.1-1.3,0.2-2,0.3
|
||||
c-0.1,0-0.3,0.1-0.4,0.1c-0.1,0-0.3,0-0.4,0c-0.1-0.2-0.2-0.3-0.2-0.5c-0.5-1.4-1.4-2.4-2.6-3.2c-0.5-0.3-1-0.6-1.5-0.8
|
||||
c-0.7-0.3-1.5-0.5-2.3-0.6c-1.3-0.2-2.6-0.3-3.8-0.3c-0.7,0-1.4,0.1-2.1,0.2c-0.8,0.1-1.6,0.3-2.4,0.5c-0.5,0.2-1,0.4-1.4,0.6
|
||||
c-1.8,1-3,2.5-3.5,4.5c-0.2,0.7-0.3,1.5-0.3,2.2c0,0.2,0,0.4,0,0.7c0,0.1,0,0.2-0.1,0.2c-0.1,0.1-0.3,0.1-0.4,0.1
|
||||
c-0.6,0.1-1.3,0.2-1.9,0.3c-0.6,0.1-1.3,0.2-1.9,0.3c-0.7,0.1-1.4,0.2-2.1,0.4c-0.7,0.1-1.3,0.2-2,0.4c-0.1,0-0.3,0.1-0.4,0
|
||||
c-0.1,0-0.1-0.1-0.1-0.2c0-0.1,0-0.3,0-0.4c0-0.9-0.1-1.8,0-2.7c0.1-2.3,0.7-4.5,1.8-6.6c1.1-2,2.6-3.6,4.4-4.8
|
||||
c1.3-0.9,2.7-1.5,4.2-2c1.1-0.4,2.3-0.6,3.4-0.8c0.6-0.1,1.3-0.2,1.9-0.3c0.6-0.1,1.3-0.1,1.9-0.1c1.2,0,2.4,0,3.6,0
|
||||
c0.2,0,0.4,0,0.5,0c0.1,0,0.2,0,0.3,0c0.8,0,1.6,0.2,2.5,0.3c1.3,0.2,2.5,0.5,3.7,0.9c1.4,0.5,2.8,1.1,4.1,2
|
||||
c1.9,1.3,3.4,2.9,4.5,5c0.4,0.8,0.8,1.7,1,2.6c0,0.1,0,0.2,0.1,0.2c0,0,0,0.1,0,0.1c-0.1,0-0.1,0.1-0.2,0.1l0,0
|
||||
C151.4,11.5,151.2,11.4,151.1,11.5L151.1,11.5L151.1,11.5z"/>
|
||||
<path class="st3" d="M151,11.5c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.2,0,0.3,0C151.4,11.5,151.2,11.5,151,11.5L151,11.5z"/>
|
||||
<path class="st3" d="M84.5,23.5C84.5,23.4,84.6,23.4,84.5,23.5c2.7-5.4,5.3-10.8,8-16.1c0,0,0-0.1,0.1-0.1c0,0,0-0.1,0.1-0.1
|
||||
c0,0,0,0,0,0c0,0,0,0,0.1,0c0.1,0.1,0.2,0.3,0.2,0.4c0.9,1.8,1.7,3.5,2.6,5.3c1.2,2.4,2.4,4.8,3.6,7.2c0.1,0.2,0.1,0.3,0.3,0.5
|
||||
c0.6-0.1,1.2-0.2,1.8-0.3c1.1-0.2,2.1-0.4,3.2-0.5c1-0.2,2-0.3,3-0.5c0.1,0,0.2-0.1,0.3-0.1c-0.1-0.2-0.2-0.3-0.2-0.5
|
||||
c-1.4-2.8-2.8-5.6-4.2-8.4c-1.5-2.9-2.9-5.8-4.4-8.7c-0.1-0.2-0.1-0.4-0.3-0.5c-0.1,0-0.1,0-0.2,0c-3.8,0-7.6,0-11.4,0
|
||||
c-0.1,0-0.1,0-0.2,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0C82.6,9,78.5,17.2,74.4,25.3c0,0,0,0.1,0,0.1c0,0,0.1,0.1,0.1,0
|
||||
C77.8,24.8,81.2,24.1,84.5,23.5z M100,21.8c0.3,0.7,4.4,9,4.6,9.3c0.1,0,0.2,0,0.3,0c2.9,0,5.8,0,8.7,0c0,0,0,0,0.1,0
|
||||
c0,0,0,0,0.1-0.1c0-0.1-0.1-0.2-0.1-0.2c-0.1-0.2-0.3-0.5-0.4-0.8c-1.6-3.1-3.2-6.3-4.7-9.4c-0.1-0.2-0.1-0.3-0.3-0.5
|
||||
C105.5,20.7,102.8,21.2,100,21.8L100,21.8z M73.7,26.8c-0.7,1.4-1.4,2.7-2,4.1c0,0.1,0,0.2-0.1,0.3h9.1c0.2-0.3,2.6-5,2.9-5.8
|
||||
c0-0.1,0-0.1,0.1-0.2c-0.1,0-0.2,0-0.3,0C80.2,25.6,76.9,26.2,73.7,26.8L73.7,26.8z M93.8,29C93.8,29,93.8,29,93.8,29
|
||||
c0.1-0.5,0.1-1,0-1.5c0-0.5-0.1-1.1,0-1.6c0-0.3,0.1-0.7,0.2-1c0.3-1.2,1.1-2,2.1-2.4c0.5-0.2,1.1-0.4,1.6-0.6
|
||||
c0.4-0.2,0.9-0.3,1.3-0.5c-0.1-0.1-0.2-0.1-0.3-0.1c-1,0-1.9,0-2.9,0c-0.9,0-1.7-0.4-2.4-1c-0.4-0.4-0.8-0.9-1-1.5
|
||||
c-0.3-0.8-0.6-1.6-0.8-2.4c0-0.1,0-0.1-0.2-0.1c0,0.2,0,0.3,0,0.5c0,0.8,0,1.7,0,2.5c0,0.8-0.2,1.5-0.7,2.1
|
||||
c-0.5,0.7-1.1,1.1-1.8,1.3c-0.8,0.3-1.6,0.6-2.4,0.9c-0.1,0-0.1,0.1-0.2,0.1c0.1,0.1,0.3,0.1,0.4,0.1c0.9,0,1.8,0,2.8,0
|
||||
c0.2,0,0.4,0,0.6,0.1c1.3,0.3,2.1,1.1,2.6,2.3c0.1,0.2,0.2,0.5,0.3,0.7C93.3,27.6,93.5,28.3,93.8,29L93.8,29z"/>
|
||||
<path class="st4" d="M93.8,29C93.8,29,93.8,29,93.8,29c0.1-0.5,0.1-1,0-1.5c0-0.5-0.1-1.1,0-1.6c0-0.3,0.1-0.7,0.2-1
|
||||
c0.3-1.2,1.1-2,2.1-2.4c0.5-0.2,1.1-0.4,1.6-0.6c0.4-0.2,0.8-0.3,1.3-0.5c-0.1-0.1-0.2-0.1-0.3-0.1c-1,0-1.9,0-2.9,0
|
||||
c-0.9,0-1.7-0.4-2.4-1c-0.4-0.4-0.8-0.9-1-1.5c-0.3-0.8-0.6-1.6-0.8-2.4c0-0.1,0-0.1-0.2-0.1c0,0.2,0,0.3,0,0.5c0,0.8,0,1.7,0,2.5
|
||||
c0,0.8-0.2,1.5-0.7,2.1c-0.5,0.7-1.1,1.1-1.8,1.3c-0.8,0.3-1.6,0.6-2.4,0.9c-0.1,0-0.1,0.1-0.2,0.1c0.1,0.1,0.3,0.1,0.4,0.1
|
||||
c0.9,0,1.8,0,2.8,0c0.2,0,0.4,0,0.6,0.1c1.3,0.3,2.1,1.1,2.6,2.3c0.1,0.2,0.2,0.5,0.3,0.7C93.3,27.6,93.5,28.3,93.8,29L93.8,29z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Logotype" class="st0">
|
||||
<g class="st1">
|
||||
<g>
|
||||
<polygon class="st3" points="100.4,22.3 104.7,30.8 113.9,30.8 108.6,20.6 "/>
|
||||
<g>
|
||||
<path class="st3" d="M122.9,16.1c0,0,0-0.1,0-0.1c0-5.2,2.9-8.3,10.2-8.3c5.7,0,8.8,1.9,9.8,5.2l8.9-1.4
|
||||
c-1.9-7-8.3-11.1-18.7-11.1c-12.5,0-19.3,5.8-19.3,15.6c0,0.5,0,1.1,0.1,1.6L122.9,16.1L122.9,16.1z"/>
|
||||
<path class="st3" d="M143.1,13.3c0.2,0.8,0.3,1.7,0.3,2.6c0,5.2-3,8.4-10.3,8.4c-6.5,0-9.6-2.5-10.1-6.8l-8.8,1.8
|
||||
c1.4,7.8,8,12.2,18.9,12.2c12.4,0,19.3-5.9,19.3-15.7c0-1.6-0.2-3.1-0.5-4.5L143.1,13.3L143.1,13.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st3" points="73.5,27 71.5,30.8 80.8,30.8 83.5,25.4 "/>
|
||||
<polygon class="st3" points="98.6,1.2 86.8,1.2 74.6,24.7 84.9,22.6 92.7,7.2 99.2,19.9 107.6,18.6 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon class="st3" points="53.6,30.2 53.6,30.8 62.2,30.8 62.2,28.8 "/>
|
||||
<polygon class="st3" points="53.6,29.1 62.2,27.3 62.2,8.5 75.7,8.5 75.7,1.2 40.1,1.2 40.1,8.5 53.6,8.5 "/>
|
||||
</g>
|
||||
<path class="st3" d="M19.3,0.4c10.9,0,17.1,4.7,18,12.3h-9.1c-0.6-2.7-3.4-5-8.8-5c-6.3,0-9.4,3.1-9.4,8.3
|
||||
c0,5.2,3.1,8.4,9.4,8.4c5.5,0,8.3-2.3,8.8-5.1h9.1c-0.9,7.7-7.1,12.4-18,12.4C7.4,31.6,0.9,26.1,0.9,16S7.4,0.4,19.3,0.4
|
||||
L19.3,0.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st5" d="M94.7,23.8c1-1.4,3.3-2.1,5.2-2.7c-2,0.1-4.4,0.3-5.8-0.6c-1.4-1-2.1-3.3-2.7-5.2c0.1,2,0.3,4.4-0.6,5.8
|
||||
c-1,1.4-3.3,2.1-5.2,2.7c2-0.1,4.4-0.3,5.8,0.6c1.4,1,2.1,3.3,2.7,5.2C93.9,27.6,93.7,25.2,94.7,23.8z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Logotype_00000134236662009793237430000016451412871672361145_">
|
||||
<g>
|
||||
<g>
|
||||
<polygon class="st3" points="100,22.3 104.3,30.7 113.5,30.7 108.2,20.5 "/>
|
||||
<g>
|
||||
<path class="st3" d="M122.4,16.1c0,0,0-0.1,0-0.1c0-5.2,2.9-8.2,10.2-8.2c5.7,0,8.7,1.9,9.8,5.2l8.8-1.4c-1.8-7-8.2-11-18.6-11
|
||||
c-12.4,0-19.1,5.7-19.1,15.5c0,0.5,0,1.1,0.1,1.6L122.4,16.1L122.4,16.1z"/>
|
||||
<path class="st3" d="M142.5,13.4c0.2,0.8,0.3,1.7,0.3,2.6c0,5.1-3,8.3-10.2,8.3c-6.4,0-9.5-2.5-10.1-6.7l-8.7,1.8
|
||||
c1.4,7.7,7.9,12.2,18.8,12.2c12.4,0,19.1-5.8,19.1-15.6c0-1.6-0.2-3.1-0.5-4.4L142.5,13.4L142.5,13.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st3" points="73.4,26.9 71.4,30.7 80.6,30.7 83.3,25.3 "/>
|
||||
<polygon class="st3" points="98.4,1.3 86.6,1.3 74.5,24.7 84.7,22.5 92.5,7.3 98.9,19.9 107.2,18.6 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon class="st3" points="53.7,30.1 53.7,30.7 62.2,30.7 62.2,28.7 "/>
|
||||
<polygon class="st3" points="53.7,29 62.2,27.3 62.2,8.5 75.6,8.5 75.6,1.3 40.2,1.3 40.2,8.5 53.7,8.5 "/>
|
||||
</g>
|
||||
<path class="st3" d="M19.6,0.5c10.8,0,17,4.7,17.8,12.2h-9.1c-0.6-2.7-3.3-5-8.8-5c-6.3,0-9.4,3.1-9.4,8.2s3.1,8.3,9.4,8.3
|
||||
c5.4,0,8.2-2.3,8.8-5.1h9.1c-0.9,7.6-7,12.3-17.8,12.3C7.8,31.5,1.3,26.1,1.3,16S7.8,0.5,19.6,0.5L19.6,0.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st3" d="M94.4,23.7c1-1.4,3.3-2.1,5.1-2.7c-2,0.1-4.4,0.3-5.8-0.6c-1.4-1-2.1-3.3-2.7-5.1c0.1,2,0.3,4.4-0.6,5.8
|
||||
c-1,1.4-3.3,2.1-5.1,2.7c2-0.1,4.4-0.3,5.8,0.6c1.4,1,2.1,3.3,2.7,5.1C93.6,27.5,93.4,25.1,94.4,23.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -1,11 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="Ebene_1" x="0" y="0" viewBox="0 0 153 46.0">
|
||||
<style>
|
||||
.st3{fill:#ffffff}
|
||||
.st5{fill:#00E4D8}
|
||||
</style>
|
||||
<g id="Logotype_00000134236662009793237430000016451412871672361145_">
|
||||
<path d="m100 22.3 4.3 8.4h9.2l-5.3-10.2zm22.4-6.2V16c0-5.2 2.9-8.2 10.2-8.2 5.7 0 8.7 1.9 9.8 5.2l8.8-1.4c-1.8-7-8.2-11-18.6-11-12.4 0-19.1 5.7-19.1 15.5 0 .5 0 1.1.1 1.6zm20.1-2.7c.2.8.3 1.7.3 2.6 0 5.1-3 8.3-10.2 8.3-6.4 0-9.5-2.5-10.1-6.7l-8.7 1.8c1.4 7.7 7.9 12.2 18.8 12.2 12.4 0 19.1-5.8 19.1-15.6 0-1.6-.2-3.1-.5-4.4zM73.4 26.9l-2 3.8h9.2l2.7-5.4zm25-25.6H86.6L74.5 24.7l10.2-2.2 7.8-15.2 6.4 12.6 8.3-1.3zM53.7 30.1v.6h8.5v-2zm0-1.1 8.5-1.7V8.5h13.4V1.3H40.2v7.2h13.5zM19.6.5c10.8 0 17 4.7 17.8 12.2h-9.1c-.6-2.7-3.3-5-8.8-5-6.3 0-9.4 3.1-9.4 8.2s3.1 8.3 9.4 8.3c5.4 0 8.2-2.3 8.8-5.1h9.1c-.9 7.6-7 12.3-17.8 12.3C7.8 31.5 1.3 26.1 1.3 16S7.8.5 19.6.5" class="st3"/>
|
||||
<path d="M94.4 23.7c1-1.4 3.3-2.1 5.1-2.7-2 .1-4.4.3-5.8-.6-1.4-1-2.1-3.3-2.7-5.1.1 2 .3 4.4-.6 5.8-1 1.4-3.3 2.1-5.1 2.7 2-.1 4.4-.3 5.8.6 1.4 1 2.1 3.3 2.7 5.1-.2-2-.4-4.4.6-5.8" class="st5"/>
|
||||
</g>
|
||||
<path d="M6.48 45.77Q5.41 45.77 4.62 45.44Q3.83 45.1 3.38 44.47Q2.94 43.83 2.9 42.92H4.53Q4.57 43.4 4.83 43.72Q5.09 44.04 5.52 44.2Q5.95 44.36 6.47 44.36Q7.01 44.36 7.43 44.19Q7.85 44.03 8.08 43.72Q8.32 43.42 8.32 43.03Q8.32 42.67 8.11 42.43Q7.9 42.2 7.53 42.03Q7.15 41.87 6.65 41.75L5.6 41.47Q4.45 41.18 3.8 40.57Q3.15 39.97 3.15 38.99Q3.15 38.18 3.59 37.57Q4.03 36.95 4.8 36.61Q5.56 36.28 6.52 36.28Q7.51 36.28 8.25 36.62Q8.99 36.96 9.41 37.56Q9.83 38.16 9.85 38.93H8.25Q8.18 38.33 7.71 38.01Q7.25 37.68 6.5 37.68Q5.98 37.68 5.6 37.84Q5.23 38 5.03 38.27Q4.83 38.55 4.83 38.9Q4.83 39.28 5.06 39.53Q5.3 39.78 5.66 39.93Q6.03 40.08 6.4 40.17L7.26 40.39Q7.77 40.51 8.26 40.72Q8.74 40.92 9.13 41.24Q9.52 41.55 9.75 41.99Q9.97 42.44 9.97 43.04Q9.97 43.85 9.56 44.47Q9.15 45.08 8.37 45.43Q7.58 45.77 6.48 45.77ZM18.24 45.75Q17.03 45.75 16.08 45.19Q15.12 44.63 14.57 43.57Q14.02 42.51 14.02 41.02Q14.02 39.53 14.58 38.47Q15.13 37.4 16.08 36.84Q17.04 36.28 18.24 36.28Q19 36.28 19.66 36.49Q20.32 36.71 20.84 37.12Q21.35 37.53 21.69 38.12Q22.02 38.72 22.13 39.47H20.47Q20.39 39.06 20.19 38.74Q20 38.43 19.71 38.21Q19.41 37.98 19.05 37.87Q18.68 37.76 18.27 37.76Q17.51 37.76 16.93 38.14Q16.34 38.52 16.01 39.25Q15.68 39.97 15.68 41.02Q15.68 42.08 16.02 42.8Q16.35 43.53 16.93 43.9Q17.52 44.27 18.27 44.27Q18.68 44.27 19.04 44.16Q19.41 44.04 19.7 43.82Q20 43.6 20.19 43.28Q20.39 42.97 20.47 42.56H22.14Q22.05 43.22 21.73 43.8Q21.42 44.38 20.91 44.82Q20.41 45.26 19.74 45.51Q19.06 45.75 18.24 45.75ZM28.13 36.4V45.63H26.48V36.4ZM32.81 45.63V36.4H38.81V37.79H34.46V40.28H38.49V41.66H34.46V44.24H38.83V45.63ZM43.31 45.63V36.4H45.18L48.38 41.48Q48.57 41.8 48.8 42.2Q49.02 42.6 49.26 43.09Q49.5 43.58 49.74 44.19H49.55Q49.51 43.66 49.48 43.12Q49.44 42.57 49.43 42.07Q49.41 41.58 49.41 41.24V36.4H51.09V45.63H49.21L46.33 41.05Q46.06 40.61 45.82 40.19Q45.57 39.76 45.3 39.22Q45.02 38.68 44.62 37.92H44.85Q44.89 38.59 44.92 39.2Q44.96 39.8 44.98 40.28Q45 40.75 45 41.05V45.63ZM59.7 45.75Q58.49 45.75 57.53 45.19Q56.58 44.63 56.03 43.57Q55.48 42.51 55.48 41.02Q55.48 39.53 56.03 38.47Q56.58 37.4 57.54 36.84Q58.5 36.28 59.7 36.28Q60.46 36.28 61.12 36.49Q61.78 36.71 62.29 37.12Q62.81 37.53 63.14 38.12Q63.48 38.72 63.59 39.47H61.92Q61.84 39.06 61.65 38.74Q61.45 38.43 61.16 38.21Q60.87 37.98 60.51 37.87Q60.14 37.76 59.73 37.76Q58.97 37.76 58.38 38.14Q57.8 38.52 57.47 39.25Q57.14 39.97 57.14 41.02Q57.14 42.08 57.47 42.8Q57.81 43.53 58.39 43.9Q58.97 44.27 59.72 44.27Q60.14 44.27 60.5 44.16Q60.86 44.04 61.16 43.82Q61.45 43.6 61.65 43.28Q61.85 42.97 61.93 42.56H63.59Q63.5 43.22 63.19 43.8Q62.88 44.38 62.37 44.82Q61.86 45.26 61.19 45.51Q60.52 45.75 59.7 45.75ZM67.93 45.63V36.4H73.93V37.79H69.59V40.28H73.61V41.66H69.59V44.24H73.95V45.63ZM84.45 45.63V36.4H87.91Q88.97 36.4 89.69 36.8Q90.41 37.2 90.78 37.89Q91.15 38.57 91.15 39.46Q91.15 40.34 90.78 41.03Q90.41 41.72 89.68 42.11Q88.95 42.51 87.88 42.51H85.59V41.15H87.66Q88.29 41.15 88.69 40.93Q89.09 40.71 89.28 40.33Q89.46 39.95 89.46 39.46Q89.46 38.96 89.28 38.59Q89.09 38.21 88.69 38Q88.28 37.78 87.65 37.78H86.11V45.63ZM99.41 45.75Q98.2 45.75 97.24 45.19Q96.28 44.63 95.72 43.57Q95.17 42.51 95.17 41.02Q95.17 39.53 95.72 38.47Q96.28 37.4 97.24 36.84Q98.2 36.28 99.41 36.28Q100.62 36.28 101.57 36.84Q102.53 37.4 103.08 38.47Q103.64 39.53 103.64 41.02Q103.64 42.51 103.08 43.57Q102.53 44.63 101.57 45.19Q100.62 45.75 99.41 45.75ZM99.41 44.27Q100.16 44.27 100.74 43.9Q101.32 43.52 101.65 42.8Q101.98 42.07 101.98 41.02Q101.98 39.96 101.65 39.23Q101.32 38.51 100.74 38.13Q100.16 37.76 99.41 37.76Q98.65 37.76 98.07 38.13Q97.49 38.51 97.16 39.24Q96.83 39.97 96.83 41.02Q96.83 42.07 97.16 42.8Q97.49 43.52 98.07 43.9Q98.65 44.27 99.41 44.27ZM108.03 45.63V36.4H111.48Q112.54 36.4 113.26 36.77Q113.99 37.14 114.36 37.81Q114.73 38.47 114.73 39.35Q114.73 40.24 114.35 40.89Q113.98 41.54 113.25 41.89Q112.52 42.24 111.45 42.24H108.99V40.87H111.23Q111.86 40.87 112.26 40.69Q112.66 40.52 112.85 40.18Q113.04 39.84 113.04 39.35Q113.04 38.86 112.85 38.51Q112.66 38.16 112.26 37.97Q111.86 37.78 111.23 37.78H109.68V45.63ZM113.22 45.63 110.98 41.44H112.79L115.07 45.63ZM118.71 37.79V36.4H126.06V37.79H123.21V45.63H121.56V37.79ZM129.7 45.63 132.92 36.4H135.02L138.31 45.63H136.5L134.86 40.84Q134.62 40.09 134.36 39.15Q134.1 38.22 133.78 37.02H134.13Q133.82 38.23 133.57 39.17Q133.32 40.12 133.09 40.84L131.51 45.63ZM131.58 43.34V42.01H136.44V43.34ZM142.37 45.63V36.4H144.02V44.24H148.1V45.63Z" class="st3"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.4 KiB |
@@ -1,10 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="Ebene_1" x="0" y="0" viewBox="0 0 153 46.0">
|
||||
<style>
|
||||
.st3{fill:#00004a}
|
||||
</style>
|
||||
<g id="Logotype_00000134236662009793237430000016451412871672361145_">
|
||||
<path d="m100 22.3 4.3 8.4h9.2l-5.3-10.2zm22.4-6.2V16c0-5.2 2.9-8.2 10.2-8.2 5.7 0 8.7 1.9 9.8 5.2l8.8-1.4c-1.8-7-8.2-11-18.6-11-12.4 0-19.1 5.7-19.1 15.5 0 .5 0 1.1.1 1.6zm20.1-2.7c.2.8.3 1.7.3 2.6 0 5.1-3 8.3-10.2 8.3-6.4 0-9.5-2.5-10.1-6.7l-8.7 1.8c1.4 7.7 7.9 12.2 18.8 12.2 12.4 0 19.1-5.8 19.1-15.6 0-1.6-.2-3.1-.5-4.4zM73.4 26.9l-2 3.8h9.2l2.7-5.4zm25-25.6H86.6L74.5 24.7l10.2-2.2 7.8-15.2 6.4 12.6 8.3-1.3zM53.7 30.1v.6h8.5v-2zm0-1.1 8.5-1.7V8.5h13.4V1.3H40.2v7.2h13.5zM19.6.5c10.8 0 17 4.7 17.8 12.2h-9.1c-.6-2.7-3.3-5-8.8-5-6.3 0-9.4 3.1-9.4 8.2s3.1 8.3 9.4 8.3c5.4 0 8.2-2.3 8.8-5.1h9.1c-.9 7.6-7 12.3-17.8 12.3C7.8 31.5 1.3 26.1 1.3 16S7.8.5 19.6.5" class="st3"/>
|
||||
<path d="M94.4 23.7c1-1.4 3.3-2.1 5.1-2.7-2 .1-4.4.3-5.8-.6-1.4-1-2.1-3.3-2.7-5.1.1 2 .3 4.4-.6 5.8-1 1.4-3.3 2.1-5.1 2.7 2-.1 4.4-.3 5.8.6 1.4 1 2.1 3.3 2.7 5.1-.2-2-.4-4.4.6-5.8" class="st3"/>
|
||||
</g>
|
||||
<path d="M6.48 45.77Q5.41 45.77 4.62 45.44Q3.83 45.1 3.38 44.47Q2.94 43.83 2.9 42.92H4.53Q4.57 43.4 4.83 43.72Q5.09 44.04 5.52 44.2Q5.95 44.36 6.47 44.36Q7.01 44.36 7.43 44.19Q7.85 44.03 8.08 43.72Q8.32 43.42 8.32 43.03Q8.32 42.67 8.11 42.43Q7.9 42.2 7.53 42.03Q7.15 41.87 6.65 41.75L5.6 41.47Q4.45 41.18 3.8 40.57Q3.15 39.97 3.15 38.99Q3.15 38.18 3.59 37.57Q4.03 36.95 4.8 36.61Q5.56 36.28 6.52 36.28Q7.51 36.28 8.25 36.62Q8.99 36.96 9.41 37.56Q9.83 38.16 9.85 38.93H8.25Q8.18 38.33 7.71 38.01Q7.25 37.68 6.5 37.68Q5.98 37.68 5.6 37.84Q5.23 38 5.03 38.27Q4.83 38.55 4.83 38.9Q4.83 39.28 5.06 39.53Q5.3 39.78 5.66 39.93Q6.03 40.08 6.4 40.17L7.26 40.39Q7.77 40.51 8.26 40.72Q8.74 40.92 9.13 41.24Q9.52 41.55 9.75 41.99Q9.97 42.44 9.97 43.04Q9.97 43.85 9.56 44.47Q9.15 45.08 8.37 45.43Q7.58 45.77 6.48 45.77ZM18.24 45.75Q17.03 45.75 16.08 45.19Q15.12 44.63 14.57 43.57Q14.02 42.51 14.02 41.02Q14.02 39.53 14.58 38.47Q15.13 37.4 16.08 36.84Q17.04 36.28 18.24 36.28Q19 36.28 19.66 36.49Q20.32 36.71 20.84 37.12Q21.35 37.53 21.69 38.12Q22.02 38.72 22.13 39.47H20.47Q20.39 39.06 20.19 38.74Q20 38.43 19.71 38.21Q19.41 37.98 19.05 37.87Q18.68 37.76 18.27 37.76Q17.51 37.76 16.93 38.14Q16.34 38.52 16.01 39.25Q15.68 39.97 15.68 41.02Q15.68 42.08 16.02 42.8Q16.35 43.53 16.93 43.9Q17.52 44.27 18.27 44.27Q18.68 44.27 19.04 44.16Q19.41 44.04 19.7 43.82Q20 43.6 20.19 43.28Q20.39 42.97 20.47 42.56H22.14Q22.05 43.22 21.73 43.8Q21.42 44.38 20.91 44.82Q20.41 45.26 19.74 45.51Q19.06 45.75 18.24 45.75ZM28.13 36.4V45.63H26.48V36.4ZM32.81 45.63V36.4H38.81V37.79H34.46V40.28H38.49V41.66H34.46V44.24H38.83V45.63ZM43.31 45.63V36.4H45.18L48.38 41.48Q48.57 41.8 48.8 42.2Q49.02 42.6 49.26 43.09Q49.5 43.58 49.74 44.19H49.55Q49.51 43.66 49.48 43.12Q49.44 42.57 49.43 42.07Q49.41 41.58 49.41 41.24V36.4H51.09V45.63H49.21L46.33 41.05Q46.06 40.61 45.82 40.19Q45.57 39.76 45.3 39.22Q45.02 38.68 44.62 37.92H44.85Q44.89 38.59 44.92 39.2Q44.96 39.8 44.98 40.28Q45 40.75 45 41.05V45.63ZM59.7 45.75Q58.49 45.75 57.53 45.19Q56.58 44.63 56.03 43.57Q55.48 42.51 55.48 41.02Q55.48 39.53 56.03 38.47Q56.58 37.4 57.54 36.84Q58.5 36.28 59.7 36.28Q60.46 36.28 61.12 36.49Q61.78 36.71 62.29 37.12Q62.81 37.53 63.14 38.12Q63.48 38.72 63.59 39.47H61.92Q61.84 39.06 61.65 38.74Q61.45 38.43 61.16 38.21Q60.87 37.98 60.51 37.87Q60.14 37.76 59.73 37.76Q58.97 37.76 58.38 38.14Q57.8 38.52 57.47 39.25Q57.14 39.97 57.14 41.02Q57.14 42.08 57.47 42.8Q57.81 43.53 58.39 43.9Q58.97 44.27 59.72 44.27Q60.14 44.27 60.5 44.16Q60.86 44.04 61.16 43.82Q61.45 43.6 61.65 43.28Q61.85 42.97 61.93 42.56H63.59Q63.5 43.22 63.19 43.8Q62.88 44.38 62.37 44.82Q61.86 45.26 61.19 45.51Q60.52 45.75 59.7 45.75ZM67.93 45.63V36.4H73.93V37.79H69.59V40.28H73.61V41.66H69.59V44.24H73.95V45.63ZM84.45 45.63V36.4H87.91Q88.97 36.4 89.69 36.8Q90.41 37.2 90.78 37.89Q91.15 38.57 91.15 39.46Q91.15 40.34 90.78 41.03Q90.41 41.72 89.68 42.11Q88.95 42.51 87.88 42.51H85.59V41.15H87.66Q88.29 41.15 88.69 40.93Q89.09 40.71 89.28 40.33Q89.46 39.95 89.46 39.46Q89.46 38.96 89.28 38.59Q89.09 38.21 88.69 38Q88.28 37.78 87.65 37.78H86.11V45.63ZM99.41 45.75Q98.2 45.75 97.24 45.19Q96.28 44.63 95.72 43.57Q95.17 42.51 95.17 41.02Q95.17 39.53 95.72 38.47Q96.28 37.4 97.24 36.84Q98.2 36.28 99.41 36.28Q100.62 36.28 101.57 36.84Q102.53 37.4 103.08 38.47Q103.64 39.53 103.64 41.02Q103.64 42.51 103.08 43.57Q102.53 44.63 101.57 45.19Q100.62 45.75 99.41 45.75ZM99.41 44.27Q100.16 44.27 100.74 43.9Q101.32 43.52 101.65 42.8Q101.98 42.07 101.98 41.02Q101.98 39.96 101.65 39.23Q101.32 38.51 100.74 38.13Q100.16 37.76 99.41 37.76Q98.65 37.76 98.07 38.13Q97.49 38.51 97.16 39.24Q96.83 39.97 96.83 41.02Q96.83 42.07 97.16 42.8Q97.49 43.52 98.07 43.9Q98.65 44.27 99.41 44.27ZM108.03 45.63V36.4H111.48Q112.54 36.4 113.26 36.77Q113.99 37.14 114.36 37.81Q114.73 38.47 114.73 39.35Q114.73 40.24 114.35 40.89Q113.98 41.54 113.25 41.89Q112.52 42.24 111.45 42.24H108.99V40.87H111.23Q111.86 40.87 112.26 40.69Q112.66 40.52 112.85 40.18Q113.04 39.84 113.04 39.35Q113.04 38.86 112.85 38.51Q112.66 38.16 112.26 37.97Q111.86 37.78 111.23 37.78H109.68V45.63ZM113.22 45.63 110.98 41.44H112.79L115.07 45.63ZM118.71 37.79V36.4H126.06V37.79H123.21V45.63H121.56V37.79ZM129.7 45.63 132.92 36.4H135.02L138.31 45.63H136.5L134.86 40.84Q134.62 40.09 134.36 39.15Q134.1 38.22 133.78 37.02H134.13Q133.82 38.23 133.57 39.17Q133.32 40.12 133.09 40.84L131.51 45.63ZM131.58 43.34V42.01H136.44V43.34ZM142.37 45.63V36.4H144.02V44.24H148.1V45.63Z" class="st3"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,110 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 640" role="img" aria-label="Architektura klasycznego CMS z bazą danych: aplikacja CMS z publicznym panelem admina działa non stop, obok baza danych i wolumen mediów; czytelnik dostaje strony renderowane na żądanie">
|
||||
<defs>
|
||||
<marker id="arrB" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M0 0 L10 5 L0 10 z" fill="#00004a"/>
|
||||
</marker>
|
||||
<filter id="softB" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="5" flood-color="#00004a" flood-opacity="0.10"/>
|
||||
</filter>
|
||||
<style>
|
||||
.t { font-family: Inter, "Segoe UI", Arial, sans-serif; }
|
||||
.box { fill: #ffffff; stroke: #00004a; stroke-width: 1.5; }
|
||||
.sub { fill: #f5f5f5; stroke: #e2e5ee; stroke-width: 1; }
|
||||
.ttl { font-weight: 700; font-size: 15.5px; fill: #00004a; letter-spacing: .04em; }
|
||||
.cap { font-size: 12.5px; fill: #46536a; }
|
||||
.lbl { font-size: 12px; fill: #46536a; paint-order: stroke; stroke: #ffffff; stroke-width: 4; }
|
||||
.chipbg { fill: #e9ebf3; }
|
||||
.chip { font-size: 11.5px; font-weight: 700; fill: #00004a; letter-spacing: .06em; }
|
||||
.flow { stroke: #00004a; stroke-width: 1.8; fill: none; marker-end: url(#arrB); }
|
||||
.pill { fill: #f5f5f5; stroke: #e2e5ee; }
|
||||
.pilltxt { font-size: 12.5px; fill: #101228; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<!-- machine boundary (mirrors the static-demo diagram 1:1) -->
|
||||
<rect x="340" y="40" width="830" height="570" rx="18" fill="#f8f9fc" stroke="#e2e5ee" stroke-width="1.5"/>
|
||||
<text class="t" x="366" y="76" font-size="13" font-weight="700" fill="#00004a" letter-spacing=".18em">MASZYNA · CMS Z BAZĄ DANYCH</text>
|
||||
<text class="t cap" x="366" y="96">np. WordPress, Strapi, Drupal — wspólny schemat tej klasy rozwiązań</text>
|
||||
|
||||
<!-- actor: redaktor -->
|
||||
<g filter="url(#softB)">
|
||||
<rect class="box" x="52" y="120" width="220" height="120" rx="16"/>
|
||||
</g>
|
||||
<circle cx="88" cy="156" r="11" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<path d="M72 186 q16 -18 32 0" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<text class="t ttl" x="116" y="162">Redaktor</text>
|
||||
<text class="t cap" x="70" y="212">panel admina w przeglądarce</text>
|
||||
<text class="t cap" x="70" y="228">logowanie do aplikacji</text>
|
||||
|
||||
<!-- actor: czytelnik -->
|
||||
<g filter="url(#softB)">
|
||||
<rect class="box" x="52" y="400" width="220" height="120" rx="16"/>
|
||||
</g>
|
||||
<circle cx="88" cy="436" r="11" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<path d="M72 466 q16 -18 32 0" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<text class="t ttl" x="116" y="442">Czytelnik</text>
|
||||
<text class="t cap" x="70" y="492">publiczna strona portalu</text>
|
||||
<text class="t cap" x="70" y="508">HTML składany na żądanie</text>
|
||||
|
||||
<!-- CMS application (tall box, always running) -->
|
||||
<g filter="url(#softB)">
|
||||
<rect class="box" x="400" y="120" width="320" height="400" rx="16"/>
|
||||
</g>
|
||||
<text class="t ttl" x="424" y="152">APLIKACJA CMS</text>
|
||||
<rect class="chipbg" x="590" y="136" width="106" height="22" rx="11"/>
|
||||
<text class="t chip" x="643" y="151" text-anchor="middle">NON STOP</text>
|
||||
<rect class="sub" x="420" y="176" width="280" height="88" rx="12"/>
|
||||
<text class="t" x="436" y="202" font-size="13.5" font-weight="700" fill="#101228">panel admina</text>
|
||||
<text class="t cap" x="436" y="224">publiczny adres + logowanie</text>
|
||||
<text class="t cap" x="436" y="242">z internetu</text>
|
||||
<rect class="sub" x="420" y="278" width="280" height="88" rx="12"/>
|
||||
<text class="t" x="436" y="304" font-size="13.5" font-weight="700" fill="#101228">renderowanie stron</text>
|
||||
<text class="t cap" x="436" y="326">każde wejście czytelnika =</text>
|
||||
<text class="t cap" x="436" y="344">praca aplikacji i bazy</text>
|
||||
<rect class="sub" x="420" y="380" width="280" height="88" rx="12"/>
|
||||
<text class="t" x="436" y="406" font-size="13.5" font-weight="700" fill="#101228">pluginy / rozszerzenia</text>
|
||||
<text class="t cap" x="436" y="428">własny cykl aktualizacji</text>
|
||||
<text class="t cap" x="436" y="446">i podatności</text>
|
||||
|
||||
<!-- database -->
|
||||
<g filter="url(#softB)">
|
||||
<rect class="box" x="790" y="120" width="340" height="185" rx="16"/>
|
||||
</g>
|
||||
<text class="t ttl" x="814" y="152">BAZA DANYCH</text>
|
||||
<rect class="chipbg" x="972" y="136" width="106" height="22" rx="11"/>
|
||||
<text class="t chip" x="1025" y="151" text-anchor="middle">NON STOP</text>
|
||||
<text class="t cap" x="814" y="188">treść + konta użytkowników</text>
|
||||
<text class="t cap" x="814" y="212">wymaga backupów i testów odtwarzania</text>
|
||||
<text class="t cap" x="814" y="236">migracje schematu przy aktualizacjach</text>
|
||||
<text class="t cap" x="814" y="266">historia zmian: zależnie od produktu,</text>
|
||||
<text class="t cap" x="814" y="284">bywa funkcją płatną</text>
|
||||
|
||||
<!-- media volume -->
|
||||
<g filter="url(#softB)">
|
||||
<rect class="sub" x="790" y="400" width="340" height="120" rx="16"/>
|
||||
</g>
|
||||
<text class="t ttl" x="814" y="432">media/</text>
|
||||
<rect class="chipbg" x="896" y="416" width="82" height="22" rx="11"/>
|
||||
<text class="t chip" x="937" y="431" text-anchor="middle">WOLUMEN</text>
|
||||
<text class="t cap" x="814" y="462">obrazy i pliki poza bazą</text>
|
||||
<text class="t cap" x="814" y="480">osobny backup</text>
|
||||
|
||||
<!-- flows -->
|
||||
<path class="flow" d="M272 180 H396"/>
|
||||
<text class="t lbl" x="334" y="170" text-anchor="middle">logowanie do panelu</text>
|
||||
|
||||
<path class="flow" d="M400 460 H276"/>
|
||||
<text class="t lbl" x="338" y="450" text-anchor="middle">HTML na żądanie</text>
|
||||
|
||||
<path class="flow" d="M720 212 H786"/>
|
||||
<text class="t lbl" x="753" y="202" text-anchor="middle">SQL</text>
|
||||
|
||||
<path class="flow" d="M720 440 H786"/>
|
||||
<text class="t lbl" x="753" y="430" text-anchor="middle">upload</text>
|
||||
|
||||
<!-- summary pills -->
|
||||
<rect class="pill" x="380" y="552" width="360" height="36" rx="18"/>
|
||||
<text class="t pilltxt" x="560" y="575" text-anchor="middle">2 procesy działają bez przerwy, także nocą</text>
|
||||
<rect class="pill" x="770" y="552" width="360" height="36" rx="18"/>
|
||||
<text class="t pilltxt" x="950" y="575" text-anchor="middle">aktualizacje bezpieczeństwa = stały obowiązek</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1,111 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 640" role="img" aria-label="Architektura demo na maszynie: redaktor i czytelnik łączą się z kontenerami podmana — Gitea, build Astro, wolumen releases i nginx">
|
||||
<defs>
|
||||
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M0 0 L10 5 L0 10 z" fill="#00004a"/>
|
||||
</marker>
|
||||
<filter id="soft" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="5" flood-color="#00004a" flood-opacity="0.10"/>
|
||||
</filter>
|
||||
<style>
|
||||
.t { font-family: Inter, "Segoe UI", Arial, sans-serif; }
|
||||
.box { fill: #ffffff; stroke: #00004a; stroke-width: 1.5; }
|
||||
.sub { fill: #f5f5f5; stroke: #e2e5ee; stroke-width: 1; }
|
||||
.ttl { font-weight: 700; font-size: 15.5px; fill: #00004a; letter-spacing: .04em; }
|
||||
.cap { font-size: 12.5px; fill: #46536a; }
|
||||
.lbl { font-size: 12px; fill: #46536a; paint-order: stroke; stroke: #ffffff; stroke-width: 4; }
|
||||
.chipbg { fill: #d2faf7; }
|
||||
.chip { font-size: 11.5px; font-weight: 700; fill: #00004a; letter-spacing: .06em; }
|
||||
.flow { stroke: #00004a; stroke-width: 1.8; fill: none; marker-end: url(#arr); }
|
||||
.mono { font-family: "SF Mono", Consolas, Menlo, monospace; font-size: 12.5px; fill: #101228; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<!-- machine boundary -->
|
||||
<rect x="340" y="40" width="830" height="570" rx="18" fill="#f8f9fc" stroke="#e2e5ee" stroke-width="1.5"/>
|
||||
<text class="t" x="366" y="76" font-size="13" font-weight="700" fill="#00004a" letter-spacing=".18em">MASZYNA DEMO · PODMAN</text>
|
||||
<text class="t cap" x="366" y="96">osobne kontenery pod systemd · wszystko w jednym katalogu użytkownika</text>
|
||||
|
||||
<!-- actor: redaktor -->
|
||||
<g filter="url(#soft)">
|
||||
<rect class="box" x="52" y="120" width="220" height="120" rx="16"/>
|
||||
</g>
|
||||
<circle cx="88" cy="156" r="11" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<path d="M72 186 q16 -18 32 0" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<text class="t ttl" x="116" y="162">Redaktor</text>
|
||||
<text class="t cap" x="70" y="212">przeglądarka · <tspan font-weight="600">/admin/</tspan> (Sveltia)</text>
|
||||
<text class="t cap" x="70" y="228">edycja WYSIWYG, podgląd 1:1</text>
|
||||
|
||||
<!-- actor: czytelnik -->
|
||||
<g filter="url(#soft)">
|
||||
<rect class="box" x="52" y="400" width="220" height="120" rx="16"/>
|
||||
</g>
|
||||
<circle cx="88" cy="436" r="11" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<path d="M72 466 q16 -18 32 0" fill="none" stroke="#00004a" stroke-width="1.8"/>
|
||||
<text class="t ttl" x="116" y="442">Czytelnik</text>
|
||||
<text class="t cap" x="70" y="492">publiczna strona portalu</text>
|
||||
<text class="t cap" x="70" y="508">czysty, szybki HTML</text>
|
||||
|
||||
<!-- gitea -->
|
||||
<g filter="url(#soft)">
|
||||
<rect class="box" x="400" y="120" width="320" height="185" rx="16"/>
|
||||
</g>
|
||||
<text class="t ttl" x="424" y="152">GITEA</text>
|
||||
<rect class="chipbg" x="490" y="136" width="52" height="22" rx="11"/>
|
||||
<text class="t chip" x="516" y="151" text-anchor="middle">:3000</text>
|
||||
<rect class="sub" x="420" y="172" width="280" height="112" rx="12"/>
|
||||
<text class="t" x="436" y="198" font-size="13.5" font-weight="700" fill="#101228">repo ctao/portal</text>
|
||||
<text class="t cap" x="436" y="220">treść: Markdown + obrazy (WebP)</text>
|
||||
<text class="t cap" x="436" y="238">każda zmiana = commit</text>
|
||||
<text class="t cap" x="436" y="256">pełna historia + rollback za darmo</text>
|
||||
|
||||
<!-- build (ephemeral) -->
|
||||
<g filter="url(#soft)">
|
||||
<rect x="790" y="120" width="340" height="185" rx="16" fill="#ffffff" stroke="#00004a" stroke-width="1.5" stroke-dasharray="7 5"/>
|
||||
</g>
|
||||
<text class="t ttl" x="814" y="152">BUILD · ASTRO</text>
|
||||
<rect class="chipbg" x="948" y="136" width="164" height="22" rx="11"/>
|
||||
<text class="t chip" x="1030" y="151" text-anchor="middle">KONTENER JEDNORAZOWY</text>
|
||||
<text class="t cap" x="814" y="188">timer systemd (co ~10 s) sprawdza,</text>
|
||||
<text class="t cap" x="814" y="206">czy w repo jest nowy commit</text>
|
||||
<text class="t cap" x="814" y="234">jeśli tak: git fetch → checkout →</text>
|
||||
<text class="t cap" x="814" y="252"><tspan font-weight="700" fill="#101228">Markdown → statyczny HTML</tspan></text>
|
||||
<text class="t cap" x="814" y="280">po buildzie kontener znika</text>
|
||||
|
||||
<!-- releases volume -->
|
||||
<g filter="url(#soft)">
|
||||
<rect class="sub" x="790" y="400" width="340" height="150" rx="16"/>
|
||||
</g>
|
||||
<text class="t ttl" x="814" y="432">releases/</text>
|
||||
<rect class="chipbg" x="908" y="416" width="82" height="22" rx="11"/>
|
||||
<text class="t chip" x="949" y="431" text-anchor="middle">WOLUMEN</text>
|
||||
<text class="t mono" x="814" y="466">9f2c1d/ poprzednia wersja</text>
|
||||
<text class="t mono" x="814" y="488">71b980/ <tspan font-weight="700" fill="#00004a">← current (symlink)</tspan></text>
|
||||
<text class="t cap" x="814" y="518">podmiana atomowa — zero przestoju</text>
|
||||
|
||||
<!-- nginx -->
|
||||
<g filter="url(#soft)">
|
||||
<rect class="box" x="400" y="400" width="320" height="150" rx="16"/>
|
||||
</g>
|
||||
<text class="t ttl" x="424" y="432">NGINX</text>
|
||||
<rect class="chipbg" x="500" y="416" width="52" height="22" rx="11"/>
|
||||
<text class="t chip" x="526" y="431" text-anchor="middle">:8080</text>
|
||||
<text class="t cap" x="424" y="466">serwuje <tspan font-weight="600">releases/current</tspan></text>
|
||||
<text class="t cap" x="424" y="484">wyłącznie statyczne pliki</text>
|
||||
<text class="t cap" x="424" y="502">brak aplikacji · brak bazy · brak PHP</text>
|
||||
|
||||
<!-- flows -->
|
||||
<path class="flow" d="M272 180 H396"/>
|
||||
<text class="t lbl" x="334" y="170" text-anchor="middle">zapis przez API (OAuth)</text>
|
||||
|
||||
<path class="flow" d="M790 212 H724"/>
|
||||
<text class="t lbl" x="757" y="202" text-anchor="middle">git fetch</text>
|
||||
|
||||
<path class="flow" d="M960 305 V396"/>
|
||||
<text class="t lbl" x="968" y="354" text-anchor="start">nowa wersja strony</text>
|
||||
|
||||
<path class="flow" d="M790 475 H724"/>
|
||||
<text class="t lbl" x="757" y="465" text-anchor="middle">current/</text>
|
||||
|
||||
<path class="flow" d="M400 475 H276"/>
|
||||
<text class="t lbl" x="338" y="465" text-anchor="middle">statyczny HTML</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |