diff --git a/DEPRECATED-kasm/README.md b/DEPRECATED-kasm/README.md deleted file mode 100644 index 9295679..0000000 --- a/DEPRECATED-kasm/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Kasm - -Stack para desplegar [Kasm](https://www.kasmweb.com/) en `kasm.sherlockhomeless.net` detrás de Traefik y Authentik. - -## 🚀 Despliegue con Docker Compose - -Asegurate de tener `kasm/.env` configurado y despliega: - -```bash -cd kasm -docker compose --env-file .env up -d -``` - -## ⚙️ Variables importantes - -Edita `kasm/.env`: - -```env -KASM_DOMAIN=kasm.sherlockhomeless.net -KASM_OPT_PATH=/opt/kasm/opt -TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker -``` - -## 📁 Preparación del host - -Antes del primer arranque: - -```bash -mkdir -p /opt/kasm/opt -``` - -## 🔐 Autenticación y acceso - -Este stack publica Kasm por Traefik con HTTPS y lo protege con `ths-authentik@docker`. - -## 🏠 Integración con Homepage - -El servicio publica labels `homepage.*` para aparecer automáticamente en Homepage dentro del grupo **Infraestructura**. diff --git a/DEPRECATED-kasm/docker-compose.yml b/DEPRECATED-kasm/docker-compose.yml deleted file mode 100644 index 4da1d89..0000000 --- a/DEPRECATED-kasm/docker-compose.yml +++ /dev/null @@ -1,226 +0,0 @@ -services: - db: - image: kasmweb/postgres:${KASM_VERSION} - container_name: kasm_db - restart: unless-stopped - stop_signal: SIGTERM - stop_grace_period: 60s - environment: - POSTGRES_PASSWORD: ${KASM_DB_PASSWORD} - POSTGRES_USER: kasmapp - POSTGRES_DB: kasm - command: postgres -c ssl=on -c ssl_cert_file=/etc/ssl/certs/db_server.crt -c ssl_key_file=/etc/ssl/certs/db_server.key -c config_file=/var/lib/postgresql/conf/postgresql.conf -c hba_file=/var/lib/postgresql/conf/pg_hba.conf - healthcheck: - test: "pg_isready --username=$$POSTGRES_USER --dbname=$$POSTGRES_DB && cat /proc/1/cmdline | grep -q '^postgres'" - timeout: 5s - retries: 20 - volumes: - - ${KASM_DB_INIT_SQL}:/docker-entrypoint-initdb.d/current.sql:ro,Z - - ${KASM_ROOT_PATH}/conf/database/pg_hba.conf:/var/lib/postgresql/conf/pg_hba.conf:ro,Z - - ${KASM_ROOT_PATH}/conf/database/postgresql.conf:/var/lib/postgresql/conf/postgresql.conf:ro,Z - - ${KASM_ROOT_PATH}/certs/db_server.crt:/etc/ssl/certs/db_server.crt:ro,Z - - ${KASM_ROOT_PATH}/certs/db_server.key:/etc/ssl/certs/db_server.key:ro,Z - - ${KASM_ROOT_PATH}/log/postgres:/var/log/postgres:Z - - ${KASM_ROOT_PATH}/tmp/kasm_db:/tmp:Z - - ${KASM_DB_DATA_PATH}:/var/lib/postgresql/data:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - kasm_api: - image: kasmweb/api:${KASM_VERSION} - container_name: kasm_api - user: "${KASM_UID}:${KASM_GID}" - read_only: true - restart: unless-stopped - depends_on: - db: - condition: service_healthy - healthcheck: - test: "/usr/bin/healthcheck.sh http://localhost:8080/api/__healthcheck \"\" 5 60" - timeout: 30s - interval: 10s - retries: 3 - start_period: 60s - volumes: - - ${KASM_ROOT_PATH}:/opt/kasm/current:Z - - ${KASM_ROOT_PATH}/healthcheck/kasm_api:/healthcheck:Z - - ${KASM_ROOT_PATH}/tmp/api:/tmp:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - kasm_manager: - image: kasmweb/manager:${KASM_VERSION} - container_name: kasm_manager - user: "${KASM_UID}:${KASM_GID}" - read_only: true - restart: unless-stopped - depends_on: - db: - condition: service_healthy - healthcheck: - test: "/usr/bin/healthcheck.sh http://localhost:8181/__healthcheck \"\" 5 60" - timeout: 30s - interval: 10s - retries: 3 - volumes: - - ${KASM_ROOT_PATH}:/opt/kasm/current:Z - - ${KASM_ROOT_PATH}/healthcheck/kasm_manager:/healthcheck:Z - - ${KASM_ROOT_PATH}/tmp/manager:/tmp:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - kasm_agent: - image: kasmweb/agent:${KASM_VERSION} - container_name: kasm_agent - user: root - read_only: true - restart: unless-stopped - depends_on: - - kasm_manager - healthcheck: - test: "/usr/bin/healthcheck.sh http://localhost:4444/__healthcheck \"\" 30 90 15" - timeout: 30s - interval: 30s - retries: 3 - volumes: - - ${KASM_ROOT_PATH}:/opt/kasm/current:Z - - ${KASM_ROOT_PATH}/healthcheck/kasm_agent:/healthcheck:Z - - /var/run/docker.sock:/var/run/docker.sock - - ${KASM_ROOT_PATH}/conf/nginx:/etc/nginx/conf.d:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - kasm_guac: - image: kasmweb/kasm-guac:${KASM_VERSION} - container_name: kasm_guac - user: "${KASM_UID}:${KASM_GID}" - read_only: true - init: true - restart: unless-stopped - healthcheck: - test: "/usr/bin/healthcheck.sh http://localhost:3000/__healthcheck \"\" 30 90" - interval: 60s - timeout: 30s - retries: 3 - volumes: - - ${KASM_ROOT_PATH}/log:/opt/kasm/current/log:Z - - ${KASM_ROOT_PATH}/tmp/guac:/opt/kasm/current/tmp/guac:Z - - ${KASM_ROOT_PATH}/conf/app/guac:/opt/kasm/current/conf/app/guac:Z - - ${KASM_ROOT_PATH}/tmp/guac:/tmp:Z - - ${KASM_ROOT_PATH}/healthcheck/kasm_guac:/healthcheck:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - rdp_gateway: - image: kasmweb/rdp-gateway:${KASM_VERSION} - container_name: kasm_rdp_gateway - user: "${KASM_UID}:${KASM_GID}" - read_only: true - restart: unless-stopped - depends_on: - - kasm_api - healthcheck: - test: "/usr/bin/healthcheck.sh http://localhost:5555/__healthcheck 3389 1 30" - interval: 60s - timeout: 30s - start_period: 30s - volumes: - - ${KASM_ROOT_PATH}/log:/opt/kasm/current/log:Z - - ${KASM_ROOT_PATH}/conf/app/rdp_gateway:/usr/local/etc/rdpproxy/conf:Z - - ${KASM_ROOT_PATH}/certs/kasm_nginx.key:/usr/local/etc/rdpproxy/rdpproxy.key:ro,Z - - ${KASM_ROOT_PATH}/certs/kasm_nginx.crt:/usr/local/etc/rdpproxy/rdpproxy.crt:ro,Z - - ${KASM_ROOT_PATH}/tmp/rdpgw/var:/usr/local/etc/rdpproxy/var:Z - - ${KASM_ROOT_PATH}/tmp/rdpgw/tmp:/tmp:Z - - ${KASM_ROOT_PATH}/healthcheck/rdp_gateway:/healthcheck:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - kasm_rdp_https_gateway: - image: kasmweb/rdp-https-gateway:${KASM_VERSION} - container_name: kasm_rdp_https_gateway - user: "${KASM_UID}:${KASM_GID}" - read_only: true - restart: unless-stopped - depends_on: - proxy: - condition: service_started - healthcheck: - test: "/usr/bin/healthcheck.sh https://localhost:9443/rdp-https-gateway/__healthcheck \"\" 1 30" - interval: 60s - timeout: 30s - start_period: 30s - volumes: - - ${KASM_ROOT_PATH}/log:/opt/kasm/current/log:Z - - ${KASM_ROOT_PATH}/conf/app/rdp_https_gateway:/opt/rdpgw/conf:Z - - ${KASM_ROOT_PATH}/certs/kasm_nginx.key:/opt/rdpgw/key.pem:ro,Z - - ${KASM_ROOT_PATH}/certs/kasm_nginx.crt:/opt/rdpgw/server.pem:ro,Z - - ${KASM_ROOT_PATH}/healthcheck/rdp_https_gateway:/healthcheck:Z - networks: - - kasm_default_network - labels: - prune.protect: "true" - - proxy: - image: kasmweb/proxy:${KASM_VERSION} - container_name: kasm_proxy - restart: unless-stopped - depends_on: - kasm_manager: - condition: service_healthy - kasm_api: - condition: service_healthy - kasm_agent: - condition: service_started - kasm_guac: - condition: service_started - volumes: - - ${KASM_ROOT_PATH}/conf/nginx:/etc/nginx/conf.d:ro,Z - - ${KASM_ROOT_PATH}/certs/kasm_nginx.key:/etc/ssl/private/kasm_nginx.key:ro,Z - - ${KASM_ROOT_PATH}/certs/kasm_nginx.crt:/etc/ssl/certs/kasm_nginx.crt:ro,Z - - ${KASM_ROOT_PATH}/log/nginx:/var/log/external/nginx:Z - - ${KASM_ROOT_PATH}/log/logrotate:/var/log/external/logrotate:Z - networks: - - kasm_default_network - - kasm_sidecar_network - - proxy - labels: - prune.protect: "true" - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - traefik.http.routers.kasm.rule: "Host(`${KASM_DOMAIN}`)" - traefik.http.routers.kasm.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}" - traefik.http.routers.kasm.tls: "true" - traefik.http.routers.kasm.tls.certresolver: "${TRAEFIK_CERTRESOLVER}" - traefik.http.routers.kasm.middlewares: "crowdsec-bouncer@file,${TRAEFIK_AUTH_MIDDLEWARE}" - traefik.http.services.kasm.loadbalancer.server.port: "3000" - traefik.http.services.kasm.loadbalancer.server.scheme: "https" - traefik.http.services.kasm.loadbalancer.passhostheader: "true" - homepage.group: "Infraestructura" - homepage.name: "Kasm" - homepage.icon: "https://www.kasmweb.com/favicon.ico" - homepage.description: "Workspaces en navegador" - homepage.href: "https://${KASM_DOMAIN}" - homepage.siteMonitor: "https://kasm_proxy:3000/" - homepage.weight: "350" - -networks: - kasm_default_network: - name: kasm_default_network - driver: bridge - kasm_sidecar_network: - name: kasm_sidecar_network - driver: bridge - proxy: - external: true diff --git a/DEPRECATED-kasm/stack.env b/DEPRECATED-kasm/stack.env deleted file mode 100644 index 4b58f52..0000000 --- a/DEPRECATED-kasm/stack.env +++ /dev/null @@ -1,10 +0,0 @@ -TZ=Europe/Madrid -KASM_IMAGE=lscr.io/linuxserver/kasm:latest -KASM_DOMAIN=app.example.com -KASM_OPT_PATH=/var/lib/kasm -TRAEFIK_DOCKER_NETWORK=proxy -TRAEFIK_ENTRYPOINT_SECURE=websecure -TRAEFIK_CERTRESOLVER=letsencrypt -TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker -SERVICE_URL_KASM=https://app.example.com -SERVICE_FQDN_KASM=app.example.com diff --git a/README.md b/README.md index 1188074..39d0302 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,8 @@ Usa `docker compose --env-file .env -f /docker-compose.yml up -d` si prefi |---|---|---|---| | Traefik | Reverse proxy con TLS automatico | `Traefik/` | [README](Traefik/README.md) | | Authentik | SSO y Forward Auth | `authentik/` | [README](authentik/README.md) | -| CrowdSec | IPS/IDS, bouncer y Grafana | `crowdsec/` | [README](crowdsec/README.md) | +| CrowdSec | IPS/IDS y bouncer | `crowdsec/` | [README](crowdsec/README.md) | | Homepage | Dashboard principal | `homepage/` | [README](homepage/README.md) | -| Dozzle | Visor de logs Docker | `dozzle/` | [README](dozzle/README.md) | -| Beszel | Monitorizacion ligera | `beszel/` | [README](beszel/README.md) | | Gitea | Git autoalojado | `gitea/` | [README](gitea/README.md) | | n8n | Automatizacion de workflows | `n8n/` | [README](n8n/README.md) | | Mail Relay | Relay SMTP interno | `mail-relay/` | [README](mail-relay/README.md) | @@ -171,13 +169,18 @@ Si un `.env` no se aplica: - CrowdSec debe ir antes de Authentik en la cadena de middlewares cuando ambos se usen. - Las instrucciones antiguas de Portainer se consideran obsoletas. -## Stacks deprecados +## Retirar un stack -Los stacks descartados de la infra (ya no se despliegan) se prefijan con -`DEPRECATED-` (ej. `DEPRECATED-kasm/`) en vez de borrarse, para conservar -la config por si hace falta consultarla. Antes de renombrar: +Los stacks descartados se borran del repo (el historial de git conserva la +config). Antes de borrar: -1. Confirmar que no queden contenedores corriendo (`docker ps -a --filter name=`). -2. Quitar/inhabilitar su ruta en `/opt/traefik/dynamic/` si tenía una. -3. Quitar su entrada de Homepage (labels en el compose o `services.yaml`). -4. `git mv DEPRECATED-` (preserva historial). +1. `docker compose --env-file .env down` desde la carpeta del stack. +2. Backup en `/opt/backups/removal--/` (`chmod 600`): datos de + `/opt/`, la carpeta del repo con su `.env` y los ficheros de + `/opt/traefik/dynamic/` que se toquen. +3. Quitar su ruta en `/opt/traefik/dynamic/` (renombrar a `.bak--removed`) + y su middleware en `sablier.yml` si lo tenía. +4. Quitar su entrada de Homepage (labels en el compose o `services.yaml`). +5. Borrar sus registros DNS con `cloudflared/cloudflare_dns.py delete `. +6. Quitar referencias en `backups/kopia/` y `n8n-observability/scripts/ops-report`. +7. Borrar los datos en `/opt/` y `git rm -r `. diff --git a/backups/kopia/README.md b/backups/kopia/README.md index eb22d56..68735f5 100644 --- a/backups/kopia/README.md +++ b/backups/kopia/README.md @@ -33,10 +33,10 @@ The snapshot paths are listed in `backup-paths.txt`. The important choices are: - Gitea: `/opt/gitea/data` and runner data. - Nextcloud: config, themes and a MariaDB dump only. `/opt/nextcloud/data`, `/opt/nextcloud/custom_apps` and `/opt/nextcloud/html` are excluded. - Databases: PostgreSQL and MariaDB dumps are written to `/opt/kopia/staging/dumps/latest`. -- Service configuration: deployment repo, Traefik, Authentik, n8n, Memos, Vikunja, Trilium, Karakeep, AdGuard, WireGuard, mail relay, Beszel, Homepage, Dozzle, Kasm and OpenCode. -- Local active deployments: Scheduler, Spintools, THSCOM, OpenClaw restore state and OpenCode runtime state. +- Service configuration: deployment repo, Traefik, Authentik, n8n, Trilium, Karakeep, AdGuard, WireGuard, mail relay, Homepage and OpenCode. +- Local active deployments: Spintools, OpenClaw restore state and OpenCode runtime state. -Live database directories are excluded when a logical dump exists. Kasm's PostgreSQL database is backed up with `pg_dump`; Docker image/layer storage under `/opt/kasm/opt/docker` is intentionally excluded because it is rebuildable and large. OpenProject's embedded PostgreSQL data is not dumped by this first version; treat its restore as best-effort unless a service-specific dump command is added. +Live database directories are excluded when a logical dump exists. ## Install Kopia diff --git a/backups/kopia/backup-paths.txt b/backups/kopia/backup-paths.txt index 12ce41b..51ba920 100644 --- a/backups/kopia/backup-paths.txt +++ b/backups/kopia/backup-paths.txt @@ -21,8 +21,6 @@ # App configuration and small persistent data. /opt/n8n/data /opt/authentik/redis -/opt/memos/data -/opt/vikunja/files /opt/trilium/data /opt/karakeep/data /opt/karakeep/meili_data @@ -34,22 +32,9 @@ /opt/traefik/certs /opt/mail-relay/opendkim /opt/mail-relay/secrets -/opt/beszel/data -/opt/beszel/agent /opt/homepage/config -/opt/dozzle/data /opt/guacamole/admin-credentials.env -# Kasm Workspaces: DB dump plus install/config state required for restore. -# Docker image/layer storage under /opt/kasm/opt/docker is intentionally omitted. -/opt/kasm/1.18.1/bin -/opt/kasm/1.18.1/certs -/opt/kasm/1.18.1/conf -/opt/kasm/1.18.1/docker -/opt/kasm/1.18.1/file_mappings -/opt/kasm/1.18.1/licenses -/opt/kasm/1.18.1/plugins - # OpenCode Web UI service configuration and runtime state. /etc/opencode-web.env /home/felidae/.config/opencode @@ -66,16 +51,10 @@ /opt/onlyoffice/lib /opt/onlyoffice/postgresql -# Scheduler: keep PostgreSQL data volume and logical dump, but not source tree. -/var/lib/docker/volumes/scheduler_app_postgres_data/_data - -# Spintools / THSCOM. +# Spintools. /opt/spintools/prod -/opt/spintools/openproject/assets -/opt/spintools/openproject-token /opt/spintools/authentik/redis /var/lib/docker/volumes/spintools_ruleta_static/_data -/var/lib/docker/volumes/thscom-backend-media/_data # OpenClaw runtime state, excluding workspaces via exclude file. /home/felidae/.openclaw diff --git a/backups/kopia/excludes.txt b/backups/kopia/excludes.txt index 9e9905a..cd6bb8d 100644 --- a/backups/kopia/excludes.txt +++ b/backups/kopia/excludes.txt @@ -7,32 +7,22 @@ /opt/paperless/media/.thumbnails # Live database directories are handled by logical dumps when possible. -/var/lib/docker/volumes/kasm_db_1.18.1 -/opt/kasm/opt/docker -/opt/kasm/1.18.1/log -/opt/kasm/1.18.1/tmp /opt/paperless/pgdata /opt/gitea/postgres /opt/n8n/postgres /opt/authentik/postgres -/opt/memos/postgres -/opt/vikunja/postgres /opt/nextcloud/db /opt/spintools/authentik/postgres -/opt/spintools/openproject/pgdata # Rebuildable caches and dependencies. **/node_modules node_modules frontend/*/node_modules -/home/felidae/scheduler_app/frontend/*/node_modules **/.next/cache frontend/*/.next -/home/felidae/scheduler_app/frontend/*/.next **/__pycache__ **/.pytest_cache **/.mypy_cache -/home/felidae/scheduler_app/.mypy_cache **/.ruff_cache **/.cache **/cache diff --git a/backups/kopia/pre-backup-dumps.sh b/backups/kopia/pre-backup-dumps.sh index c3e9b94..d35e09f 100755 --- a/backups/kopia/pre-backup-dumps.sh +++ b/backups/kopia/pre-backup-dumps.sh @@ -73,13 +73,8 @@ dump_mariadb() { dump_postgres "paperless-db" "paperless" "paperless" dump_postgres "gitea-postgres" "gitea" "gitea" dump_postgres "n8n-pg" "n8n" "n8n" -dump_postgres "vikunja-db" "vikunja" "vikunja" -dump_postgres "memos-db" "memos" "memos" dump_postgres "ths-authentik-postgres" "authentik" "authentik" -dump_postgres "scheduler-db" "scheduler" "scheduler" dump_postgres "guacamole-postgres" "guacamole" "guacamole" -dump_postgres "kasm_db" "kasmapp" "kasm" -dump_postgres "thscom-db" "postgres" "postgres" dump_postgres "spintools-db" "postgres" "postgres" dump_postgres "spintools-authentik-postgres" "authentik" "authentik" dump_postgres "charge-card-lab-postgres" "charge_card_lab" "charge_card_lab" diff --git a/beszel/README.md b/beszel/README.md deleted file mode 100644 index 5779b07..0000000 --- a/beszel/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Beszel - -Stack para desplegar [Beszel](https://beszel.dev/) en `beszel.sherlockhomeless.net`, con el **hub** publicado por Traefik y un **agent** local para monitorizar este mismo host Docker. - -## 🚀 Despliegue con Docker Compose - -Asegurate de tener `beszel/.env` configurado y despliega: - -```bash -cd beszel -docker compose --env-file .env up -d -``` - -## ⚙️ Variables importantes - -Edita `beszel/.env`: - -```env -BESZEL_DOMAIN=beszel.sherlockhomeless.net -BESZEL_APP_URL=https://beszel.sherlockhomeless.net -BESZEL_DATA_PATH=/opt/beszel/data -BESZEL_SOCKET_PATH=/opt/beszel/socket -BESZEL_AGENT_DATA_PATH=/opt/beszel/agent -BESZEL_AGENT_TOKEN=pega-aqui-tu-token -BESZEL_AGENT_KEY="ssh-ed25519 AAAA..." -``` - -## 📁 Preparación del host - -Crea los directorios persistentes antes del primer arranque: - -```bash -mkdir -p /opt/beszel/data /opt/beszel/socket /opt/beszel/agent -``` - -## 🔐 Autenticación y acceso - -Beszel sí incluye autenticación propia, soporte multiusuario y OIDC, así que el router de Traefik no añade `ths-authentik@docker` por defecto para evitar doble login. - -El acceso externo queda expuesto por HTTPS en `https://beszel.sherlockhomeless.net`, pero la autenticación se resuelve dentro del propio hub de Beszel. Si más adelante quieres federarlo con Authentik, lo natural es configurar OIDC dentro de Beszel en lugar de meter un forward auth delante. - -## 🔌 Alta del agente local - -Este stack monta un socket Unix compartido entre hub y agent, que es la forma recomendada por Beszel para monitorizar el mismo host sin depender de IPs internas. - -Después de crear tu usuario administrador en la UI: - -1. Ve a **Add System** y copia la clave pública y el token. -2. Pégalos en `BESZEL_AGENT_KEY` y `BESZEL_AGENT_TOKEN`. -3. Actualiza el stack. -4. En el campo **Host / IP** del sistema usa `/beszel_socket/beszel.sock`. - -## 🏠 Integración con Homepage - -El hub publica labels `homepage.*`, así que Homepage puede mostrarlo automáticamente dentro del grupo **Observabilidad** apuntando a `https://beszel.sherlockhomeless.net`. diff --git a/beszel/docker-compose.yml b/beszel/docker-compose.yml deleted file mode 100644 index 87c71b6..0000000 --- a/beszel/docker-compose.yml +++ /dev/null @@ -1,49 +0,0 @@ -services: - beszel: - image: ${BESZEL_IMAGE} - container_name: beszel - restart: unless-stopped - environment: - TZ: ${TZ} - APP_URL: ${BESZEL_APP_URL} - volumes: - - ${BESZEL_DATA_PATH}:/beszel_data:Z - - ${BESZEL_SOCKET_PATH}:/beszel_socket:Z - networks: - - proxy - labels: - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - traefik.http.routers.beszel.rule: "Host(`${BESZEL_DOMAIN}`)" - traefik.http.routers.beszel.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}" - traefik.http.routers.beszel.tls: "true" - traefik.http.routers.beszel.tls.certresolver: "${TRAEFIK_CERTRESOLVER}" - traefik.http.services.beszel.loadbalancer.server.port: "${BESZEL_HTTP_PORT}" - homepage.group: "Observabilidad" - homepage.name: "Beszel" - homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/beszel.svg" - homepage.description: "Monitorización ligera de host y contenedores" - homepage.href: "https://${BESZEL_DOMAIN}" - homepage.siteMonitor: "http://beszel:8090/" - homepage.showStats: "false" - homepage.weight: "200" - - beszel-agent: - image: ${BESZEL_AGENT_IMAGE} - container_name: beszel-agent - restart: unless-stopped - network_mode: host - volumes: - - ${BESZEL_AGENT_DATA_PATH}:/var/lib/beszel-agent:Z - - ${BESZEL_SOCKET_PATH}:/beszel_socket:Z - - /var/run/docker.sock:/var/run/docker.sock:ro - environment: - TZ: ${TZ} - LISTEN: /beszel_socket/beszel.sock - HUB_URL: http://localhost:${BESZEL_HTTP_PORT} - TOKEN: ${BESZEL_AGENT_TOKEN} - KEY: ${BESZEL_AGENT_KEY} - -networks: - proxy: - external: true diff --git a/beszel/stack.env b/beszel/stack.env deleted file mode 100644 index 7929da7..0000000 --- a/beszel/stack.env +++ /dev/null @@ -1,16 +0,0 @@ -TZ=Europe/Madrid -BESZEL_IMAGE=henrygd/beszel:latest -BESZEL_AGENT_IMAGE=henrygd/beszel-agent:latest -BESZEL_DOMAIN=beszel.sherlockhomeless.net -BESZEL_APP_URL=https://beszel.sherlockhomeless.net -BESZEL_HTTP_PORT=8090 -BESZEL_DATA_PATH=/opt/beszel/data -BESZEL_SOCKET_PATH=/opt/beszel/socket -BESZEL_AGENT_DATA_PATH=/opt/beszel/agent -BESZEL_AGENT_TOKEN=CAMBIAME_token_generado_en_beszel -BESZEL_AGENT_KEY=ssh-ed25519 CAMBIAME_clave_publica_generada_en_beszel -TRAEFIK_DOCKER_NETWORK=proxy -TRAEFIK_ENTRYPOINT_SECURE=websecure -TRAEFIK_CERTRESOLVER=letsencrypt -SERVICE_URL_BESZEL=https://beszel.sherlockhomeless.net -SERVICE_FQDN_BESZEL=beszel.sherlockhomeless.net diff --git a/bookstack/README.md b/bookstack/README.md deleted file mode 100644 index ee60a38..0000000 --- a/bookstack/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# BookStack - -Base de conocimiento y documentación desplegada con MariaDB, acceso por Traefik y envío de correo mediante `mail-relay`. - -## Arquitectura y propósito - -`bookstack` sirve la aplicación y guarda adjuntos/configuración en `BOOKSTACK_DATA_PATH`; `bookstack-db` conserva páginas, permisos y estructura en MariaDB. La base sólo usa la red interna `bookstack`. La aplicación se añade a `proxy` para Traefik y a `mail_internal` para enviar correo sin publicar la base de datos ni el relay. - -## Configuración - -- `BOOKSTACK_DOMAIN` y `APP_URL` deben coincidir para que enlaces, cookies y redirecciones HTTPS sean válidos. -- `APP_KEY` cifra datos de aplicación: genérala una vez, mantenla estable y respáldala como secreto. -- Las variables `BOOKSTACK_DB_*` conectan ambos contenedores; las contraseñas deben existir sólo en `.env`. -- `BOOKSTACK_PUID` y `BOOKSTACK_PGID` deben tener acceso a `BOOKSTACK_DATA_PATH`. -- `BOOKSTACK_LANG` y `BOOKSTACK_DARK_MODE` fijan los valores iniciales de interfaz. -- `BOOKSTACK_MAIL_FROM*` identifica el remitente; el transporte usa el servicio interno `mail-relay`. - -Separar datos y base permite actualizar la imagen sin perder contenido y respaldar cada componente con el método adecuado. - -## Requisitos - -- Docker Compose -- Redes externas `proxy` y `mail_internal` -- Un archivo `.env` local con las imágenes, dominio, rutas, credenciales de base de datos y `APP_KEY` - -## Despliegue - -```bash -cd bookstack -docker compose --env-file .env config -docker compose --env-file .env up -d -``` - -Los datos de BookStack y MariaDB se conservan en las rutas indicadas por `BOOKSTACK_DATA_PATH` y `BOOKSTACK_DB_PATH`. - -## Operación - -```bash -docker compose --env-file .env ps -docker compose --env-file .env logs -f bookstack -``` diff --git a/bookstack/docker-compose.yml b/bookstack/docker-compose.yml deleted file mode 100644 index e6ce863..0000000 --- a/bookstack/docker-compose.yml +++ /dev/null @@ -1,66 +0,0 @@ -services: - bookstack-db: - image: ${BOOKSTACK_DB_IMAGE} - container_name: bookstack-db - restart: unless-stopped - labels: - prune.protect: "true" - environment: - MYSQL_ROOT_PASSWORD: ${BOOKSTACK_DB_ROOT_PASSWORD} - MYSQL_DATABASE: ${BOOKSTACK_DB_NAME} - MYSQL_USER: ${BOOKSTACK_DB_USER} - MYSQL_PASSWORD: ${BOOKSTACK_DB_PASSWORD} - TZ: ${TZ} - volumes: - - ${BOOKSTACK_DB_PATH}:/var/lib/mysql:Z - networks: - - bookstack - - bookstack: - image: ${BOOKSTACK_IMAGE} - container_name: bookstack - restart: unless-stopped - depends_on: - - bookstack-db - environment: - PUID: ${BOOKSTACK_PUID} - PGID: ${BOOKSTACK_PGID} - TZ: ${TZ} - APP_KEY: ${APP_KEY} - APP_URL: https://${BOOKSTACK_DOMAIN} - DB_HOST: bookstack-db - DB_PORT: 3306 - DB_DATABASE: ${BOOKSTACK_DB_NAME} - DB_USERNAME: ${BOOKSTACK_DB_USER} - DB_PASSWORD: ${BOOKSTACK_DB_PASSWORD} - APP_LANG: ${BOOKSTACK_LANG} - APP_DEFAULT_DARK_MODE: ${BOOKSTACK_DARK_MODE} - MAIL_DRIVER: smtp - MAIL_HOST: mail-relay - MAIL_PORT: 587 - MAIL_FROM: ${BOOKSTACK_MAIL_FROM} - MAIL_FROM_NAME: ${BOOKSTACK_MAIL_FROM_NAME} - volumes: - - ${BOOKSTACK_DATA_PATH}:/config:Z - networks: - - bookstack - - proxy - - mail_internal - labels: - prune.protect: "true" - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - homepage.group: "Productividad" - homepage.name: "BookStack" - homepage.icon: "bookstack.png" - homepage.href: "https://${BOOKSTACK_DOMAIN}/" - homepage.description: "Base de conocimiento y documentacion" - homepage.siteMonitor: "https://${BOOKSTACK_DOMAIN}/" - -networks: - bookstack: - driver: bridge - mail_internal: - external: true - proxy: - external: true diff --git a/bookstack/stack.env b/bookstack/stack.env deleted file mode 100644 index 6935805..0000000 --- a/bookstack/stack.env +++ /dev/null @@ -1,29 +0,0 @@ -##### MariaDB BookStack ##### -BOOKSTACK_DB_IMAGE=mariadb:11 -BOOKSTACK_DB_ROOT_PASSWORD=change-me-root -BOOKSTACK_DB_NAME=bookstack -BOOKSTACK_DB_USER=bookstack -BOOKSTACK_DB_PASSWORD=change-me -BOOKSTACK_DB_PATH=/opt/bookstack/db - -##### BookStack ##### -BOOKSTACK_IMAGE=lscr.io/linuxserver/bookstack:latest -BOOKSTACK_PUID=1000 -BOOKSTACK_PGID=1000 -TZ=Europe/Madrid - -BOOKSTACK_DOMAIN=wiki.example.com -APP_KEY= -BOOKSTACK_LANG=es -BOOKSTACK_DARK_MODE=true -BOOKSTACK_DATA_PATH=/opt/bookstack/data - -##### Correo ##### -BOOKSTACK_MAIL_FROM=bookstack@example.com -BOOKSTACK_MAIL_FROM_NAME=BookStack - -##### Traefik ##### -TRAEFIK_DOCKER_NETWORK=proxy -TRAEFIK_ENTRYPOINT_SECURE=websecure -TRAEFIK_CERTRESOLVER=letsencrypt -TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker diff --git a/changedetection/README.md b/changedetection/README.md deleted file mode 100644 index 51d5c5d..0000000 --- a/changedetection/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# changedetection.io - -changedetection.io published at `https://changedetection.sherlockhomeless.net`. - -## Qué hace y cómo funciona - -Supervisa páginas y avisa cuando cambia su contenido. `changedetection` guarda reglas e histórico en `CHANGEDETECTION_DATA_PATH`; `changedetection-browser` renderiza sitios con JavaScript mediante Playwright. El navegador sólo está en `changedetection_internal`, porque su puerto de depuración no debe exponerse. - -## Configuración - -- `CHANGEDETECTION_DOMAIN` forma `BASE_URL` y debe coincidir con Traefik. -- `CHANGEDETECTION_IMAGE` y `CHANGEDETECTION_BROWSER_IMAGE` fijan las versiones de aplicación y navegador. -- `CHANGEDETECTION_DATA_PATH` contiene toda la configuración que debe respaldarse. -- `PLAYWRIGHT_DRIVER_URL` ya apunta al sidecar; elige el fetcher Playwright dentro de la UI sólo para páginas que lo necesiten, ya que consume más recursos. -- El router dinámico combina CrowdSec, Authentik y Sablier: seguridad, control de identidad y arranque bajo demanda, respectivamente. - -## Despliegue - -```bash -docker compose --env-file .env config -docker compose --env-file .env up -d -``` - -The stack includes a Browserless Chrome sidecar for JavaScript-heavy pages. - -The public route is defined in Traefik dynamic config and protected by: - -- `crowdsec-bouncer@file` -- `ths-authentik@docker` -- `sablier-changedetection@file` diff --git a/changedetection/docker-compose.yml b/changedetection/docker-compose.yml deleted file mode 100644 index bd81e00..0000000 --- a/changedetection/docker-compose.yml +++ /dev/null @@ -1,45 +0,0 @@ -services: - changedetection: - image: ${CHANGEDETECTION_IMAGE} - container_name: changedetection - restart: unless-stopped - environment: - TZ: ${TZ} - BASE_URL: https://${CHANGEDETECTION_DOMAIN} - PLAYWRIGHT_DRIVER_URL: ws://changedetection-browser:3000 - volumes: - - ${CHANGEDETECTION_DATA_PATH}:/datastore:Z - depends_on: - - changedetection-browser - networks: - - changedetection_internal - - proxy - labels: - prune.protect: "true" - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - homepage.group: "Utilidades" - homepage.name: "ChangeDetection" - homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/changedetection.svg" - homepage.description: "Monitor de cambios web" - homepage.href: "https://${CHANGEDETECTION_DOMAIN}/" - homepage.siteMonitor: "http://changedetection:5000/" - homepage.weight: "530" - - changedetection-browser: - image: ${CHANGEDETECTION_BROWSER_IMAGE} - container_name: changedetection-browser - restart: unless-stopped - shm_size: "2gb" - networks: - - changedetection_internal - labels: - prune.protect: "true" - -networks: - changedetection_internal: - driver: bridge - labels: - prune.protect: "true" - proxy: - external: true diff --git a/crowdsec/README.md b/crowdsec/README.md index 685c969..84948b5 100644 --- a/crowdsec/README.md +++ b/crowdsec/README.md @@ -8,7 +8,6 @@ en tiempo real. Usa inteligencia comunitaria para compartir reputación de IPs e Este stack despliega: - **CrowdSec Engine**: Motor de detección que analiza logs de Traefik y otros contenedores - **CrowdSec Bouncer (Traefik Plugin)**: Middleware que bloquea IPs maliciosas a nivel HTTP (L7) -- **Grafana**: Dashboard web para visualizar alertas, decisiones y métricas (protegido con Authentik) - Baneos automáticos contra ataques de fuerza bruta, escaneos, CVEs conocidos y más ## 🚀 Despliegue @@ -20,10 +19,7 @@ Este stack despliega: docker network create proxy ``` -2. **Registro DNS**: Configura el registro A para el dashboard - - `grafana.tudominio.com` → IP del servidor - -3. **Directorios**: Créalos automáticamente con el setup: +2. **Directorios**: Créalos automáticamente con el setup: ```bash cd crowdsec && ./setup.sh ``` @@ -42,9 +38,6 @@ Variables críticas: # Clave API del bouncer (generada automáticamente por setup.sh o pon una manual) CROWDSEC_BOUNCER_API_KEY=tu-key-de-64-caracteres -# Dominio del dashboard Grafana -CROWDSEC_GRAFANA_DOMAIN=grafana.tudominio.com - # Colecciones a instalar CROWDSEC_COLLECTIONS=crowdsecurity/traefik @@ -105,35 +98,6 @@ docker exec crowdsec cscli metrics docker exec crowdsec cscli bouncers list ``` -## 🔐 Configurar Authentik para el Dashboard (Grafana) - -El dashboard de Grafana (`grafana.tudominio.com`) está protegido con `ths-authentik@docker`. Para que funcione: - -### En el panel de Authentik: - -1. **Crear Proxy Provider**: - - Ve a **Applications** → **Providers** → **Create** - - Tipo: **Proxy Provider** - - Name: `CrowdSec Grafana` - - External host: `https://grafana.tudominio.com` - - Authentication flow: `default-authentication-flow` - - Authorization flow: `default-provider-authorization-implicit-consent` - - Mode: `Forward auth (single application)` - -2. **Crear Application**: - - Ve a **Applications** → **Create** - - Name: `CrowdSec Grafana` - - Slug: `grafana` - - Provider: selecciona el creado en paso 1 - - UI Settings: opcional (icono, descripción) - -3. **Asociar al Embedded Outpost**: - - Ve a **Outposts** → `authentik Embedded Outpost` → **Edit** - - Asegúrate de que la aplicación `CrowdSec Grafana` está seleccionada - - Haz clic en **Update** - -> El middleware `ths-authentik@docker` ya está configurado en las labels del servicio `crowdsec-grafana`. Si otros stacks también lo usan, comparte la misma configuración de Authentik. - ## 🛡️ Proteger servicios con CrowdSec ### Método 1: Middleware global (recomendado) @@ -354,7 +318,6 @@ Requiere que el bot se ejecute en el mismo host que el contenedor `crowdsec` (ac - **API local solo en loopback**: La API de CrowdSec (`cscli lapi`) solo escucha en `127.0.0.1:8080` - **Bouncer integrado en Traefik**: No expone puertos adicionales, todo el filtrado ocurre dentro de Traefik -- **Dashboard protegido por Authentik**: Grafana requiere autenticación SSO previa - **Motor con capacidades mínimas**: Solo `NET_BIND_SERVICE`, sin `CAP_SYS_ADMIN` ni privilegios elevados - **SELinux**: Volúmenes con contexto `:Z` para entornos con SELinux habilitado - **Key del bouncer**: Generada aleatoriamente y almacenada solo en `.env` (gitignorado) @@ -407,21 +370,6 @@ Requiere que el bot se ejecute en el mismo host que el contenedor `crowdsec` (ac docker exec crowdsec cscli decisions list ``` -### El dashboard pide login pero Authentik no redirige - -1. Verifica que el middleware está correctamente referenciado en las labels: - ```bash - docker inspect crowdsec-grafana | grep -A 20 Labels - ``` - -2. Revisa que la aplicación existe en Authentik y está asociada al Embedded Outpost -3. Comprueba los logs de Authentik: - ```bash - docker logs ths-authentik-server - ``` - - - ## 💾 Backups Incluye en tus backups de Kopia (ya configurados en `backups/kopia/`): @@ -442,7 +390,6 @@ Para actualizar CrowdSec: 1. Edita `.env` y actualiza la versión si es necesario: ```env CROWDSEC_IMAGE=crowdsecurity/crowdsec:latest - GRAFANA_IMAGE=grafana/grafana:latest ``` 2. Redespiega: ```bash @@ -458,5 +405,4 @@ Para actualizar CrowdSec: - [Documentación oficial de CrowdSec](https://docs.crowdsec.net/) - [CrowdSec + Traefik Plugin](https://plugins.traefik.io/plugins/6335349fe93a526d1ec2aed6/crowdsec-bouncer) - [CrowdSec Hub (colecciones)](https://hub.crowdsec.net/) -- [Grafana Docs](https://grafana.com/docs/grafana/latest/) - [CrowdSec Discord](https://discord.gg/crowdsec) diff --git a/crowdsec/docker-compose.yml b/crowdsec/docker-compose.yml index 7e926b5..f349a14 100644 --- a/crowdsec/docker-compose.yml +++ b/crowdsec/docker-compose.yml @@ -14,11 +14,6 @@ services: BOUNCER_KEY_TRAEFIK: ${CROWDSEC_BOUNCER_API_KEY} LEVEL: ${CROWDSEC_LOG_LEVEL} TZ: ${TZ:-America/Mexico_City} - POSTGRES_HOST: crowdsec-postgres - POSTGRES_PORT: "5432" - POSTGRES_DB: ${CROWDSEC_POSTGRES_DB} - POSTGRES_USER: ${CROWDSEC_POSTGRES_USER} - POSTGRES_PASSWORD: ${CROWDSEC_POSTGRES_PASSWORD} volumes: - ${CROWDSEC_CONFIG_PATH}:/etc/crowdsec:Z - crowdsec_lib:/var/lib/crowdsec @@ -31,7 +26,6 @@ services: ports: - "127.0.0.1:8080:8080" networks: - - crowdsec_internal - proxy healthcheck: test: ["CMD", "cscli", "lapi", "status"] @@ -39,85 +33,7 @@ services: timeout: 5s retries: 3 - crowdsec-postgres: - image: ${CROWDSEC_POSTGRES_IMAGE} - container_name: crowdsec-postgres - restart: unless-stopped - environment: - POSTGRES_USER: ${CROWDSEC_POSTGRES_USER} - POSTGRES_PASSWORD: ${CROWDSEC_POSTGRES_PASSWORD} - POSTGRES_DB: ${CROWDSEC_POSTGRES_DB} - volumes: - - ${CROWDSEC_POSTGRES_PATH}:/var/lib/postgresql/data:Z - networks: - - crowdsec_internal - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${CROWDSEC_POSTGRES_USER} -d ${CROWDSEC_POSTGRES_DB}"] - interval: 10s - timeout: 5s - retries: 5 - - crowdsec-prometheus: - image: prom/prometheus@sha256:e4254400b85610324913f0dc4acf92603d9984e7519414c5a12811aa6146acc3 - container_name: crowdsec-prometheus - restart: unless-stopped - command: - - "--config.file=/etc/prometheus/prometheus.yml" - - "--storage.tsdb.path=/prometheus" - - "--storage.tsdb.retention.time=7d" - - "--web.enable-lifecycle" - volumes: - - ${CROWDSEC_PROMETHEUS_CONFIG}/prometheus.yml:/etc/prometheus/prometheus.yml:ro - - ${CROWDSEC_PROMETHEUS_PATH}:/prometheus:Z - networks: - - crowdsec_internal - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/-/healthy"] - interval: 30s - timeout: 5s - retries: 3 - - crowdsec-grafana: - image: ${GRAFANA_IMAGE} - container_name: crowdsec-grafana - restart: unless-stopped - environment: - GF_SERVER_ROOT_URL: https://${CROWDSEC_GRAFANA_DOMAIN} - GF_AUTH_PROXY_ENABLED: "true" - GF_AUTH_PROXY_HEADER_NAME: X-Authentik-Username - GF_AUTH_PROXY_HEADER_EMAIL: X-Authentik-Email - GF_AUTH_PROXY_HEADER_GROUPS: X-Authentik-Groups - GF_AUTH_PROXY_AUTO_SIGN_UP: "true" - GF_AUTH_PROXY_ENABLE_LOGIN_TOKEN: "false" - GF_AUTH_DISABLE_LOGIN_FORM: "true" - GF_AUTH_SIGNOUT_REDIRECT: https://${AUTHENTIK_DOMAIN:-auth.sherlockhomeless.net}/application/o/${CROWDSEC_GRAFANA_SLUG:-grafana}/end-session/ - volumes: - - ${CROWDSEC_GRAFANA_PATH}:/var/lib/grafana:Z - - ${CROWDSEC_GRAFANA_PROVISIONING}:/etc/grafana/provisioning:ro - - ${CROWDSEC_GRAFANA_DASHBOARDS}:/var/lib/grafana/dashboards:ro - networks: - - crowdsec_internal - - proxy - labels: - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - traefik.http.routers.crowdsec-grafana.rule: "Host(`${CROWDSEC_GRAFANA_DOMAIN}`)" - traefik.http.routers.crowdsec-grafana.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}" - traefik.http.routers.crowdsec-grafana.tls: "true" - traefik.http.routers.crowdsec-grafana.tls.certresolver: "${TRAEFIK_CERTRESOLVER}" - traefik.http.routers.crowdsec-grafana.service: "crowdsec-grafana" - traefik.http.routers.crowdsec-grafana.middlewares: "crowdsec-bouncer@file,${TRAEFIK_AUTH_MIDDLEWARE}" - traefik.http.services.crowdsec-grafana.loadbalancer.server.port: "3000" - homepage.group: "Observabilidad" - homepage.name: "Grafana" - homepage.href: "https://${CROWDSEC_GRAFANA_DOMAIN}" - homepage.description: "Dashboards CrowdSec y monitorizacion" - homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/grafana.svg" - homepage.siteMonitor: "https://${CROWDSEC_GRAFANA_DOMAIN}" - networks: - crowdsec_internal: - driver: bridge proxy: external: true diff --git a/crowdsec/metrics-export.sh b/crowdsec/metrics-export.sh deleted file mode 100755 index 14555ce..0000000 --- a/crowdsec/metrics-export.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -# ============================================================ -# crowdsec-metrics-export.sh -# Exporta métricas de CrowdSec a PostgreSQL para Grafana. -# Ejecutar cada 5 minutos via cron. -# ============================================================ -set -euo pipefail - -PG_DSN="postgresql://crowdsec:crowdsec_metrics_2026@crowdsec-postgres:5432/crowdsec" - -# ----------------------------------------------------------- -# 1. Decisiones activas (IPs bloqueadas) -# ----------------------------------------------------------- -docker exec crowdsec cscli decisions list -o json 2>/dev/null | \ - python3 -c " -import sys, json -data = json.load(sys.stdin) -for entry in data: - for d in entry.get('decisions', []): - ip = d.get('value','').replace(chr(39),chr(39)+chr(39)) - scenario = d.get('scenario','').replace(chr(39),chr(39)+chr(39)) - dtype = d.get('type','').replace(chr(39),chr(39)+chr(39)) - origin = d.get('origin','').replace(chr(39),chr(39)+chr(39)) - scope = d.get('scope','').replace(chr(39),chr(39)+chr(39)) - dur = d.get('duration','').replace(chr(39),chr(39)+chr(39)) - print(f'{ip}|{scenario}|{dtype}|{origin}|{scope}|{dur}') -" 2>/dev/null | sort -u > /tmp/cs_decisions.txt - -# Limpiar tabla y re-insertar -docker exec crowdsec-postgres psql "$PG_DSN" -c "DELETE FROM decisions" 2>/dev/null - -DECISION_COUNT=0 -while IFS='|' read -r ip reason action origin scope dur; do - [ -z "$ip" ] && continue - docker exec crowdsec-postgres psql "$PG_DSN" -c " - INSERT INTO decisions (ip, reason, action, origin, scope, duration) - VALUES ('$ip', '$reason', '$action', '$origin', '$scope', '$dur') - " 2>/dev/null || true - DECISION_COUNT=$((DECISION_COUNT + 1)) -done < /tmp/cs_decisions.txt - -# ----------------------------------------------------------- -# 2. Métricas agregadas -# ----------------------------------------------------------- -ALERTS=$(docker exec crowdsec cscli alerts list -o json 2>/dev/null | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo 0) - -docker exec crowdsec-postgres psql "$PG_DSN" -c " - INSERT INTO metrics (metric_name, metric_value, labels) VALUES - ('active_decisions', $DECISION_COUNT, '{}'::jsonb), - ('active_alerts', $ALERTS, '{}'::jsonb) -" 2>/dev/null || true - -echo "$(date '+%Y-%m-%d %H:%M:%S') crowdsec-metrics: $DECISION_COUNT decisions, $ALERTS alerts" - -rm -f /tmp/cs_decisions.txt diff --git a/crowdsec/setup.sh b/crowdsec/setup.sh index d677aa3..3ba9f54 100755 --- a/crowdsec/setup.sh +++ b/crowdsec/setup.sh @@ -92,5 +92,3 @@ echo " 4. El middleware se usa asi: crowdsec-bouncer@file" echo "" echo "Para proteger un servicio, agrega el middleware en sus labels de Traefik:" echo ' traefik.http.routers..middlewares: "crowdsec-bouncer@file"' -echo "" -echo "Dashboard Grafana (requiere Authentik): https://${CROWDSEC_GRAFANA_DOMAIN}" diff --git a/crowdsec/stack.env b/crowdsec/stack.env index 8fc51bf..a1e8dc6 100644 --- a/crowdsec/stack.env +++ b/crowdsec/stack.env @@ -1,7 +1,5 @@ ##### Imágenes ##### CROWDSEC_IMAGE=crowdsecurity/crowdsec:latest -CROWDSEC_POSTGRES_IMAGE=docker.io/library/postgres:16-alpine -GRAFANA_IMAGE=grafana/grafana:latest ##### CrowdSec Engine ##### CROWDSEC_BOUNCER_API_KEY=change-me-to-a-random-64-char-hex @@ -9,26 +7,7 @@ CROWDSEC_FW_BOUNCER_KEY=change-me-to-another-random-64-char-hex CROWDSEC_LOG_LEVEL=info CROWDSEC_LOCAL_API_PORT=8080 -##### Base de datos PostgreSQL (métricas para Grafana) ##### -CROWDSEC_POSTGRES_DB=crowdsec -CROWDSEC_POSTGRES_USER=crowdsec -CROWDSEC_POSTGRES_PASSWORD=change-me -CROWDSEC_POSTGRES_PATH=/opt/crowdsec/postgres - ##### Directorios de datos ##### CROWDSEC_CONFIG_PATH=/opt/crowdsec/config CROWDSEC_DATA_PATH=/opt/crowdsec/data -CROWDSEC_PROMETHEUS_CONFIG=/opt/crowdsec/prometheus -CROWDSEC_PROMETHEUS_PATH=/opt/crowdsec/prometheus-data -CROWDSEC_GRAFANA_PATH=/opt/crowdsec/grafana -CROWDSEC_GRAFANA_PROVISIONING=/opt/crowdsec/grafana/provisioning -CROWDSEC_GRAFANA_DASHBOARDS=/opt/crowdsec/grafana/dashboards TRAEFIK_LOG_PATH=/opt/traefik/logs - -##### Traefik / dominios ##### -TRAEFIK_DOCKER_NETWORK=proxy -CROWDSEC_GRAFANA_DOMAIN=grafana.sherlockhomeless.net -TRAEFIK_ENTRYPOINT_SECURE=websecure -TRAEFIK_CERTRESOLVER=letsencrypt -TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker -TRAEFIK_CROWDSEC_MIDDLEWARE=crowdsec-bouncer@file diff --git a/dozzle/README.md b/dozzle/README.md deleted file mode 100644 index 886dd1c..0000000 --- a/dozzle/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Dozzle - -Stack para desplegar [Dozzle](https://dozzle.dev/) como visor ligero de logs Docker en `dozzle.sherlockhomeless.net`. - -## 🚀 Despliegue con Docker Compose - -Asegurate de tener `dozzle/.env` configurado y despliega: - -```bash -cd dozzle -docker compose --env-file .env up -d -``` - -## ⚙️ Variables importantes - -Edita `dozzle/.env`: - -```env -DOZZLE_DOMAIN=dozzle.sherlockhomeless.net -DOZZLE_DATA_PATH=/opt/dozzle/data -TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker -DOZZLE_ENABLE_ACTIONS=false -DOZZLE_ENABLE_SHELL=false -``` - -## 📁 Preparación del host - -Crea el directorio persistente antes del primer arranque: - -```bash -mkdir -p /opt/dozzle/data -``` - -## 🔐 Autenticación y acceso - -Dozzle no trae autenticación suficiente para exponerse tal cual a Internet, así que este stack lo publica detrás de Traefik y fuerza el middleware compartido `ths-authentik@docker`. - -La autenticación se resuelve por completo en Traefik + Authentik antes de llegar al contenedor. Dozzle no expone puertos directos al host, así que no queda accesible sin pasar por ese middleware. Se mantienen desactivadas las acciones y el acceso shell para no dar más privilegios de los necesarios sobre `docker.sock`. - -## 🏠 Integración con Homepage - -El servicio publica labels `homepage.*`, así que puede aparecer automáticamente en Homepage dentro del grupo **Observabilidad** como enlace al dominio configurado. Homepage no dispone de un widget nativo para Dozzle, así que aquí solo se expone la tarjeta del servicio. diff --git a/dozzle/docker-compose.yml b/dozzle/docker-compose.yml deleted file mode 100644 index 0d3d41e..0000000 --- a/dozzle/docker-compose.yml +++ /dev/null @@ -1,30 +0,0 @@ -services: - dozzle: - image: ${DOZZLE_IMAGE} - container_name: dozzle - restart: unless-stopped - environment: - TZ: ${TZ} - DOZZLE_NO_ANALYTICS: ${DOZZLE_NO_ANALYTICS} - DOZZLE_ENABLE_ACTIONS: ${DOZZLE_ENABLE_ACTIONS} - DOZZLE_ENABLE_SHELL: ${DOZZLE_ENABLE_SHELL} - volumes: - - ${DOZZLE_DATA_PATH}:/data:Z - - /var/run/docker.sock:/var/run/docker.sock:ro - networks: - - proxy - labels: - prune.protect: "true" - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - homepage.group: "Observabilidad" - homepage.name: "Dozzle" - homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/dozzle.svg" - homepage.description: "Logs en tiempo real de contenedores Docker" - homepage.href: "https://${DOZZLE_DOMAIN}" - homepage.siteMonitor: "http://dozzle:8080/" - homepage.weight: "100" - -networks: - proxy: - external: true diff --git a/dozzle/stack.env b/dozzle/stack.env deleted file mode 100644 index 13bdf09..0000000 --- a/dozzle/stack.env +++ /dev/null @@ -1,13 +0,0 @@ -TZ=Europe/Madrid -DOZZLE_IMAGE=amir20/dozzle:latest -DOZZLE_DOMAIN=dozzle.sherlockhomeless.net -DOZZLE_DATA_PATH=/opt/dozzle/data -DOZZLE_NO_ANALYTICS=true -DOZZLE_ENABLE_ACTIONS=false -DOZZLE_ENABLE_SHELL=false -TRAEFIK_DOCKER_NETWORK=proxy -TRAEFIK_ENTRYPOINT_SECURE=websecure -TRAEFIK_CERTRESOLVER=letsencrypt -TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker -SERVICE_URL_DOZZLE=https://dozzle.sherlockhomeless.net -SERVICE_FQDN_DOZZLE=dozzle.sherlockhomeless.net diff --git a/finance/README.md b/finance/README.md deleted file mode 100644 index a1901c2..0000000 --- a/finance/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Actual Budget - -Actual Budget published at `https://finance.sherlockhomeless.net`. - -## Qué hace y cómo funciona - -Actual Budget permite administrar presupuesto personal con un modelo local-first y sincronización mediante el servidor. Los datos del servidor se guardan en `ACTUALBUDGET_DATA_PATH`; no hay base de datos separada. - -## Configuración - -- `ACTUALBUDGET_DOMAIN` define el dominio publicado. -- `ACTUALBUDGET_IMAGE` controla la versión que se despliega. -- `ACTUALBUDGET_DATA_PATH` debe incluirse en backups y tener permisos de escritura. -- La red interna aísla el servicio y `proxy` permite a Traefik alcanzarlo. -- El router externo aplica CrowdSec, Authentik y Sablier. Authentik protege el acceso al servidor, pero no sustituye las credenciales/cifrado que configure Actual Budget. - -## Despliegue - -```bash -docker compose --env-file .env config -docker compose --env-file .env up -d -``` - -The public route is defined in Traefik dynamic config and protected by: - -- `crowdsec-bouncer@file` -- `ths-authentik@docker` -- `sablier-actualbudget@file` diff --git a/finance/docker-compose.yml b/finance/docker-compose.yml deleted file mode 100644 index ccd3f80..0000000 --- a/finance/docker-compose.yml +++ /dev/null @@ -1,31 +0,0 @@ -services: - actualbudget: - image: ${ACTUALBUDGET_IMAGE} - container_name: actualbudget - restart: unless-stopped - environment: - TZ: ${TZ} - volumes: - - ${ACTUALBUDGET_DATA_PATH}:/data:Z - networks: - - finance_internal - - proxy - labels: - prune.protect: "true" - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - homepage.group: "Personal" - homepage.name: "Finance" - homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/actual-budget.svg" - homepage.description: "Presupuesto personal" - homepage.href: "https://${ACTUALBUDGET_DOMAIN}/" - homepage.siteMonitor: "http://actualbudget:5006/" - homepage.weight: "520" - -networks: - finance_internal: - driver: bridge - labels: - prune.protect: "true" - proxy: - external: true diff --git a/ghost-me/.env.example b/ghost-me/.env.example deleted file mode 100644 index 549b125..0000000 --- a/ghost-me/.env.example +++ /dev/null @@ -1,19 +0,0 @@ -TZ=Europe/Madrid - -GHOST_ME_IMAGE=ghost:6-alpine -GHOST_ME_DOMAIN=me.thehomelesssherlock.com -GHOST_ME_CONTENT_PATH=/opt/ghost-me/content -GHOST_ME_ROUTES_PATH=./routes.yaml - -GHOST_ME_DB_IMAGE=mysql:8.4 -GHOST_ME_DB_DATA_PATH=/opt/ghost-me/mysql -GHOST_ME_DB_NAME=ghost_me -GHOST_ME_DB_USER=ghost_me -GHOST_ME_DB_PASSWORD=change-me -GHOST_ME_DB_ROOT_PASSWORD=change-me - -GHOST_ME_MAIL_FROM="Eduardo Paredes " - -TRAEFIK_DOCKER_NETWORK=proxy -TRAEFIK_ENTRYPOINT_SECURE=websecure -TRAEFIK_CERTRESOLVER=letsencrypt diff --git a/ghost-me/README.md b/ghost-me/README.md deleted file mode 100644 index 9cd01b9..0000000 --- a/ghost-me/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Ghost Me - -Ghost publication for the personal site currently exposed as: - -- `https://me.thehomelesssherlock.com` - -## Qué hace y arquitectura - -Es el sitio personal y portfolio. `ghost-me-db` conserva contenido en MySQL y `ghost-me` sirve Ghost con el tema local `theme-source-personal`. `routes.yaml` separa inicio, blog y proyectos mediante colecciones y etiquetas. - -## Configuración - -- `GHOST_ME_DOMAIN` es el dominio canónico; `GHOST_ME_DOMAIN_ALT` redirige permanentemente al principal. -- `GHOST_ME_DB_*` configura MySQL y debe permanecer sólo en `.env`. -- `GHOST_ME_CONTENT_PATH` conserva uploads y configuración de Ghost. -- `GHOST_ME_ROUTES_PATH` monta las rutas de contenido y debe apuntar a `./routes.yaml`. -- `GHOST_ME_MAIL_FROM` y `mail_internal` permiten correo mediante `mail-relay`. -- El tema se monta desde el repositorio para poder versionarlo; valida sus cambios con `npm test` dentro de `theme-source-personal` antes de actualizarlo. - -La base queda aislada en `ghost_me_internal`; únicamente Ghost se conecta a `proxy` y `mail_internal`. - -## Despliegue - -```bash -docker compose --env-file .env config -docker compose --env-file .env up -d -``` - -Copy `.env.example` to `.env` and keep real secrets only in `.env`. diff --git a/ghost-me/docker-compose.yml b/ghost-me/docker-compose.yml deleted file mode 100644 index 7896644..0000000 --- a/ghost-me/docker-compose.yml +++ /dev/null @@ -1,91 +0,0 @@ -services: - ghost-me-db: - image: ${GHOST_ME_DB_IMAGE} - container_name: ghost-me-db - restart: unless-stopped - labels: - prune.protect: "true" - environment: - MYSQL_ROOT_PASSWORD: ${GHOST_ME_DB_ROOT_PASSWORD} - MYSQL_DATABASE: ${GHOST_ME_DB_NAME} - MYSQL_USER: ${GHOST_ME_DB_USER} - MYSQL_PASSWORD: ${GHOST_ME_DB_PASSWORD} - TZ: ${TZ} - volumes: - - ${GHOST_ME_DB_DATA_PATH}:/var/lib/mysql:Z - healthcheck: - test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u${GHOST_ME_DB_USER} -p${GHOST_ME_DB_PASSWORD} --silent"] - interval: 10s - timeout: 5s - retries: 20 - start_period: 30s - networks: - - ghost_me_internal - - ghost-me: - image: ${GHOST_ME_IMAGE} - container_name: ghost-me - restart: unless-stopped - depends_on: - ghost-me-db: - condition: service_healthy - environment: - NODE_ENV: production - TZ: ${TZ} - url: https://${GHOST_ME_DOMAIN} - database__client: mysql - database__connection__host: ghost-me-db - database__connection__user: ${GHOST_ME_DB_USER} - database__connection__password: ${GHOST_ME_DB_PASSWORD} - database__connection__database: ${GHOST_ME_DB_NAME} - mail__transport: SMTP - mail__from: ${GHOST_ME_MAIL_FROM} - mail__options__host: mail-relay - mail__options__port: 587 - mail__options__secure: "false" - mail__options__ignoreTLS: "true" - volumes: - - ${GHOST_ME_CONTENT_PATH}:/var/lib/ghost/content:Z - - ${GHOST_ME_ROUTES_PATH}:/var/lib/ghost/content/settings/routes.yaml:Z - - ./theme-source-personal:/var/lib/ghost/content/themes/source-personal:Z - networks: - - ghost_me_internal - - proxy - - mail_internal - labels: - prune.protect: "true" - traefik.enable: "true" - traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}" - traefik.http.routers.ghost-me.rule: "Host(`${GHOST_ME_DOMAIN}`)" - traefik.http.routers.ghost-me.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}" - traefik.http.routers.ghost-me.tls: "true" - traefik.http.routers.ghost-me.tls.certresolver: "${TRAEFIK_CERTRESOLVER}" - traefik.http.routers.ghost-me.service: "ghost-me" - traefik.http.routers.ghost-me.middlewares: "crowdsec-bouncer@file" - traefik.http.services.ghost-me.loadbalancer.server.port: "2368" - traefik.http.routers.ghost-me-alt.rule: "Host(`${GHOST_ME_DOMAIN_ALT}`)" - traefik.http.routers.ghost-me-alt.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}" - traefik.http.routers.ghost-me-alt.tls: "true" - traefik.http.routers.ghost-me-alt.tls.certresolver: "${TRAEFIK_CERTRESOLVER}" - traefik.http.routers.ghost-me-alt.service: "ghost-me" - traefik.http.routers.ghost-me-alt.middlewares: "crowdsec-bouncer@file,ghost-me-alt-redirect" - traefik.http.middlewares.ghost-me-alt-redirect.redirectregex.permanent: "true" - traefik.http.middlewares.ghost-me-alt-redirect.redirectregex.regex: "^https://${GHOST_ME_DOMAIN_ALT}(:443)?/(.*)" - traefik.http.middlewares.ghost-me-alt-redirect.redirectregex.replacement: "https://${GHOST_ME_DOMAIN}/$${2}" - homepage.group: "Personal" - homepage.name: "Me" - homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/ghost.svg" - homepage.description: "Sitio personal y CV de Eduardo Paredes" - homepage.href: "https://${GHOST_ME_DOMAIN}/" - homepage.siteMonitor: "http://ghost-me:2368/" - homepage.weight: "140" - -networks: - ghost_me_internal: - driver: bridge - labels: - prune.protect: "true" - mail_internal: - external: true - proxy: - external: true diff --git a/ghost-me/routes.yaml b/ghost-me/routes.yaml deleted file mode 100644 index d66d00f..0000000 --- a/ghost-me/routes.yaml +++ /dev/null @@ -1,18 +0,0 @@ -routes: - /: - data: page.inicio - template: page-inicio - -collections: - /blog/: - permalink: /blog/{slug}/ - template: index - filter: tag:-hash-project - /proyectos/: - permalink: /proyectos/{slug}/ - template: projects - filter: tag:hash-project - -taxonomies: - tag: /tag/{slug}/ - author: /author/{slug}/ diff --git a/ghost-me/theme-source-personal/LICENSE b/ghost-me/theme-source-personal/LICENSE deleted file mode 100644 index d24c76d..0000000 --- a/ghost-me/theme-source-personal/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013-2026 Ghost Foundation - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/ghost-me/theme-source-personal/README.md b/ghost-me/theme-source-personal/README.md deleted file mode 100644 index 05eb458..0000000 --- a/ghost-me/theme-source-personal/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# Source - -The default theme for [Ghost](http://github.com/tryghost/ghost/). This is the latest development version of Source! If you're just looking to download the latest release, head over to the [releases](https://github.com/TryGhost/Source/releases) page. - -  - -# First time using a Ghost theme? - -Ghost uses a simple templating language called [Handlebars](http://handlebarsjs.com/) for its themes. - -This theme has lots of code comments to help explain what's going on just by reading the code. Once you feel comfortable with how everything works, we also have full [theme API documentation](https://ghost.org/docs/themes/) which explains every possible Handlebars helper and template. - -**The main files are:** - -- `default.hbs` - The parent template file, which includes your global header/footer -- `home.hbs` - The homepage -- `index.hbs` - The main template to generate a list of posts -- `post.hbs` - The template used to render individual posts -- `page.hbs` - Used for individual pages -- `tag.hbs` - Used for tag archives, eg. "all posts tagged with `news`" -- `author.hbs` - Used for author archives, eg. "all posts written by Jamie" - -One neat trick is that you can also create custom one-off templates by adding the slug of a page to a template file. For example: - -- `page-about.hbs` - Custom template for an `/about/` page -- `tag-news.hbs` - Custom template for `/tag/news/` archive -- `author-ali.hbs` - Custom template for `/author/ali/` archive - - -# Development - -Source styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need [Node](https://nodejs.org/), [Yarn](https://yarnpkg.com/) and [Gulp](https://gulpjs.com) installed globally. After that, from the theme's root directory: - -```bash -# install dependencies -yarn install - -# run development server -yarn dev -``` - -Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/` automatically. - -The `zip` Gulp task packages the theme files into `dist/.zip`, which you can then upload to your site. - -```bash -# create .zip file -yarn zip -``` - -# PostCSS Features Used - -- Autoprefixer - Don't worry about writing browser prefixes of any kind, it's all done automatically with support for the latest 2 major versions of every browser. - - -# SVG Icons - -Source uses inline SVG icons, included via Handlebars partials. You can find all icons inside `/partials/icons`. To use an icon just include the name of the relevant file, eg. To include the SVG icon in `/partials/icons/rss.hbs` - use `{{> "icons/rss"}}`. - -You can add your own SVG icons in the same manner. - -# Translations - -Please see [@TryGhost/Themes/theme-translations/README.md](https://github.com/TryGhost/Themes/blob/main/packages/theme-translations/README.md) for how to build, edit, or contribute translations. - -# Copyright & License - -Copyright (c) 2013-2026 Ghost Foundation - Released under the [MIT license](LICENSE). diff --git a/ghost-me/theme-source-personal/assets/built/screen.css b/ghost-me/theme-source-personal/assets/built/screen.css deleted file mode 100644 index 3e06df5..0000000 --- a/ghost-me/theme-source-personal/assets/built/screen.css +++ /dev/null @@ -1 +0,0 @@ -:root{--color-white:#fff;--color-lighter-gray:rgba(0,0,0,.05);--color-light-gray:#e6e6e6;--color-mid-gray:#ccc;--color-dark-gray:#444;--color-darker-gray:#15171a;--color-black:#000;--color-primary-text:var(--color-darker-gray);--color-secondary-text:rgba(0,0,0,.55);--color-border:rgba(0,0,0,.08);--color-dark-border:rgba(0,0,0,.55);--font-sans:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;--font-serif:"EB Garamond",Georgia,Times,serif;--font-serif-alt:Georgia,Times,serif;--font-mono:"JetBrains Mono",Menlo,Consolas,Monaco,"Liberation Mono","Lucida Console",monospace;--container-width:1320px;--container-gap:clamp(24px,1.7032rem + 1.9355vw,48px);--grid-gap:42px}:is(.gh-navigation,.gh-footer).has-accent-color,:root.has-light-text{--color-lighter-gray:hsla(0,0%,100%,.1);--color-darker-gray:#fff;--color-secondary-text:hsla(0,0%,100%,.64);--color-border:hsla(0,0%,100%,.15);--color-dark-border:hsla(0,0%,100%,.5)}*,:after,:before{box-sizing:border-box}*{margin:0}html{font-size:62.5%}body{line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}canvas,img,picture,svg,video{display:block;height:auto;max-width:100%}iframe{display:block}button,input,select,textarea{font:inherit}h1,h2,h3,h4,h5,h6,p{overflow-wrap:break-word}h1,h2,h3,h4,h5,h6{line-height:1.2}sub,sup{line-height:1}body{background-color:var(--background-color);color:var(--color-primary-text);font-family:var(--gh-font-body,var(--font-sans));font-size:1.6rem}h1,h2,h3,h4,h5,h6{font-family:var(--gh-font-heading,var(--font-sans))}a{color:var(--color-darker-gray);text-decoration:none}a:hover{opacity:.8}.gh-button{align-items:center;background-color:var(--ghost-accent-color);border:0;border-radius:100px;color:var(--color-white);cursor:pointer;display:inline-flex;font-size:1.5rem;font-weight:600;gap:.4em;justify-content:center;letter-spacing:-.004em;line-height:1;padding:.8em 1.4em}.gh-button:hover{opacity:.95}.gh-icon-button{align-items:center;background-color:transparent;border:0;color:var(--color-darker-gray);cursor:pointer;display:inline-flex;height:32px;justify-content:center;outline:none;padding:0;width:32px}.gh-icon-button:hover :is(svg,span){opacity:.8}.gh-icon-button svg{height:20px;width:20px}.gh-form{align-items:center;background-color:var(--color-lighter-gray);border-radius:40px;display:flex;font-size:1.7rem;font-weight:450;height:56px;letter-spacing:-.008em;max-width:560px;position:relative;transition:background-color .2s ease;width:100%}.gh-form.success{pointer-events:none}.gh-form.error{box-shadow:0 0 0 1px red}.gh-form:hover{background-color:rgba(0,0,0,.065)}.gh-footer.has-accent-color .gh-form:hover,.has-light-text .gh-form:hover{background-color:hsla(0,0%,100%,.15)}.gh-form-input{background-color:transparent;border:0;border-radius:40px;font-size:inherit;height:100%;inset:0;letter-spacing:inherit;line-height:1.1;outline:none;padding-inline:26px;position:absolute;transition:.3s ease-in-out;width:100%}.gh-form-input::-moz-placeholder{color:rgba(0,0,0,.3)}.gh-form-input::placeholder,button.gh-form-input{color:rgba(0,0,0,.3)}:is(.has-serif-title,.has-mono-title):not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-form-input,body[class*=" gh-font-heading"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) .gh-form-input,body[class^=gh-font-heading]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) .gh-form-input{padding-inline:20px}.gh-form.gh-form.success .gh-form-input{opacity:.5}.gh-footer.has-accent-color .gh-form-input,.has-light-text .gh-form-input{color:#fff}.gh-footer.has-accent-color .gh-form-input::-moz-placeholder,.has-light-text .gh-form-input::-moz-placeholder{color:hsla(0,0%,100%,.55)}.gh-footer.has-accent-color .gh-form-input::placeholder,.has-light-text .gh-form-input::placeholder,.has-light-text button.gh-form-input{color:hsla(0,0%,100%,.55)}.gh-header.is-classic.has-image .gh-form-input{color:#15171a}.gh-header.is-classic.has-image .gh-form-input::-moz-placeholder{color:rgba(0,0,0,.5)}.gh-header.is-classic.has-image .gh-form-input::placeholder,.gh-header.is-classic.has-image .gh-form>svg,.gh-header.is-classic.has-image button.gh-form-input{color:rgba(0,0,0,.5)}button.gh-form-input{color:var(--color-secondary-text);cursor:pointer;padding-inline-start:56px;text-align:left}:is(.has-serif-title,.has-mono-title):not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) button.gh-form-input,body[class*=" gh-font-heading"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) button.gh-form-input,body[class^=gh-font-heading]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) button.gh-form-input{padding-inline-start:50px}.gh-form .gh-button{font-size:inherit;height:44px;min-width:132px;padding-inline:24px;position:absolute;right:6px}.gh-form>svg{color:var(--color-secondary-text);height:20px;left:22px;position:relative;width:20px}:is(.has-serif-title,.has-mono-title):not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-form>svg{left:16px}.gh-form .gh-button svg{display:none;margin-top:1px;position:absolute}.gh-form .gh-button>span:last-child{display:none}.gh-form:is(.loading,.success) .gh-button>span:first-child{visibility:hidden}.gh-form.loading .gh-button svg:first-of-type{display:block}.gh-form.success .gh-button>span:first-child{display:none}.gh-form.success .gh-button>span:last-child{display:inline}.gh-form [data-members-error]{font-size:1.4rem;line-height:1.4;margin-top:10px;position:absolute;top:100%;width:100%}@media (max-width:576px){.gh-form{font-size:1.6rem}.gh-form .gh-button{min-width:104px;padding-inline:12px}}.gh-viewport{display:flex;flex-direction:column;min-height:100vh;position:relative}.gh-outer{padding:0 max(4vmin,20px)}.gh-outer .gh-outer{padding:0}.gh-inner{margin:0 auto;max-width:var(--container-width);width:100%}.gh-main{flex-grow:1}.gh-canvas,.kg-width-full.kg-content-wide{--main:min(var(--content-width,720px),100% - var(--container-gap) * 2);--wide:minmax(0,calc((var(--container-width, 1200px) - var(--content-width, 720px))/2));--full:minmax(var(--container-gap),1fr);display:grid;grid-template-columns:[full-start] var(--full) [wide-start] var(--wide) [main-start] var(--main) [main-end] var(--wide) [wide-end] var(--full) [full-end]}.gh-canvas>*{grid-column:main}.kg-content-wide>div,.kg-width-wide{grid-column:wide}.kg-width-full{grid-column:full}.gh-navigation{background-color:var(--background-color);color:var(--color-darker-gray);font-size:1.5rem;font-weight:550;height:100px}.gh-navigation :is(.gh-navigation-logo,a:not(.gh-button),.gh-icon-button){color:inherit}.gh-navigation-inner{align-items:center;-moz-column-gap:24px;column-gap:24px;display:grid;grid-auto-flow:row dense;height:100%}.gh-navigation-brand{line-height:1}.gh-navigation-logo{font-family:var(--gh-font-heading,var(--font-sans));font-size:calc(2.4rem*var(--factor, 1));font-weight:725;letter-spacing:-.015em;position:relative;white-space:nowrap}.gh-navigation-logo img{max-height:40px}.gh-navigation-menu{align-items:center;display:flex;gap:24px}.gh-navigation .nav{align-items:center;display:inline-flex;gap:28px;list-style:none;margin:0;padding:0;white-space:nowrap}.gh-navigation .gh-more-toggle{font-size:inherit;margin:0 -6px;position:relative;text-transform:inherit}.gh-navigation .gh-more-toggle svg{height:24px;width:24px}.gh-navigation-actions{align-items:center;background-color:var(--background-color);display:flex;gap:24px;justify-content:flex-end}.gh-navigation.has-accent-color .gh-navigation-actions{background-color:var(--ghost-accent-color)}.gh-navigation-members{align-items:center;display:flex;gap:20px;white-space:nowrap}.gh-navigation-members .gh-button{font-size:inherit;font-weight:600}.gh-search{margin-left:-2px;margin-right:-2px}@media (max-width:767px){.gh-navigation-logo{white-space:normal}.gh-navigation-members{flex-direction:column-reverse;gap:16px;width:100%}.gh-navigation-actions .gh-search{display:none}}@media (min-width:768px){.gh-navigation-brand .gh-search{display:none}.gh-navigation:not(.is-dropdown-loaded) .gh-navigation-menu .nav>li{opacity:0}}.gh-navigation.has-accent-color{background-color:var(--ghost-accent-color)}.gh-navigation.has-accent-color .gh-button{background-color:#fff;color:#15171a}.gh-navigation.is-left-logo .gh-navigation-inner{grid-template-columns:auto 1fr auto}@media (min-width:768px){.gh-navigation.is-left-logo .gh-navigation-logo:not(:has(img)){top:-2px}}@media (min-width:992px){.gh-navigation.is-left-logo .gh-navigation-menu{margin-left:16px;margin-right:100px}}.gh-navigation.is-middle-logo .gh-navigation-inner{grid-template-columns:1fr auto 1fr}.gh-navigation.is-middle-logo .gh-navigation-brand{grid-column-start:2}.gh-navigation.is-middle-logo .gh-navigation-actions{gap:28px}@media (min-width:992px){.gh-navigation.is-middle-logo .gh-navigation-menu{margin-right:64px}}.gh-navigation.is-stacked{height:auto;position:relative}.gh-navigation.is-stacked .gh-navigation-inner{grid-template-columns:1fr auto 1fr}.gh-navigation.is-stacked .gh-navigation-brand{align-items:center;display:flex;grid-column-start:2;grid-row-start:1;min-height:80px}@media (max-width:767px){.gh-navigation.is-stacked .gh-navigation-brand{min-height:unset}}@media (min-width:992px){.gh-navigation.is-stacked .gh-navigation-inner{padding:0}.gh-navigation.is-stacked .gh-navigation-brand{align-items:center;display:flex;height:80px}.gh-navigation.is-stacked .gh-navigation-menu{grid-column:1/4;grid-row-start:2;height:60px;justify-content:center;margin:0 48px}.gh-navigation.is-stacked .gh-navigation-menu:after,.gh-navigation.is-stacked .gh-navigation-menu:before{background-color:var(--color-border);content:"";height:1px;left:0;position:absolute;top:80px;width:100%}.gh-navigation.is-stacked .gh-navigation-menu:after{top:140px}.gh-navigation.is-stacked .gh-navigation-actions{grid-column:1/4;grid-row-start:1;justify-content:space-between}.gh-navigation.is-stacked .gh-navigation-actions .gh-search{display:flex;gap:10px;width:auto}}.gh-dropdown{background-color:#fff;border-radius:5px;box-shadow:0 0 0 1px rgba(0,0,0,.04),0 7px 20px -5px rgba(0,0,0,.15);margin-top:24px;opacity:0;padding:12px 0;position:absolute;right:-16px;text-align:left;top:100%;transform:translate3d(0,6px,0);transition:opacity .3s,transform .2s;visibility:hidden;width:200px;z-index:90}.gh-dropdown.is-left{left:-16px;right:auto}.is-dropdown-mega .gh-dropdown{-moz-column-gap:40px;column-gap:40px;display:grid;grid-auto-flow:column;grid-template-columns:1fr 1fr;padding:20px 32px;width:auto}.is-dropdown-open .gh-dropdown{opacity:1;transform:translateY(0);visibility:visible}.gh-dropdown li a{color:#15171a!important;display:block;line-height:1.5;padding:7px 20px;white-space:normal}.is-dropdown-mega .gh-dropdown li a{padding:8px 0}.gh-burger{align-items:center;display:flex;display:none;justify-content:center;margin-left:4px;margin-right:-7px;position:relative}.gh-burger svg{height:24px;width:24px}.gh-burger svg:last-child,.is-open .gh-burger svg:first-child{display:none}.is-open .gh-burger svg:last-child{display:block}@media (max-width:767px){.gh-burger{display:flex}#gh-navigation{height:64px}#gh-navigation .gh-navigation-inner{gap:48px;grid-template-columns:1fr;grid-template-rows:auto 1fr auto}#gh-navigation .gh-navigation-brand{align-items:center;display:grid;grid-column-start:1;grid-template-columns:1fr auto auto;height:64px}#gh-navigation .gh-navigation-logo{font-size:2.2rem}#gh-navigation .gh-navigation-actions,#gh-navigation .gh-navigation-menu{justify-content:center;opacity:0;position:fixed;visibility:hidden}#gh-navigation .gh-navigation-menu{transform:translateY(0);transition:none}#gh-navigation .nav{align-items:center;gap:20px;line-height:1.4}#gh-navigation .nav a{font-size:1.75rem;font-weight:600;text-transform:none}#gh-navigation .nav li{opacity:0;transform:translateY(-4px)}#gh-navigation .gh-navigation-actions{text-align:center}#gh-navigation :is(.gh-button,a[data-portal=signin]){opacity:0;transform:translateY(8px)}#gh-navigation .gh-button{font-size:1.75rem;text-transform:none;width:100%}#gh-navigation a[data-portal=signin]{font-size:1.75rem}#gh-main{transition:opacity .4s}.is-open#gh-navigation{height:100%;inset:0;overflow-y:scroll;position:fixed;z-index:3999999;-webkit-overflow-scrolling:touch}.is-open#gh-navigation .gh-navigation-actions,.is-open#gh-navigation .gh-navigation-menu{opacity:1;position:static;visibility:visible}.is-open#gh-navigation .nav{display:flex;flex-direction:column}.is-open#gh-navigation .nav li{opacity:1;transform:translateY(0);transition:transform .2s,opacity .2s}.is-open#gh-navigation .gh-navigation-actions{align-items:center;bottom:0;display:inline-flex;flex-direction:column;gap:12px;left:0;padding:var(--container-gap) 0;position:sticky;right:0}.is-open#gh-navigation :is(.gh-button,a[data-portal=signin]){opacity:1;transform:translateY(0);transition:transform .4s,opacity .4s;transition-delay:.2s}.is-open#gh-navigation a[data-portal=signin]{transition-delay:.4s}.is-open#gh-main{opacity:0}}.gh-card{position:relative}.gh-card-link{display:flex;flex-direction:column;gap:20px}.gh-card-link:hover{opacity:1}.gh-card-image{aspect-ratio:16/9;flex-shrink:0;position:relative}.gh-card-image img{height:100%;inset:0;-o-object-fit:cover;object-fit:cover;position:absolute;width:100%}.gh-card-wrapper{flex-grow:1}.gh-card-tag{display:none;font-size:1.2rem;font-weight:500;letter-spacing:.01em;margin-bottom:4px;text-transform:uppercase}.gh-card-title{font-size:calc(1.9rem*var(--factor, 1));font-weight:725;letter-spacing:-.014em;line-height:1.3}.gh-card-link:hover .gh-card-title{opacity:.8}.gh-card-excerpt{display:-webkit-box;font-size:1.45rem;-webkit-line-clamp:2;line-height:1.4;margin-top:8px;overflow-y:hidden;-webkit-box-orient:vertical}.gh-card-meta{align-items:center;color:var(--color-secondary-text);font-size:1.25rem;font-weight:500;letter-spacing:-.004em;line-height:1.4;padding-bottom:1px}.gh-card-meta svg{display:inline-block;height:12px;margin-right:2px;position:relative;top:1px;width:12px}.gh-card-meta:not(:empty){margin-top:8px}.gh-card-author+.gh-card-date:before{content:"—";margin-right:4px}.gh-header{margin-top:40px;position:relative}.gh-header-inner{overflow:hidden;position:relative}.gh-header.is-magazine .gh-header-inner{display:grid;gap:var(--grid-gap);grid-template-columns:repeat(16,1fr)}.gh-header.is-magazine .gh-header-inner>div{display:flex;flex-direction:column;gap:var(--grid-gap);grid-row:1}.gh-header.is-magazine .gh-header-left{grid-column:1/span 4}.gh-header.is-magazine .gh-header-inner>.gh-card{grid-column:5/span 8;position:relative}.gh-header.is-magazine .gh-header-right{grid-column:13/-1}.gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-link{gap:28px}.gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-image{aspect-ratio:1.618033}.gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-tag{display:block;margin-bottom:12px}.gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-title{font-size:clamp(2.8rem,1.36vw + 2.25rem,4rem);font-weight:700;letter-spacing:-.022em;line-height:1.1}.gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-excerpt{font-size:1.8rem;letter-spacing:-.02em;margin-top:clamp(12px,.45vw + 10.18px,16px);max-width:90%}.gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-meta:not(:empty){margin-top:14px}.gh-header.is-magazine :is(.gh-header-left,.gh-header-right) .gh-card:last-child .gh-card-image{display:none}.gh-header.is-magazine .gh-header-inner>div .gh-card-excerpt{display:none}.gh-header.is-magazine .gh-header-inner>.gh-card:after,.gh-header.is-magazine .gh-header-inner>.gh-card:before{background-color:var(--color-border);content:"";height:100%;left:calc(var(--grid-gap)/-2);position:absolute;top:0;width:1px}.gh-header.is-magazine .gh-header-inner>.gh-card:after{left:auto;right:calc(var(--grid-gap)/-2)}.gh-header.is-magazine .gh-header-inner>div .gh-card+.gh-card:before{background-color:var(--color-border);content:"";height:1px;left:0;position:absolute;top:calc(var(--grid-gap)/-2);width:100%}@media (max-width:1199px){.gh-header.is-magazine .gh-header-inner{grid-template-columns:repeat(12,1fr)}.gh-header.is-magazine .gh-header-inner>.gh-card{grid-column:1/span 8}.gh-header.is-magazine .gh-header-left{grid-column:9/-1}.gh-header.is-magazine .gh-header-inner>div.gh-header-right{flex-direction:row;grid-column:1/-1;grid-row:2}.gh-header.is-magazine .gh-header-right .gh-card{flex:1}.gh-header.is-magazine .gh-header-right .gh-card:last-child .gh-card-image{display:block}.gh-header.is-magazine .gh-header-right{position:relative}.gh-header.is-magazine .gh-header-right:before{background-color:var(--color-border);content:"";height:1px;left:0;position:absolute;top:calc(var(--grid-gap)/-2);width:100%}.gh-header.is-magazine .gh-header-right .gh-card:before{display:none}.gh-header.is-magazine .gh-header-right .gh-card:after{background-color:var(--color-border);content:"";height:100%;position:absolute;right:calc(var(--grid-gap)/-2);top:0;width:1px}}@media (max-width:991px){.gh-header.is-magazine .gh-header-left .gh-card:nth-child(2) .gh-card-image{display:none}}@media (max-width:767px){.gh-header.is-magazine .gh-header-inner{display:flex;flex-direction:column;gap:var(--grid-gap)}.gh-header.is-magazine .gh-header-inner>div.gh-header-right{flex-direction:column}.gh-header.is-magazine .gh-card-image{display:block!important}.gh-header.is-magazine .gh-card:before{background-color:var(--color-border);content:"";display:block!important;height:1px;left:0;position:absolute;top:calc(var(--grid-gap)/-2);width:100%}}.gh-header.is-highlight .gh-header-inner{display:grid;gap:var(--grid-gap);grid-template-columns:repeat(16,1fr)}.gh-header.is-highlight .gh-header-left{grid-column:span 8;position:relative}.gh-header.is-highlight .gh-header-left .gh-card{grid-column:span 8;grid-row:span 3}.gh-header.is-highlight .gh-header-left .gh-card .gh-card-link{gap:28px}.gh-header.is-highlight .gh-header-left .gh-card .gh-card-image{aspect-ratio:3/2}.gh-header.is-highlight .gh-header-left .gh-card .gh-card-tag{display:block;margin-bottom:12px}.gh-header.is-highlight .gh-header-left .gh-card .gh-card-title{font-size:clamp(2.8rem,1.36vw + 2.25rem,4rem);font-weight:700;letter-spacing:-.022em;line-height:1.1}.gh-header.is-highlight .gh-header-left .gh-card .gh-card-excerpt{font-size:1.8rem;margin-top:clamp(12px,.45vw + 10.18px,16px)}.gh-header.is-highlight .gh-header-left .gh-card .gh-card-meta:not(:empty){margin-top:12px}.gh-header.is-highlight .gh-header-middle{display:flex;flex-direction:column;gap:var(--grid-gap);grid-column:9/span 4;position:relative}.gh-header.is-highlight .gh-header-middle .gh-card .gh-card-excerpt,.gh-header.is-highlight .gh-header-middle .gh-card:last-child .gh-card-image{display:none}.gh-header.is-highlight .gh-header-right{grid-column:13/-1}.gh-header.is-highlight .gh-featured{margin-top:0;padding:0}.gh-header.is-highlight .gh-featured-feed{display:flex;flex-direction:column}.gh-header.is-highlight .gh-featured-feed .gh-card-title{font-size:clamp(1.4rem,.23vw + 1.31rem,1.6rem)}.gh-header.is-highlight .gh-header-left:after,.gh-header.is-highlight .gh-header-middle:after{background-color:var(--color-border);content:"";height:100%;position:absolute;right:calc(var(--grid-gap)/-2);top:0;width:1px}.gh-header.is-highlight .gh-card:before{background-color:var(--color-border);content:"";height:1px;left:0;position:absolute;top:calc(var(--grid-gap)/-2);width:100%}.gh-header.is-highlight .gh-featured .gh-card:first-child:before{display:none}@media (max-width:1199px){.gh-header.is-highlight .gh-header-inner{grid-template-columns:repeat(9,1fr)}.gh-header.is-highlight .gh-header-left{grid-column:span 6}.gh-header.is-highlight .gh-header-middle{grid-column:7/-1}.gh-header.is-highlight .gh-header-right{grid-column:1/-1}.gh-header.is-highlight .gh-featured-feed{display:grid;grid-template-columns:repeat(3,1fr)}.gh-header.is-highlight .gh-featured-feed .gh-card:before{width:calc(100% + var(--grid-gap))}.gh-header.is-highlight .gh-featured-feed .gh-card:after{background-color:var(--color-border);content:"";height:100%;left:calc(var(--grid-gap)/-2);position:absolute;top:0;width:1px}}@media (max-width:991px){.gh-header.is-highlight .gh-header-middle .gh-card:nth-child(2) .gh-card-image{display:none}}@media (max-width:767px){.gh-header.is-highlight .gh-header-inner{display:flex;flex-direction:column}.gh-header.is-highlight .gh-featured-feed{display:flex}.gh-header.is-highlight .gh-card-image{display:block!important}.gh-header.is-highlight .gh-header-middle .gh-card .gh-card-excerpt{display:-webkit-box}}.gh-header.is-classic{display:flex;margin-top:0;padding-block:160px}.gh-header.is-classic .gh-header-inner{align-items:center;display:flex;flex-direction:column;gap:48px;margin:auto;max-width:1020px;overflow:unset;text-align:center}.gh-header.is-classic .gh-header-title{font-size:calc(clamp(3rem, 1.82vw + 2.27rem, 4.6rem)*var(--factor, 1));letter-spacing:-.028em;line-height:1.1}.gh-header.is-classic.has-image{margin-top:0}.gh-header.is-classic.has-image:before{background-color:var(--color-black);content:"";inset:0;opacity:.3;position:absolute;transition:opacity 1.5s ease}.gh-header.is-classic.has-image .gh-header-inner{color:#fff}.gh-header.is-classic.has-image .gh-header-image{height:100%;inset:0;-o-object-fit:cover;object-fit:cover;position:absolute;width:100%;z-index:-1}.gh-header.is-classic.has-image .gh-form{background-color:#fff}.gh-cta{display:none;margin-top:max(4vw,40px)}.gh-header:is(.is-highlight,.is-magazine)+.gh-cta{display:block}.gh-cta-inner{align-items:center;background-color:var(--color-lighter-gray);display:flex;flex-direction:column;gap:36px;overflow:hidden;padding:clamp(48px,3.64vw + 33.45px,80px) clamp(40px,2.73vw + 29.09px,64px);position:relative;text-align:center}.gh-cta-content{max-width:640px}.gh-cta-title{font-size:clamp(2.8rem,1.36vw + 2.25rem,4rem);font-weight:700;letter-spacing:-.021em;line-height:1.1}.gh-cta-description{font-size:1.8rem;letter-spacing:-.015em;line-height:1.4;margin-top:12px}.gh-featured{margin-top:100px}.gh-navigation+.gh-featured{margin-top:64px}.gh-header.is-classic:not(.has-image)+.gh-featured{margin-top:0}.gh-featured-inner{overflow:hidden}.gh-featured-title{border-bottom:1px solid var(--color-border);font-size:1.2rem;font-weight:550;letter-spacing:.025em;margin-bottom:20px;padding-bottom:12px;text-transform:uppercase}.gh-featured-feed{display:grid;gap:var(--grid-gap);grid-template-columns:repeat(4,1fr)}.gh-featured-feed .gh-card{container-name:featured-card;container-type:inline-size}.gh-featured-feed .gh-card-link{align-items:flex-start;display:flex;flex-direction:row-reverse}.gh-featured-feed .gh-card-image{aspect-ratio:1;width:72px}@container featured-card (width < 240px){.gh-featured-feed .gh-card-image{display:none}}@container featured-card (240px <= width <= 270px){.gh-featured-feed .gh-card-image{width:64px}}.gh-featured-feed .gh-card-wrapper{container-name:featured-card-wrapper;container-type:inline-size}.gh-featured-feed .gh-card-title{font-size:1.6rem;font-weight:650;letter-spacing:-.011em}@container featured-card-wrapper (width < 170px){.gh-featured-feed .gh-card-title{font-size:1.6rem}}.gh-featured-feed .gh-card-excerpt{display:none}.gh-featured-feed .gh-card-meta:not(:empty){margin-top:8px}.gh-featured-feed .gh-card:before{background-color:var(--color-border);content:"";height:100%;left:calc(var(--grid-gap)/-2);position:absolute;top:0;width:1px}@media (max-width:1199px){.gh-viewport>.gh-featured .gh-featured-feed{grid-template-columns:repeat(3,1fr)}.gh-viewport>.gh-featured .gh-featured-feed .gh-card:nth-child(4){display:none}}@media (max-width:767px){.gh-viewport>.gh-featured .gh-featured-feed{display:flex;flex-direction:column}}.gh-container{flex-grow:1;margin-top:64px}.gh-container-inner{-moz-column-gap:var(--grid-gap);column-gap:var(--grid-gap);display:grid;grid-template-columns:repeat(16,1fr)}:is(.gh-featured,.gh-cta)+.gh-container{margin-top:max(4vw,40px)}.gh-header.is-classic:not(.has-image)+.gh-container{margin-top:0}.gh-navigation+.gh-container .gh-container-title,:is(.paged,.tag-template,.author-template) .gh-container:not(.has-sidebar) .gh-container-title{display:none}.gh-more{display:none;font-size:calc(1.9rem*var(--factor, 1));font-weight:725;grid-column:1/-1;letter-spacing:-.014em;margin-top:48px}.gh-container.has-sidebar .gh-more{grid-column:span 12}.home-template .gh-feed:has(>:nth-child(12):last-child)~.gh-more{display:block}.gh-more a{align-items:center;display:flex;gap:4px}.gh-more svg{height:18px;margin-top:-1px;width:18px}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-more svg{margin-top:0}.gh-container.has-sidebar .gh-main{grid-column:1/span 12;position:relative}.gh-container.has-sidebar .gh-sidebar{grid-column:13/-1}.gh-container.has-sidebar .gh-main:after{background-color:var(--color-border);content:"";height:100%;position:absolute;right:calc(var(--grid-gap)/-2);top:0;width:1px}.gh-container:not(.has-sidebar) :is(.gh-container-title,.gh-main,.gh-more){grid-column:3/span 12}.gh-container.is-list.no-image:not(.has-sidebar) :is(.gh-container-title,.gh-main,.gh-more){grid-column:4/span 10}.gh-header:is(.is-highlight,.is-magazine)~.gh-container.is-grid:not(.has-sidebar) :is(.gh-container-title,.gh-main,.gh-more){grid-column:1/-1}@media (max-width:1199px){.gh-container-inner{display:block;overflow:hidden}.gh-container.has-sidebar .gh-sidebar{display:none}}.gh-container-title{border-bottom:1px solid var(--color-border);font-size:1.2rem;font-weight:550;grid-column:1/-1;letter-spacing:.025em;margin-bottom:calc(var(--grid-gap)/2);padding-bottom:12px;text-transform:uppercase}.gh-container:not(:has(.gh-card)) .gh-container-title{display:none}.gh-container .gh-feed{gap:var(--grid-gap)}.gh-container .gh-card-meta:not(:empty){margin-top:12px}.gh-container.is-list .gh-feed{container-name:list-feed;container-type:inline-size;display:flex;flex-direction:column}.gh-container.is-list .gh-card-link{align-items:center;flex-direction:row;gap:24px}.gh-container.is-list .no-image .gh-card-link{padding-block:20px}.gh-container.is-list .gh-card-image{aspect-ratio:1.618033;flex-shrink:0;width:220px}@container list-feed (width < 600px){.gh-container.is-list .gh-card-image{width:160px}}.gh-container.is-list .gh-card:not(.no-image) .gh-card-wrapper{max-width:600px}.gh-container.is-list .gh-card-title{--factor:1.05}.gh-container.is-list .no-image .gh-card-title{--factor:1.2}.gh-container.is-list .gh-card-excerpt{margin-top:6px}.gh-container.is-list .gh-card+.gh-card:before{background-color:var(--color-border);content:"";height:1px;left:0;position:absolute;top:calc(var(--grid-gap)/-2);width:100%}.home-template .gh-container.is-list .gh-card:first-child:before{display:none}@media (max-width:767px){.gh-container.is-list .gh-card-link{align-items:flex-start;flex-direction:column}.gh-container.is-list .gh-card-image{width:100%}}.gh-container.is-grid .gh-feed{display:grid;grid-template-columns:repeat(auto-fit,minmax(248px,1fr));overflow:hidden;row-gap:calc(var(--grid-gap)*1.5)}.gh-container.is-grid .gh-card:before{height:1px;right:calc(var(--grid-gap)/-2);top:calc(var(--grid-gap)/-2)}.gh-container.is-grid .gh-card:after,.gh-container.is-grid .gh-card:before{background-color:var(--color-border);content:"";left:calc(var(--grid-gap)/-2);position:absolute}.gh-container.is-grid .gh-card:after{height:100%;top:0;width:1px}@media (max-width:767px){.gh-container.is-grid .gh-feed{grid-template-columns:repeat(2,1fr)}}@media (max-width:576px){.gh-container.is-grid .gh-feed{display:flex;flex-direction:column}}.gh-container.is-list.no-image .gh-card-image{display:none}.gh-sidebar-inner{position:sticky;top:calc(var(--grid-gap)/2)}.gh-sidebar-title{border-bottom:1px solid var(--color-border);font-size:1.2rem;font-weight:550;grid-column:1/-1;letter-spacing:.025em;margin-bottom:calc(var(--grid-gap)/2);padding-bottom:12px;text-transform:uppercase}.gh-about{align-items:center;background-color:var(--color-lighter-gray);display:flex;flex-direction:column;justify-content:center;min-height:380px;padding:48px 24px;text-align:center}.gh-about-icon{border-radius:50%;height:60px;margin-bottom:24px;width:60px}.gh-about-title{font-size:calc(2.4rem*var(--factor, 1));font-weight:700;letter-spacing:-.019em}.gh-about-description{font-size:1.45rem;line-height:1.4;margin-top:12px}.gh-about .gh-button{margin-top:32px}.gh-recommendations{margin-top:48px}.gh-recommendations .recommendations{display:flex;flex-direction:column;gap:26px;list-style-type:none;margin:0;padding:0}.gh-recommendations .recommendation:first-child{margin-top:4px}.gh-recommendations .recommendation a{display:grid;gap:4px 12px;grid-template-columns:24px auto}.gh-recommendations .recommendation a:hover{opacity:1}.gh-recommendations .recommendation-favicon{border-radius:4px;grid-row:span 2;width:100%}.gh-recommendations .recommendation-title{font-size:1.5rem;font-weight:650;letter-spacing:-.009em;margin-top:-2px}.gh-recommendations .recommendation a:hover .recommendation-title{opacity:.8}.gh-recommendations .recommendation-url{color:var(--color-secondary-text);font-size:1.4rem;line-height:1.25;order:1;overflow:hidden;text-overflow:ellipsis}.gh-recommendations .recommendation-description{color:var(--color-secondary-text);display:-webkit-box;display:none;font-size:1.4rem;grid-column:2;-webkit-line-clamp:2;line-height:1.4;overflow-y:hidden;-webkit-box-orient:vertical}.gh-recommendations button{align-items:center;background-color:transparent;border:0;color:var(--color-darker-gray);cursor:pointer;display:inline-flex;font-size:1.2rem;font-weight:550;gap:2px;letter-spacing:.025em;margin-top:24px;padding:0;text-transform:uppercase}.gh-recommendations button svg{margin-top:-1px;width:12px}.gh-recommendations button:hover{opacity:.8}.gh-article{--container-width:1120px;word-break:break-word}.gh-article-header{margin:clamp(40px,3.64vw + 25.45px,72px) 0 40px}.gh-article-tag{color:var(--ghost-accent-color);font-size:1.3rem;font-weight:500;letter-spacing:.01em;margin-bottom:12px;text-transform:uppercase}.gh-article-title{font-size:calc(clamp(3.4rem, 1.36vw + 2.85rem, 4.6rem)*var(--factor, 1));letter-spacing:-.022em;line-height:1.1}.gh-article-excerpt{font-size:clamp(1.7rem,.23vw + 1.61rem,1.9rem);letter-spacing:-.018em;line-height:1.45;margin-top:clamp(12px,.45vw + 10.18px,16px);max-width:720px}.gh-article-meta{align-items:center;display:flex;gap:8px;margin-left:6px}.gh-article-author-image{display:flex;margin-right:8px}.gh-article-author-image a{background-color:var(--color-light-gray);border:3px solid var(--background-color);border-radius:50%;height:56px;margin:0 -8px;overflow:hidden;position:relative;width:56px}.gh-article-author-image a:first-child{z-index:10}.gh-article-author-image a:nth-child(2){z-index:9}.gh-article-author-image a:nth-child(3){z-index:8}.gh-article-author-image :is(img,svg){height:100%;inset:0;-o-object-fit:cover;object-fit:cover;position:absolute;width:100%}.gh-article-meta-wrapper{display:flex;flex-direction:column;gap:4px}.gh-article-author-name{font-size:1.6rem;font-weight:650;letter-spacing:-.013em}.gh-article-meta-content{color:var(--color-secondary-text);font-size:1.35rem;font-weight:500;letter-spacing:-.006em;line-height:1.2}.gh-article-image{grid-column:wide;margin-top:40px}.gh-article-image img{width:100%}.page-template .gh-article-header{margin-block:72px 32px}.page-template .gh-content:only-child>:first-child:not(.kg-width-full){margin-top:64px}.page-template .gh-content>:last-child:not(.kg-width-full){margin-bottom:6vw}.page-template .gh-footer{margin-top:0}.gh-content{font-size:var(--content-font-size,1.7rem);letter-spacing:-.01em}.gh-content>*+*{margin-bottom:0;margin-top:calc(28px*var(--content-spacing-factor, 1))}.gh-content>.kg-width-full+.kg-width-full:not(.kg-width-full.kg-card-hascaption+.kg-width-full){margin-top:0}.gh-content>[id]:not(:first-child){margin-top:calc(56px*var(--content-spacing-factor, 1))}.post-template .gh-content.drop-cap>p:first-of-type:first-letter{float:left;font-size:3.1em;font-weight:700;line-height:1;margin:0 .2em 0 -1px}.has-serif-body.post-template:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content.drop-cap>p:first-of-type:first-letter{font-size:3.2em}.gh-content>[id]+p{margin-top:calc(12px*var(--content-spacing-factor, 1))}.gh-content>:is(hr,blockquote,iframe){margin-top:calc(48px*var(--content-spacing-factor, 1))!important;position:relative}.gh-content>:is(hr,blockquote,iframe)+*{margin-top:calc(48px*var(--content-spacing-factor, 1))!important}.gh-content h1{font-size:calc(2.2em*var(--factor, 1));letter-spacing:-.02em}.gh-content h2{font-size:calc(1.6em*var(--factor, 1));letter-spacing:-.02em}.gh-content h3{font-size:calc(1.3em*var(--factor, 1));letter-spacing:-.017em}.gh-content a{color:var(--ghost-accent-color);text-decoration:underline}.gh-content .kg-callout-card .kg-callout-text,.gh-content .kg-toggle-card .kg-toggle-content>:is(ul,ol,p){font-size:.95em}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content .kg-callout-text,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content .kg-toggle-content>ol,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content .kg-toggle-content>p,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content .kg-toggle-content>ul,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content>blockquote,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content>dl,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content>ol,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content>p,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-content>ul{font-family:var(--font-serif-alt)}.gh-content :is(ul,ol){padding-left:28px}.gh-content :is(li+li,li :is(ul,ol)){margin-top:8px}.gh-content ol ol li{list-style-type:lower-alpha}.gh-content ol ol ol li{list-style-type:lower-roman}.gh-content hr{background-color:var(--color-border);border:0;height:1px;width:100%}.gh-content .gh-table{overflow-x:scroll;-webkit-overflow-scrolling:touch}.gh-content .gh-table table{border-collapse:collapse;border-spacing:0;font-family:var(--font-sans);font-size:1.5rem;vertical-align:top;white-space:nowrap;width:100%}.gh-content .gh-table table th{color:var(--color-darkgrey);font-size:1.2rem;font-weight:700;letter-spacing:.2px;text-align:left;text-transform:uppercase}.gh-content .gh-table table :is(th,td),.gh-content .gh-table table td{border-bottom:1px solid var(--color-border);padding:6px 12px}.gh-content .gh-table table :is(th,td):first-child{padding-left:0}.gh-content .gh-table table :is(th,td):last-child{padding-right:0}.gh-content pre{border-radius:6px;font-size:1.5rem;line-height:1.5em;overflow:auto;padding:16px}.gh-content :not(pre)>code,.gh-content pre{background:var(--color-lighter-gray);font-family:var(--font-mono)}.gh-content :not(pre)>code{border-radius:.25em;font-size:.95em;font-weight:400;line-height:1em;padding:.15em .4em;vertical-align:baseline}.gh-content :not(.kg-card):not(table):not([id])+:is(.kg-card,table){margin-top:calc(48px*var(--content-spacing-factor, 1))}.gh-content :is(.kg-card,table)+:not(.kg-card):not(table):not([id]){margin-top:calc(48px*var(--content-spacing-factor, 1))}.gh-content .kg-card.kg-width-full+:not(.kg-card):not([id]),.gh-content :not(.kg-card):not([id])+.kg-card.kg-width-full{margin-top:calc(68px*var(--content-spacing-factor, 1))}.kg-image{margin-left:auto;margin-right:auto}.kg-embed-card{align-items:center;display:flex;flex-direction:column;width:100%}.kg-gallery-image,.kg-image[width][height]{cursor:pointer}.kg-gallery-image a:hover,.kg-image-card a:hover{opacity:1!important}.kg-card.kg-toggle-card .kg-toggle-heading-text{font-size:2rem;font-weight:700}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .kg-toggle-card .kg-toggle-heading-text{font-family:var(--font-serif)}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .kg-toggle-card .kg-toggle-heading-text{font-family:var(--font-mono)}.kg-callout-card.kg-card{border-radius:.25em}.kg-callout-card-accent a{text-decoration:underline}blockquote:not([class]){border-left:4px solid var(--ghost-accent-color);padding-left:2rem}blockquote.kg-blockquote-alt{color:var(--color-secondary-text);font-style:normal;font-weight:400}.kg-card.kg-button-card .kg-btn{font-size:1em;height:unset;line-height:1.2em;padding:.6em 1.2em;text-align:center}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .kg-card.kg-header-card h2.kg-header-card-header{font-family:var(--font-serif)}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .kg-card.kg-header-card h2.kg-header-card-header{font-family:var(--font-mono)}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .kg-header-card h3.kg-header-card-subheader{font-family:var(--font-serif)}.kg-bookmark-card .kg-bookmark-container{border-radius:.25em!important}.kg-bookmark-card .kg-bookmark-container:hover{opacity:1}.kg-bookmark-card a.kg-bookmark-container,.kg-bookmark-card a.kg-bookmark-container:hover{background:var(--background-color)!important;color:var(--color-darker-gray)!important}.kg-bookmark-card .kg-bookmark-content{padding:1.15em}.kg-bookmark-card .kg-bookmark-title{font-size:.9em}.kg-bookmark-card .kg-bookmark-description{font-size:.8em;margin-top:.3em;max-height:none}.kg-bookmark-card .kg-bookmark-metadata{font-size:.8em}.kg-bookmark-card .kg-bookmark-thumbnail img{border-radius:0 .2em .2em 0}.kg-product-card.kg-card .kg-product-card-image{margin-bottom:12px}.kg-product-card.kg-card a.kg-product-card-button{height:2.8em;margin-top:12px}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .kg-product-card.kg-card .kg-product-card-title{font-family:var(--font-serif)}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .kg-product-card.kg-card .kg-product-card-title{font-family:var(--font-mono)}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .kg-product-card-description :is(p,ul,ol){font-family:var(--font-serif-alt)}.kg-file-card.kg-card .kg-file-card-container{padding:.6em}.kg-file-card.kg-card .kg-file-card-contents{margin:4px 8px 6px}.kg-file-card.kg-card .kg-file-card-metadata{font-size:.9em}.kg-file-card.kg-card .kg-file-card-filesize:before{margin-left:6px;margin-right:6px}figcaption{font-size:1.4rem;margin-top:12px;text-align:center}.kg-card.kg-width-full figcaption{padding:0 16px}figcaption a{color:var(--ghost-accent-color);text-decoration:underline}.gh-comments{margin-top:48px}.post-template .gh-container{margin-top:120px}.post-template .gh-container-inner{display:block}.post-template .gh-container.is-grid .gh-feed{grid-template-columns:repeat(4,1fr)}.post-template .gh-container .gh-container-title{display:block}.gh-archive{display:grid;gap:var(--grid-gap);grid-template-columns:repeat(16,1fr);margin-block:80px 24px}.gh-archive.has-image{margin-top:48px}.gh-archive-inner{border-bottom:1px solid var(--color-border);display:grid;gap:var(--grid-gap);grid-column:1/-1;grid-template-columns:1fr 1fr;padding-bottom:clamp(40px,2.73vw + 29.09px,64px)}.gh-archive.has-image .gh-archive-inner{align-items:center;grid-column:1/-1}.gh-archive:not(.has-sidebar):not(.has-image) .gh-archive-inner{grid-column:3/span 12}.gh-archive .gh-article-image{grid-column:auto;margin-top:0}:is(.tag-template,.author-template) .gh-container{margin-top:0}.author-template .gh-archive-inner{display:flex;flex-direction:row-reverse;gap:24px;justify-content:flex-end}.author-template .gh-article-image{border-radius:50%;height:120px;margin-top:0;-o-object-fit:cover;object-fit:cover;width:120px}.author-template .gh-article-title{font-size:3.6rem}.gh-author-meta{color:var(--color-secondary-text);display:flex;font-size:1.5rem;font-weight:550;gap:10px;margin-top:14px}.gh-author-meta a{color:inherit}.gh-author-social{align-items:center;display:flex;gap:16px;padding-left:3px}.gh-author-social svg{height:20px;width:20px}@media (max-width:1199px){.gh-archive{display:block}}@media (max-width:767px){.gh-archive-inner{align-items:flex-start;display:flex}.author-template .gh-archive-inner,.gh-archive-inner{flex-direction:column-reverse}}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]){--factor:1.15}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]){--factor:1.1}.has-sans-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) :is(.is-title,.gh-content :is(h2,h3)){font-family:var(--gh-font-heading,var(--font-sans))}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) :is(.is-title,.gh-content :is(h2,h3)){font-family:var(--gh-font-heading,var(--font-serif));font-weight:550}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) :is(.is-title,.gh-content :is(h2,h3)){font-family:var(--gh-font-heading,var(--font-mono))}.has-sans-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .is-body{font-family:var(--gh-font-body,var(--font-sans))}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .is-body{font-family:var(--gh-font-body,var(--font-serif-alt))}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-header.is-classic .gh-header-title{font-weight:550;letter-spacing:-.015em}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-header.is-classic .gh-header-title{letter-spacing:-.01em}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-form{border-radius:0}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-card-title{font-size:calc(2rem*var(--factor, 1));letter-spacing:-.006em;line-height:1.15}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-featured-feed .gh-card-title{font-size:calc(1.6rem*var(--factor, 1))}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-featured-feed .gh-card-title{font-size:calc(1.5rem*var(--factor, 1));letter-spacing:0}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-header.is-highlight .gh-featured-feed .gh-card-title{font-size:clamp(1.6rem,.23vw + 1.51rem,1.8rem)}.has-mono-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-card-title{font-size:calc(1.8rem*var(--factor, 1));line-height:1.2}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-about-title{letter-spacing:-.009em}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-article-title,.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-footer-signup-header{letter-spacing:-.019em}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]){--content-font-size:1.9rem}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-card-excerpt{font-size:1.65rem;letter-spacing:.0005em;line-height:1.4}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-header.is-highlight .gh-card:first-child .gh-card-excerpt,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-excerpt{font-size:1.8rem;letter-spacing:-.001em}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-header.is-highlight .gh-header-left .gh-card-title,.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-title{font-size:clamp(3.2rem,1.82vw + 2.47rem,4.9rem);font-weight:550}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-about-description{font-size:1.6rem}.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-article-excerpt,.has-serif-body:not([class*=" gh-font-body"]):not([class^=gh-font-body]) .gh-footer-signup-subhead{letter-spacing:0}:is(.has-serif-title,.has-mono-title):not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) :is(.gh-button,.gh-form,.gh-form-input),body[class*=" gh-font-heading"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) :is(.gh-button,.gh-form,.gh-form-input),body[class^=gh-font-heading]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) :is(.gh-button,.gh-form,.gh-form-input){border-radius:0}.has-serif-title:not([class*=" gh-font-heading"]):not([class^=gh-font-heading]) .gh-cta-title{font-size:4.8rem}.gh-footer{color:var(--color-darker-gray);font-size:1.5rem;margin-top:120px}.gh-footer a:not(.gh-button){color:inherit}.gh-footer.has-accent-color{background-color:var(--ghost-accent-color)}.gh-footer.has-accent-color .gh-footer-bar{border-top:0}.gh-footer.has-accent-color .gh-button{background-color:#fff;color:#15171a}.gh-footer-bar{align-items:center;border-block:1px solid var(--color-border);-moz-column-gap:32px;column-gap:32px;display:grid;font-weight:550;grid-template-columns:1fr auto 1fr;margin-bottom:120px;padding-block:28px}.gh-footer-logo{font-family:var(--gh-font-heading,var(--font-sans));font-size:calc(2.4rem*var(--factor, 1));font-weight:725;letter-spacing:-.015em;position:relative;white-space:nowrap}.gh-footer-logo img{max-height:40px}.gh-footer-menu .nav{display:flex;flex-wrap:wrap;gap:8px 28px;justify-content:center;list-style-type:none;margin:0;padding:0}.gh-footer-copyright{text-align:right;white-space:nowrap}.gh-footer-copyright a{text-decoration:underline}.gh-footer-signup{align-items:center;display:flex;flex-direction:column;margin-bottom:120px;text-align:center}.gh-footer-signup-header{font-size:calc(clamp(2.8rem,1.36vw + 2.25rem,4rem)*var(--factor, 1));font-weight:700;letter-spacing:-.03em}.gh-footer-signup-subhead{font-size:1.8rem;font-weight:450;letter-spacing:-.014em;line-height:1.4;margin-top:12px;max-width:640px;opacity:.75}.gh-footer-signup .gh-form{margin-top:40px}@media (max-width:991px){.gh-footer-bar{display:flex;flex-direction:column;gap:20px}}.gh-social-links{display:flex;gap:20px;justify-content:center;margin-bottom:32px}.gh-social-links a{will-change:opacity}.gh-social-links svg{height:20px;width:20px}.pswp{backface-visibility:hidden;display:none;height:100%;left:0;outline:none;overflow:hidden;position:absolute;top:0;touch-action:none;width:100%;z-index:3999999;-webkit-text-size-adjust:100%}.pswp img{max-width:none}.pswp--animate_opacity{opacity:.001;transition:opacity 333ms cubic-bezier(.4,0,.22,1);will-change:opacity}.pswp--open{display:block}.pswp--zoom-allowed .pswp__img{cursor:zoom-in}.pswp--zoomed-in .pswp__img{cursor:grab}.pswp--dragging .pswp__img{cursor:grabbing}.pswp__bg{backface-visibility:hidden;background-color:rgba(0,0,0,.85);opacity:0;transform:translateZ(0);transition:opacity 333ms cubic-bezier(.4,0,.22,1);will-change:opacity}.pswp__bg,.pswp__scroll-wrap{height:100%;left:0;position:absolute;top:0;width:100%}.pswp__scroll-wrap{overflow:hidden}.pswp__container,.pswp__zoom-wrap{backface-visibility:hidden;bottom:0;left:0;position:absolute;right:0;top:0;touch-action:none}.pswp__container,.pswp__img{-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pswp__zoom-wrap{position:absolute;transform-origin:left top;transition:transform 333ms cubic-bezier(.4,0,.22,1);width:100%}.pswp--animated-in .pswp__bg,.pswp--animated-in .pswp__zoom-wrap{transition:none}.pswp__item{bottom:0;overflow:hidden;right:0}.pswp__img,.pswp__item{left:0;position:absolute;top:0}.pswp__img{height:auto;width:auto}.pswp__img--placeholder{backface-visibility:hidden}.pswp__img--placeholder--blank{background:var(--color-black)}.pswp--ie .pswp__img{height:auto!important;left:0;top:0;width:100%!important}.pswp__error-msg{color:var(--color-secondary-text);font-size:14px;left:0;line-height:16px;margin-top:-8px;position:absolute;text-align:center;top:50%;width:100%}.pswp__error-msg a{color:var(--color-secondary-text);text-decoration:underline}.pswp__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;box-shadow:none;cursor:pointer;display:block;float:right;height:44px;margin:0;overflow:visible;padding:0;position:relative;transition:opacity .2s;width:44px}.pswp__button:focus,.pswp__button:hover{opacity:1}.pswp__button:active{opacity:.9;outline:none}.pswp__button::-moz-focus-inner{border:0;padding:0}.pswp__ui--over-close .pswp__button--close{opacity:1}.pswp__button,.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{background:url(../images/default-skin.png) 0 0 no-repeat;background-size:264px 88px;height:44px;width:44px}@media (min-resolution:1.1dppx),(min-resolution:105dpi){.pswp--svg .pswp__button,.pswp--svg .pswp__button--arrow--left:before,.pswp--svg .pswp__button--arrow--right:before{background-image:url(../images/default-skin.svg)}.pswp--svg .pswp__button--arrow--left,.pswp--svg .pswp__button--arrow--right{background:none}}.pswp__button--close{background-position:0 -44px}.pswp__button--share{background-position:-44px -44px}.pswp__button--fs{display:none}.pswp--supports-fs .pswp__button--fs{display:block}.pswp--fs .pswp__button--fs{background-position:-44px 0}.pswp__button--zoom{background-position:-88px 0;display:none}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__button--zoom{background-position:-132px 0}.pswp--touch .pswp__button--arrow--left,.pswp--touch .pswp__button--arrow--right{visibility:hidden}.pswp__button--arrow--left,.pswp__button--arrow--right{background:none;height:100px;margin-top:-50px;position:absolute;top:50%;width:70px}.pswp__button--arrow--left{left:0}.pswp__button--arrow--right{right:0}.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{content:"";height:30px;position:absolute;top:35px;width:32px}.pswp__button--arrow--left:before{background-position:-138px -44px;left:6px}.pswp__button--arrow--right:before{background-position:-94px -44px;right:6px}.pswp__counter{color:var(--color-white);font-size:11px;font-weight:700;height:44px;left:0;line-height:44px;padding:0 15px;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pswp__caption{bottom:0;left:0;min-height:44px;position:absolute;width:100%}.pswp__caption__center{color:var(--color-white);font-size:11px;line-height:1.6;margin:0 auto;max-width:420px;padding:25px 15px 30px;text-align:center}.pswp__caption__center .post-caption-title{font-size:15px;font-weight:500;margin-bottom:7px;text-transform:uppercase}.pswp__caption__center .post-caption-meta-item+.post-caption-meta-item:before{content:"\02022";padding:0 4px}.pswp__caption--empty{display:none}.pswp__caption--fake{visibility:hidden}.pswp__preloader{direction:ltr;height:44px;left:50%;margin-left:-22px;opacity:0;position:absolute;top:0;transition:opacity .25s ease-out;width:44px;will-change:opacity}.pswp__preloader__icn{height:20px;margin:12px;width:20px}.pswp__preloader--active{opacity:1}.pswp__preloader--active .pswp__preloader__icn{background:url(../images/preloader.gif) 0 0 no-repeat}.pswp--css_animation .pswp__preloader--active{opacity:1}.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn{animation:clockwise .5s linear infinite}.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut{animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite}.pswp--css_animation .pswp__preloader__icn{background:none;height:14px;left:15px;margin:0;opacity:.75;position:absolute;top:15px;width:14px}.pswp--css_animation .pswp__preloader__cut{height:14px;overflow:hidden;position:relative;width:7px}.pswp--css_animation .pswp__preloader__donut{background:none;border-bottom:2px solid transparent;border-left:2px solid transparent;border-radius:50%;border-right:2px solid var(--color-white);border-top:2px solid var(--color-white);box-sizing:border-box;height:14px;left:0;margin:0;position:absolute;top:0;width:14px}@media screen and (max-width:1024px){.pswp__preloader{float:right;left:auto;margin:0;position:relative;top:auto}}@keyframes clockwise{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes donut-rotate{0%{transform:rotate(0)}50%{transform:rotate(-140deg)}to{transform:rotate(0)}}.pswp__ui{opacity:1;visibility:visible;z-index:1550;-webkit-font-smoothing:auto}.pswp__top-bar{height:44px;left:0;position:absolute;top:0;width:100%}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right,.pswp__caption,.pswp__top-bar{backface-visibility:hidden;transition:opacity 333ms cubic-bezier(.4,0,.22,1);will-change:opacity}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right{visibility:visible}.pswp__ui--idle .pswp__button--arrow--left,.pswp__ui--idle .pswp__button--arrow--right,.pswp__ui--idle .pswp__top-bar{opacity:0}.pswp__ui--hidden .pswp__button--arrow--left,.pswp__ui--hidden .pswp__button--arrow--right,.pswp__ui--hidden .pswp__caption,.pswp__ui--hidden .pswp__top-bar{opacity:.001}.pswp__ui--one-slide .pswp__button--arrow--left,.pswp__ui--one-slide .pswp__button--arrow--right,.pswp__ui--one-slide .pswp__counter{display:none}.pswp__element--disabled{display:none!important}.pswp--minimal--dark .pswp__top-bar{background:none}.gh-meta-share{align-items:center;display:flex;justify-content:space-between;margin-top:20px}.has-light-text .gh-button-share{border-color:hsla(0,0%,100%,.25);color:hsla(0,0%,100%,.85)}.has-light-text .gh-button-share:hover{border-color:hsla(0,0%,100%,.85)}.gh-button-share{align-items:center;background:transparent;border:1px solid rgba(0,0,0,.15);border-radius:999px;color:rgba(0,0,0,.85);cursor:pointer;display:inline-flex;transition:all .4s ease}.gh-button-share:hover{border-color:rgba(0,0,0,.5)}/*# sourceMappingURL=screen.css.map */ diff --git a/ghost-me/theme-source-personal/assets/built/screen.css.map b/ghost-me/theme-source-personal/assets/built/screen.css.map deleted file mode 100644 index 7ec5cee..0000000 --- a/ghost-me/theme-source-personal/assets/built/screen.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["screen.css"],"names":[],"mappings":"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","file":"screen.css","sourcesContent":["/* Table of contents\n/* ------------------------------------------------------------\n\nThis is a development CSS file which is built to a minified\nproduction stylesheet in assets/built/screen.css\n\n1. Variables\n2. Fonts\n3. Resets\n4. Globals\n5. Layout\n6. Navigation\n 6.1. Navigation styles\n 6.2. Navigation layouts\n 6.3. Dropdown menu\n 6.4. Mobile menu\n7. Card\n8. Header\n 8.1. Magazine layout\n 8.2. Highlight layout\n 8.3. Classic layout\n9. CTA\n10. Featured posts\n11. Container\n 11.1. With sidebar\n 11.2. Without sidebar\n12. Post list\n 12.1. List style\n 12.2. Grid style\n 12.3. No image list\n13. Sidebar\n14. Post/page\n 14.1. Article\n 14.2. Page template\n 14.3. Page without header\n15. Content\n16. Cards\n17. Comments\n18. Recent posts\n19. Archive\n20. Design settings\n21. Footer\n 21.1. Footer styles\n 21.2. Footer bar\n 21.3. Footer signup\n 21.4. Social links\n22. Lightbox\n\n*/\n\n/* 1. Variables\n/* ---------------------------------------------------------- */\n\n:root {\n --color-white: #fff;\n --color-lighter-gray: rgb(0 0 0 / 0.05);\n --color-light-gray: #e6e6e6;\n --color-mid-gray: #ccc;\n --color-dark-gray: #444;\n --color-darker-gray: #15171a;\n --color-black: #000;\n --color-primary-text: var(--color-darker-gray);\n --color-secondary-text: rgb(0 0 0 / 0.55);\n --color-border: rgb(0 0 0 / 0.08);\n --color-dark-border: rgb(0 0 0 / 0.55);\n --font-sans: Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n --font-serif: \"EB Garamond\", Georgia, Times, serif;\n --font-serif-alt: Georgia, Times, serif;\n --font-mono: \"JetBrains Mono\", Menlo, Consolas, Monaco, \"Liberation Mono\", \"Lucida Console\", monospace;\n --container-width: 1320px;\n --container-gap: clamp(24px, 1.7032rem + 1.9355vw, 48px);\n --grid-gap: 42px;\n}\n\n:root.has-light-text,\n:is(.gh-navigation, .gh-footer).has-accent-color {\n --color-lighter-gray: rgb(255 255 255 / 0.1);\n --color-darker-gray: #fff;\n --color-secondary-text: rgb(255 255 255 / 0.64);\n --color-border: rgb(255 255 255 / 0.15);\n --color-dark-border: rgb(255 255 255 / 0.5);\n}\n\n/* 2. Fonts\n/* ---------------------------------------------------------- */\n\n/* Fonts are preloaded and defined in default.hbs to avoid layout shift */\n\n/* 3. Resets\n/* ---------------------------------------------------------- */\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n\n* {\n margin: 0;\n}\n\nhtml {\n font-size: 62.5%;\n}\n\nbody {\n line-height: 1.6;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nimg, picture, video, canvas, svg {\n display: block;\n height: auto;\n max-width: 100%;\n}\n\niframe {\n display: block;\n}\n\ninput, button, textarea, select {\n font: inherit;\n}\n\np, h1, h2, h3, h4, h5, h6 {\n overflow-wrap: break-word;\n}\n\nh1, h2, h3, h4, h5, h6 {\n line-height: 1.2;\n}\n\nsub, sup {\n line-height: 1;\n}\n\n/* 4. Globals\n/* ---------------------------------------------------------- */\n\nbody {\n font-family: var(--gh-font-body, var(--font-sans));\n font-size: 1.6rem;\n background-color: var(--background-color);\n color: var(--color-primary-text);\n}\n\nh1, h2, h3, h4, h5, h6 {\n font-family: var(--gh-font-heading, var(--font-sans));\n}\n\na {\n color: var(--color-darker-gray);\n text-decoration: none;\n}\n\na:hover {\n opacity: 0.8;\n}\n\n.gh-button {\n display: inline-flex;\n gap: 0.4em;\n align-items: center;\n justify-content: center;\n padding: 0.8em 1.4em;\n font-size: 1.5rem;\n font-weight: 600;\n letter-spacing: -0.004em;\n line-height: 1;\n color: var(--color-white);\n cursor: pointer;\n background-color: var(--ghost-accent-color);\n border: 0;\n border-radius: 100px;\n}\n\n.gh-button:hover {\n opacity: 0.95;\n}\n\n.gh-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n color: var(--color-darker-gray);\n cursor: pointer;\n background-color: transparent;\n border: 0;\n outline: none;\n}\n\n.gh-icon-button:hover :is(svg, span) {\n opacity: 0.8;\n}\n\n.gh-icon-button svg {\n width: 20px;\n height: 20px;\n}\n\n.gh-form {\n display: flex;\n align-items: center;\n position: relative;\n max-width: 560px;\n width: 100%;\n height: 56px;\n font-size: 1.7rem;\n font-weight: 450;\n letter-spacing: -0.008em;\n border-radius: 40px;\n background-color: var(--color-lighter-gray);\n transition: background-color 0.2s ease;\n}\n\n.gh-form.success {\n pointer-events: none;\n}\n\n.gh-form.error {\n box-shadow: 0 0 0 1px red;\n}\n\n.gh-form:hover {\n background-color: rgb(0 0 0 / 0.065);\n}\n\n.has-light-text .gh-form:hover,\n.gh-footer.has-accent-color .gh-form:hover {\n background-color: rgb(255 255 255 / 0.15);\n}\n\n.gh-form-input {\n position: absolute;\n inset: 0;\n padding-inline: 26px;\n width: 100%;\n height: 100%;\n font-size: inherit;\n letter-spacing: inherit;\n line-height: 1.1;\n border: 0;\n border-radius: 40px;\n background-color: transparent;\n outline: none;\n transition: 0.3s ease-in-out;\n}\n\n.gh-form-input::placeholder,\nbutton.gh-form-input {\n color: rgb(0 0 0 / 0.3);\n}\n\n:is(.has-serif-title, .has-mono-title):not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-form-input,\nbody[class*=\" gh-font-heading\"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) .gh-form-input,\nbody[class^=\"gh-font-heading\"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) .gh-form-input {\n padding-inline: 20px;\n}\n\n.gh-form.gh-form.success .gh-form-input {\n opacity: 0.5;\n}\n\n.has-light-text .gh-form-input,\n.gh-footer.has-accent-color .gh-form-input {\n color: #fff;\n}\n\n.has-light-text .gh-form-input::placeholder,\n.has-light-text button.gh-form-input,\n.gh-footer.has-accent-color .gh-form-input::placeholder {\n color: rgb(255 255 255 / 0.55);\n}\n\n.gh-header.is-classic.has-image .gh-form-input {\n color: #15171a;\n}\n\n.gh-header.is-classic.has-image .gh-form-input::placeholder,\n.gh-header.is-classic.has-image button.gh-form-input,\n.gh-header.is-classic.has-image .gh-form > svg {\n color: rgb(0 0 0 / 0.5);\n}\n\nbutton.gh-form-input {\n padding-inline-start: 56px;\n text-align: left;\n color: var(--color-secondary-text);\n cursor: pointer;\n}\n\n:is(.has-serif-title,.has-mono-title):not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) button.gh-form-input,\nbody[class*=\" gh-font-heading\"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) button.gh-form-input,\nbody[class^=\"gh-font-heading\"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) button.gh-form-input {\n padding-inline-start: 50px;\n}\n\n.gh-form .gh-button {\n position: absolute;\n right: 6px;\n min-width: 132px;\n padding-inline: 24px;\n height: 44px;\n font-size: inherit;\n}\n\n.gh-form > svg {\n position: relative;\n left: 22px;\n width: 20px;\n height: 20px;\n color: var(--color-secondary-text);\n}\n\n:is(.has-serif-title,.has-mono-title):not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-form > svg {\n left: 16px;\n}\n\n.gh-form .gh-button svg {\n display: none;\n position: absolute;\n margin-top: 1px;\n}\n\n.gh-form .gh-button > span:last-child {\n display: none;\n}\n\n.gh-form:is(.loading, .success) .gh-button > span:first-child {\n visibility: hidden;\n}\n\n.gh-form.loading .gh-button svg:first-of-type {\n display: block;\n}\n\n.gh-form.success .gh-button > span:first-child {\n display: none;\n}\n\n.gh-form.success .gh-button > span:last-child {\n display: inline;\n}\n\n.gh-form [data-members-error] {\n position: absolute;\n top: 100%;\n margin-top: 10px;\n width: 100%;\n font-size: 1.4rem;\n line-height: 1.4;\n}\n\n@media (max-width: 576px) {\n .gh-form {\n font-size: 1.6rem;\n }\n\n .gh-form .gh-button {\n min-width: 104px;\n padding-inline: 12px;\n }\n}\n\n/* 5. Layout\n/* ---------------------------------------------------------- */\n\n.gh-viewport {\n position: relative;\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n}\n\n.gh-outer {\n padding: 0 max(4vmin, 20px);\n}\n\n.gh-outer .gh-outer {\n padding: 0;\n}\n\n.gh-inner {\n margin: 0 auto;\n max-width: var(--container-width);\n width: 100%;\n}\n\n.gh-main {\n flex-grow: 1;\n}\n\n.gh-canvas,\n.kg-width-full.kg-content-wide {\n --main: min(var(--content-width, 720px), 100% - var(--container-gap) * 2);\n --wide: minmax(0, calc((var(--container-width, 1200px) - var(--content-width, 720px)) / 2));\n --full: minmax(var(--container-gap), 1fr);\n\n display: grid;\n grid-template-columns:\n [full-start] var(--full)\n [wide-start] var(--wide)\n [main-start] var(--main) [main-end]\n var(--wide) [wide-end]\n var(--full) [full-end];\n}\n\n.gh-canvas > * {\n grid-column: main;\n}\n\n.kg-width-wide,\n.kg-content-wide > div {\n grid-column: wide;\n}\n\n.kg-width-full {\n grid-column: full;\n}\n\n/* 6. Navigation\n/* ---------------------------------------------------------- */\n\n.gh-navigation {\n height: 100px;\n font-size: 1.5rem;\n font-weight: 550;\n background-color: var(--background-color);\n color: var(--color-darker-gray);\n}\n\n.gh-navigation :is(.gh-navigation-logo, a:not(.gh-button), .gh-icon-button) {\n color: inherit;\n}\n\n.gh-navigation-inner {\n display: grid;\n grid-auto-flow: row dense;\n column-gap: 24px;\n align-items: center;\n height: 100%;\n}\n\n.gh-navigation-brand {\n line-height: 1;\n}\n\n.gh-navigation-logo {\n position: relative;\n font-family: var(--gh-font-heading, var(--font-sans));\n font-size: calc(2.4rem * var(--factor, 1));\n font-weight: 725;\n letter-spacing: -0.015em;\n white-space: nowrap;\n}\n\n.gh-navigation-logo img {\n max-height: 40px;\n}\n\n.gh-navigation-menu {\n display: flex;\n gap: 24px;\n align-items: center;\n}\n\n.gh-navigation .nav {\n display: inline-flex;\n gap: 28px;\n align-items: center;\n padding: 0;\n margin: 0;\n white-space: nowrap;\n list-style: none;\n}\n\n.gh-navigation .gh-more-toggle {\n position: relative;\n margin: 0 -6px;\n font-size: inherit;\n text-transform: inherit;\n}\n\n.gh-navigation .gh-more-toggle svg {\n width: 24px;\n height: 24px;\n}\n\n.gh-navigation-actions {\n display: flex;\n gap: 24px;\n align-items: center;\n justify-content: flex-end;\n background-color: var(--background-color);\n}\n\n.gh-navigation.has-accent-color .gh-navigation-actions {\n background-color: var(--ghost-accent-color);\n}\n\n.gh-navigation-members {\n display: flex;\n gap: 20px;\n align-items: center;\n white-space: nowrap;\n}\n\n.gh-navigation-members .gh-button {\n font-size: inherit;\n font-weight: 600;\n}\n\n.gh-search {\n margin-right: -2px;\n margin-left: -2px;\n}\n\n@media (max-width: 767px) {\n .gh-navigation-logo {\n white-space: normal;\n }\n\n .gh-navigation-members {\n flex-direction: column-reverse;\n gap: 16px;\n width: 100%;\n }\n\n .gh-navigation-actions .gh-search {\n display: none;\n }\n}\n\n@media (min-width: 768px) {\n .gh-navigation-brand .gh-search {\n display: none;\n }\n\n .gh-navigation:not(.is-dropdown-loaded) .gh-navigation-menu .nav > li {\n opacity: 0;\n }\n}\n\n/* 6.1. Navigation styles */\n\n.gh-navigation.has-accent-color {\n background-color: var(--ghost-accent-color);\n}\n\n.gh-navigation.has-accent-color .gh-button {\n background-color: #fff;\n color: #15171a;\n}\n\n/* 6.2. Navigation layouts */\n\n/*\n======================================================================\nLOGO Home About Collection Author Portal Login Subscribe\n======================================================================\n*/\n\n.gh-navigation.is-left-logo .gh-navigation-inner {\n grid-template-columns: auto 1fr auto;\n}\n\n@media (min-width: 768px) {\n .gh-navigation.is-left-logo .gh-navigation-logo:not(:has(img)) {\n top: -2px;\n }\n}\n\n@media (min-width: 992px) {\n .gh-navigation.is-left-logo .gh-navigation-menu {\n margin-right: 100px;\n margin-left: 16px;\n }\n}\n\n/*\n======================================================================\nHome About Collection LOGO Login Subscribe\n======================================================================\n*/\n\n.gh-navigation.is-middle-logo .gh-navigation-inner {\n grid-template-columns: 1fr auto 1fr;\n}\n\n.gh-navigation.is-middle-logo .gh-navigation-brand {\n grid-column-start: 2;\n}\n\n.gh-navigation.is-middle-logo .gh-navigation-actions {\n gap: 28px;\n}\n\n@media (min-width: 992px) {\n .gh-navigation.is-middle-logo .gh-navigation-menu {\n margin-right: 64px;\n }\n}\n\n/*\n======================================================================\nSearch LOGO Login Subscribe\n Home About Collection Author Portal\n======================================================================\n*/\n\n.gh-navigation.is-stacked {\n position: relative;\n height: auto;\n}\n\n.gh-navigation.is-stacked .gh-navigation-inner {\n grid-template-columns: 1fr auto 1fr;\n}\n\n.gh-navigation.is-stacked .gh-navigation-brand {\n display: flex;\n align-items: center;\n grid-row-start: 1;\n grid-column-start: 2;\n min-height: 80px;\n}\n\n@media (max-width: 767px) {\n .gh-navigation.is-stacked .gh-navigation-brand {\n min-height: unset;\n }\n}\n\n@media (min-width: 992px) {\n .gh-navigation.is-stacked .gh-navigation-inner {\n padding: 0;\n }\n\n .gh-navigation.is-stacked .gh-navigation-brand {\n display: flex;\n align-items: center;\n height: 80px;\n }\n\n .gh-navigation.is-stacked .gh-navigation-menu {\n grid-row-start: 2;\n grid-column: 1 / 4;\n justify-content: center;\n height: 60px;\n margin: 0 48px;\n }\n\n .gh-navigation.is-stacked .gh-navigation-menu::before,\n .gh-navigation.is-stacked .gh-navigation-menu::after {\n position: absolute;\n top: 80px;\n left: 0;\n width: 100%;\n height: 1px;\n content: \"\";\n background-color: var(--color-border);\n }\n\n .gh-navigation.is-stacked .gh-navigation-menu::after {\n top: 140px;\n }\n\n .gh-navigation.is-stacked .gh-navigation-actions {\n grid-row-start: 1;\n grid-column: 1 / 4;\n justify-content: space-between;\n }\n\n .gh-navigation.is-stacked .gh-navigation-actions .gh-search {\n display: flex;\n gap: 10px;\n width: auto;\n }\n}\n\n/* 6.3. Dropdown menu */\n\n.gh-dropdown {\n position: absolute;\n top: 100%;\n right: -16px;\n z-index: 90;\n width: 200px;\n padding: 12px 0;\n margin-top: 24px;\n text-align: left;\n visibility: hidden;\n background-color: #fff;\n border-radius: 5px;\n box-shadow: 0 0 0 1px rgb(0 0 0 / 0.04), 0 7px 20px -5px rgb(0 0 0 / 0.15);\n opacity: 0;\n transition: opacity 0.3s, transform 0.2s;\n transform: translate3d(0, 6px, 0);\n}\n\n.gh-dropdown.is-left {\n right: auto;\n left: -16px;\n}\n\n.is-dropdown-mega .gh-dropdown {\n display: grid;\n grid-template-columns: 1fr 1fr;\n grid-auto-flow: column;\n column-gap: 40px;\n width: auto;\n padding: 20px 32px;\n}\n\n.is-dropdown-open .gh-dropdown {\n visibility: visible;\n opacity: 1;\n transform: translateY(0);\n}\n\n.gh-dropdown li a {\n display: block;\n padding: 7px 20px;\n line-height: 1.5;\n white-space: normal;\n color: #15171a !important;\n}\n\n.is-dropdown-mega .gh-dropdown li a {\n padding: 8px 0;\n}\n\n/* 6.4. Mobile menu */\n\n.gh-burger {\n display: flex;\n justify-content: center;\n align-items: center;\n position: relative;\n display: none;\n margin-right: -7px;\n margin-left: 4px;\n}\n\n.gh-burger svg {\n width: 24px;\n height: 24px;\n}\n\n.gh-burger svg:last-child {\n display: none;\n}\n\n.is-open .gh-burger svg:first-child {\n display: none;\n}\n\n.is-open .gh-burger svg:last-child {\n display: block;\n}\n\n@media (max-width: 767px) {\n .gh-burger {\n display: flex;\n }\n\n #gh-navigation {\n height: 64px;\n }\n\n #gh-navigation .gh-navigation-inner {\n grid-template-rows: auto 1fr auto;\n grid-template-columns: 1fr;\n gap: 48px;\n }\n\n #gh-navigation .gh-navigation-brand {\n display: grid;\n grid-template-columns: 1fr auto auto;\n grid-column-start: 1;\n align-items: center;\n height: 64px;\n }\n\n #gh-navigation .gh-navigation-logo {\n font-size: 2.2rem;\n }\n\n #gh-navigation .gh-navigation-menu,\n #gh-navigation .gh-navigation-actions {\n position: fixed;\n justify-content: center;\n visibility: hidden;\n opacity: 0;\n }\n\n #gh-navigation .gh-navigation-menu {\n transition: none;\n transform: translateY(0);\n }\n\n #gh-navigation .nav {\n gap: 20px;\n align-items: center;\n line-height: 1.4;\n }\n\n #gh-navigation .nav a {\n font-size: 1.75rem;\n font-weight: 600;\n text-transform: none;\n }\n\n #gh-navigation .nav li {\n opacity: 0;\n transform: translateY(-4px);\n }\n\n #gh-navigation .gh-navigation-actions {\n text-align: center;\n }\n\n #gh-navigation :is(.gh-button, a[data-portal=\"signin\"]) {\n opacity: 0;\n transform: translateY(8px);\n }\n\n #gh-navigation .gh-button {\n width: 100%;\n font-size: 1.75rem;\n text-transform: none;\n }\n\n #gh-navigation a[data-portal=\"signin\"] {\n font-size: 1.75rem;\n }\n\n #gh-main {\n transition: opacity 0.4s;\n }\n\n .is-open#gh-navigation {\n position: fixed;\n inset: 0;\n z-index: 3999999;\n height: 100%;\n overflow-y: scroll;\n -webkit-overflow-scrolling: touch;\n }\n\n .is-open#gh-navigation .gh-navigation-menu,\n .is-open#gh-navigation .gh-navigation-actions {\n position: static;\n visibility: visible;\n opacity: 1;\n }\n\n .is-open#gh-navigation .nav {\n display: flex;\n flex-direction: column;\n }\n\n .is-open#gh-navigation .nav li {\n opacity: 1;\n transition: transform 0.2s, opacity 0.2s;\n transform: translateY(0);\n }\n\n .is-open#gh-navigation .gh-navigation-actions {\n position: sticky;\n right: 0;\n bottom: 0;\n left: 0;\n display: inline-flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n padding: var(--container-gap) 0;\n }\n\n .is-open#gh-navigation :is(.gh-button, a[data-portal=\"signin\"]) {\n opacity: 1;\n transition: transform 0.4s, opacity 0.4s;\n transition-delay: 0.2s;\n transform: translateY(0);\n }\n\n .is-open#gh-navigation a[data-portal=\"signin\"] {\n transition-delay: 0.4s;\n }\n\n .is-open#gh-main {\n opacity: 0;\n }\n}\n\n/* 7. Card\n/* ---------------------------------------------------------- */\n\n.gh-card {\n position: relative;\n}\n\n.gh-card-link {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.gh-card-link:hover {\n opacity: 1;\n}\n\n.gh-card-image {\n position: relative;\n flex-shrink: 0;\n aspect-ratio: 16 / 9;\n}\n\n.gh-card-image img {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.gh-card-wrapper {\n flex-grow: 1;\n}\n\n.gh-card-tag {\n display: none;\n margin-bottom: 4px;\n font-size: 1.2rem;\n font-weight: 500;\n letter-spacing: 0.01em;\n text-transform: uppercase;\n}\n\n.gh-card-title {\n font-size: calc(1.9rem * var(--factor, 1));\n font-weight: 725;\n letter-spacing: -0.014em;\n line-height: 1.3;\n}\n\n.gh-card-link:hover .gh-card-title {\n opacity: 0.8;\n}\n\n.gh-card-excerpt {\n display: -webkit-box;\n overflow-y: hidden;\n margin-top: 8px;\n font-size: 1.45rem;\n line-height: 1.4;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.gh-card-meta {\n align-items: center;\n padding-bottom: 1px;\n font-size: 1.25rem;\n font-weight: 500;\n line-height: 1.4;\n letter-spacing: -0.004em;\n color: var(--color-secondary-text);\n}\n\n.gh-card-meta svg {\n position: relative;\n top: 1px;\n display: inline-block;\n width: 12px;\n height: 12px;\n margin-right: 2px;\n}\n\n.gh-card-meta:not(:empty) {\n margin-top: 8px;\n}\n\n.gh-card-author + .gh-card-date::before {\n content: \"—\";\n margin-right: 4px;\n}\n\n/* 8. Header\n/* ---------------------------------------------------------- */\n\n.gh-header {\n position: relative;\n margin-top: 40px;\n}\n\n.gh-header-inner {\n position: relative;\n overflow: hidden;\n}\n\n/* 8.1. Magazine layout */\n\n.gh-header.is-magazine .gh-header-inner {\n display: grid;\n grid-template-columns: repeat(16, 1fr);\n gap: var(--grid-gap);\n}\n\n.gh-header.is-magazine .gh-header-inner > div {\n display: flex;\n flex-direction: column;\n gap: var(--grid-gap);\n grid-row: 1;\n}\n\n.gh-header.is-magazine .gh-header-left {\n grid-column: 1 / span 4;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card {\n position: relative;\n grid-column: 5 / span 8;\n}\n\n.gh-header.is-magazine .gh-header-right {\n grid-column: 13 / -1;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-link {\n gap: 28px;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-image {\n aspect-ratio: 1.618033;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-tag {\n display: block;\n margin-bottom: 12px;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-title {\n font-size: clamp(2.8rem, 1.36vw + 2.25rem, 4rem);\n font-weight: 700;\n line-height: 1.1;\n letter-spacing: -0.022em;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-excerpt {\n margin-top: clamp(12px, 0.45vw + 10.18px, 16px);\n font-size: 1.8rem;\n letter-spacing: -0.02em;\n max-width: 90%;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-meta:not(:empty) {\n margin-top: 14px;\n}\n\n.gh-header.is-magazine :is(.gh-header-left, .gh-header-right) .gh-card:last-child .gh-card-image {\n display: none;\n}\n\n.gh-header.is-magazine .gh-header-inner > div .gh-card-excerpt {\n display: none;\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card::before,\n.gh-header.is-magazine .gh-header-inner > .gh-card::after {\n position: absolute;\n top: 0;\n left: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n}\n\n.gh-header.is-magazine .gh-header-inner > .gh-card::after {\n right: calc(var(--grid-gap) / -2);\n left: auto;\n}\n\n.gh-header.is-magazine .gh-header-inner > div .gh-card + .gh-card::before {\n position: absolute;\n top: calc(var(--grid-gap) / -2);\n left: 0;\n content: \"\";\n width: 100%;\n height: 1px;\n background-color: var(--color-border);\n}\n\n@media (max-width: 1199px) {\n .gh-header.is-magazine .gh-header-inner {\n grid-template-columns: repeat(12, 1fr);\n }\n\n .gh-header.is-magazine .gh-header-inner > .gh-card {\n grid-column: 1 / span 8;\n }\n\n .gh-header.is-magazine .gh-header-left {\n grid-column: 9 / -1;\n }\n\n .gh-header.is-magazine .gh-header-inner > div.gh-header-right {\n grid-column: 1 / -1;\n grid-row: 2;\n flex-direction: row;\n }\n\n .gh-header.is-magazine .gh-header-right .gh-card {\n flex: 1;\n }\n\n .gh-header.is-magazine .gh-header-right .gh-card:last-child .gh-card-image {\n display: block;\n }\n\n .gh-header.is-magazine .gh-header-right {\n position: relative;\n }\n\n .gh-header.is-magazine .gh-header-right::before {\n position: absolute;\n top: calc(var(--grid-gap) / -2);\n left: 0;\n content: \"\";\n width: 100%;\n height: 1px;\n background-color: var(--color-border);\n }\n\n .gh-header.is-magazine .gh-header-right .gh-card::before {\n display: none;\n }\n\n .gh-header.is-magazine .gh-header-right .gh-card::after {\n position: absolute;\n top: 0;\n right: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n }\n}\n\n@media (max-width: 991px) {\n .gh-header.is-magazine .gh-header-left .gh-card:nth-child(2) .gh-card-image {\n display: none;\n }\n}\n\n@media (max-width: 767px) {\n .gh-header.is-magazine .gh-header-inner {\n display: flex;\n flex-direction: column;\n gap: var(--grid-gap);\n }\n\n .gh-header.is-magazine .gh-header-inner > div.gh-header-right {\n flex-direction: column;\n }\n\n .gh-header.is-magazine .gh-card-image {\n display: block !important;\n }\n\n .gh-header.is-magazine .gh-card::before {\n display: block !important;\n position: absolute;\n top: calc(var(--grid-gap) / -2);\n left: 0;\n content: \"\";\n width: 100%;\n height: 1px;\n background-color: var(--color-border);\n }\n}\n\n/* 8.2. Highlight layout */\n\n.gh-header.is-highlight .gh-header-inner {\n display: grid;\n grid-template-columns: repeat(16, 1fr);\n gap: var(--grid-gap);\n}\n\n.gh-header.is-highlight .gh-header-left {\n position: relative;\n grid-column: span 8;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card {\n grid-column: span 8;\n grid-row: span 3;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card .gh-card-link {\n gap: 28px;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card .gh-card-image {\n aspect-ratio: 3 / 2;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card .gh-card-tag {\n display: block;\n margin-bottom: 12px;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card .gh-card-title {\n font-size: clamp(2.8rem, 1.36vw + 2.25rem, 4rem);\n font-weight: 700;\n line-height: 1.1;\n letter-spacing: -0.022em;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card .gh-card-excerpt {\n margin-top: clamp(12px, 0.45vw + 10.18px, 16px);\n font-size: 1.8rem;\n}\n\n.gh-header.is-highlight .gh-header-left .gh-card .gh-card-meta:not(:empty) {\n margin-top: 12px;\n}\n\n.gh-header.is-highlight .gh-header-middle {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: var(--grid-gap);\n grid-column: 9 / span 4;\n}\n\n.gh-header.is-highlight .gh-header-middle .gh-card:last-child .gh-card-image {\n display: none;\n}\n\n.gh-header.is-highlight .gh-header-middle .gh-card .gh-card-excerpt {\n display: none;\n}\n\n.gh-header.is-highlight .gh-header-right {\n grid-column: 13 / -1;\n}\n\n.gh-header.is-highlight .gh-featured {\n margin-top: 0;\n padding: 0;\n}\n\n.gh-header.is-highlight .gh-featured-feed {\n display: flex;\n flex-direction: column;\n}\n\n.gh-header.is-highlight .gh-featured-feed .gh-card-title {\n font-size: clamp(1.4rem, 0.23vw + 1.31rem, 1.6rem);\n}\n\n.gh-header.is-highlight .gh-header-left::after,\n.gh-header.is-highlight .gh-header-middle::after {\n position: absolute;\n top: 0;\n right: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n}\n\n.gh-header.is-highlight .gh-card::before {\n position: absolute;\n top: calc(var(--grid-gap) / -2);\n left: 0;\n content: \"\";\n width: 100%;\n height: 1px;\n background-color: var(--color-border);\n}\n\n.gh-header.is-highlight .gh-featured .gh-card:first-child::before {\n display: none;\n}\n\n@media (max-width: 1199px) {\n .gh-header.is-highlight .gh-header-inner {\n grid-template-columns: repeat(9, 1fr);\n }\n\n .gh-header.is-highlight .gh-header-left {\n grid-column: span 6;\n }\n\n .gh-header.is-highlight .gh-header-middle {\n grid-column: 7 / -1;\n }\n\n .gh-header.is-highlight .gh-header-right {\n grid-column: 1 / -1;\n }\n\n .gh-header.is-highlight .gh-featured-feed {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n }\n\n .gh-header.is-highlight .gh-featured-feed .gh-card:before {\n width: calc(100% + var(--grid-gap));\n }\n\n .gh-header.is-highlight .gh-featured-feed .gh-card::after {\n position: absolute;\n top: 0;\n left: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n }\n}\n\n@media (max-width: 991px) {\n .gh-header.is-highlight .gh-header-middle .gh-card:nth-child(2) .gh-card-image {\n display: none;\n }\n}\n\n@media (max-width: 767px) {\n .gh-header.is-highlight .gh-header-inner {\n display: flex;\n flex-direction: column;\n }\n\n .gh-header.is-highlight .gh-featured-feed {\n display: flex;\n /* gap: var(--grid-gap); */\n }\n\n .gh-header.is-highlight .gh-card-image {\n display: block !important;\n }\n\n .gh-header.is-highlight .gh-header-middle .gh-card .gh-card-excerpt {\n display: -webkit-box;\n }\n}\n\n/* 8.3. Classic layout */\n\n.gh-header.is-classic {\n display: flex;\n margin-top: 0;\n padding-block: 160px;\n}\n\n.gh-header.is-classic .gh-header-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 48px;\n overflow: unset;\n margin: auto;\n max-width: 1020px;\n text-align: center;\n}\n\n.gh-header.is-classic .gh-header-title {\n font-size: calc(clamp(3rem, 1.82vw + 2.27rem, 4.6rem) * var(--factor, 1));\n line-height: 1.1;\n letter-spacing: -0.028em;\n}\n\n.gh-header.is-classic.has-image {\n margin-top: 0;\n}\n\n.gh-header.is-classic.has-image::before {\n position: absolute;\n inset: 0;\n content: \"\";\n opacity: 0.3;\n background-color: var(--color-black);\n transition: opacity 1.5s ease;\n}\n\n.gh-header.is-classic.has-image .gh-header-inner {\n color: #fff;\n}\n\n.gh-header.is-classic.has-image .gh-header-image {\n position: absolute;\n inset: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.gh-header.is-classic.has-image .gh-form {\n background-color: #fff;\n}\n\n/* 9. CTA\n/* ---------------------------------------------------------- */\n\n.gh-cta {\n display: none;\n margin-top: max(4vw, 40px);\n}\n\n.gh-header:is(.is-highlight, .is-magazine) + .gh-cta {\n display: block;\n}\n\n.gh-cta-inner {\n position: relative;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 36px;\n padding: clamp(48px, 3.64vw + 33.45px, 80px) clamp(40px, 2.73vw + 29.09px, 64px);\n text-align: center;\n background-color: var(--color-lighter-gray);\n}\n\n.gh-cta-content {\n max-width: 640px;\n}\n\n.gh-cta-title {\n font-size: clamp(2.8rem,1.36vw + 2.25rem,4rem);\n font-weight: 700;\n line-height: 1.1;\n letter-spacing: -0.021em;\n}\n\n.gh-cta-description {\n margin-top: 12px;\n font-size: 1.8rem;\n line-height: 1.4;\n letter-spacing: -0.015em;\n}\n\n/* 10. Featured posts\n/* ---------------------------------------------------------- */\n\n.gh-featured {\n margin-top: 100px;\n}\n\n.gh-navigation + .gh-featured {\n margin-top: 64px;\n}\n\n.gh-header.is-classic:not(.has-image) + .gh-featured {\n margin-top: 0;\n}\n\n.gh-featured-inner {\n overflow: hidden;\n}\n\n.gh-featured-title {\n margin-bottom: 20px;\n padding-bottom: 12px;\n font-size: 1.2rem;\n font-weight: 550;\n letter-spacing: 0.025em;\n text-transform: uppercase;\n border-bottom: 1px solid var(--color-border);\n}\n\n.gh-featured-feed {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: var(--grid-gap);\n}\n\n.gh-featured-feed .gh-card {\n container-type: inline-size;\n container-name: featured-card;\n}\n\n.gh-featured-feed .gh-card-link {\n display: flex;\n flex-direction: row-reverse;\n align-items: flex-start;\n}\n\n.gh-featured-feed .gh-card-image {\n width: 72px;\n aspect-ratio: 1;\n}\n\n@container featured-card (width < 240px) {\n .gh-featured-feed .gh-card-image {\n display: none;\n }\n}\n\n@container featured-card (240px <= width <= 270px) {\n .gh-featured-feed .gh-card-image {\n width: 64px;\n }\n}\n\n.gh-featured-feed .gh-card-wrapper {\n container-type: inline-size;\n container-name: featured-card-wrapper;\n}\n\n.gh-featured-feed .gh-card-title {\n font-size: 1.6rem;\n font-weight: 650;\n letter-spacing: -0.011em;\n}\n\n@container featured-card-wrapper (width < 170px) {\n .gh-featured-feed .gh-card-title {\n font-size: 1.6rem;\n }\n}\n\n.gh-featured-feed .gh-card-excerpt {\n display: none;\n}\n\n.gh-featured-feed .gh-card-meta:not(:empty) {\n margin-top: 8px;\n}\n\n.gh-featured-feed .gh-card::before {\n position: absolute;\n top: 0;\n left: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n}\n\n@media (max-width: 1199px) {\n .gh-viewport > .gh-featured .gh-featured-feed {\n grid-template-columns: repeat(3, 1fr);\n }\n\n .gh-viewport > .gh-featured .gh-featured-feed .gh-card:nth-child(4) {\n display: none;\n }\n}\n\n@media (max-width: 767px) {\n .gh-viewport > .gh-featured .gh-featured-feed {\n display: flex;\n flex-direction: column;\n }\n}\n\n/* 11. Container\n/* ---------------------------------------------------------- */\n\n.gh-container {\n flex-grow: 1;\n margin-top: 64px;\n}\n\n.gh-container-inner {\n display: grid;\n grid-template-columns: repeat(16, 1fr);\n column-gap: var(--grid-gap);\n}\n\n:is(.gh-featured, .gh-cta) + .gh-container {\n margin-top: max(4vw, 40px);\n}\n\n.gh-header.is-classic:not(.has-image) + .gh-container {\n margin-top: 0;\n}\n\n.gh-navigation + .gh-container .gh-container-title,\n:is(.paged, .tag-template, .author-template) .gh-container:not(.has-sidebar) .gh-container-title {\n display: none;\n}\n\n.gh-more {\n display: none;\n grid-column: 1 / -1;\n margin-top: 48px;\n font-size: calc(1.9rem * var(--factor, 1));\n font-weight: 725;\n letter-spacing: -0.014em;\n}\n\n.gh-container.has-sidebar .gh-more {\n grid-column: span 12;\n}\n\n.home-template .gh-feed:has(> :nth-child(12):last-child) ~ .gh-more {\n display: block;\n}\n\n.gh-more a {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.gh-more svg {\n margin-top: -1px;\n width: 18px;\n height: 18px;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-more svg {\n margin-top: 0;\n}\n\n/* 11.1. With sidebar */\n\n.gh-container.has-sidebar .gh-main {\n grid-column: 1 / span 12;\n position: relative;\n}\n\n.gh-container.has-sidebar .gh-sidebar {\n grid-column: 13 / -1;\n}\n\n.gh-container.has-sidebar .gh-main::after {\n position: absolute;\n top: 0;\n right: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n}\n\n/* 11.2. Without sidebar */\n\n.gh-container:not(.has-sidebar) :is(.gh-container-title, .gh-main, .gh-more) {\n grid-column: 3 / span 12;\n}\n\n.gh-container.is-list.no-image:not(.has-sidebar) :is(.gh-container-title, .gh-main, .gh-more) {\n grid-column: 4 / span 10;\n}\n\n.gh-header:is(.is-highlight, .is-magazine) ~ .gh-container.is-grid:not(.has-sidebar) :is(.gh-container-title, .gh-main, .gh-more) {\n grid-column: 1 / -1;\n}\n\n@media (max-width: 1199px) {\n .gh-container-inner {\n display: block;\n overflow: hidden;\n }\n\n .gh-container.has-sidebar .gh-sidebar {\n display: none;\n }\n}\n\n/* 12. Post list\n/* ---------------------------------------------------------- */\n\n.gh-container-title {\n grid-column: 1 / -1;\n margin-bottom: calc(var(--grid-gap) / 2);\n padding-bottom: 12px;\n font-size: 1.2rem;\n font-weight: 550;\n letter-spacing: 0.025em;\n text-transform: uppercase;\n border-bottom: 1px solid var(--color-border);\n}\n\n.gh-container:not(:has(.gh-card)) .gh-container-title {\n display: none;\n}\n\n.gh-container .gh-feed {\n gap: var(--grid-gap);\n}\n\n.gh-container .gh-card-meta:not(:empty) {\n margin-top: 12px;\n}\n\n/* 12.1. List style */\n\n.gh-container.is-list .gh-feed {\n display: flex;\n flex-direction: column;\n container-type: inline-size;\n container-name: list-feed;\n}\n\n.gh-container.is-list .gh-card-link {\n flex-direction: row;\n align-items: center;\n gap: 24px;\n}\n\n.gh-container.is-list .no-image .gh-card-link {\n padding-block: 20px;\n}\n\n.gh-container.is-list .gh-card-image {\n flex-shrink: 0;\n width: 220px;\n aspect-ratio: 1.618033;\n}\n\n@container list-feed (width < 600px) {\n .gh-container.is-list .gh-card-image {\n width: 160px;\n }\n}\n\n.gh-container.is-list .gh-card:not(.no-image) .gh-card-wrapper {\n max-width: 600px;\n}\n\n.gh-container.is-list .gh-card-title {\n --factor: 1.05;\n}\n\n.gh-container.is-list .no-image .gh-card-title {\n --factor: 1.2;\n}\n\n.gh-container.is-list .gh-card-excerpt {\n margin-top: 6px;\n}\n\n.gh-container.is-list .gh-card + .gh-card::before {\n position: absolute;\n top: calc(var(--grid-gap) / -2);\n left: 0;\n content: \"\";\n width: 100%;\n height: 1px;\n background-color: var(--color-border);\n}\n\n.home-template .gh-container.is-list .gh-card:first-child:before {\n display: none;\n}\n\n@media (max-width: 767px) {\n .gh-container.is-list .gh-card-link {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .gh-container.is-list .gh-card-image {\n width: 100%;\n }\n}\n\n/* 12.2. Grid style */\n\n.gh-container.is-grid .gh-feed {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));\n row-gap: calc(var(--grid-gap) * 1.5);\n overflow: hidden;\n}\n\n.gh-container.is-grid .gh-card::before {\n position: absolute;\n top: calc(var(--grid-gap) / -2);\n right: calc(var(--grid-gap) / -2);\n left: calc(var(--grid-gap) / -2);\n content: \"\";\n height: 1px;\n background-color: var(--color-border);\n}\n\n.gh-container.is-grid .gh-card::after {\n position: absolute;\n top: 0;\n left: calc(var(--grid-gap) / -2);\n content: \"\";\n width: 1px;\n height: 100%;\n background-color: var(--color-border);\n}\n\n@media (max-width: 767px) {\n .gh-container.is-grid .gh-feed {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 576px) {\n .gh-container.is-grid .gh-feed {\n display: flex;\n flex-direction: column;\n }\n}\n\n/* 12.3. No image list */\n\n.gh-container.is-list.no-image .gh-card-image {\n display: none;\n}\n\n/* 13. Sidebar\n/* ---------------------------------------------------------- */\n\n.gh-sidebar-inner {\n position: sticky;\n top: calc(var(--grid-gap) / 2);\n}\n\n.gh-sidebar-title {\n grid-column: 1 / -1;\n margin-bottom: calc(var(--grid-gap) / 2);\n padding-bottom: 12px;\n font-size: 1.2rem;\n font-weight: 550;\n letter-spacing: 0.025em;\n text-transform: uppercase;\n border-bottom: 1px solid var(--color-border);\n}\n\n.gh-about {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n padding: 48px 24px;\n min-height: 380px;\n text-align: center;\n background-color: var(--color-lighter-gray);\n}\n\n.gh-about-icon {\n margin-bottom: 24px;\n width: 60px;\n height: 60px;\n border-radius: 50%;\n}\n\n.gh-about-title {\n font-size: calc(2.4rem * var(--factor, 1));\n font-weight: 700;\n letter-spacing: -0.019em;\n}\n\n.gh-about-description {\n margin-top: 12px;\n font-size: 1.45rem;\n line-height: 1.4;\n}\n\n.gh-about .gh-button {\n margin-top: 32px;\n}\n\n.gh-recommendations {\n margin-top: 48px;\n}\n\n.gh-recommendations .recommendations {\n display: flex;\n flex-direction: column;\n gap: 26px;\n margin: 0;\n padding: 0;\n list-style-type: none;\n}\n\n.gh-recommendations .recommendation:first-child {\n margin-top: 4px;\n}\n\n.gh-recommendations .recommendation a {\n display: grid;\n grid-template-columns: 24px auto;\n gap: 4px 12px;\n}\n\n.gh-recommendations .recommendation a:hover {\n opacity: 1;\n}\n\n.gh-recommendations .recommendation-favicon {\n grid-row: span 2;\n width: 100%;\n border-radius: 4px;\n}\n\n.gh-recommendations .recommendation-title {\n margin-top: -2px;\n font-size: 1.5rem;\n font-weight: 650;\n letter-spacing: -0.009em;\n}\n\n.gh-recommendations .recommendation a:hover .recommendation-title {\n opacity: 0.8;\n}\n\n.gh-recommendations .recommendation-url {\n order: 1;\n overflow: hidden;\n font-size: 1.4rem;\n line-height: 1.25;\n color: var(--color-secondary-text);\n text-overflow: ellipsis;\n}\n\n.gh-recommendations .recommendation-description {\n display: -webkit-box;\n display: none;\n overflow-y: hidden;\n grid-column: 2;\n font-size: 1.4rem;\n line-height: 1.4;\n color: var(--color-secondary-text);\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.gh-recommendations button {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n margin-top: 24px;\n padding: 0;\n cursor: pointer;\n font-size: 1.2rem;\n font-weight: 550;\n letter-spacing: 0.025em;\n text-transform: uppercase;\n background-color: transparent;\n border: 0;\n color: var(--color-darker-gray);\n}\n\n.gh-recommendations button svg {\n margin-top: -1px;\n width: 12px;\n}\n\n.gh-recommendations button:hover {\n opacity: 0.8;\n}\n\n/* 14. Post/page\n/* ---------------------------------------------------------- */\n\n/* 14.1. Article */\n\n.gh-article {\n --container-width: 1120px;\n\n word-break: break-word;\n}\n\n.gh-article-header {\n margin: clamp(40px, 3.64vw + 25.45px, 72px) 0 40px;\n}\n\n.gh-article-tag {\n margin-bottom: 12px;\n font-size: 1.3rem;\n font-weight: 500;\n letter-spacing: 0.01em;\n text-transform: uppercase;\n color: var(--ghost-accent-color);\n}\n\n.gh-article-title {\n font-size: calc(clamp(3.4rem, 1.36vw + 2.85rem, 4.6rem) * var(--factor, 1));\n line-height: 1.1;\n letter-spacing: -0.022em;\n}\n\n.gh-article-excerpt {\n margin-top: clamp(12px, 0.45vw + 10.18px, 16px);\n max-width: 720px;\n font-size: clamp(1.7rem, 0.23vw + 1.61rem, 1.9rem);\n line-height: 1.45;\n letter-spacing: -0.018em;\n}\n\n.gh-article-meta {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: 6px;\n}\n\n.gh-article-author-image {\n display: flex;\n margin-right: 8px;\n}\n\n.gh-article-author-image a {\n position: relative;\n margin: 0 -8px;\n width: 56px;\n height: 56px;\n overflow: hidden;\n background-color: var(--color-light-gray);\n border-radius: 50%;\n border: 3px solid var(--background-color);\n}\n\n.gh-article-author-image a:first-child {\n z-index: 10;\n}\n\n.gh-article-author-image a:nth-child(2) {\n z-index: 9;\n}\n\n.gh-article-author-image a:nth-child(3) {\n z-index: 8;\n}\n\n.gh-article-author-image :is(img, svg) {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.gh-article-meta-wrapper {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.gh-article-author-name {\n font-size: 1.6rem;\n font-weight: 650;\n letter-spacing: -0.013em;\n}\n\n.gh-article-meta-content {\n font-size: 1.35rem;\n font-weight: 500;\n line-height: 1.2;\n letter-spacing: -0.006em;\n color: var(--color-secondary-text);\n}\n\n.gh-article-image {\n grid-column: wide;\n margin-top: 40px;\n}\n\n.gh-article-image img {\n width: 100%;\n}\n\n/* 14.2. Page template */\n\n.page-template .gh-article-header {\n margin-block: 72px 32px;\n}\n\n/* 14.3. Page without header */\n\n.page-template .gh-content:only-child > *:first-child:not(.kg-width-full) {\n margin-top: 64px;\n}\n\n.page-template .gh-content > *:last-child:not(.kg-width-full) {\n margin-bottom: 6vw;\n}\n\n.page-template .gh-footer {\n margin-top: 0;\n}\n\n/* 15. Content\n/* ---------------------------------------------------------- */\n\n/* Content refers to styling all page and post content that is\ncreated within the Ghost editor. The main content handles\nheadings, text, images and lists. We deal with cards lower down. */\n\n.gh-content {\n font-size: var(--content-font-size, 1.7rem);\n letter-spacing: -0.01em;\n}\n\n/* Default vertical spacing */\n.gh-content > * + * {\n margin-top: calc(28px * var(--content-spacing-factor, 1));\n margin-bottom: 0;\n}\n\n/* Remove space between full-width cards */\n.gh-content > .kg-width-full + .kg-width-full:not(.kg-width-full.kg-card-hascaption + .kg-width-full) {\n margin-top: 0;\n}\n\n/* Add back a top margin to all headings,\nunless a heading is the very first element in the post content */\n.gh-content > [id]:not(:first-child) {\n margin-top: calc(56px * var(--content-spacing-factor, 1));\n}\n\n/* Add drop cap setting */\n.post-template .gh-content.drop-cap > p:first-of-type:first-letter {\n margin :0 0.2em 0em 0;\n font-size: 3.1em;\n float:left;\n line-height: 1;\n margin-left: -1px;\n font-weight: 700;\n}\n\n.has-serif-body.post-template:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content.drop-cap > p:first-of-type:first-letter {\n font-size: 3.2em;\n}\n\n/* Add a small margin between a heading and paragraph after it */\n.gh-content > [id] + p {\n margin-top: calc(12px * var(--content-spacing-factor, 1));\n}\n\n/* A larger margin before/after dividers, blockquotes and embeds */\n.gh-content > :is(hr, blockquote, iframe) {\n position: relative;\n margin-top: calc(48px * var(--content-spacing-factor, 1)) !important;\n}\n\n.gh-content > :is(hr, blockquote, iframe) + * {\n margin-top: calc(48px * var(--content-spacing-factor, 1)) !important;\n}\n\n/* Now the content typography styles */\n.gh-content h1 {\n font-size: calc(2.2em * var(--factor, 1));\n letter-spacing: -0.02em;\n}\n\n.gh-content h2 {\n font-size: calc(1.6em * var(--factor, 1));\n letter-spacing: -0.02em;\n}\n\n.gh-content h3 {\n font-size: calc(1.3em * var(--factor, 1));\n letter-spacing: -0.017em;\n}\n\n.gh-content a {\n color: var(--ghost-accent-color);\n text-decoration: underline;\n}\n\n.gh-content .kg-callout-card .kg-callout-text,\n.gh-content .kg-toggle-card .kg-toggle-content > :is(ul, ol, p) {\n font-size: 0.95em;\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content > blockquote,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content > ol,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content > ul,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content > dl,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content > p,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content .kg-callout-text,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content .kg-toggle-content > ol,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content .kg-toggle-content > ul,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-content .kg-toggle-content > p {\n font-family: var(--font-serif-alt);\n}\n\n.gh-content :is(ul, ol) {\n padding-left: 28px;\n}\n\n.gh-content :is(li + li, li :is(ul, ol)) {\n margin-top: 8px;\n}\n\n.gh-content ol ol li {\n list-style-type: lower-alpha;\n}\n\n.gh-content ol ol ol li {\n list-style-type: lower-roman;\n}\n\n.gh-content hr {\n width: 100%;\n height: 1px;\n background-color: var(--color-border);\n border: 0;\n}\n\n.gh-content .gh-table {\n overflow-x: scroll;\n -webkit-overflow-scrolling: touch;\n}\n\n.gh-content .gh-table table {\n width: 100%;\n font-family: var(--font-sans);\n font-size: 1.5rem;\n white-space: nowrap;\n vertical-align: top;\n border-spacing: 0;\n border-collapse: collapse;\n}\n\n.gh-content .gh-table table th {\n font-size: 1.2rem;\n font-weight: 700;\n color: var(--color-darkgrey);\n text-align: left;\n text-transform: uppercase;\n letter-spacing: 0.2px;\n}\n\n.gh-content .gh-table table :is(th, td),\n.gh-content .gh-table table td {\n padding: 6px 12px;\n border-bottom: 1px solid var(--color-border);\n}\n\n.gh-content .gh-table table :is(th, td):first-child {\n padding-left: 0;\n}\n\n.gh-content .gh-table table :is(th, td):last-child {\n padding-right: 0;\n}\n\n.gh-content pre {\n overflow: auto;\n padding: 16px;\n font-size: 1.5rem;\n line-height: 1.5em;\n background: var(--color-lighter-gray);\n border-radius: 6px;\n font-family: var(--font-mono);\n}\n\n.gh-content :not(pre) > code {\n vertical-align: baseline;\n padding: 0.15em 0.4em;\n font-weight: 400;\n font-size: 0.95em;\n line-height: 1em;\n background: var(--color-lighter-gray);\n border-radius: 0.25em;\n font-family: var(--font-mono);\n}\n\n/* 16. Cards\n/* ---------------------------------------------------------- */\n\n/* Add extra margin before/after any cards, except for when immediately preceeded by a heading */\n\n.gh-content :not(.kg-card):not(table):not([id]) + :is(.kg-card, table) {\n margin-top: calc(48px * var(--content-spacing-factor, 1));\n}\n\n.gh-content :is(.kg-card, table) + :not(.kg-card):not(table):not([id]) {\n margin-top: calc(48px * var(--content-spacing-factor, 1));\n}\n\n.gh-content :not(.kg-card):not([id]) + .kg-card.kg-width-full {\n margin-top: calc(68px * var(--content-spacing-factor, 1));\n}\n\n.gh-content .kg-card.kg-width-full + :not(.kg-card):not([id]) {\n margin-top: calc(68px * var(--content-spacing-factor, 1));\n}\n\n/* Image */\n\n.kg-image {\n margin-right: auto;\n margin-left: auto;\n}\n\n/* Embed */\n\n.kg-embed-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n}\n\n/* Gallery */\n\n.kg-image[width][height],\n.kg-gallery-image {\n cursor: pointer;\n}\n\n.kg-image-card a:hover,\n.kg-gallery-image a:hover {\n opacity: 1 !important;\n}\n\n/* Toggle */\n\n.kg-card.kg-toggle-card .kg-toggle-heading-text {\n font-size: 2rem;\n font-weight: 700;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .kg-toggle-card .kg-toggle-heading-text {\n font-family: var(--font-serif);\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .kg-toggle-card .kg-toggle-heading-text {\n font-family: var(--font-mono);\n}\n\n/* Callout */\n\n.kg-callout-card.kg-card {\n border-radius: 0.25em;\n}\n\n.kg-callout-card-accent a {\n text-decoration: underline;\n}\n\n/* Blockquote */\n\nblockquote:not([class]) {\n padding-left: 2rem;\n border-left: 4px solid var(--ghost-accent-color);\n}\n\nblockquote.kg-blockquote-alt {\n font-style: normal;\n font-weight: 400;\n color: var(--color-secondary-text);\n}\n\n/* Button */\n\n.kg-card.kg-button-card .kg-btn {\n height: unset;\n padding: .6em 1.2em;\n text-align: center;\n font-size: 1em;\n line-height: 1.2em;\n}\n\n/* Header */\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .kg-card.kg-header-card h2.kg-header-card-header {\n font-family: var(--font-serif);\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .kg-card.kg-header-card h2.kg-header-card-header {\n font-family: var(--font-mono);\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .kg-header-card h3.kg-header-card-subheader {\n font-family: var(--font-serif);\n}\n\n/* Bookmark */\n\n.kg-bookmark-card .kg-bookmark-container {\n border-radius: 0.25em !important;\n}\n\n.kg-bookmark-card .kg-bookmark-container:hover {\n opacity: 1;\n}\n\n.kg-bookmark-card a.kg-bookmark-container,\n.kg-bookmark-card a.kg-bookmark-container:hover {\n background: var(--background-color) !important;\n color: var(--color-darker-gray) !important;\n}\n\n.kg-bookmark-card .kg-bookmark-content {\n padding: 1.15em;\n}\n\n.kg-bookmark-card .kg-bookmark-title {\n font-size: 0.9em;\n}\n\n.kg-bookmark-card .kg-bookmark-description {\n max-height: none;\n margin-top: 0.3em;\n font-size: 0.8em;\n}\n\n.kg-bookmark-card .kg-bookmark-metadata {\n font-size: 0.8em;\n}\n\n.kg-bookmark-card .kg-bookmark-thumbnail img {\n border-radius: 0 0.2em 0.2em 0;\n}\n\n/* Product */\n\n.kg-product-card.kg-card .kg-product-card-image {\n margin-bottom: 12px;\n}\n\n.kg-product-card.kg-card a.kg-product-card-button {\n height: 2.8em;\n margin-top: 12px;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .kg-product-card.kg-card .kg-product-card-title {\n font-family: var(--font-serif);\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .kg-product-card.kg-card .kg-product-card-title {\n font-family: var(--font-mono);\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .kg-product-card-description :is(p, ul, ol) {\n font-family: var(--font-serif-alt);\n}\n\n/* File */\n\n.kg-file-card.kg-card .kg-file-card-container {\n padding: 0.6em;\n}\n\n.kg-file-card.kg-card .kg-file-card-contents {\n margin: 4px 8px 6px;\n}\n\n.kg-file-card.kg-card .kg-file-card-metadata {\n font-size: 0.9em;\n}\n\n.kg-file-card.kg-card .kg-file-card-filesize::before {\n margin-right: 6px;\n margin-left: 6px;\n}\n\n/* Caption */\n\nfigcaption {\n margin-top: 12px;\n font-size: 1.4rem;\n text-align: center;\n}\n\n.kg-card.kg-width-full figcaption {\n padding: 0 16px;\n}\n\nfigcaption a {\n color: var(--ghost-accent-color);\n text-decoration: underline;\n}\n\n/* 17. Comments\n/* ---------------------------------------------------------- */\n\n.gh-comments {\n margin-top: 48px;\n}\n\n/* 18. Recent posts\n/* ---------------------------------------------------------- */\n\n.post-template .gh-container {\n margin-top: 120px;\n}\n\n.post-template .gh-container-inner {\n display: block;\n}\n\n.post-template .gh-container.is-grid .gh-feed {\n grid-template-columns: repeat(4, 1fr);\n}\n\n.post-template .gh-container .gh-container-title {\n display: block;\n}\n\n/* 19. Archive\n/* ---------------------------------------------------------- */\n\n.gh-archive {\n display: grid;\n grid-template-columns: repeat(16, 1fr);\n gap: var(--grid-gap);\n margin-block: 80px 24px;\n}\n\n.gh-archive.has-image {\n margin-top: 48px;\n}\n\n.gh-archive-inner {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: var(--grid-gap);\n grid-column: 1 / -1;\n padding-bottom: clamp(40px, 2.73vw + 29.09px, 64px);\n border-bottom: 1px solid var(--color-border);\n}\n\n.gh-archive.has-image .gh-archive-inner {\n align-items: center;\n grid-column: 1 / -1;\n}\n\n.gh-archive:not(.has-sidebar):not(.has-image) .gh-archive-inner {\n grid-column: 3 / span 12;\n}\n\n.gh-archive .gh-article-image {\n grid-column: auto;\n margin-top: 0;\n}\n\n:is(.tag-template, .author-template) .gh-container {\n margin-top: 0;\n}\n\n.author-template .gh-archive-inner {\n display: flex;\n flex-direction: row-reverse;\n justify-content: flex-end;\n gap: 24px;\n}\n\n.author-template .gh-article-image {\n margin-top: 0;\n width: 120px;\n height: 120px;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.author-template .gh-article-title {\n font-size: 3.6rem;\n}\n\n.gh-author-meta {\n display: flex;\n gap: 10px;\n margin-top: 14px;\n font-size: 1.5rem;\n font-weight: 550;\n color: var(--color-secondary-text);\n}\n\n.gh-author-meta a {\n color: inherit;\n}\n\n.gh-author-social {\n display: flex;\n gap: 16px;\n align-items: center;\n padding-left: 3px;\n}\n\n.gh-author-social svg {\n width: 20px;\n height: 20px;\n}\n\n@media (max-width: 1199px) {\n .gh-archive {\n display: block;\n }\n}\n\n@media (max-width: 767px) {\n .gh-archive-inner {\n display: flex;\n flex-direction: column-reverse;\n align-items: flex-start;\n }\n\n .author-template .gh-archive-inner {\n flex-direction: column-reverse;\n }\n}\n\n/* 20. Design settings\n/* ---------------------------------------------------------- */\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) {\n --factor: 1.15;\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) {\n --factor: 1.1;\n}\n\n.has-sans-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) :is(.is-title, .gh-content :is(h2, h3)) {\n font-family: var(--gh-font-heading, var(--font-sans));\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) :is(.is-title, .gh-content :is(h2, h3)) {\n font-family: var(--gh-font-heading, var(--font-serif));\n font-weight: 550;\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) :is(.is-title, .gh-content :is(h2, h3)) {\n font-family: var(--gh-font-heading, var(--font-mono));\n}\n\n.has-sans-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .is-body {\n font-family: var(--gh-font-body, var(--font-sans));\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .is-body {\n font-family: var(--gh-font-body, var(--font-serif-alt));\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-header.is-classic .gh-header-title {\n font-weight: 550;\n letter-spacing: -0.015em;\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-header.is-classic .gh-header-title {\n letter-spacing: -0.01em;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-form {\n border-radius: 0;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-card-title {\n line-height: 1.15;\n letter-spacing: -0.006em;\n font-size: calc(2.0rem*var(--factor, 1))\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-featured-feed .gh-card-title {\n font-size: calc(1.6rem*var(--factor, 1))\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-featured-feed .gh-card-title {\n font-size: calc(1.5rem*var(--factor, 1));\n letter-spacing: 0;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-header.is-highlight .gh-featured-feed .gh-card-title {\n font-size: clamp(1.6rem, 0.23vw + 1.51rem, 1.8rem);\n}\n\n.has-mono-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-card-title {\n font-size: calc(1.8rem*var(--factor, 1));\n line-height: 1.2;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-about-title {\n letter-spacing: -0.009em;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-footer-signup-header {\n letter-spacing: -0.019em;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-article-title {\n letter-spacing: -0.019em;\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) {\n --content-font-size: 1.9rem;\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-card-excerpt {\n font-size: 1.65rem;\n line-height: 1.4;\n letter-spacing: 0.0005em;\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-header.is-magazine .gh-header-inner > .gh-card .gh-card-excerpt,\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-header.is-highlight .gh-card:first-child .gh-card-excerpt {\n font-size: 1.8rem;\n letter-spacing: -0.001em;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-header.is-magazine .gh-header-inner>.gh-card .gh-card-title,\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-header.is-highlight .gh-header-left .gh-card-title {\n font-weight: 550;\n font-size: clamp(3.2rem,1.82vw + 2.47rem,4.9rem)\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-about-description {\n font-size: 1.6rem;\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-article-excerpt {\n letter-spacing: 0;\n}\n\n.has-serif-body:not([class*=\" gh-font-body\"]):not([class^=\"gh-font-body\"]) .gh-footer-signup-subhead {\n letter-spacing: 0;\n}\n\n:is(.has-serif-title,.has-mono-title):not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) :is(.gh-button, .gh-form, .gh-form-input),\nbody[class*=\" gh-font-heading\"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) :is(.gh-button, .gh-form, .gh-form-input),\nbody[class^=\"gh-font-heading\"]:not(.gh-font-heading-fira-sans):not(.gh-font-heading-inter):not(.gh-font-heading-manrope):not(.gh-font-heading-noto-sans):not(.gh-font-heading-nunito):not(.gh-font-heading-poppins):not(.gh-font-heading-roboto):not(.gh-font-heading-space-grotesk) :is(.gh-button, .gh-form, .gh-form-input) {\n border-radius: 0;\n}\n\n.has-serif-title:not([class*=\" gh-font-heading\"]):not([class^=\"gh-font-heading\"]) .gh-cta-title {\n font-size: 4.8rem;\n}\n\n/* 21. Footer\n/* ---------------------------------------------------------- */\n\n.gh-footer {\n margin-top: 120px;\n font-size: 1.5rem;\n color: var(--color-darker-gray);\n}\n\n.gh-footer a:not(.gh-button) {\n color: inherit;\n}\n\n/* 21.1 Footer styles */\n\n.gh-footer.has-accent-color {\n background-color: var(--ghost-accent-color);\n}\n\n.gh-footer.has-accent-color .gh-footer-bar {\n border-top: 0;\n}\n\n.gh-footer.has-accent-color .gh-button {\n background-color: #fff;\n color: #15171a;\n}\n\n/* 21.2. Footer bar */\n\n.gh-footer-bar {\n display: grid;\n grid-template-columns: 1fr auto 1fr;\n align-items: center;\n column-gap: 32px;\n margin-bottom: 120px;\n padding-block: 28px;\n font-weight: 550;\n border-block: 1px solid var(--color-border);\n}\n\n.gh-footer-logo {\n position: relative;\n font-family: var(--gh-font-heading, var(--font-sans));\n font-size: calc(2.4rem * var(--factor, 1));\n font-weight: 725;\n letter-spacing: -0.015em;\n white-space: nowrap;\n}\n\n.gh-footer-logo img {\n max-height: 40px;\n}\n\n.gh-footer-menu .nav {\n display: flex;\n justify-content: center;\n gap: 8px 28px;\n flex-wrap: wrap;\n margin: 0;\n padding: 0;\n list-style-type: none;\n}\n\n.gh-footer-copyright {\n text-align: right;\n white-space: nowrap;\n}\n\n.gh-footer-copyright a {\n text-decoration: underline;\n}\n\n/* 21.3. Footer signup */\n\n.gh-footer-signup {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-bottom: 120px;\n text-align: center;\n}\n\n.gh-footer-signup-header {\n font-size: calc(clamp(2.8rem,1.36vw + 2.25rem,4rem) * var(--factor, 1));\n font-weight: 700;\n letter-spacing: -0.03em;\n}\n\n.gh-footer-signup-subhead {\n margin-top: 12px;\n max-width: 640px;\n font-size: 1.8rem;\n font-weight: 450;\n line-height: 1.4;\n letter-spacing: -0.014em;\n opacity: 0.75;\n}\n\n.gh-footer-signup .gh-form {\n margin-top: 40px;\n}\n\n@media (max-width: 991px) {\n .gh-footer-bar {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n}\n\n/* 21.4. Social links */\n\n.gh-social-links {\n display: flex;\n justify-content: center;\n gap: 20px;\n margin-bottom: 32px;\n}\n\n.gh-social-links a {\n will-change: opacity;\n}\n\n.gh-social-links svg {\n width: 20px;\n height: 20px;\n}\n\n/* 22. Lightbox\n/* ---------------------------------------------------------- */\n\n.pswp {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 3999999;\n display: none;\n width: 100%;\n height: 100%;\n overflow: hidden;\n -ms-touch-action: none;\n touch-action: none;\n outline: none;\n backface-visibility: hidden;\n -webkit-text-size-adjust: 100%;\n}\n\n.pswp img {\n max-width: none;\n}\n\n.pswp--animate_opacity {\n opacity: 0.001;\n transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);\n will-change: opacity;\n}\n\n.pswp--open {\n display: block;\n}\n\n.pswp--zoom-allowed .pswp__img {\n cursor: zoom-in;\n}\n\n.pswp--zoomed-in .pswp__img {\n cursor: grab;\n}\n\n.pswp--dragging .pswp__img {\n cursor: grabbing;\n}\n\n.pswp__bg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.85);\n opacity: 0;\n transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);\n transform: translateZ(0);\n backface-visibility: hidden;\n will-change: opacity;\n}\n\n.pswp__scroll-wrap {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.pswp__container,\n.pswp__zoom-wrap {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n touch-action: none;\n backface-visibility: hidden;\n}\n\n.pswp__container,\n.pswp__img {\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n -webkit-touch-callout: none;\n}\n\n.pswp__zoom-wrap {\n position: absolute;\n width: 100%;\n transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1);\n transform-origin: left top;\n}\n\n.pswp--animated-in .pswp__bg,\n.pswp--animated-in .pswp__zoom-wrap {\n transition: none;\n}\n\n.pswp__item {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n overflow: hidden;\n}\n\n.pswp__img {\n position: absolute;\n top: 0;\n left: 0;\n width: auto;\n height: auto;\n}\n\n.pswp__img--placeholder {\n backface-visibility: hidden;\n}\n\n.pswp__img--placeholder--blank {\n background: var(--color-black);\n}\n\n.pswp--ie .pswp__img {\n top: 0;\n left: 0;\n width: 100% !important;\n height: auto !important;\n}\n\n.pswp__error-msg {\n position: absolute;\n top: 50%;\n left: 0;\n width: 100%;\n margin-top: -8px;\n font-size: 14px;\n line-height: 16px;\n color: var(--color-secondary-text);\n text-align: center;\n}\n\n.pswp__error-msg a {\n color: var(--color-secondary-text);\n text-decoration: underline;\n}\n\n.pswp__button {\n position: relative;\n display: block;\n float: right;\n width: 44px;\n height: 44px;\n padding: 0;\n margin: 0;\n overflow: visible;\n appearance: none;\n cursor: pointer;\n background: none;\n border: 0;\n box-shadow: none;\n transition: opacity 0.2s;\n}\n\n.pswp__button:focus,\n.pswp__button:hover {\n opacity: 1;\n}\n\n.pswp__button:active {\n outline: none;\n opacity: 0.9;\n}\n\n.pswp__button::-moz-focus-inner {\n padding: 0;\n border: 0;\n}\n\n.pswp__ui--over-close .pswp__button--close {\n opacity: 1;\n}\n\n.pswp__button,\n.pswp__button--arrow--left::before,\n.pswp__button--arrow--right::before {\n width: 44px;\n height: 44px;\n background: url(\"../images/default-skin.png\") 0 0 no-repeat;\n background-size: 264px 88px;\n}\n\n@media (-webkit-min-device-pixel-ratio: 1.1), (-webkit-min-device-pixel-ratio: 1.09375), (min-resolution: 105dpi), (min-resolution: 1.1dppx) {\n .pswp--svg .pswp__button,\n .pswp--svg .pswp__button--arrow--left::before,\n .pswp--svg .pswp__button--arrow--right::before {\n background-image: url(\"../images/default-skin.svg\");\n }\n\n .pswp--svg .pswp__button--arrow--left,\n .pswp--svg .pswp__button--arrow--right {\n background: none;\n }\n}\n\n.pswp__button--close {\n background-position: 0 -44px;\n}\n\n.pswp__button--share {\n background-position: -44px -44px;\n}\n\n.pswp__button--fs {\n display: none;\n}\n\n.pswp--supports-fs .pswp__button--fs {\n display: block;\n}\n\n.pswp--fs .pswp__button--fs {\n background-position: -44px 0;\n}\n\n.pswp__button--zoom {\n display: none;\n background-position: -88px 0;\n}\n\n.pswp--zoom-allowed .pswp__button--zoom {\n display: block;\n}\n\n.pswp--zoomed-in .pswp__button--zoom {\n background-position: -132px 0;\n}\n\n.pswp--touch .pswp__button--arrow--left,\n.pswp--touch .pswp__button--arrow--right {\n visibility: hidden;\n}\n\n.pswp__button--arrow--left,\n.pswp__button--arrow--right {\n position: absolute;\n top: 50%;\n width: 70px;\n height: 100px;\n margin-top: -50px;\n background: none;\n}\n\n.pswp__button--arrow--left {\n left: 0;\n}\n\n.pswp__button--arrow--right {\n right: 0;\n}\n\n.pswp__button--arrow--left::before,\n.pswp__button--arrow--right::before {\n position: absolute;\n top: 35px;\n width: 32px;\n height: 30px;\n content: \"\";\n}\n\n.pswp__button--arrow--left::before {\n left: 6px;\n background-position: -138px -44px;\n}\n\n.pswp__button--arrow--right::before {\n right: 6px;\n background-position: -94px -44px;\n}\n\n.pswp__counter {\n position: absolute;\n top: 0;\n left: 0;\n height: 44px;\n padding: 0 15px;\n font-size: 11px;\n font-weight: 700;\n line-height: 44px;\n color: var(--color-white);\n user-select: none;\n}\n\n.pswp__caption {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n min-height: 44px;\n}\n\n.pswp__caption__center {\n max-width: 420px;\n padding: 25px 15px 30px;\n margin: 0 auto;\n font-size: 11px;\n line-height: 1.6;\n color: var(--color-white);\n text-align: center;\n}\n\n.pswp__caption__center .post-caption-title {\n margin-bottom: 7px;\n font-size: 15px;\n font-weight: 500;\n text-transform: uppercase;\n}\n\n.pswp__caption__center .post-caption-meta-item + .post-caption-meta-item::before {\n padding: 0 4px;\n content: \"\\02022\";\n}\n\n.pswp__caption--empty {\n display: none;\n}\n\n.pswp__caption--fake {\n visibility: hidden;\n}\n\n.pswp__preloader {\n position: absolute;\n top: 0;\n left: 50%;\n width: 44px;\n height: 44px;\n margin-left: -22px;\n opacity: 0;\n transition: opacity 0.25s ease-out;\n direction: ltr;\n will-change: opacity;\n}\n\n.pswp__preloader__icn {\n width: 20px;\n height: 20px;\n margin: 12px;\n}\n\n.pswp__preloader--active {\n opacity: 1;\n}\n\n.pswp__preloader--active .pswp__preloader__icn {\n background: url(\"../images/preloader.gif\") 0 0 no-repeat;\n}\n\n.pswp--css_animation .pswp__preloader--active {\n opacity: 1;\n}\n\n.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn {\n animation: clockwise 500ms linear infinite;\n}\n\n.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut {\n animation: donut-rotate 1000ms cubic-bezier(0.4, 0, 0.22, 1) infinite;\n}\n\n.pswp--css_animation .pswp__preloader__icn {\n position: absolute;\n top: 15px;\n left: 15px;\n width: 14px;\n height: 14px;\n margin: 0;\n background: none;\n opacity: 0.75;\n}\n\n.pswp--css_animation .pswp__preloader__cut {\n position: relative;\n width: 7px;\n height: 14px;\n overflow: hidden;\n}\n\n.pswp--css_animation .pswp__preloader__donut {\n position: absolute;\n top: 0;\n left: 0;\n box-sizing: border-box;\n width: 14px;\n height: 14px;\n margin: 0;\n background: none;\n border: 2px solid var(--color-white);\n border-bottom-color: transparent;\n border-left-color: transparent;\n border-radius: 50%;\n}\n\n@media screen and (max-width: 1024px) {\n .pswp__preloader {\n position: relative;\n top: auto;\n left: auto;\n float: right;\n margin: 0;\n }\n}\n\n@keyframes clockwise {\n 0% {\n transform: rotate(0deg);\n }\n\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes donut-rotate {\n 0% {\n transform: rotate(0);\n }\n\n 50% {\n transform: rotate(-140deg);\n }\n\n 100% {\n transform: rotate(0);\n }\n}\n\n.pswp__ui {\n z-index: 1550;\n visibility: visible;\n opacity: 1;\n -webkit-font-smoothing: auto;\n}\n\n.pswp__top-bar {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 44px;\n}\n\n.pswp__caption,\n.pswp__top-bar,\n.pswp--has_mouse .pswp__button--arrow--left,\n.pswp--has_mouse .pswp__button--arrow--right {\n backface-visibility: hidden;\n transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);\n will-change: opacity;\n}\n\n.pswp--has_mouse .pswp__button--arrow--left,\n.pswp--has_mouse .pswp__button--arrow--right {\n visibility: visible;\n}\n\n.pswp__ui--idle .pswp__top-bar {\n opacity: 0;\n}\n\n.pswp__ui--idle .pswp__button--arrow--left,\n.pswp__ui--idle .pswp__button--arrow--right {\n opacity: 0;\n}\n\n.pswp__ui--hidden .pswp__top-bar,\n.pswp__ui--hidden .pswp__caption,\n.pswp__ui--hidden .pswp__button--arrow--left,\n.pswp__ui--hidden .pswp__button--arrow--right {\n opacity: 0.001;\n}\n\n.pswp__ui--one-slide .pswp__button--arrow--left,\n.pswp__ui--one-slide .pswp__button--arrow--right,\n.pswp__ui--one-slide .pswp__counter {\n display: none;\n}\n\n.pswp__element--disabled {\n display: none !important;\n}\n\n.pswp--minimal--dark .pswp__top-bar {\n background: none;\n}\n\n/* SHARE */\n.gh-meta-share {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 20px;\n}\n\n.has-light-text .gh-button-share {\n border-color: rgba(255, 255, 255, 0.25);\n color: rgba(255, 255, 255, 0.85);\n}\n\n.has-light-text .gh-button-share:hover {\n border-color: rgba(255, 255, 255, 0.85);\n}\n\n.gh-button-share {\n display: inline-flex;\n align-items: center;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 999px;\n color: rgba(0, 0, 0, 0.85);\n background: transparent;\n cursor: pointer;\n transition: all 0.4s ease;\n}\n\n.gh-button-share:hover {\n border-color: rgba(0, 0, 0, 0.5);\n}\n"]} \ No newline at end of file diff --git a/ghost-me/theme-source-personal/assets/built/source.js b/ghost-me/theme-source-personal/assets/built/source.js deleted file mode 100644 index 1b94003..0000000 --- a/ghost-me/theme-source-personal/assets/built/source.js +++ /dev/null @@ -1 +0,0 @@ -function dropdown(){let r=window.matchMedia("(max-width: 767px)"),a=document.querySelector(".gh-navigation"),s=a.querySelector(".gh-navigation-menu"),l=s?.querySelector(".nav");if(l){let e=document.querySelector(".gh-navigation-logo"),t=l.innerHTML;r.matches&&l.querySelectorAll("li").forEach(function(e,t){e.style.transitionDelay=.03*(t+1)+"s"});let n=function(){if(!r.matches){for(var e=[];l.offsetWidth+64>s.offsetWidth&&l.lastElementChild;)e.unshift(l.lastElementChild),l.lastElementChild.remove();if(e.length){let t=document.createElement("button"),n=(t.setAttribute("class","gh-more-toggle gh-icon-button"),t.setAttribute("aria-label","More"),t.innerHTML='',document.createElement("div"));n.setAttribute("class","gh-dropdown"),10<=e.length?(a.classList.add("is-dropdown-mega"),n.style.gridTemplateRows=`repeat(${Math.ceil(e.length/2)}, 1fr)`):a.classList.remove("is-dropdown-mega"),e.forEach(function(e){n.appendChild(e)}),t.appendChild(n),l.appendChild(t);var o=t.getBoundingClientRect(),i=window.innerWidth/2;o.left{l.innerHTML=t,n()},1)})}}function lightbox(e){document.querySelectorAll(e).forEach(function(e){e.addEventListener("click",function(e){var t=e;t.preventDefault();for(var n,o=[],i=0,r=t.target.closest(".kg-card").previousElementSibling;r&&(r.classList.contains("kg-image-card")||r.classList.contains("kg-gallery-card"));){var a=[];r.querySelectorAll("img").forEach(function(e){a.push({src:e.getAttribute("src"),msrc:e.getAttribute("src"),w:e.getAttribute("width"),h:e.getAttribute("height"),el:e}),i+=1}),r=r.previousElementSibling,o=a.concat(o)}t.target.classList.contains("kg-image")?o.push({src:t.target.getAttribute("src"),msrc:t.target.getAttribute("src"),w:t.target.getAttribute("width"),h:t.target.getAttribute("height"),el:t.target}):(n=!1,t.target.closest(".kg-gallery-card").querySelectorAll("img").forEach(function(e){o.push({src:e.getAttribute("src"),msrc:e.getAttribute("src"),w:e.getAttribute("width"),h:e.getAttribute("height"),el:e}),n||e===t.target?n=!0:i+=1}));for(var s=t.target.closest(".kg-card").nextElementSibling;s&&(s.classList.contains("kg-image-card")||s.classList.contains("kg-gallery-card"));)s.querySelectorAll("img").forEach(function(e){o.push({src:e.getAttribute("src"),msrc:e.getAttribute("src"),w:e.getAttribute("width"),h:e.getAttribute("height"),el:e})}),s=s.nextElementSibling;e=document.querySelectorAll(".pswp")[0];new PhotoSwipe(e,PhotoSwipeUI_Default,o,{bgOpacity:.9,closeOnScroll:!0,fullscreenEl:!1,history:!1,index:i,shareEl:!1,zoomEl:!1,getThumbBoundsFn:function(e){var e=o[e].el,t=window.pageYOffset||document.documentElement.scrollTop,e=e.getBoundingClientRect();return{x:e.left,y:e.top+t,w:e.width}}}).init()})})}function pagination(e=!0,s,l=!1){let c=document.querySelector(".gh-feed");if(!c)return;let t=!1,n=document.querySelector(".gh-footer"),u=document.querySelector(".gh-loadmore"),o=(!document.querySelector("link[rel=next]")&&u&&u.remove(),async function(){var o=document.querySelector("link[rel=next]");if(o)try{var e=await(await fetch(o.href)).text(),i=(new DOMParser).parseFromString(e,"text/html"),r=i.querySelectorAll(".gh-feed:not(.gh-featured):not(.gh-related) > *");let t=document.createDocumentFragment(),n=[];r.forEach(function(e){e=document.importNode(e,!0);l&&(e.style.visibility="hidden"),t.appendChild(e),n.push(e)}),c.appendChild(t),s&&s(n,d);var a=i.querySelector("link[rel=next]");a&&a.href?o.href=a.href:(o.remove(),u&&u.remove())}catch(e){throw o.remove(),e}}),d=async function(){n.getBoundingClientRect().top<=window.innerHeight&&document.querySelector("link[rel=next]")&&await o()};let i=new IntersectionObserver(async function(e){if(!t){if(t=!0,e[0].isIntersecting)if(l)await o();else for(;n.getBoundingClientRect().top<=window.innerHeight&&document.querySelector("link[rel=next]");)await o();t=!1,document.querySelector("link[rel=next]")||i.disconnect()}});e?i.observe(n):u.addEventListener("click",o)}((e,t)=>{"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",t):"object"==typeof module&&module.exports?module.exports=t():e.EvEmitter=t()})("undefined"!=typeof window?window:this,function(){function e(){}var t=e.prototype;return t.on=function(e,t){var n;if(e&&t)return-1==(n=(n=this._events=this._events||{})[e]=n[e]||[]).indexOf(t)&&n.push(t),this},t.once=function(e,t){var n;if(e&&t)return this.on(e,t),((n=this._onceEvents=this._onceEvents||{})[e]=n[e]||{})[t]=!0,this},t.off=function(e,t){e=this._events&&this._events[e];if(e&&e.length)return-1!=(t=e.indexOf(t))&&e.splice(t,1),this},t.emitEvent=function(e,t){var n=this._events&&this._events[e];if(n&&n.length){n=n.slice(0),t=t||[];for(var o=this._onceEvents&&this._onceEvents[e],i=0;i{"function"==typeof define&&define.amd?define(["ev-emitter/ev-emitter"],function(e){return n(t,e)}):"object"==typeof module&&module.exports?module.exports=n(t,require("ev-emitter")):t.imagesLoaded=n(t,t.EvEmitter)})("undefined"!=typeof window?window:this,function(t,e){function r(e,t){for(var n in t)e[n]=t[n];return e}function a(e,t,n){var o,i;return this instanceof a?(o="string"==typeof(o=e)?document.querySelectorAll(e):o)?(this.elements=(i=o,Array.isArray(i)?i:"object"==typeof i&&"number"==typeof i.length?c.call(i):[i]),this.options=r({},this.options),"function"==typeof t?n=t:r(this.options,t),n&&this.on("always",n),this.getImages(),s&&(this.jqDeferred=new s.Deferred),void setTimeout(this.check.bind(this))):void l.error("Bad element for imagesLoaded "+(o||e)):new a(e,t,n)}function n(e){this.img=e}function o(e,t){this.url=e,this.element=t,this.img=new Image}var s=t.jQuery,l=t.console,c=Array.prototype.slice,u=((a.prototype=Object.create(e.prototype)).options={},a.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},a.prototype.addElementImages=function(e){"IMG"==e.nodeName&&this.addImage(e),!0===this.options.background&&this.addElementBackgroundImages(e);var t=e.nodeType;if(t&&u[t]){for(var n=e.querySelectorAll("img"),o=0;o{"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.PhotoSwipeUI_Default=t()})(this,function(){return function(o,s){function e(e){if(T)return!0;e=e||window.event,C.timeToIdle&&C.mouseUsed&&!y&&a();for(var t,n,o=(e.target||e.srcElement).getAttribute("class")||"",i=0;i