6 Commits
Author SHA1 Message Date
zwitschi 17ac04856b feat: redesign color system to monochrome palette with sharp corners
Release / release (push) Successful in 1m0s
CI / test (push) Successful in 11m6s
CI / docker (push) Successful in 41s
CI / release (push) Skipped
2026-08-05 17:26:30 +02:00
zwitschi 69df0e51b8 release version 1.0.6
CI / test (push) Successful in 9m23s
CI / docker (push) Successful in 3m14s
CI / release (push) Skipped
2026-08-05 17:09:03 +02:00
zwitschi 9a06dc389d feat: update css with new color scheme
CI / test (push) Successful in 7m11s
CI / docker (push) Successful in 51s
CI / release (push) Skipped
2026-08-05 16:31:18 +02:00
zwitschi 51f3e98816 feat: CI pipeline improvements
CI / test (push) Successful in 7m17s
CI / docker (push) Successful in 7m49s
CI / release (push) Skipped
- remove image build duplication
- update workflows to use caching
2026-08-05 16:10:15 +02:00
zwitschi 68ba3a25b9 fix: deployment health check
CI / test (push) Successful in 1m52s
CI / docker (push) Successful in 3m20s
CI / release (push) Skipped
2026-08-05 12:44:40 +02:00
zwitschi 7e9308c48a fix: move admin pages
CI / test (push) Successful in 10m45s
CI / docker (push) Successful in 3m20s
CI / release (push) Skipped
2026-08-05 12:18:44 +02:00
21 changed files with 238 additions and 122 deletions

No files matched your search

+1 -1
View File
@@ -86,7 +86,7 @@ jobs:
# Check nginx health # Check nginx health
echo "Checking nginx health..." echo "Checking nginx health..."
if ! curl -f http://192.168.88.40:8080/; then if ! curl -f http://192.168.88.40/health/; then
echo "Nginx health check failed" echo "Nginx health check failed"
docker logs linearvoid-nginx --tail 50 docker logs linearvoid-nginx --tail 50
exit 1 exit 1
+19 -26
View File
@@ -34,17 +34,14 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "1.22" go-version: "1.25"
cache: true cache: true
cache-dependency-path: | cache-dependency-path: backend/chat/go.sum
backend/playout/go.sum env:
backend/chat/go.sum GOTOOLCHAIN: local
- name: Validate Playlist Normalization - name: Download Go modules
run: cd backend/playout && go run src/playlist.go playlist.txt || echo "Validation script not yet complete" run: cd backend/chat && GOTOOLCHAIN=local go mod download
- name: Build Docker Images
run: docker compose build --no-cache
- name: Run Tests - name: Run Tests
run: echo "Tests will be added in future CI steps (per TODO.md)" run: echo "Tests will be added in future CI steps (per TODO.md)"
@@ -89,6 +86,8 @@ jobs:
push: true push: true
tags: ${{ steps.meta-playout.outputs.tags }} tags: ${{ steps.meta-playout.outputs.tags }}
labels: ${{ steps.meta-playout.outputs.labels }} labels: ${{ steps.meta-playout.outputs.labels }}
cache-from: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:playout
cache-to: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:playout,mode=max
- name: Extract metadata for Chat - name: Extract metadata for Chat
id: meta-chat id: meta-chat
@@ -109,6 +108,8 @@ jobs:
push: true push: true
tags: ${{ steps.meta-chat.outputs.tags }} tags: ${{ steps.meta-chat.outputs.tags }}
labels: ${{ steps.meta-chat.outputs.labels }} labels: ${{ steps.meta-chat.outputs.labels }}
cache-from: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:chat
cache-to: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:chat,mode=max
- name: Extract metadata for Nginx - name: Extract metadata for Nginx
id: meta-nginx id: meta-nginx
@@ -123,23 +124,15 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}} type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Nginx image - name: Build and push Nginx image
run: | uses: docker/build-push-action@v5
TAGS="${{ steps.meta-nginx.outputs.tags }}" with:
LABELS="${{ steps.meta-nginx.outputs.labels }}" context: .
TAG_ARGS="" file: infrastructure/nginx/Dockerfile
for tag in $TAGS; do push: true
TAG_ARGS="$TAG_ARGS --tag $tag" tags: ${{ steps.meta-nginx.outputs.tags }}
done labels: ${{ steps.meta-nginx.outputs.labels }}
LABEL_ARGS="" cache-from: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:nginx
while IFS= read -r label; do cache-to: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:nginx,mode=max
[ -n "$label" ] && LABEL_ARGS="$LABEL_ARGS --label $label"
done <<< "$LABELS"
docker buildx build \
--push \
--file infrastructure/nginx/Dockerfile \
$TAG_ARGS \
$LABEL_ARGS \
.
release: release:
needs: docker needs: docker
+5 -3
View File
@@ -30,13 +30,15 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "1.22" go-version: "1.25"
cache: true cache: true
env:
GOTOOLCHAIN: local
- name: Update Go Dependencies - name: Update Go Dependencies
run: | run: |
cd backend/playout && go get -u ./... && go mod tidy cd backend/playout && GOTOOLCHAIN=local go get -u ./... && go mod tidy
cd ../chat && go get -u ./... && go mod tidy cd ../chat && GOTOOLCHAIN=local go get -u ./... && go mod tidy
- name: Commit and push changes - name: Commit and push changes
run: | run: |
+8 -2
View File
@@ -3,11 +3,11 @@ name: Release
on: on:
push: push:
tags: tags:
- "v*" - "*.*.*" # Trigger on any semantic version tag (e.g., 1.0.0, 2.1.3)
workflow_dispatch: workflow_dispatch:
inputs: inputs:
version: version:
description: "Version to release (e.g., v1.0.0)" description: "Version to release (e.g., 1.0.0)"
required: true required: true
type: string type: string
@@ -71,6 +71,8 @@ jobs:
push: true push: true
tags: ${{ steps.meta-playout.outputs.tags }} tags: ${{ steps.meta-playout.outputs.tags }}
labels: ${{ steps.meta-playout.outputs.labels }} labels: ${{ steps.meta-playout.outputs.labels }}
cache-from: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:playout
cache-to: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:playout,mode=max
- name: Extract metadata for Chat - name: Extract metadata for Chat
id: meta-chat id: meta-chat
@@ -89,6 +91,8 @@ jobs:
push: true push: true
tags: ${{ steps.meta-chat.outputs.tags }} tags: ${{ steps.meta-chat.outputs.tags }}
labels: ${{ steps.meta-chat.outputs.labels }} labels: ${{ steps.meta-chat.outputs.labels }}
cache-from: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:chat
cache-to: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:chat,mode=max
- name: Extract metadata for Nginx - name: Extract metadata for Nginx
id: meta-nginx id: meta-nginx
@@ -108,6 +112,8 @@ jobs:
push: true push: true
tags: ${{ steps.meta-nginx.outputs.tags }} tags: ${{ steps.meta-nginx.outputs.tags }}
labels: ${{ steps.meta-nginx.outputs.labels }} labels: ${{ steps.meta-nginx.outputs.labels }}
cache-from: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:nginx
cache-to: type=registry,ref=git.allucanget.biz/zwitschi/linearvoid/buildcache:nginx,mode=max
- name: Create Release on Gitea - name: Create Release on Gitea
run: | run: |
+7 -2
View File
@@ -2,7 +2,7 @@
<!-- markdownlint-disable MD024 --> <!-- markdownlint-disable MD024 -->
## [1.0.5] - 2026-08-05 ## [1.0.6] - 2026-08-05
### Added ### Added
@@ -23,13 +23,18 @@
- Rebuilt viewer, admin, and admin-login pages around custom semantic class structures with accessibility-focused landmarks, tab semantics, and keyboard-focus behavior. - Rebuilt viewer, admin, and admin-login pages around custom semantic class structures with accessibility-focused landmarks, tab semantics, and keyboard-focus behavior.
- Replaced legacy and Tailwind-based stylesheet rules with a custom design-token CSS system covering responsive layouts, forms, tables, and reduced-motion behavior. - Replaced legacy and Tailwind-based stylesheet rules with a custom design-token CSS system covering responsive layouts, forms, tables, and reduced-motion behavior.
- Switched frontend theme to dark-mode-first token defaults with light-scheme override. - Switched frontend theme to dark-mode-first token defaults with light-scheme override.
- Applied new color palette (`#32292f` dark, `#b4c4ae` light, `#587792` brand, `#2ebfa5` focus, `#04650d` ok) across all 22 CSS custom properties in dark and light themes.
- Replaced hardcoded admin sidebar and tab-trigger colors with CSS custom properties.
- Optimized CI pipeline: removed duplicate `docker compose build --no-cache` from test job, removed broken playlist validation step, fixed Go module cache path, added Docker Buildx registry cache to docker/release jobs.
- Bumped chat healthcheck `start_period` from 10s to 30s in `docker-compose.prod.yml`. - Bumped chat healthcheck `start_period` from 10s to 30s in `docker-compose.prod.yml`.
- CD workflow now verifies nginx (port 8080) + chat (3000) + playout (8081); dumps container logs for all failing services. - CD workflow now verifies nginx (port 8080) + chat (3000) + playout (8081); dumps container logs for all failing services.
- Updated Prometheus scrape targets and Grafana dashboard queries to use live chat metrics. - Updated Prometheus scrape targets and Grafana dashboard queries to use live chat metrics.
### Fixed ### Fixed
- Go module cache in CI now correctly references `backend/playout/go.sum` and `backend/chat/go.sum`. - Go module cache in CI now correctly references only `backend/chat/go.sum` (playout go.sum did not exist); added `go mod download` step to seed cache.
- Removed broken playlist validation step (`go run src/playlist.go` without go.mod) from CI test job.
- Converted nginx CI build from custom shell `docker buildx` to `docker/build-push-action@v5` for cache consistency.
- Enforced 2GB upload ceiling plus server-side media file type/size validation for admin uploads. - Enforced 2GB upload ceiling plus server-side media file type/size validation for admin uploads.
- Increased nginx `client_max_body_size` to allow resumable admin upload chunks without 413 errors. - Increased nginx `client_max_body_size` to allow resumable admin upload chunks without 413 errors.
- Removed unused `data-admin-*` Vite env var attributes from admin HTML template. - Removed unused `data-admin-*` Vite env var attributes from admin HTML template.
+119 -2
View File
@@ -20,8 +20,8 @@ Thank you for considering contributing to Linear Void!
## Code Style ## Code Style
- Go: Use standard formatting (`go fmt`). - Go: Use standard formatting (`go fmt`).
- TypeScript: ESLint and Prettier. - TypeScript: `tsc --noEmit` for type-checking (see `frontend/package.json`).
- Tailwind: Follow the utility-first approach. - CSS: Design-token system via CSS custom properties in `frontend/src/style.css`. No utility framework.
## Pull Requests ## Pull Requests
@@ -30,4 +30,121 @@ Thank you for considering contributing to Linear Void!
- Ensure all tests pass and documentation is updated. - Ensure all tests pass and documentation is updated.
- The CI workflow will validate normalization, linting, and Docker builds. - The CI workflow will validate normalization, linting, and Docker builds.
## Versioning and Releases
### Version Scheme
Linear Void follows **Semantic Versioning** ([SemVer](https://semver.org)): `MAJOR.MINOR.PATCH`.
- **MAJOR** — breaking changes to the viewer, API, or deployment model.
- **MINOR** — new features (endpoints, admin tabs, UI capabilities) that are backward-compatible.
- **PATCH** — bug fixes, optimizations, documentation polish.
Git tags use a `v` prefix: `1.0.2`, `1.1.0`, `v2.0.0`.
### Where Versions Are Declared
| File | Token | Example |
| ------------------------------ | -------------- | ------------------------- |
| `frontend/package.json` | `"version"` | `"1.0.2"` |
| `CHANGELOG.md` | `## [X.Y.Z]` | `## [1.0.2] - 2026-08-05` |
| `README.md` | Version badge | `version-1.0.2-blue` |
| `.github/instructions/TODO.md` | Section header | `## Version 1.0.2` |
### Tag Triggers
| Tag Pattern | Workflow | What Happens |
| ------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `v*` (e.g. `1.0.2`) | `release.yml` | Builds all 3 images, pushes to registry with semver tags (`1.0.2`, `1.0`, `latest`), creates Gitea Release via API |
| Push to `main` | `ci.yml` → `cd.yml` | CI builds + pushes images with `main`/`latest` tags, CD deploys to production |
### Full Release Procedure
#### Step 1: Bump version numbers
Update these files to the new version (replace `X.Y.Z`):
- [frontend/package.json](frontend/package.json)
- [CHANGELOG.md](CHANGELOG.md) — add new section at top
- [README.md](README.md) — version badge
```bash
# frontend/package.json
"version": "X.Y.Z"
# CHANGELOG.md — add new section at top
## [X.Y.Z] - YYYY-MM-DD
# README.md — version badge
version-X.Y.Z-blue
```
#### Step 2: Write changelog
Add entries under `## [X.Y.Z]` in `CHANGELOG.md` following [Keep a Changelog](https://keepachangelog.com) format (`Added`, `Changed`, `Fixed`, `Removed`).
#### Step 3: Commit and tag
```bash
# Stage all version bumps + changelog
git add frontend/package.json CHANGELOG.md README.md .github/instructions/TODO.md
# Commit
git commit -m "chore: bump version to X.Y.Z"
# Create annotated tag
git tag -a X.Y.Z -m "Release X.Y.Z"
# Push commit and tag
git push origin main
git push origin X.Y.Z
```
#### Step 4: Verify CI/CD
- CI workflow (`ci.yml`) runs on push to `main` → builds & pushes `main`/`latest` images.
- Release workflow (`release.yml`) triggers on `X.Y.Z` tag → builds images with semver tags (`X.Y.Z`, `X.Y`, `latest`), creates Gitea Release.
- CD workflow (`cd.yml`) triggers after CI completes → deploys to production.
Monitor at: [git.allucanget.biz/zwitschi/linearvoid/actions](https://git.allucanget.biz/zwitschi/linearvoid/actions)
#### Step 5: Verify release
Check the Gitea Releases page for the new tag:
[git.allucanget.biz/zwitschi/linearvoid/releases](https://git.allucanget.biz/zwitschi/linearvoid/releases)
### Manual Release (workflow_dispatch)
If a tag push fails or a re-release is needed:
1. Go to [Actions → Release workflow](https://git.allucanget.biz/zwitschi/linearvoid/actions?workflow=release.yml)
2. Click "Run workflow"
3. Enter version (e.g. `1.0.2`)
4. The workflow builds images, pushes semver tags, and creates the Gitea Release
### Docker Image Tags
Every release produces these tags in the Gitea Container Registry:
| Image | Tags |
| --------- | ------------------------ |
| `playout` | `X.Y.Z`, `X.Y`, `latest` |
| `chat` | `X.Y.Z`, `X.Y`, `latest` |
| `nginx` | `X.Y.Z`, `X.Y`, `latest` |
Example for `1.0.2`:
```text
git.allucanget.biz/zwitschi/linearvoid/chat:1.0.2
git.allucanget.biz/zwitschi/linearvoid/chat:1.0
git.allucanget.biz/zwitschi/linearvoid/chat:latest
git.allucanget.biz/zwitschi/linearvoid/playout:1.0.2
git.allucanget.biz/zwitschi/linearvoid/playout:1.0
git.allucanget.biz/zwitschi/linearvoid/playout:latest
```
### Moving Completed Tasks
After release, move completed sections from `TODO.md` to `DONE.md` and update `CHANGELOG.md` if needed. The `DONE.md` file serves as the historical record linking tasks to releases.
See the ADRs for architectural decisions and `docs/architecture/README.md` for the big picture. Thank you for contributing! See the ADRs for architectural decisions and `docs/architecture/README.md` for the big picture. Thank you for contributing!
+4
View File
@@ -38,6 +38,10 @@ See .env.example and SETUP.md for full variable reference.
## Pull-and-Run Deployment ## Pull-and-Run Deployment
Images are built and pushed automatically by the CI and release workflows (see [CONTRIBUTING.md](CONTRIBUTING.md#versioning-and-releases) for the release procedure).
Every push to `main` produces `:main` and `:latest` tags. Semantic version tags (`v*`) produce `:X.Y.Z`, `:X.Y`, and `:latest` tags.
From repository root: From repository root:
```bash ```bash
+2 -2
View File
@@ -7,7 +7,7 @@
[![Build Status](https://git.allucanget.biz/zwitschi/linearvoid/actions/workflows/ci.yml/badge.svg)](https://git.allucanget.biz/zwitschi/linearvoid/actions) [![Build Status](https://git.allucanget.biz/zwitschi/linearvoid/actions/workflows/ci.yml/badge.svg)](https://git.allucanget.biz/zwitschi/linearvoid/actions)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Gitea](https://img.shields.io/badge/Gitea-1.27.1-blue)](https://git.allucanget.biz) [![Gitea](https://img.shields.io/badge/Gitea-1.27.1-blue)](https://git.allucanget.biz)
[![Version](https://img.shields.io/badge/version-1.0.5-blue)](https://git.allucanget.biz/zwitschi/linearvoid/releases) [![Version](https://img.shields.io/badge/version-1.0.6-blue)](https://git.allucanget.biz/zwitschi/linearvoid/releases)
[![Release Notes](https://img.shields.io/badge/release-notes-green)](CHANGELOG.md) [![Release Notes](https://img.shields.io/badge/release-notes-green)](CHANGELOG.md)
## Architecture ## Architecture
@@ -224,7 +224,7 @@ Contributions are welcome! See [`CONTRIBUTING.md`](CONTRIBUTING.md) for guidelin
3. Open PRs on [Gitea](https://git.allucanget.biz/zwitschi/linearvoid). 3. Open PRs on [Gitea](https://git.allucanget.biz/zwitschi/linearvoid).
4. CI validates builds and tests automatically. 4. CI validates builds and tests automatically.
Since this a linear project, we also rely on a linear development and release model: Only main branch is used for releases, and all features are merged into main after review and CI validation. Releases are tagged with semantic versioning (v1.0.3, v1.0.4, etc.) and automatically built/pushed to the container registry. Since this a linear project, we also rely on a linear development and release model: Only main branch is used for releases, and all features are merged into main after review and CI validation. Releases are tagged with semantic versioning (1.0.3, 1.0.4, etc.) and automatically built/pushed to the container registry.
[MIT License](LICENSE) [MIT License](LICENSE)
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.23-alpine AS builder FROM golang:1.25-alpine AS builder
RUN apk add --no-cache gcc musl-dev RUN apk add --no-cache gcc musl-dev
+1 -1
View File
@@ -1,6 +1,6 @@
module chat module chat
go 1.23.0 go 1.25.0
require ( require (
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "frontend", "name": "frontend",
"private": true, "private": true,
"version": "1.0.5", "version": "1.0.6",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+70 -81
View File
@@ -6,47 +6,47 @@
--font-display: "Space Grotesk", "Segoe UI", sans-serif; --font-display: "Space Grotesk", "Segoe UI", sans-serif;
--font-mono: "IBM Plex Mono", Consolas, monospace; --font-mono: "IBM Plex Mono", Consolas, monospace;
--bg-0: #0d1417; --bg-0: #000000;
--bg-1: #172227; --bg-1: #0a0a0a;
--bg-2: #0a1012; --bg-2: #000000;
--ink-0: #edf6f3; --ink-0: #ede8e6;
--ink-1: #cadbd6; --ink-1: #b0a8a4;
--ink-soft: #9cb2ab; --ink-soft: #78706c;
--panel: #17252b; --panel: #111111;
--panel-2: #1f3138; --panel-2: #1a1a1a;
--line: #30464d; --line: #2a2a2a;
--line-soft: #3d5962; --line-soft: #1f1f1f;
--brand: #2ec4b6; --brand: #587792;
--brand-strong: #20a79a; --brand-strong: #4a6780;
--brand-contrast: #061412; --brand-contrast: #f4f8fb;
--ok: #5add94; --ok: #04650d;
--warn: #f2b560; --warn: #d49624;
--danger: #ff7d8f; --danger: #c44a5e;
--danger-soft: #3a1f27; --danger-soft: #1f1216;
--focus: #78f2e0; --focus: #2ebfa5;
--shadow-1: 0 14px 30px rgba(0, 0, 0, 0.34); --shadow-1: 0 14px 30px rgba(0, 0, 0, 0.5);
--shadow-2: 0 22px 44px rgba(0, 0, 0, 0.45); --shadow-2: 0 22px 44px rgba(0, 0, 0, 0.6);
--bg-grad-a: #132129; --bg-grad-a: #000000;
--bg-grad-b: var(--bg-0); --bg-grad-b: #000000;
--bg-grad-c: var(--bg-2); --bg-grad-c: #000000;
--live-dot: #ff6b6b; --live-dot: #ff6b6b;
--overlay-bg: rgba(4, 14, 18, 0.84); --overlay-bg: rgba(0, 0, 0, 0.88);
--input-bg: #131f24; --input-bg: #0d0d0d;
--input-border: var(--line-soft); --input-border: var(--line-soft);
--placeholder: #90a8a1; --placeholder: #6a6260;
--badge-start: #35c8bb; --badge-start: #2ebfa5;
--badge-end: #1f8d85; --badge-end: #1a8c78;
--radius-1: 0.6rem; --radius-1: 0;
--radius-2: 1rem; --radius-2: 0;
--radius-3: 1.6rem; --radius-3: 0;
--space-1: 0.25rem; --space-1: 0.25rem;
--space-2: 0.5rem; --space-2: 0.5rem;
@@ -63,43 +63,43 @@
:root { :root {
color-scheme: light; color-scheme: light;
--bg-0: #f4f6ef; --bg-0: #e8e8e8;
--bg-1: #e3e8db; --bg-1: #dcdcdc;
--bg-2: #eff3ea; --bg-2: #f0f0f0;
--ink-0: #101b18; --ink-0: #0d0d0d;
--ink-1: #2d3a36; --ink-1: #2a2a2a;
--ink-soft: #5a6963; --ink-soft: #555555;
--panel: #fffffd; --panel: #ffffff;
--panel-2: #f7fbf2; --panel-2: #f5f5f5;
--line: #c6d1c5; --line: #cccccc;
--line-soft: #d8e2d8; --line-soft: #dddddd;
--brand: #005f73; --brand: #587792;
--brand-strong: #00464f; --brand-strong: #4a6780;
--brand-contrast: #f9fffd; --brand-contrast: #f4f8fb;
--ok: #2f7a43; --ok: #04650d;
--warn: #b76a00; --warn: #a86200;
--danger: #a7283f; --danger: #a7283f;
--danger-soft: #fff3f6; --danger-soft: #fff3f6;
--focus: #0a9396; --focus: #2ebfa5;
--shadow-1: 0 14px 30px rgba(31, 54, 47, 0.12); --shadow-1: 0 8px 20px rgba(0, 0, 0, 0.08);
--shadow-2: 0 22px 44px rgba(20, 39, 35, 0.2); --shadow-2: 0 16px 36px rgba(0, 0, 0, 0.12);
--bg-grad-a: #dce9d6; --bg-grad-a: #e8e8e8;
--bg-grad-b: var(--bg-0); --bg-grad-b: var(--bg-0);
--bg-grad-c: #eff3ea; --bg-grad-c: #f0f0f0;
--live-dot: #cb271a; --live-dot: #cb271a;
--overlay-bg: rgba(0, 16, 19, 0.84); --overlay-bg: rgba(0, 0, 0, 0.88);
--input-bg: #fff; --input-bg: #ffffff;
--input-border: #c2d2c1; --input-border: #cccccc;
--placeholder: #74817b; --placeholder: #888888;
--badge-start: #0a9396; --badge-start: #2ebfa5;
--badge-end: #005f73; --badge-end: #1a8c78;
} }
} }
@@ -375,7 +375,7 @@ select {
} }
.viewer-header { .viewer-header {
padding: var(--space-5); padding: var(--space-3) var(--space-4);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@@ -392,7 +392,7 @@ select {
.brand-badge { .brand-badge {
width: 2.5rem; width: 2.5rem;
height: 2.5rem; height: 2.5rem;
border-radius: 0.9rem; border-radius: 0;
display: grid; display: grid;
place-items: center; place-items: center;
font-weight: 800; font-weight: 800;
@@ -424,7 +424,7 @@ select {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: var(--space-2); gap: var(--space-2);
border-radius: 999px; border-radius: 0;
background: var(--panel); background: var(--panel);
border: 1px solid var(--line); border: 1px solid var(--line);
color: var(--ink-1); color: var(--ink-1);
@@ -447,7 +447,7 @@ select {
.player { .player {
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 1.1rem; border-radius: 0;
border: 1px solid var(--line-soft); border: 1px solid var(--line-soft);
background: #000; background: #000;
box-shadow: var(--shadow-1); box-shadow: var(--shadow-1);
@@ -467,14 +467,14 @@ select {
background: var(--overlay-bg); background: var(--overlay-bg);
color: #f0fffb; color: #f0fffb;
padding: 0.44rem 0.72rem; padding: 0.44rem 0.72rem;
border-radius: 999px; border-radius: 0;
backdrop-filter: blur(3px); backdrop-filter: blur(3px);
} }
.live-label { .live-label {
background: #d62828; background: var(--live-dot);
color: #fff; color: #fff;
border-radius: 999px; border-radius: 0;
padding: 0.1rem 0.45rem; padding: 0.1rem 0.45rem;
font-size: 0.72rem; font-size: 0.72rem;
font-weight: 700; font-weight: 700;
@@ -542,7 +542,7 @@ select {
.message-bubble { .message-bubble {
max-width: 83%; max-width: 83%;
border-radius: 1rem; border-radius: 0;
padding: 0.58rem 0.72rem; padding: 0.58rem 0.72rem;
box-shadow: var(--shadow-1); box-shadow: var(--shadow-1);
animation: messageIn var(--fast); animation: messageIn var(--fast);
@@ -563,7 +563,7 @@ select {
color: var(--ink-1); color: var(--ink-1);
background: color-mix(in srgb, var(--brand) 22%, var(--panel-2)); background: color-mix(in srgb, var(--brand) 22%, var(--panel-2));
border: 1px solid color-mix(in srgb, var(--brand) 45%, var(--line)); border: 1px solid color-mix(in srgb, var(--brand) 45%, var(--line));
border-radius: 999px; border-radius: 0;
padding: 0.24rem 0.68rem; padding: 0.24rem 0.68rem;
animation: messageIn var(--fast); animation: messageIn var(--fast);
} }
@@ -609,18 +609,7 @@ select {
.admin-body { .admin-body {
min-height: 100vh; min-height: 100vh;
padding: var(--space-4); padding: var(--space-4);
background: background: #000000;
radial-gradient(
circle at 82% 12%,
rgba(20, 48, 54, 0.5) 0%,
transparent 44%
),
radial-gradient(
circle at 16% 85%,
rgba(8, 28, 34, 0.55) 0%,
transparent 40%
),
var(--bg-0);
} }
.admin-shell { .admin-shell {
@@ -637,8 +626,8 @@ select {
} }
.admin-sidebar { .admin-sidebar {
background: #102a2f; background: var(--bg-2);
color: #ecfff6; color: var(--ink-0);
display: grid; display: grid;
grid-template-rows: auto auto 1fr; grid-template-rows: auto auto 1fr;
gap: var(--space-4); gap: var(--space-4);
@@ -666,7 +655,7 @@ select {
width: 100%; width: 100%;
text-align: left; text-align: left;
background: transparent; background: transparent;
color: #ddf8ee; color: var(--ink-1);
border: 1px solid transparent; border: 1px solid transparent;
border-radius: var(--radius-1); border-radius: var(--radius-1);
padding: 0.62rem 0.72rem; padding: 0.62rem 0.72rem;