Compare commits

..
Author SHA1 Message Date
pastilhasandClaude Opus 5 91147b403b deploy/2026.08.27.02 — a plan with commands, and a schema claim that is checked
2026.08.27.01 was REFUSED before a single host was contacted, and the commander
was right twice over. its plan described the release instead of instructing the
rollout — no step list at all, where deploy/README.md defines a plan as "what to
run, in order, on which hosts" and steps 4 and 5 of the procedure are plan-driven.
and it asserted "nothing here changes a schema" on the day dav/schema.ts was
deleted out of core.

that second one was not a formatting mistake. dav_app_passwords now lives in
plugins/caldav, and gen-plugin-schemas follows plugin DIRECTORIES — so on a host
without that directory the table is in the database and not in the schema, and
`db:push` proposes dropping it. on alpha that is eight device credentials.

so this plan answers it from a survey rather than a guess. alpha has the plugin
and 8 rows; the other six have no plugin and an empty leftover table; zero hosts
run officer-marketplace, which retires the `tags` column question entirely. the
orphan table is dropped EXPLICITLY, guarded by a count, and skipped on alpha —
never as a db:push side effect.

step 6 is new and would have been missed: officer-opencode has to restart or none
of the skills, agent-identity or credential work in this release does anything.

ALSO THE SIGN-OUT. a single 401 from any endpoint wiped the token from both
storages and reloaded — which signs the owner out of every tab and keeps them
there, since nothing is left to recover from. that is the right response to a
revoked session and far too violent a response to one endpoint answering 401 for
its own reasons. it now confirms against /auth/me first, and treats an unreachable
server as emphatically not a revocation: rebooting the box must not end the
session. reported mid-demo, with nothing in the logs and a freshly signed token
working against every route the app loads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-28 20:27:11 +01:00
pastilhasandClaude Opus 5 ec6c793143 deploy/2026.08.27.01 — the plan, and the version to match it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 17:06:10 +01:00
pastilhasandClaude Opus 5 421e742590 a dock tile for /bots, which had a screen and no way in
the route, the screen and the list have existed since bots did — `/bots` and
`/bots/:sessionId` are both in App.tsx. what was missing was any way to GET
there: no entry in CORE_DOCK_ITEMS, so it could not even be added to a dock, and
no `nav.bots` label in any of the six locales.

placed beside Command HQ, which is the neighbouring idea: a commander runs a job,
a bot watches one thing. left as "Bots" in all six locales — a borrowed technical
noun, and inventing translations for it would be worse than not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-27 17:05:50 +01:00
pastilhasandClaude Opus 5 6e805c3607 the new wordmark in the header, following the theme
two marks, same 1062x220 crop: white "Off" for a dark background, dark "Off" for
a light one, yellow "icer" untouched in both. the dark variant is the light one
with only its DESATURATED pixels inverted, so the yellow is bit-identical and the
alpha and dimensions never move.

CLASSIFIED BY LUMINANCE, not by the mode comment. only 22 of the 227 theme files
declare one, and the cost of guessing wrong is a white wordmark on a white bar —
so each theme's own `--background` is read and thresholded. 203 dark, 24 light.

the signed-out screen is deliberately untouched and still uses the inline SVG.

AND THE BUG THIS UNCOVERED, which was not about logos at all. `useThemeAsset`
read the computed style inside an effect, and react runs CHILD effects before
parent ones — every consumer is a descendant of `ThemeProvider`, which sets
`data-theme` in ITS effect. so the read always saw the PREVIOUS theme's value:
switch themes and the logo was one theme behind, switch again and behind again.
it reads as a race and is deterministic, which is why it reproduced every time
somebody watched for it.

the read moved into requestAnimationFrame — past every effect in that commit and
past style recalculation — plus a MutationObserver on data-theme/class for the
case a frame cannot cover: a theme installed at runtime arrives as a <link> that
loads whenever it loads. the wallpaper uses the same hook for `--page-bg-src` and
had the same lag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-27 17:05:50 +01:00
241 changed files with 431 additions and 244 deletions
+37
View File
@@ -0,0 +1,37 @@
# deploy/2026.08.27.01
55 commits since `deploy/2026.08.26.02`. A full day's work, most of it in two areas.
## What is in it
**Calendar and contacts became usable rather than readable.** Create, edit and delete on both screens; a
filter on each; `?collection=<name>` instead of an escaped DAV path. The agent skill was rewritten off
hand-written iCalendar onto JSON routes — an editor now patches the stored text rather than rebuilding it,
so alarms, attendees and recurrence rules survive an edit made from a form that cannot show them.
**OpenCode can reach the platform.** It gets the skills index, an Officer identity instead of "you are a
coding agent", an API credential, and its permission prompts answered — a server session has nobody to
answer them and a turn simply hung. Its chats also keep their name, their transcript and their model when
reopened.
**Smaller, and each one somebody hit today:** `/api/notify/user` (and `/broadcast`, which had answered 404
since it landed — shadowed by the sidecar proxy's catch-all); a commander started from a plugin chat, so
pointing one at a mailbox no longer needs a path only the owner can type; file preview inside a
commander's own browser; a dock tile for `/bots`; and the new wordmark in the header, following the theme.
## Risk
Low-to-moderate. Nothing here changes a schema. The two worth watching after the rollout:
- **`useThemeAsset`** now reads in `requestAnimationFrame` rather than during the effect. It fixes the
logo and the wallpaper being one theme behind; if a themed asset ever fails to appear, this is the first
place to look.
- **The notify router's mount order.** The platform's own routes now sit before the sidecar proxy's
catch-all. Device registration still forwards — verified — but it is the change most likely to surprise.
## Hosts
Seven. `officer-dev` is skipped: it is the host running the rollout, and restarting it ends the rollout.
alpha · fofos · macbookpro · macbruno · production-pertento-bridge · edge-pertento-bridge ·
deadpool-rezio-bridge
+78
View File
@@ -0,0 +1,78 @@
# 2026.08.27.02
Everything in `2026.08.27.01`, which was **refused before any host was contacted** — its plan named no
commands and claimed "no schema change", which was false. This plan replaces it. `2026.08.27.01` stays
claimed and undeployed; do not try to revive it.
Plus one fix made because of that refusal: a single 401 no longer signs the owner out of every tab.
## The schema question, answered per host
`officer_db/src/dav/schema.ts` was **deleted** — `dav_app_passwords` moved into `plugins/caldav`.
`gen-plugin-schemas` follows plugin DIRECTORIES, so the table is only declared on a host that has
`plugins/caldav/`. Everywhere else `bun db:push` will propose **dropping** it.
Surveyed 2026-08-28, every host:
| Host | `plugins/caldav/` | `dav_app_passwords` |
| --- | --- | --- |
| `alpha` | present | **8 rows** |
| `fofos` | absent | present, 0 rows |
| `macbookpro` | absent | present, not read (bun at `/opt/homebrew/bin`) |
| `macbruno` | absent | present, 0 rows |
| `production-pertento-bridge` | absent | present, 0 rows |
| `edge-pertento-bridge` | absent | present, 0 rows |
| `deadpool-rezio-bridge` | absent | not read (ssh refused at survey time) |
So: **alpha pushes normally.** Everywhere else the table is a leftover of a feature that has left core,
and it is empty — but it is dropped **explicitly, with a guard**, not as a `db:push` side effect.
`officer_marketplace` and its new `tags` column: **no host runs `officer-marketplace`** — checked, zero
of seven. Nothing to apply. If that changes, the column has no push script and must be added by hand.
## Every host
1. `git fetch origin --tags` then `git merge --ff-only deploy/2026.08.27.02`
2. **Only if `plugins/caldav/` is ABSENT on this host** — retire the orphan table, refusing to if it
holds anything:
```
psql "$POSTGRES_URL" -Atc "select count(*) from dav_app_passwords"
# 0 → drop it: psql "$POSTGRES_URL" -c "drop table dav_app_passwords"
# anything else → STOP. Report the count and do not continue on this host.
```
Read the variable name from `.env` — several hosts use `OFFICERDEV_POSTGRES_URL`.
3. `bun db:push < /dev/null` — **stdin closed on purpose**, so a push needing an answer fails instead of
hanging. Expect **no changes** after step 2. Anything destructive: stop and report.
4. `bun run plugins:update`
5. `pm2 restart officer`
6. `pm2 restart officer-opencode` — this release rewires how OpenCode gets its skills, its agent identity
and its credential, and all of that is built when the sidecar boots. Without this the code ships and
nothing about OpenCode changes.
**`alpha`:** skip step 2 entirely — it has the plugin and 8 real credentials in that table. Step 3 runs
normally and must report no changes.
**`macbookpro`:** prepend `/opt/homebrew/bin` to PATH for `bun`; run `pm2` separately. Asleep is a skip
with a note.
**`deadpool-rezio-bridge`:** login is `br`, checkout `/home/br/officerdev/platform`. SSH refused once
during the survey — if it refuses again, note it and move on rather than retrying in a loop.
**Do not restart `officer-claude-code`.** It ends every live agent session on the host, nothing here needs
it, and it is the owner's call.
## Risk
Moderate, and concentrated in step 2 — the only destructive command in this release. It is guarded by a
count and it is skipped on the one host where the table has contents.
After the rollout, two things are worth a look: `useThemeAsset` now reads in `requestAnimationFrame`, so
a themed logo or wallpaper failing to appear points here; and the notify router's mount order changed, so
device registration is worth one check (it forwards correctly on `officer-dev`).
## Hosts
alpha · fofos · macbookpro · macbruno · production-pertento-bridge · edge-pertento-bridge ·
deadpool-rezio-bridge
`officer-dev` is skipped: it is the host running the rollout.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "officer", "name": "officer",
"version": "2026.08.26.02", "version": "2026.08.27.02",
"private": true, "private": true,
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

@@ -142,22 +142,23 @@ export const Dock = ({ items, className, boundaryRef }: DockProps) => {
}; };
import { import {
Home,
MessageCircle,
FolderOpen,
Code,
LayoutGrid,
Monitor,
Globe,
Workflow,
Music,
Activity, Activity,
Radio, Bot,
Code,
FolderOpen,
GitBranch, GitBranch,
Store, Globe,
Home,
LayoutGrid,
MessageCircle,
Monitor,
Music,
Puzzle, Puzzle,
Radar, Radar,
Radio,
Send, Send,
Store,
Workflow,
} from 'lucide-react'; } from 'lucide-react';
/** /**
@@ -176,6 +177,10 @@ export const CORE_DOCK_ITEMS: CoreDockItem[] = [
{ labelKey: 'nav.files', to: '/files', icon: FolderOpen, color: '#fbbf24' }, { labelKey: 'nav.files', to: '/files', icon: FolderOpen, color: '#fbbf24' },
{ labelKey: 'nav.chat', to: '/chat', icon: MessageCircle, color: '#60a5fa' }, { labelKey: 'nav.chat', to: '/chat', icon: MessageCircle, color: '#60a5fa' },
{ labelKey: 'nav.commandHq', to: '/command-hq', icon: Radar, color: '#f43f5e' }, { labelKey: 'nav.commandHq', to: '/command-hq', icon: Radar, color: '#f43f5e' },
// Beside Command HQ, which is the neighbouring idea: a commander runs a job, a bot watches one thing.
// The route and the screen have existed since bots did; there was simply never a tile, so the only way
// to reach /bots was to type it.
{ labelKey: 'nav.bots', to: '/bots', icon: Bot, color: '#34d399' },
{ labelKey: 'nav.editor', to: '/code-editor', icon: Code, color: '#a78bfa' }, { labelKey: 'nav.editor', to: '/code-editor', icon: Code, color: '#a78bfa' },
{ labelKey: 'nav.jobs', to: '/jobs', icon: Workflow, color: '#14b8a6' }, { labelKey: 'nav.jobs', to: '/jobs', icon: Workflow, color: '#14b8a6' },
{ labelKey: 'nav.terminal', to: '/terminal', icon: Monitor, color: '#f97316' }, { labelKey: 'nav.terminal', to: '/terminal', icon: Monitor, color: '#f97316' },
+1
View File
@@ -463,6 +463,7 @@
"files": "Dateien", "files": "Dateien",
"chat": "Chat", "chat": "Chat",
"commandHq": "Command HQ", "commandHq": "Command HQ",
"bots": "Bots",
"editor": "Editor", "editor": "Editor",
"jobs": "Jobs", "jobs": "Jobs",
"terminal": "Terminal", "terminal": "Terminal",
+1
View File
@@ -463,6 +463,7 @@
"files": "Files", "files": "Files",
"chat": "Chat", "chat": "Chat",
"commandHq": "Command HQ", "commandHq": "Command HQ",
"bots": "Bots",
"editor": "Editor", "editor": "Editor",
"jobs": "Jobs", "jobs": "Jobs",
"terminal": "Terminal", "terminal": "Terminal",
+1
View File
@@ -463,6 +463,7 @@
"files": "Archivos", "files": "Archivos",
"chat": "Chat", "chat": "Chat",
"commandHq": "Command HQ", "commandHq": "Command HQ",
"bots": "Bots",
"editor": "Editor", "editor": "Editor",
"jobs": "Trabajos", "jobs": "Trabajos",
"terminal": "Terminal", "terminal": "Terminal",
+1
View File
@@ -463,6 +463,7 @@
"files": "Fichiers", "files": "Fichiers",
"chat": "Chat", "chat": "Chat",
"commandHq": "Command HQ", "commandHq": "Command HQ",
"bots": "Bots",
"editor": "Éditeur", "editor": "Éditeur",
"jobs": "Jobs", "jobs": "Jobs",
"terminal": "Terminal", "terminal": "Terminal",
+1
View File
@@ -463,6 +463,7 @@
"files": "Ficheiros", "files": "Ficheiros",
"chat": "Chat", "chat": "Chat",
"commandHq": "Command HQ", "commandHq": "Command HQ",
"bots": "Bots",
"editor": "Editor", "editor": "Editor",
"jobs": "Trabalhos", "jobs": "Trabalhos",
"terminal": "Terminal", "terminal": "Terminal",
+1
View File
@@ -463,6 +463,7 @@
"files": "Filer", "files": "Filer",
"chat": "Chatt", "chat": "Chatt",
"commandHq": "Command HQ", "commandHq": "Command HQ",
"bots": "Bots",
"editor": "Editor", "editor": "Editor",
"jobs": "Jobb", "jobs": "Jobb",
"terminal": "Terminal", "terminal": "Terminal",
+39
View File
@@ -206,6 +206,45 @@ const handleRevokedSession = (url: string) => {
if (revocationHandled) return; if (revocationHandled) return;
revocationHandled = true; revocationHandled = true;
/*
Guard 2b: CONFIRM the session is dead before destroying it.
A 401 from any one endpoint used to be enough to wipe the token out of both storages and reload —
which signs the owner out of every tab, and keeps them signed out, because there is then no token
anywhere to recover from. That is the right response to a revoked session and far too violent a
response to one endpoint answering 401 for its own reasons.
Reported 2026-08-27, mid-demo: every refresh and every new tab came back signed out, with nothing in
the logs and a freshly signed token working fine against every route the app loads. One transient
401 is indistinguishable from a revocation at the call site — so ask the one endpoint whose whole
job is to answer it.
`/auth/me` is exempt from this handler (the `/auth/` guard above), so this cannot recurse.
*/
void (async () => {
try {
// Derived from the URL that just failed, because the base is passed per call rather than held in
// config — a relative guess would be wrong on any host that mounts the API elsewhere.
const probe = /\/api\//.test(url) ? url.replace(/\/api\/.*$/, '/api/auth/me') : '/api/auth/me';
const res = await fetch(probe, { headers: { Authorization: `Bearer ${theToken}` } });
// Still good: that 401 belonged to one endpoint, not to the session. Leave everything alone and
// let the next revocation try again.
if (res.ok) {
revocationHandled = false;
return;
}
} catch {
// The server is unreachable — a restart, a dropped network. Emphatically not a revocation, and
// wiping the session because the box was rebooting is the failure this guard exists to stop.
revocationHandled = false;
return;
}
destroySession();
})();
};
/** Actually end it: forget the token everywhere a load could read it back, then reload once. */
const destroySession = () => {
theToken = null; theToken = null;
// Every key `createClient` reads, or the next load signs straight back in with the dead token. // Every key `createClient` reads, or the next load signs straight back in with the dead token.
for (const key of ['PERTENTO_EDITOR_AUTH_TOKEN', 'BEARER_TOKEN']) { for (const key of ['PERTENTO_EDITOR_AUTH_TOKEN', 'BEARER_TOKEN']) {
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #eb8c60; --duck-orange: #eb8c60;
--duck-forest: #cea37f; --duck-forest: #cea37f;
--duck-beige: #252422; --duck-beige: #252422;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #8e707d; --duck-orange: #8e707d;
--duck-forest: #014761; --duck-forest: #014761;
--duck-beige: #222225; --duck-beige: #222225;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #c58364; --duck-orange: #c58364;
--duck-forest: #66987b; --duck-forest: #66987b;
--duck-beige: #2e3a37; --duck-beige: #2e3a37;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #a2e080; --duck-orange: #a2e080;
--duck-forest: #e20342; --duck-forest: #e20342;
--duck-beige: #0f1b2c; --duck-beige: #0f1b2c;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #a64c2e; --duck-orange: #a64c2e;
--duck-forest: #a46d2d; --duck-forest: #a46d2d;
--duck-beige: #dacbb3; --duck-beige: #dacbb3;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #ca5832; --duck-orange: #ca5832;
--duck-forest: #66cc33; --duck-forest: #66cc33;
--duck-beige: #1a1a1a; --duck-beige: #1a1a1a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #c55b5b; --duck-orange: #c55b5b;
--duck-forest: #c05a5a; --duck-forest: #c05a5a;
--duck-beige: #312727; --duck-beige: #312727;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #a3a79f; --duck-orange: #a3a79f;
--duck-forest: #98b3a3; --duck-forest: #98b3a3;
--duck-beige: #36393a; --duck-beige: #36393a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #fc8670; --duck-orange: #fc8670;
--duck-forest: #00e8c6; --duck-forest: #00e8c6;
--duck-beige: #363940; --duck-beige: #363940;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #e7e7e7; --duck-orange: #e7e7e7;
--duck-forest: #bdbdbd; --duck-forest: #bdbdbd;
--duck-beige: #191919; --duck-beige: #191919;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #bfa09a; --duck-orange: #bfa09a;
--duck-forest: #98a09b; --duck-forest: #98a09b;
--duck-beige: #292524; --duck-beige: #292524;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #e7914b; --duck-orange: #e7914b;
--duck-forest: #3cec85; --duck-forest: #3cec85;
--duck-beige: #222535; --duck-beige: #222535;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #f0957e; --duck-orange: #f0957e;
--duck-forest: #9ece6a; --duck-forest: #9ece6a;
--duck-beige: #31323c; --duck-beige: #31323c;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #fcb39c; --duck-orange: #fcb39c;
--duck-forest: #5ffbf1; --duck-forest: #5ffbf1;
--duck-beige: #2d1c43; --duck-beige: #2d1c43;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #ab635d; --duck-orange: #ab635d;
--duck-forest: #9f6769; --duck-forest: #9f6769;
--duck-beige: #2f3235; --duck-beige: #2f3235;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #949494; --duck-orange: #949494;
--duck-forest: #767676; --duck-forest: #767676;
--duck-beige: #272727; --duck-beige: #272727;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #e8925a; --duck-orange: #e8925a;
--duck-forest: #87c05f; --duck-forest: #87c05f;
--duck-beige: #272a30; --duck-beige: #272a30;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #be9379; --duck-orange: #be9379;
--duck-forest: #79be9a; --duck-forest: #79be9a;
--duck-beige: #3b353a; --duck-beige: #3b353a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #b07d22; --duck-orange: #b07d22;
--duck-forest: #7d9726; --duck-forest: #7d9726;
--duck-beige: #35342e; --duck-beige: #35342e;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #e5b9d8; --duck-orange: #e5b9d8;
--duck-forest: #8be9fd; --duck-forest: #8be9fd;
--duck-beige: #3d3f49; --duck-beige: #3d3f49;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #f28e61; --duck-orange: #f28e61;
--duck-forest: #7fd962; --duck-forest: #7fd962;
--duck-beige: #1d2024; --duck-beige: #1d2024;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #eb8b59; --duck-orange: #eb8b59;
--duck-forest: #6cbf43; --duck-forest: #6cbf43;
--duck-beige: #e0e2e3; --duck-beige: #e0e2e3;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f4a771; --duck-orange: #f4a771;
--duck-forest: #87d96c; --duck-forest: #87d96c;
--duck-beige: #30353f; --duck-beige: #30353f;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #1ab3e6; --duck-orange: #1ab3e6;
--duck-forest: #00e0b8; --duck-forest: #00e0b8;
--duck-beige: #1a2431; --duck-beige: #1a2431;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #819fb7; --duck-orange: #819fb7;
--duck-forest: #61a7d6; --duck-forest: #61a7d6;
--duck-beige: #2e3a4b; --duck-beige: #2e3a4b;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #703922; --duck-orange: #703922;
--duck-forest: #921416; --duck-forest: #921416;
--duck-beige: #2e241f; --duck-beige: #2e241f;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #edec32; --duck-orange: #edec32;
--duck-forest: #c8be46; --duck-forest: #c8be46;
--duck-beige: #292b2b; --duck-beige: #292b2b;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #d4b192; --duck-orange: #d4b192;
--duck-forest: #a5a297; --duck-forest: #a5a297;
--duck-beige: #212121; --duck-beige: #212121;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #d9966e; --duck-orange: #d9966e;
--duck-forest: #789fa2; --duck-forest: #789fa2;
--duck-beige: #26292e; --duck-beige: #26292e;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #f1976e; --duck-orange: #f1976e;
--duck-forest: #9fc69a; --duck-forest: #9fc69a;
--duck-beige: #2f3d46; --duck-beige: #2f3d46;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #ed6d54; --duck-orange: #ed6d54;
--duck-forest: #7ad573; --duck-forest: #7ad573;
--duck-beige: #371a2e; --duck-beige: #371a2e;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #e39c45; --duck-orange: #e39c45;
--duck-forest: #768f80; --duck-forest: #768f80;
--duck-beige: #2d2726; --duck-beige: #2d2726;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #8f8f8f; --duck-orange: #8f8f8f;
--duck-forest: #8e8e8e; --duck-forest: #8e8e8e;
--duck-beige: #1a1a1a; --duck-beige: #1a1a1a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #905b57; --duck-orange: #905b57;
--duck-forest: #a3850e; --duck-forest: #a3850e;
--duck-beige: #23221e; --duck-beige: #23221e;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #985962; --duck-orange: #985962;
--duck-forest: #2a593f; --duck-forest: #2a593f;
--duck-beige: #20201d; --duck-beige: #20201d;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #be989b; --duck-orange: #be989b;
--duck-forest: #8fecd5; --duck-forest: #8fecd5;
--duck-beige: #1d1f1f; --duck-beige: #1d1f1f;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #a20f0f; --duck-orange: #a20f0f;
--duck-forest: #ff3535; --duck-forest: #ff3535;
--duck-beige: #2e1a1a; --duck-beige: #2e1a1a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #d1a256; --duck-orange: #d1a256;
--duck-forest: #7ea67c; --duck-forest: #7ea67c;
--duck-beige: #30353b; --duck-beige: #30353b;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #893f3f; --duck-orange: #893f3f;
--duck-forest: #630a0a; --duck-forest: #630a0a;
--duck-beige: #262525; --duck-beige: #262525;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #da6864; --duck-orange: #da6864;
--duck-forest: #806c61; --duck-forest: #806c61;
--duck-beige: #30211f; --duck-beige: #30211f;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -90,5 +90,5 @@
--duck-orange: #d84e2b; --duck-orange: #d84e2b;
--duck-forest: #40a02b; --duck-forest: #40a02b;
--duck-beige: #ced2db; --duck-beige: #ced2db;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f6b7ac; --duck-orange: #f6b7ac;
--duck-forest: #a6e3a1; --duck-forest: #a6e3a1;
--duck-beige: #303042; --duck-beige: #303042;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -90,5 +90,5 @@
--duck-orange: #f6b6ab; --duck-orange: #f6b6ab;
--duck-forest: #a6e3a1; --duck-forest: #a6e3a1;
--duck-beige: #303042; --duck-beige: #303042;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f6b7ac; --duck-orange: #f6b7ac;
--duck-forest: #a6e3a1; --duck-forest: #a6e3a1;
--duck-beige: #2c2e33; --duck-beige: #2c2e33;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #c22a2a; --duck-orange: #c22a2a;
--duck-forest: #dce0e6; --duck-forest: #dce0e6;
--duck-beige: #282a30; --duck-beige: #282a30;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f6b7ac; --duck-orange: #f6b7ac;
--duck-forest: #a6e3a1; --duck-forest: #a6e3a1;
--duck-beige: #242531; --duck-beige: #242531;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #874400; --duck-orange: #874400;
--duck-forest: #008700; --duck-forest: #008700;
--duck-beige: #d6d6d6; --duck-beige: #d6d6d6;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #fb8f39; --duck-orange: #fb8f39;
--duck-forest: #d1d2d1; --duck-forest: #d1d2d1;
--duck-beige: #1d1c1c; --duck-beige: #1d1c1c;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #eac027; --duck-orange: #eac027;
--duck-forest: #ffc107; --duck-forest: #ffc107;
--duck-beige: #2d190c; --duck-beige: #2d190c;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #c68061; --duck-orange: #c68061;
--duck-forest: #e48a3e; --duck-forest: #e48a3e;
--duck-beige: #312d37; --duck-beige: #312d37;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #ff271e; --duck-orange: #ff271e;
--duck-forest: #27a75c; --duck-forest: #27a75c;
--duck-beige: #360606; --duck-beige: #360606;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #2c4869; --duck-orange: #2c4869;
--duck-forest: #2d4764; --duck-forest: #2d4764;
--duck-beige: #121b24; --duck-beige: #121b24;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #a93b19; --duck-orange: #a93b19;
--duck-forest: #396847; --duck-forest: #396847;
--duck-beige: #dbd7d8; --duck-beige: #dbd7d8;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #a49a9a; --duck-orange: #a49a9a;
--duck-forest: #a49a9a; --duck-forest: #a49a9a;
--duck-beige: #1a1a1a; --duck-beige: #1a1a1a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #ca9741; --duck-orange: #ca9741;
--duck-forest: #5a9f72; --duck-forest: #5a9f72;
--duck-beige: #183357; --duck-beige: #183357;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #a6a3d3; --duck-orange: #a6a3d3;
--duck-forest: #7f86b8; --duck-forest: #7f86b8;
--duck-beige: #282a34; --duck-beige: #282a34;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #ff9382; --duck-orange: #ff9382;
--duck-forest: #05ffa1; --duck-forest: #05ffa1;
--duck-beige: #251b37; --duck-beige: #251b37;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #cf340e; --duck-orange: #cf340e;
--duck-forest: #586259; --duck-forest: #586259;
--duck-beige: #242321; --duck-beige: #242321;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #bd7a5d; --duck-orange: #bd7a5d;
--duck-forest: #7a9977; --duck-forest: #7a9977;
--duck-beige: #dfdcd9; --duck-beige: #dfdcd9;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #d38760; --duck-orange: #d38760;
--duck-forest: #5fb3ac; --duck-forest: #5fb3ac;
--duck-beige: #2f2f37; --duck-beige: #2f2f37;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #e3964e; --duck-orange: #e3964e;
--duck-forest: #b14242; --duck-forest: #b14242;
--duck-beige: #292929; --duck-beige: #292929;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #f8a871; --duck-orange: #f8a871;
--duck-forest: #1e90ff; --duck-forest: #1e90ff;
--duck-beige: #272a3d; --duck-beige: #272a3d;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #f8a871; --duck-orange: #f8a871;
--duck-forest: #50fa7b; --duck-forest: #50fa7b;
--duck-beige: #3d3f49; --duck-beige: #3d3f49;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #fb8f91; --duck-orange: #fb8f91;
--duck-forest: #78a682; --duck-forest: #78a682;
--duck-beige: #2d2328; --duck-beige: #2d2328;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #900b8a; --duck-orange: #900b8a;
--duck-forest: #7f049e; --duck-forest: #7f049e;
--duck-beige: #221e2d; --duck-beige: #221e2d;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -61,7 +61,7 @@
--header-border: rgba(255, 255, 255, 0.35); --header-border: rgba(255, 255, 255, 0.35);
--header-fg: #1d2724; --header-fg: #1d2724;
--header-blur: 24px; --header-blur: 24px;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
/* ── Surfaces ─────────────────────────────────────────────────────────────────────────────────── */ /* ── Surfaces ─────────────────────────────────────────────────────────────────────────────────── */
--glass-bg: rgba(0, 0, 0, 0.2); --glass-bg: rgba(0, 0, 0, 0.2);
@@ -63,7 +63,7 @@
--header-border: rgba(255, 255, 255, 0.35); --header-border: rgba(255, 255, 255, 0.35);
--header-fg: #1d2724; --header-fg: #1d2724;
--header-blur: 24px; --header-blur: 24px;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
/* ── Surfaces ───────────────────────────────────────────────────────────────────────────────── /* ── Surfaces ─────────────────────────────────────────────────────────────────────────────────
Panels are the cornerstone of the layout, so they are themed as first-class surfaces rather than Panels are the cornerstone of the layout, so they are themed as first-class surfaces rather than
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #cfa370; --duck-orange: #cfa370;
--duck-forest: #70cf6c; --duck-forest: #70cf6c;
--duck-beige: #1a1d1a; --duck-beige: #1a1d1a;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #d77f59; --duck-orange: #d77f59;
--duck-forest: #9e8f70; --duck-forest: #9e8f70;
--duck-beige: #2e2d2b; --duck-beige: #2e2d2b;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -90,5 +90,5 @@
--duck-orange: #eb8b54; --duck-orange: #eb8b54;
--duck-forest: #92a593; --duck-forest: #92a593;
--duck-beige: #1f1f2c; --duck-beige: #1f1f2c;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #cc5f39; --duck-orange: #cc5f39;
--duck-forest: #8edf5f; --duck-forest: #8edf5f;
--duck-beige: #332744; --duck-beige: #332744;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f28c89; --duck-orange: #f28c89;
--duck-forest: #29d398; --duck-forest: #29d398;
--duck-beige: #2e3037; --duck-beige: #2e3037;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #e59e70; --duck-orange: #e59e70;
--duck-forest: #8ccf7e; --duck-forest: #8ccf7e;
--duck-beige: #282e31; --duck-beige: #282e31;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -90,5 +90,5 @@
--duck-orange: #e09d7f; --duck-orange: #e09d7f;
--duck-forest: #a7c080; --duck-forest: #a7c080;
--duck-beige: #3e4446; --duck-beige: #3e4446;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f5a88d; --duck-orange: #f5a88d;
--duck-forest: #cbe3b3; --duck-forest: #cbe3b3;
--duck-beige: #313a3c; --duck-beige: #313a3c;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #ab9b8d; --duck-orange: #ab9b8d;
--duck-forest: #9bab8c; --duck-forest: #9bab8c;
--duck-beige: #35373b; --duck-beige: #35373b;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #949494; --duck-orange: #949494;
--duck-forest: #e7e9ea; --duck-forest: #e7e9ea;
--duck-beige: #171717; --duck-beige: #171717;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f16e2c; --duck-orange: #f16e2c;
--duck-forest: #2a9d8f; --duck-forest: #2a9d8f;
--duck-beige: #193641; --duck-beige: #193641;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #cc907d; --duck-orange: #cc907d;
--duck-forest: #889889; --duck-forest: #889889;
--duck-beige: #212835; --duck-beige: #212835;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #e6622d; --duck-orange: #e6622d;
--duck-forest: #1a6b6e; --duck-forest: #1a6b6e;
--duck-beige: #242322; --duck-beige: #242322;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f8a871; --duck-orange: #f8a871;
--duck-forest: #50fa7b; --duck-forest: #50fa7b;
--duck-beige: #3d3f49; --duck-beige: #3d3f49;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #ae5a15; --duck-orange: #ae5a15;
--duck-forest: #66800b; --duck-forest: #66800b;
--duck-beige: #232221; --duck-beige: #232221;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -90,5 +90,5 @@
--duck-orange: #d0772b; --duck-orange: #d0772b;
--duck-forest: #879a39; --duck-forest: #879a39;
--duck-beige: #d1cfc5; --duck-beige: #d1cfc5;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark-dark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #e6a58a; --duck-orange: #e6a58a;
--duck-forest: #a6d189; --duck-forest: #a6d189;
--duck-beige: #3d4256; --duck-beige: #3d4256;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #f27128; --duck-orange: #f27128;
--duck-forest: #10b981; --duck-forest: #10b981;
--duck-beige: #26272b; --duck-beige: #26272b;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
@@ -93,5 +93,5 @@
--duck-orange: #dc9379; --duck-orange: #dc9379;
--duck-forest: #6bbf7a; --duck-forest: #6bbf7a;
--duck-beige: #1e2e22; --duck-beige: #1e2e22;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }
+1 -1
View File
@@ -93,5 +93,5 @@
--duck-orange: #93a4b2; --duck-orange: #93a4b2;
--duck-forest: #95a8b8; --duck-forest: #95a8b8;
--duck-beige: #1e232f; --duck-beige: #1e232f;
--logo-src: '/officer-logo.svg'; --logo-src: '/officer-wordmark.png';
} }

Some files were not shown because too many files have changed in this diff Show More