agnes-the-ai-analyst/app/web/templates/home_not_onboarded.html
Vojtech 001e5ce40e
feat(web): /home value-first redesign + unified page-shell across app (#366)
* feat(web): value-first /home reskin (CEO mock palette + pillars + first-session)

Restructures `/home` to lead with product value instead of install steps,
matching the CEO mock proposed for the homepage:

- New intro hero on top — eyebrow `Welcome, {{ display_name }}`, H1
  `{{ instance_brand }} is your team's AI workspace`, lede framing the
  product as an "AI Chief of Staff", two CTAs (`Set up in ~15 min →`
  jumps to the wizard, `Just browse — no install needed` jumps to
  `#look-around`), and a four-pillar row (Data packages · Plugins ·
  Skills · Memory). Renders for both onboarded and not-onboarded users
  so the value framing is consistent across visits.
- New `first-session` narrative — five-beat walkthrough (launch → pick
  project → memory loads → ask → close) with mock terminal frames
  carrying traffic-light dots, prompts, and dimmed system output.
- Setup wizard chrome — progress chip (`Step 1 of N · ~15 min ·
  One-time · Reversible`), thin progress bar, and per-step number
  badges on each `.install-block` so the wizard reads as bounded
  instead of an open-ended scroll.
- Palette shift from blue to green/navy: `--hp-primary` aliases
  `#2ea877` (mint), `--hp-hero-bg` is navy `#0f1b3a`, code panels stay
  near-black `#0c1224` with warm-yellow `#ffd866` accents. The token
  alias is reused so downstream rules pick up the new accent
  automatically; instance theme overrides via
  `config.theme_overrides()` still win.
- VS Code surface tile carries a `Recommended` pill; the existing
  "Want to look around first?" section is renamed to `Explore your
  workspace` and gets the `#look-around` anchor.

All test-pinned class names and IDs (`install-hero`, `install-block`,
`home-mock`, `self-mark-btn`, `setupClaudeBtn`, `offboard-strip`,
`home-getting-started`, `home-gs-item`, `home-overview`,
`home-usage`) preserved as structural anchors; new visual language
overlays via additional classes. Existing onboarded/not-onboarded
branching, `/api/me/onboarded` POST, status frame gating, post-CTA
modal, and OS-tab switching JS unchanged. Stray `~/FoundryAI`
comment swapped for `~/{{ workspace_dir }}` to honor the
vendor-agnostic OSS rule.

51 home tests pass without modification.

* fix(web): /home palette inversion — dark intro hero on top, light setup card below

Previous reskin commit kept the install-hero as a dark navy gradient and
rendered the new intro hero as a light surface — opposite of what the CEO
mock specifies. Playwright comparison vs `data/ceo_home.html` confirmed:

- CEO mock: dark navy hero at TOP (with white pillars on navy), LIGHT
  white setup card BELOW with light step rows and dark code panels
  inset.
- Previous: light intro hero on top, dark setup card below. Inverted.

This patch flips both:

- `.home-hero-intro` now: dark navy gradient `#0f1b3a → #1a2a5f`, green
  radial glow in the corner, green eyebrow, white H1 (`accent` span
  green), rgba-white lede, green pill primary CTA, translucent-white
  secondary CTA, pillars row separated by hairline border-top with
  green square-dot bullets in front of each pillar header.
- `.install-hero` and `.install-block` now: white surface card with
  thin green accent strip across the top, light step rows split by
  hairline borders, green-tinted step-number circles (`#e6f9f0` bg,
  `#1f8a5e` ink), green progress chip + bar. Code panels
  (`.install-cmd`) and terminal frames stay dark — they're the "type
  this" surfaces.
- All previously-rgba-white descendants of `.install-hero`
  (close button, eyebrow, h1, lead, links, code chips, OS tabs,
  install notes, setup-CTA button, self-mark fallback, auto-detect
  badge, terminal-howto disclosure) re-skinned for light surface.

All 12 home page tests still pass (no markup changes, only CSS).

* fix(web): /home parity polish — system font + mock sizes + blue info hint + gray step-num

After v2 palette flip, user comparison vs CEO mock surfaced three
remaining gaps in the wizard area:

- Font stack mismatch: Agnes inherits Inter via `style-custom.css`,
  but the CEO mock uses the platform system stack (San Francisco on
  macOS, Segoe UI on Windows). The rendered weight/letterforms read
  noticeably different. `.home-mock` now declares
  `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`
  for itself and all descendants, with the monospace stack reserved
  for `code`/`kbd`/`pre`, `.install-cmd`, and `.terminal-body`.
- Step number badges were green-tinted; mock uses neutral gray
  (`#f0f2f6` bg, `#4a5168` ink) — green is reserved for the "done"
  state. Switched to `--hp-surface-dim` + `--hp-text-secondary`.
- "Don't have a terminal open?" disclosure was an amber/yellow
  variant left over from the old dark-hero palette. Mock uses a
  blue info-hint vocabulary (`--info-bg: #eef3ff`,
  `--info-line: #4f7cf2`, `--info-ink: #1c3994`) with white kbd
  chips. Added the info-* tokens to the `:root` block and re-skinned
  `details.terminal-howto` (incl. summary, body, kbd) to match.

Step-body type sizes also brought in line with the mock spec —
`.install-block .label` (step h3 equivalent) is now 17px / 700 with
6px gap; `.install-note` body type is 14px / 1.55.

`--hp-info-bg / --hp-info-ink / --hp-info-line / --hp-warn-bg /
--hp-warn-ink / --hp-warn-line / --hp-surface-dim` added as
first-class tokens so future hint/warn callouts pick the same colors
without a duplicate vocabulary.

12/12 home tests pass.

* feat(web): centralize design tokens + reword /home wizard to 6 steps (CEO mock parity)

Two intertwined changes that touch both global design + /home structure:

GLOBAL TOKEN SHIFT (app/web/static/style-custom.css)
- `--primary` flipped from blue `#0073D1` to green `#2ea877` — same brand
  alias the rest of the app referenced, so every page picks up the new
  accent automatically. Old `--primary-dark` / `--primary-light` recolored
  to match.
- New tokens added: `--brand-accent`, `--hero-bg`, `--hero-ink`,
  `--surface-dim`, `--info-bg/ink/line`, `--warn-bg/ink/line`. Brings
  the global vocabulary in line with the CEO mock's `:root` block so
  callouts and hero surfaces don't have to invent local tokens.
- `--font-primary` switched from Inter-led stack to the system stack
  (`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter",
  system-ui, sans-serif`) so weight/letterforms render identically on
  macOS (San Francisco) and Windows (Segoe UI) — matches the mock and
  avoids a font-loading flash for analysts without Inter installed.
- Shadow tints re-cast in navy `rgba(15,27,58,...)`; focus ring uses
  the new green `rgba(46,168,119,0.25)`.
- `.app-nav-link` font-size 13px → 14px, padding 6px 12px → 8px 14px,
  hover bg → `--primary-light` (mint), color → `--primary-dark`.
  `.app-nav-menu-item.is-active` re-tinted to the same green system.
- Sweep across 26 templates (style-custom.css + 25 template files)
  replacing every hardcoded `#0073D1` / `#005BA3` / `#E6F3FC` /
  `rgba(0,115,209,…)` / `rgba(0,86,163,…)` with token references or
  the new green hexes — 175 occurrences total. Pages that styled their
  own buttons / borders / shadows pick up the new brand color without
  per-page overrides.

/HOME WIZARD: 6 STEPS PER MOCK (app/web/templates/home_not_onboarded.html)
- Step 1 reworded `Install Claude Code on your computer` + `~3 min`
  subhead (mock copy).
- Step 2 renamed `Pick a folder for {{ instance_brand }}` (was
  `create your workspace folder`) — same `mkdir` command, mock-aligned
  framing.
- NEW Step 3 `Open a terminal inside that folder` — no shell command,
  just the "you are standing in the right directory" reassurance with
  a Finder/PowerShell/file-manager howto disclosure. Mirrors the CEO
  mock's Step 3.
- Step 4 (was Step 3, gated by `home_automode.show`) renamed
  `Launch Claude with auto-approve on`. Body copy lightly updated so
  it references "the next step" instead of "Step 4".
- Step 5 (was Step 4) renamed `Get the install script and paste it
  into Claude`. The setup-cta-lead now explicitly says
  "pasting the script into Claude Code will install {{ instance_brand
  }}…" so existing test assertions pinning the `install Agnes`
  substring still match.
- NEW Step 6 `Optional: create a one-word shortcut for next time` —
  prints an `echo 'alias {{workspace_dir|lower}}=…' >> ~/.zshrc`
  one-liner for Unix and an `Add-Content $PROFILE …` equivalent for
  Windows. OS tabs + copy buttons reuse the existing wizard chrome.
- Progress chip dynamic: `Step 1 of 6` when home_automode is on,
  `Step 1 of 5` when off. Progress bar fill `100 // total_steps` so
  the bar sits at 16-20 % on first paint.
- `.step-lede` token added for the new short body copy beneath each
  step label (14.5px / ink-soft).
- `macOS / Linux / WSL` tab labels changed to `macOS / Linux` per
  user instruction. Terminal-howto `WSL:` paragraph dropped; the
  paste-shortcut hint now reads `(Linux)` instead of `(Linux/WSL)`.
  Functional WSL handling in `connector_prompts.py` (it's a Linux
  detection fallback, not user-facing label) preserved.
- `setup_instructions.py` Claude Code install hint:
  `npm (Linux / WSL)` → `npm (Linux)`.

SURFACES — 4 CARDS PER MOCK
- Replaced the 3-tile `.home-usage-grid` with a 4-card grid:
  - VS Code (Recommended) — `.surface-card.feature`, green ring,
    DAILY USE eyebrow + 5-step numbered list + `Open VS Code setup
    guide →` link to `/setup-advanced#vscode`.
  - Terminal — QUICK ACCESS eyebrow + 4-step list.
  - Claude Code (Desktop app) — CONNECT IT eyebrow + 4-step list.
  - Cowork (claude.ai) — `.surface-card.incomplete`, warn-tinted
    border + `Instructions needed` badge + a TODO callout describing
    the missing content. The card is intentionally honest about the
    gap rather than hiding it.

TEST UPDATES
- `test_web_home_page.py` negative onboarded-state assertions
  rebased on the new step labels (6 entries instead of 4).
- `test_home_route_resolution.py` `test_home_renders_automode_block_by_default`
  + its `_when_env_off` counterpart now check the new
  `Step 4 — Launch Claude with auto-approve on` label.

* fix(web): /home section content + layout — verbatim mock match

User comparison flagged several remaining gaps; this patch rewrites
the three lower sections of /home to match the CEO mock spec exactly:

FIRST-SESSION (5 beats)
- h2 28px / 700 / -.5px tracking (was 19px / 600).
- lede 18px ink-soft (was 13.5px secondary).
- `.session-walk` wrapper, 36px gap between beats (mock spec).
- `.session-step` grid 48px / 1fr, gap 22px — number circle on
  the left, content on the right.
- `.session-num` 40 × 40 circle with SOLID GREEN bg (`--primary`)
  and WHITE text + soft green shadow (was 28px mint pill w/
  dark-green text).
- `.session-content h3` 18px / 600 (was 14.5px / 600).
- `.session-content > p` 15px.
- `.session-content .annotation` 13.5px ink-muted body type with
  `strong` for highlighting (replaces the upper-case "WHAT'S
  HAPPENING" eyebrow pattern that didn't match the mock).
- `.session-intro` callout card (white surface + mint icon block)
  framing the "five beats" tagline.
- `.session-tldr` summary box (brand-light bg + brand-dark left
  border) wrapping up the loop.
- Terminal frames re-skinned: `#0c1224` body / `#182241` bar /
  real macOS traffic-light colors `#ff5f57` / `#febc2e` / `#28c840`.
- Terminal body 13px / 1.65 line-height with mock-spec class
  vocabulary: `.you` (yellow input), `.ai-name` (brand bold),
  `.path` (light blue), `.dim` (translucent code-ink), `.caret`
  (blinking cursor).
- Five beats rewritten with mock's exact narrative flow (launch →
  menu → pick → ask → close), vendor-agnostic project names
  (`RevenueAnalysis`, `Onboarding`, etc.) replacing the customer-
  specific `GRPN_*` examples in the mock. Templated `{{
  instance_brand }}` / `{{ workspace_dir }}` / `{{ workspace_dir |
  lower }}` (the shortcut alias) everywhere.

SURFACES (4 cards)
- The section is no longer wrapped in a white rectangle; the
  `.home-usage` class loses its bg + border + padding (mock has the
  cards directly on the page bg).
- h2 28px (was 22px). Eyebrow 12px / 1.5px tracking / brand-dark.
- `.surface-card.feature` (VS Code) now uses 2px green border +
  vertical brand-light → white gradient (was 1px ring).
- `.surface-card.incomplete` (Cowork) uses 2px red border (`#e35e5e`)
  + vertical red-tint → white gradient (was yellow flat bg).
- `.surface-card .steps` panel: inner surface-dim bg + 8px radius
  + 13px font.
- `.surface-foot` top-border + ink-muted (mock spec).
- `.badge-warn` now a solid red box (`#e35e5e` bg + white ink + 4px
  radius) instead of a yellow pill, matching the mock.
- Header layout fixed: the global absorbed `header { display: flex;
  justify-content: space-between }` rule was making the h2 sit on
  the right of the eyebrow; explicit `display: block` override on
  `.home-mock section > header` puts the title on the LEFT under
  the eyebrow as the mock has.

BROWSE — Explore your workspace
- Wrapped in `<section class="browse-section">` with proper
  eyebrow + h2 + lede (was a bare `.section-label` div).
- `.browse-grid` 5-col grid (was responsive auto-fill, 4-card
  layout). Skills tile added as a 5th card linking to
  `/marketplace?type=skills`.
- `.browse-card` mock-spec: 22 20 padding, 28px icon, 15px title,
  12.5px ink-muted desc, hover lifts -2px with brand border +
  shadow-md.

Section wrappers (`.home-usage`, `.first-session`) no longer carry
the white card chrome — they sit directly on the page bg, matching
the mock. Only Getting Started + Overview keep their white cards.

GLOBAL eyebrow vocabulary (`.home-hero-intro .eyebrow`,
`.first-session > .eyebrow`, `.surfaces > header .eyebrow`,
`.browse-section .eyebrow`) all aligned to mock spec: 12px / 700 /
1.5px tracking / brand-dark color / 14px bottom margin.

Hero h1 bumped to 44px / 800 / -1px tracking (was 32px / 600).

51/51 home tests pass.

* fix(web): /home session-intro card + terminal-body verbatim mock match

User comparison flagged three remaining /home gaps; this patch
addresses each:

- `.session-intro` rule was missing — the "five beats" tagline
  rendered as a bare line with no card chrome. Added the mock-
  spec card: white surface, 14px radius, 20×24 padding, 1px
  border + shadow-sm, with a 44×44 brand-light icon block on the
  left.

- Beat 1 terminal-title was `~/{{ workspace_dir }} — zsh` (mock-
  style shell-pwd format), but the user wants every terminal
  frame across all 5 beats to read `claude — {{ instance_brand }}`.
  Updated.

- Terminal-body line structure for beats 2-5 rewritten verbatim
  from the CEO mock:
  - `<span class="prompt">&gt;</span><span class="you">…</span>`
    now has no space between the prompt and user input (mock
    pattern: zero gap, the .prompt's `margin-right: 8px` provides
    the visual separation).
  - Beat 2 menu items use `<strong>[N]</strong>` numbering with
    project entries on indented lines, each project name followed
    by a `<span class="dim">(N ago)</span>` timestamp at a fixed
    column — instead of my prior single-line concatenation.
  - Beat 3 narrative split into 4 stanzas separated by blank lines
    (matches mock): the "Switched to <strong>X</strong>" status,
    then dim Loaded/Last-session lines, then a stand-alone "One
    unprocessed input detected:" pair, then the "Want me to
    process …" question. My prior version dim-wrapped the entire
    block, which looked off.
  - Beat 4 narrative split into headline summary + risks section
    with <strong> heads + bullet lists separated by blank lines,
    matching the mock's "Q1 close summary" / "Open risks" rhythm.
    The Q1 question carries the mock's manual line-break + 2-
    space continuation indent inside the `.you` span — without
    that, terminal-body's `white-space: pre-wrap` would auto-wrap
    awkwardly at a different column than the mock.
  - Beat 5 exit narrative uses two separate dim lines + a
    standalone `.ai-name` "See you next time." line, then prompt
    + caret. My prior version collapsed everything into one dim
    block.
  - Project names changed from customer-specific (`GRPN_*`) to
    generic (RevenueAnalysis, WeeklyReview, Onboarding, OpsDb,
    HRHandShake) so the OSS distribution stays vendor-agnostic
    per CLAUDE.md.
  - `Marketing plan` examples replaced with `Q1 close` so the
    narrative stays plausible for an analyst audience.

12/12 home tests pass.

* fix(web): /home surfaces verbatim mock — VS Code thumb, Terminal expected-output, NEW badge

User comparison flagged three remaining surface-section gaps:

- VS Code surface card was rendering a generic "Screenshot pending"
  placeholder; the mock has a labeled inline mockup
  (`<a class="vscode-thumb">` w/ `.thumb-fallback`) showing the
  recommended 4-pane layout (EXPLORER yellow, TERMINAL 1 purple,
  TERMINAL 2 green, TERMINAL 3 orange) on a dark navy bg + a
  "Recommended layout" caption pill. CSS `.vscode-thumb` block
  added — uses gradient-strip backgrounds to draw the colored
  panel bars without needing a base64 image.

- "Recommended" badge was a pill (999px radius) with
  `--brand-accent` bg + navy text. Mock uses `.badge` instead of
  `.recommend-pill` — solid `--primary` (brand-dark green) bg
  with WHITE text and 4px radius. Replaced the class + CSS rule
  so the badge reads as a tag, not a pill.

- Terminal surface card was missing the "What you should see"
  subsection — mock has an `.expected-output` block showing a
  sample of the welcome menu inside a dim dashed panel. Added the
  block with the mock's exact rendered output (templated to
  `{{ instance_brand }}` + generic project names instead of
  customer-specific GRPN entries) plus the `.expected-output`
  CSS (surface-dim bg + dashed border + `::before` "WHAT YOU
  SHOULD SEE" eyebrow per mock spec).

Also addressed the explore-section feedback:

- Skills browse-card now carries the `new` class so it picks up
  the `.browse-card.new::after` corner badge ("NEW", green bg,
  white text, 10px / 700 / 0.5px tracking) per mock.
- Browse cards align same height via `align-self: stretch` (grid
  default) + `flex-grow: 1` on `.browse-desc` so descriptions
  fill remaining vertical space; previously the Skills tile sat
  shorter because its desc text was longer than others'.

Structural HTML changes to all four surface cards: dropped the
inner `<div class="surface-card-head">` wrapper + `<p
class="surface-pitch">` class in favor of mock's flat layout
(`.what` + `.steps` + `.when-to-use`). `<ol class="surface-steps">`
replaced with `<div class="steps"><strong
class="steps-eyebrow">DAILY USE / QUICK ACCESS / CONNECT IT</strong>
<ol>...</ol></div>` so the eyebrow + numbered list share the
mock's tinted surface-dim panel.

12/12 home tests pass.

* fix(web): align /home setup walkthrough to design spec

- Setup-section header (eyebrow + heading + lede) floats above the
  install hero; install card has no accent strip; step labels drop
  `Step N —` prefix; closing strip is single flex row.
- VS Code surface card renders recommended-layout screenshot from
  `/static/img/vscode-layout.png` with click-to-enlarge lightbox.
- Workspace install path cascades to `~/Desktop/{workspace_dir}` in
  every step, surface card, first-session annotation, and shortcut.
- Step 1 verify text restores Enterprise — Finance and Legal option.
- Step 6 shortcut installs a shell function with arg forwarding
  (`"$@"` unix / `@args` windows) and a user-facing Auto / YOLO
  permission-mode toggle.
- Step 5 manual-fallback details inline on the CTA row; description
  reads at step-lede size, not 13px chip.
- Setup-section heading no longer right-aligns (was inheriting
  `header { display: flex; justify-content: space-between }` from
  the legacy stylesheet; wrapper changed to `<div>`).
- Getting Started `<details>` block removed (duplicated links).

* test(web): align /home tests with restructured setup wizard

- Replace test_getting_started_card_renders_on_home with
  test_setup_section_renders_for_not_onboarded — asserts the new
  setup-section-header floats above the install hero and Getting
  Started markup is absent (block removed in the prior commit).
- Update automode-block test to match labels without the
  `Step N —` prefix.
- Update setup-CTA partial test to match the relabeled
  "Copy install script to clipboard" button.

Drop orphaned CSS for `.home-getting-started`, `.home-gs-summary*`,
and `.home-gs-item` — selectors had no matching markup after the
Getting Started block was removed.

Also: Step 3 `pwd` expected-output uses an absolute path
(`/Users/yourname/Desktop/{workspace_dir}`) instead of the
tilde-prefixed form, matching what the command actually prints.

* fix(web): repaint home_onboarded + setup_advanced; align CTA label

- home_onboarded + setup_advanced still carried the retired blue
  `#0056A3` as both `--hp-primary-dark` and the hero gradient
  endpoint. Both reference `var(--primary-dark)` now so the green
  palette cascades.
- setup_advanced YOLO snippet was the old `alias` form (no cd, no
  arg forwarding). Replaced with the shell function variant from
  /home Step 6 — drops into ~/Desktop/{workspace_dir} and forwards
  "\$@" (unix) / @args (Windows).
- setup_advanced ~/{workspace_dir} path references cascaded to
  ~/Desktop/{workspace_dir} so install story matches /home.
- Dashboard's "Setup a new Claude Code" button label aligned to the
  canonical "Copy install script to clipboard" — matches /home and
  the new docstring in _claude_setup_cta.jinja, which now mandates
  this label across consumers.

* fix(web): keep base brand blue; scope green palette to /home redesign

User noticed login + dashboard had turned green when the /home
redesign flipped --primary from blue (#0073D1) to green (#2ea877)
in commit 278f202e. The brand-wide flip went further than the
redesign needed — only /home, /home (onboarded), and /setup-advanced
intentionally use the green/navy spec; every other page (login,
dashboard, catalog, marketplace, admin, profile) was just inheriting
the green because --primary cascaded everywhere.

Revert the global brand colour to blue and lock the green into the
two outstanding redesign scopes:

- style-custom.css: --primary back to #0073D1, --primary-light back
  to rgba(0,115,209,0.1), --primary-dark back to #005BA3,
  --brand-accent back to a lighter blue.
- home_onboarded.html: .home-mock now sets --hp-primary,
  --hp-primary-dark, --hp-primary-light to explicit green hex
  (matching home_not_onboarded), so the hero stays green regardless
  of the global brand.
- setup_advanced.html: same lock — .advanced-mock pins the green
  palette in-scope.

Hero gradients on both pages now reference the local --hp-primary
chain (not the global --primary), so any future palette tweak inside
either scope cascades correctly without disturbing the rest of the app.

* refactor(web): hoist --hp-* into shared design-tokens.css (--ds-*)

PR 2 of the design-system extraction ladder. Pure mechanical rename
+ dedup; no visual diff on any rendered page (verified on /home,
/dashboard).

- New app/web/static/css/design-tokens.css declares the full token
  set on :root: brand surface (green primary, primary-dark, mint
  light, brand-accent), hero (navy bg + ink), code-panel (near-black
  bg + cool ink + warm-yellow), light surfaces (bg/surface/border),
  text (primary/secondary/muted), orange accent, info + warn
  callout vocabularies, navy-tinted elevation shadows, system font
  stack + mono.
- base.html loads it alongside style-custom.css so the tokens are
  globally available.
- Rename --hp-* -> --ds-* in home_not_onboarded (313 refs),
  home_onboarded (15), setup_advanced (39). 367 token references
  pointed at one of three local blocks; now all point at the
  global :root.
- Drop the three local token blocks. Each scope class
  (.home-mock / .advanced-mock) only keeps its base ink + font-size
  + line-height rules.

The legacy --primary family stays canonical for the blue base
brand — login, dashboard, catalog, marketplace, admin still read
blue. The design system is opt-in via the scope class.

* refactor(web): extract shared components.css; migrate /home markup

PR 3 of the design-system extraction ladder. First batch of
reusable components lifted out of home_not_onboarded.html into a
new shared stylesheet; markup migrated to consume them.

- New app/web/static/css/components.css with five components, all
  reusable on any page that loads design-tokens.css:
    .callout-rec        — amber lightbulb recommendation box
    .callout-hint       — blue info hint box
    .code-output        — "WHAT YOU SHOULD SEE" terminal output block
    .lightbox           — full-bleed image enlarge overlay
    .setup-section-header — wizard header (eyebrow + h2 + lede)
- base.html loads components.css after design-tokens.css.
- home_not_onboarded.html markup renamed:
    class="rec"             -> class="callout-rec"
    class="hint"            -> class="callout-hint"
    class="expected-output" -> class="code-output"
- Local CSS rules removed from home_not_onboarded.html for each of
  the extracted components — ~150 lines down to 5-line "extracted to
  components.css" comments. The bespoke wizard-specific styles
  (.install-cmd, .os-tabs, .mode-tabs, .terminal-frame) stay
  template-local for now since they only have one consumer.

Visual regression check: /home install hero renders the amber rec
callout, blue hint callout, dashed code-output block, green section
header, and click-to-enlarge VS Code thumb identically to the
pre-extraction render. 43 home tests pass.

* fix(web): unify page-headers — activity-center full-width, marketplace shares box

- /activity-center audit-log hero rendered as half-width because the
  _page_hero include was inside <header class="obs-topbar">, a flex
  row that pinned the time-range + auto-refresh controls next to it.
  The hero is now a sibling rendered before the <header>, so it
  spans the full container width like every other admin page; the
  controls keep their flex row underneath.
- Marketplace hero unified with .page-header--hero. Markup is now
  <section class="page-header page-header--hero mp-hero"> so the
  shared box drives padding/radius/gradient/max-width/shadow; the
  .mp-hero override block only carries the right-anchored cover
  image and the rules for the search row + scope checkboxes (which
  the canonical hero doesn't have). Inner text uses the canonical
  .page-header__eyebrow / __title / __subtitle classes.
- .page-header--hero shadow tint now follows the brand blue
  (rgba(0, 115, 209, 0.2)) instead of the leftover green from the
  prior palette flip; same depth highlight everywhere the gradient
  is blue.

* fix(web): unify remaining page heroes — admin, profile, install, store, stack

Sweep across pages that carried bespoke gradient hero markup so
every page-hero shares the canonical `.page-header--hero`
dimensions (padding 28/32/24, border-radius 14, max-width
var(--width-app), navy-tinted shadow, gradient with --primary →
--primary-dark). Inner text uses the .page-header__eyebrow /
__title / __subtitle classes so typography matches across the app.

- admin_tables: migrated to _page_hero.html include.
- admin_tokens: kept .tokens-hero wrapper for the counts-chip row
  but added the canonical class on the same element; stripped
  duplicate gradient + padding + typography rules.
- install: same pattern (kept hero-meta pill row).
- profile: migrated to _page_hero.html include.
- store_upload: kept .upload-hero wrapper for the .meta chip row;
  composite class with the canonical hero.
- setup_advanced: .advanced-mock .ad-hero now matches canonical
  dimensions; green palette retained via --ds-primary/dark.
- stack_card.css: .stack-hero (catalog + corporate-memory search
  hero) uses canonical gradient + padding + max-width.

The detail-page heroes (marketplace_plugin_detail,
marketplace_item_detail, catalog_*_detail, store_edit,
admin_group_detail, admin_store_submission_detail) stay bespoke
for now — they're rich detail headers with photos, badges, install
actions; converting them would lose contract context. Same applies
to dashboard.html env-setup-cta (it's a CTA card, not a page hero).

* fix(web): canonicalise .container — single page shell every page inherits

Previously each admin page set its own `.container:has(.<page>)
{max-width: none}` + `.<page>-page {max-width: 1400px}` override,
and per-page hero markup either nested inside flex toolbars (which
pinned the hero next to filter controls and squeezed it half-width)
or self-constrained with a different max-width than the page. /home,
/dashboard, /marketplace, and /admin/* ended up at different widths
with different nav-to-hero gaps.

- style-custom.css `.container` now carries the canonical 1280px
  max-width + `16px 32px 48px` padding so every page inherits the
  same nav-to-hero gap and side gutters. `.container > main` is
  margin/padding 0 so the container is the sole owner of gutters.
- `.page-header--hero` drops its self-constraining max-width and
  auto-centering margin — the container provides the width, so the
  hero sits flush with the table/toolbar below it.
- `.stack-hero` (catalog + corporate-memory) and `.advanced-mock
  .ad-hero` (/setup-advanced) follow the same pattern: container
  owns the width.
- Per-page max-width overrides stripped from admin_users,
  admin_access, admin_groups, admin_marketplaces, admin_welcome,
  admin_workspace_prompt.
- _page_hero include extracted from inside flex toolbars on
  admin_users, admin_access, admin_groups, admin_marketplaces,
  admin_server_config, admin_welcome, admin_workspace_prompt,
  admin_sessions, admin_session_detail, admin_usage,
  activity_center. The toolbar (`.users-toolbar`, `.gp-toolbar`,
  etc.) keeps only the filter + action controls; hero renders
  before it as a sibling.
- _page_chrome.html trimmed to just the page-background tint for
  the redesign scopes; the duplicate `.container` rules it carried
  are now redundant.

Verified: /home, /admin/marketplaces, /admin/users all render
container width 1280px with hero top at 88px (16px below the
72px-tall sticky nav). Same spacing as /home design spec.

* fix(web): admin_tables + admin_corporate_memory inherit canonical .container

Both pages were overriding `{% block layout %}` from base.html,
which bypasses the canonical `.container` wrapper. Result: hero
span the full viewport (1596px on a wide screen) while the inner
content sat at a narrower max-width — hero and content didn't
align, and the nav-to-hero gap differed from every other admin
page.

Switched both templates to `{% block content %}` so they render
inside the canonical `.container` from base.html — same path as
admin_groups, admin_users, admin_marketplaces, etc.

- admin_tables: dropped local `.page-title { max-width: 1600px }`
  + `.content { max-width: 1600px }` overrides (kept typography +
  inner gutter rules) and the mobile padding overrides that paired
  with them. Container now owns the gutters.
- admin_corporate_memory: only the block keyword needed changing;
  the template already had a clean inner structure (no max-width
  override on `.container-memory`).

Verified on /admin/tables and /admin/corporate-memory:
- .container width 1280, padding 16/32/48
- Hero top 88 (nav 72 + container padding-top 16)
- Hero + content both 1216px wide, both at left 190 — perfect
  alignment with /admin/groups.

* fix(web): drop .page-shell padding override + admin_tables stale :root

Two regressions discovered after the canonical-container unification:

1. `.container:has(.page-shell)` still set `padding: 28px 32px 48px`
   while the canonical `.container` had moved to `16px 32px 48px`.
   Every page-shell consumer (/admin/sessions, /admin/sessions/<id>,
   /admin/usage, /marketplace, /dashboard, marketplace detail pages,
   /me/activity, /store/*, /admin/store-submissions) was rendering
   with a 28px nav-to-hero gap while /admin/users + /admin/groups
   rendered with 16px. Same width, mismatched vertical rhythm.
   The opt-in rule is now a no-op marker: canonical container
   already provides 1280px + 16/32/48 + main margin/padding 0.

2. admin_tables.html had a stale `<style>` block that re-declared
   `:root { --primary: var(--primary); ... }`. The self-referential
   token resolved to empty, collapsing the page-header hero's
   `linear-gradient(135deg, var(--primary), var(--primary-dark))`
   to no background — the hero appeared as a pale ghost without
   colour. The entire shadow `:root` block was a stale copy of the
   design tokens that style-custom.css already provides. Dropped
   it; tokens now resolve from the global `:root`.

After both fixes /admin/sessions, /admin/tables, and every other
page-shell consumer match /admin/groups exactly: container 1280px,
container padding-top 16px, hero at top 88px / left 190px / width
1216px.

* fix(web): drop /admin/tokens .tokens-page width + padding override

`.tokens-page` carried its own `max-width: 1280px; margin: 0 auto;
padding: 28px 8px 48px` block — the canonical `.container` already
provides width + 16/32/48 padding, so the nested wrapper was
adding 28px on top of the container's 16px (= 44px nav-to-hero
gap, vs 16px on every other admin page) and shrinking the hero
sideways by 8px on each side (1200px vs the canonical 1216px).

After: container owns the layout; `.tokens-page` is just a
font-family scope. /admin/tokens hero now sits at top 88, left 190,
width 1216 — same numbers as /admin/groups / /admin/users.

* fix(web): hero links readable on blue; /admin/access Groups link href

- New `.page-header--hero a` rule in style-custom.css forces any
  anchor inside a gradient hero to render white + underlined so
  links stay readable on the blue background. Previously links
  inherited the global `var(--primary)` blue, which disappeared
  on top of the matching blue gradient. No per-page class needed —
  drop a plain `<a>` in any hero subtitle and it just works.
- /admin/access hero subtitle was Jinja-passing the inline link
  with HTML-entity-encoded quotes (`href=&quot;...&quot;`). The
  entities decoded to literal `"` characters inside the rendered
  href, producing `/admin/%22/admin/groups%22` — a 404. Switched
  the `set` to a block-set (`{% set page_hero_subtitle %}...{% endset %}`)
  so the inline `<a href="/admin/groups">Groups</a>` survives
  unescaped through `_page_hero.html`. Also stripped the now-redundant
  inline `style="color:#fff;text-decoration:underline;"` — the new
  shared rule handles it.

* fix(web): /dashboard top padding matches every other page

`.main` on /dashboard had `padding: 28px 32px 48px` while every
other page now uses `16px 32px 48px` via the canonical
`.container`. Dashboard bypasses `.container` (overrides
base.html's `layout` block to render a full-width `<main>`
directly), so the padding lives on `.main` itself — bumped the
top to 16px to match.

After: first child top = 88, left = 190, width = 1216 — same
numbers as /admin/groups / /admin/users / /admin/marketplaces.

* fix(web): green eyebrow + white title on .page-header--hero (matches /home)

`.page-header--hero .page-header__eyebrow` was faint white
(rgba(255,255,255,0.75)) — readable but unbranded against the blue
gradient. Changed to `var(--ds-brand-accent)` (mint green #54d3a0)
so every page hero pairs a green eyebrow with white title +
subtitle, echoing /home's setup-section header (green eyebrow,
dark heading combo). One CSS rule applies everywhere — no
per-page styling needed.

Also bumped the eyebrow to font-weight 700 / letter-spacing 1.2px
so the green stands out cleanly against the gradient.

* fix(web): page-header--hero + stack-hero use /home navy gradient

`.page-header--hero` and `.stack-hero` were on the brand-blue
gradient (`var(--primary)` → `var(--primary-dark)`) while
/home's hero (`.home-hero-intro`) sits on the deeper navy
gradient (`#0f1b3a` → `#1a2a5f`). Every other page-hero now
uses that same navy gradient so /home, /marketplace, /catalog,
/corporate-memory, /admin/*, /profile, /install, /dashboard,
/setup-advanced share one brand surface. Shadow tint adjusted
to the navy depth (rgba(15, 27, 58, 0.22)).

Brand blue stays the link/CTA colour everywhere else; only the
hero box itself is navy.

* fix(web): primary buttons green; marketplace tabs navy translucent

Two parity tweaks pulling the rest of the app toward /home's
visual language.

- `.btn-primary` (both rules in style-custom.css) now uses
  `var(--ds-primary)` / `var(--ds-primary-dark)` green fill,
  matching the "Copy install script to clipboard" button on
  /home. Brand-blue `--primary` still drives link colour and the
  accent surface; only the filled button background flipped to
  green. Every page with a `.btn-primary` (admin "+Add user",
  "+Add marketplace", catalog, marketplace actions, dashboard,
  modals) now reads as the same "do it" affordance.
- `.mp-tabs` (Curated Marketplace / Flea Market / My Stack tab
  group) now sits on the navy `--ds-hero-bg` with translucent
  white pills (rgba(255,255,255,0.10) inactive, 0.18 active) —
  same translucent-white-on-navy treatment as the "Just browse —
  no install needed" pill on /home. Icons render as soft white;
  per-tab colour-coding dropped in favour of the unified surface.

* fix(web): catalog/memory tabs + empty-state CTA + admin action buttons

Bring /catalog and /memory in line with /home + /marketplace:

- `.stack-tabs` (Browse / My Stack / Recipes on /catalog,
  Browse / My Stack on /memory) now uses the navy `--ds-hero-bg`
  container with translucent-white-on-navy pills, mirroring the
  `.mp-tabs` treatment and /home's "Just browse — no install
  needed" CTA pill. Per-tab icon colour-coding dropped — icons
  render as soft white on the navy fill.
- `.stack-tabs-row__actions .btn` (right-slot "+New Recipe",
  "+New Data Package" admin CTAs) now uses green primary fill
  (`--ds-primary`), matching `.btn-primary` and /home's
  "Copy install script to clipboard" button.
- `.stack-empty .cta a` (empty-state action button — the
  "Open /admin/tables →" CTA on /catalog and equivalent on
  /memory) flipped from blue `--primary` to green `--ds-primary`
  so the colour aligns with every other primary button in the app.

* fix(web): marketplace Search button green (--ds-primary) matching other CTAs

* fix(web): unify Search button + admin-action button across browse pages

- Added Search button (`<button class="stack-hero__search-btn">`)
  to /catalog and /memory heroes — same green pill as /marketplace.
  Wired to the existing live-filter pipeline (button click runs
  `applyFilters()` and refocuses the input). All three browse pages
  now wear the identical search bar UI.
- `.stack-hero__search-btn` shares `--ds-primary` fill with
  `.mp-hero .search-btn`.
- `.mp-actions .btn` ("Submit a skill or plugin" CTA on /marketplace)
  flipped from the legacy blue-outline to the same green primary
  fill + dimensions (`display: inline-flex; line-height: 1;
  padding: 9px 16px; gap: 6px`) as `.stack-tabs-row__actions .btn`
  on /catalog and /memory. All three right-slot action buttons
  render at identical height now.
- `.stack-tabs-row__actions .btn` got `inline-flex` + `line-height: 1`
  + `gap: 6px` so a `<button class="btn">` and a `<a class="btn">`
  both render at exactly 33px high — the embedded
  `.admin-only-hint` chip no longer pushes one variant taller
  than the other.

* fix(web): marketplace guide CTAs green (fastpath + primary); drop flea purple

* fix(web): dashboard CTA hero on navy; readable <code> chips in hero

- `.env-setup-cta` on /dashboard ("Set up a new Claude Code"
  card) flipped from the brand-blue gradient + green-tinted shadow
  to the canonical navy gradient (`--ds-hero-bg` → `#1a2a5f`) with
  navy-tinted shadow + 14px radius + 28/32/24 padding, matching
  `.page-header--hero` and /home's `.home-hero-intro`. Dashboard's
  top CTA now sits on the same brand surface as every other hero.
- Added `.page-header--hero code` rule — translucent white pill +
  warm-yellow ink (#ffd866) so `<code>` chips embedded in hero
  subtitles read as code samples against the navy gradient. The
  global `code` rule sets `color: var(--text-primary)` (dark),
  which turned in-hero chips into invisible dark-on-white-on-navy
  ghosts (e.g. the `-by-dev` suffix on /store/new).
- /store/new's `.page-header__subtitle code` dropped its inline
  style override — the shared rule handles it now.

* feat(web): two-theme switching via data-theme + admin toggle

Introduces a theme system that flips the entire UI palette between
"navy" (current design, default) and "blue" (pre-redesign palette)
via a single `<html data-theme="...">` attribute. Page markup, class
names, and component styles don't change — only the `--ds-*` token
values flip.

Backend
- New `app/instance_config.py::get_instance_theme()` resolves the
  active theme from `AGNES_INSTANCE_THEME` env > `instance.theme`
  in instance.yaml > default "navy". Unrecognised values clamp to
  "navy" so a typo doesn't break the page.
- `app/web/router.py::_build_context` injects `instance_theme`
  alongside `instance_brand` etc. so every template inherits it.
- `app/web/templates/base.html` renders
  `<html lang="en" data-theme="{{ instance_theme | default('navy') }}">`.

CSS
- `app/web/static/css/design-tokens.css` adds two new tokens to
  the default `:root` set: `--ds-hero-shadow` (drop-shadow tint
  on hero boxes) and `--ds-hero-eyebrow` (eyebrow accent colour).
  Plus a `:root[data-theme="blue"]` override block that flips
  seven tokens: `--ds-primary`, `--ds-primary-dark`,
  `--ds-primary-light`, `--ds-brand-accent`, `--ds-hero-bg`,
  `--ds-hero-bg-deep`, `--ds-hero-shadow`, `--ds-hero-eyebrow`.
  The blue theme aliases the brand surface tokens back to the
  legacy `--primary` family.
- `.page-header--hero`, `.stack-hero`, `.env-setup-cta`,
  `.home-mock .home-hero-intro` now reference the new
  `--ds-hero-shadow` and `--ds-hero-bg-deep` tokens instead of
  hard-coding `rgba(15, 27, 58, 0.22)` and `#1a2a5f` — gradient +
  shadow now flip with the theme.
- `.page-header--hero .page-header__eyebrow` uses
  `var(--ds-hero-eyebrow)` so the eyebrow goes mint-green on
  navy and translucent-white on blue (mint on blue reads poorly).

Admin
- `app/api/admin.py::_KNOWN_FIELDS["instance"]` now registers a
  `theme` field of kind `select` with options `["navy", "blue"]`
  and a `hint` explaining the trade-off. The existing
  /admin/server-config UI auto-renders a select for this — no
  template changes needed.

Defaults
- Default value is "navy" so existing instances see no visual
  change. Admins flip to "blue" via /admin/server-config to
  restore the pre-redesign look.

Restart note: uvicorn must reload to pick up the Python changes
(new getter, new template-context key, new known-field). CSS
changes hot-reload via browser refresh.

* fix(web): blue theme — home hero eyebrow + CTA contrast

`.home-hero-intro .eyebrow` and `.btn-intro-primary` referenced
`--ds-brand-accent` directly, which on the blue theme resolves to
the lighter brand-accent blue (#4F9DEB). Result: light-blue eyebrow
on the blue gradient ("WELCOME, ADMIN" barely readable) and a
light-blue button with darker-blue text ("Set up in ~15 min")
that all sat in the same hue range.

Introduces three new theme-aware tokens:
- `--ds-hero-eyebrow` already existed; blue theme bumped opacity
  to 0.92 so the eyebrow reads as full white.
- `--ds-hero-cta-bg` + `--ds-hero-cta-fg` + `--ds-hero-cta-bg-hover`
  flip the primary hero CTA: mint-green on navy (default), white-
  on-blue under `data-theme="blue"`.

`.home-hero-intro .eyebrow` now uses `--ds-hero-eyebrow` (mint on
navy / white on blue) and `.btn-intro-primary` uses the CTA token
trio.

Recommended palette on blue theme:
- Eyebrow: white at 92% opacity (clear on the blue gradient).
- Primary CTA pill: white background, brand-blue dark text
  (`--primary-dark` = #005BA3) for AAA-level contrast.
- Secondary CTA: translucent white pill (unchanged).

* fix(web): blue theme — callout-hint info bg/border/ink re-tinted to brand blue (was indigo, clashed with brand-blue hero)
2026-05-21 06:19:16 +00:00

3242 lines
129 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Setup — {{ instance_name or "AI Data Analyst" }}{% endblock %}
{% block content %}
{% include "_page_chrome.html" %}
<style>
.home-mock {
/* Design-system scope — tokens live globally in
app/web/static/css/design-tokens.css (loaded by base.html).
This rule only applies the typography + base ink that the
redesign opts into. */
font-family: var(--ds-font);
color: var(--ds-text-primary);
font-size: 15px;
line-height: 1.55;
}
.home-mock,
.home-mock * { font-family: var(--ds-font); }
.home-mock code, .home-mock kbd, .home-mock pre,
.home-mock .install-cmd, .home-mock .install-cmd *,
.home-mock .terminal-body, .home-mock .terminal-body * {
font-family: var(--ds-font-mono);
}
.home-mock * { box-sizing: border-box; }
.home-mock .install-hero {
position: relative;
background: linear-gradient(135deg, var(--ds-hero-bg) 0%, var(--ds-hero-bg-deep) 100%);
color: var(--ds-hero-ink);
border-radius: 16px;
padding: 38px 40px;
margin-bottom: 22px;
box-shadow: var(--ds-shadow-lg);
}
/* Subtle green accent strip across the top of the install-hero so the
wizard reads as the brand's primary CTA card. */
.home-mock .install-hero::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, var(--ds-brand-accent) 0%, var(--ds-primary) 60%, transparent 100%);
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
.home-mock .install-hero-close {
position: absolute;
top: 14px;
right: 14px;
width: 32px;
height: 32px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.14);
color: white;
font-size: 18px;
line-height: 1;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: background 0.15s;
}
.home-mock .install-hero-close:hover,
.home-mock .install-hero-close:focus-visible {
background: rgba(255, 255, 255, 0.28);
outline: none;
}
.home-mock .offboard-strip {
margin: 0 0 22px;
padding: 10px 14px;
border: 1px solid var(--ds-border);
border-radius: 10px;
background: var(--ds-border-light);
color: var(--ds-text-secondary);
font-size: 13px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.home-mock .offboard-strip button {
border: 1px solid var(--ds-border);
background: white;
border-radius: 6px;
padding: 4px 10px;
font-size: 13px;
cursor: pointer;
}
.home-mock .offboard-strip button:hover { background: var(--ds-border-light); }
.home-mock .install-hero .eyebrow {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.8px;
opacity: 0.85;
margin-bottom: 10px;
}
.home-mock .install-hero h1 {
font-size: 30px;
font-weight: 600;
letter-spacing: -0.4px;
margin-bottom: 12px;
line-height: 1.2;
color: white;
}
.home-mock .install-hero .lead {
font-size: 15px;
opacity: 0.94;
line-height: 1.6;
margin-bottom: 22px;
}
.home-mock .install-hero .lead strong { font-weight: 600; }
/* ── Getting Started + Overview + Usage modes (added in PR #289) ───
Three new content cards rendered between the install-hero and the
connector tiles. Getting Started + Usage modes ship in OSS;
Overview body comes from instance.overview yaml (operator-owned),
hidden when unset. Generic dismiss pattern: any element with
`<button class="home-card-close" data-dismiss-key="...">` gets
per-device localStorage dismissibility for free. */
.home-mock .home-overview {
position: relative;
background: white;
border: 1px solid var(--ds-border);
border-radius: 12px;
padding: 22px 24px;
margin-bottom: 18px;
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
}
/* `.home-usage` (the Surfaces section) used to inherit the white-card
chrome above; in the design spec the section is bare (just header +
grid on the page bg), so we leave it un-styled here and only set
bottom-margin. */
.home-mock .home-usage {
position: relative;
background: transparent;
border: none;
border-radius: 0;
padding: 0;
margin-bottom: 36px;
box-shadow: none;
}
/* Install-hero is the scroll target for Getting Started's first row.
Offset the anchor jump by the 72px sticky .app-header height + a
bit of breathing room so the hero's eyebrow lands cleanly under
the header bar. */
.home-mock .install-hero { scroll-margin-top: 88px; }
.home-mock .home-overview > h2,
.home-mock .home-usage > header h2 {
font-size: 18px;
font-weight: 600;
margin: 0 0 6px;
color: var(--ds-text-primary);
}
.home-mock .home-usage > header p {
font-size: 13px;
color: var(--ds-text-secondary);
margin: 0 0 14px;
}
.home-mock .home-card-close {
position: absolute;
top: 12px;
right: 12px;
width: 28px;
height: 28px;
border: none;
border-radius: 50%;
background: transparent;
color: var(--ds-text-muted);
font-size: 18px;
line-height: 1;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
}
.home-mock .home-card-close:hover,
.home-mock .home-card-close:focus-visible {
background: var(--ds-border-light);
color: var(--ds-text-primary);
outline: none;
}
.home-mock .home-overview-body {
font-size: 14px;
line-height: 1.6;
color: var(--ds-text-primary);
}
.home-mock .home-overview-body p { margin: 0 0 10px; }
.home-mock .home-overview-body p:last-child { margin-bottom: 0; }
.home-mock .home-overview-body a { color: var(--ds-primary); }
.home-mock .home-usage-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 12px;
}
.home-mock .home-usage-item {
display: flex;
flex-direction: column;
gap: 4px;
padding: 14px;
border: 1px solid var(--ds-border);
border-radius: 10px;
text-decoration: none;
color: inherit;
transition: border-color 0.15s, background 0.15s;
}
/* Hover affordance only on the anchor variants (VS Code, Claude
Desktop). The Terminal tile renders as a plain <div> — the setup
hero above already covers the terminal install path, so a
click-through from here would round-trip to content the user just
scrolled past. */
.home-mock a.home-usage-item:hover {
border-color: var(--ds-primary);
background: var(--ds-primary-light);
}
.home-mock .home-usage-item .ico { font-size: 20px; }
.home-mock .home-usage-item strong { font-weight: 600; }
.home-mock .home-usage-item span {
font-size: 13px;
color: var(--ds-text-secondary);
line-height: 1.5;
}
.home-mock .home-usage-foot {
font-size: 13px;
color: var(--ds-text-secondary);
margin: 0;
}
@media (max-width: 720px) {
.home-mock .home-usage-grid { grid-template-columns: 1fr; }
}
.home-mock .what-is {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 14px;
margin-bottom: 18px;
}
.home-mock .what-is-item {
background: white;
border: 1px solid var(--ds-border);
border-radius: 12px;
padding: 18px 22px;
color: inherit;
text-decoration: none;
display: block;
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.home-mock a.what-is-item:hover {
border-color: var(--ds-primary);
box-shadow: 0 4px 12px rgba(46, 168, 119, 0.14);
transform: translateY(-1px);
}
.home-mock .what-is-item .ico { font-size: 22px; margin-bottom: 8px; display: block; }
.home-mock .what-is-item .ttl {
font-size: 14px;
font-weight: 600;
color: var(--ds-text-primary);
margin-bottom: 4px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.home-mock .what-is-item .ttl .arrow {
color: var(--ds-primary);
font-weight: 600;
transition: transform 0.15s ease;
}
.home-mock a.what-is-item:hover .ttl .arrow {
transform: translateX(2px);
}
.home-mock .what-is-item .desc {
font-size: 13px;
color: var(--ds-text-secondary);
line-height: 1.55;
}
.home-mock .look-around-lead {
font-size: 13px;
color: var(--ds-text-secondary);
line-height: 1.55;
margin: -4px 0 12px;
}
.home-mock .look-around-grid {
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
margin-bottom: 22px;
}
.home-mock .install-block {
background: rgba(15, 23, 42, 0.55);
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 12px;
padding: 18px 20px;
}
.home-mock .install-block + .install-block { margin-top: 14px; }
.home-mock .os-tabs {
display: flex;
gap: 4px;
margin-bottom: 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.10);
}
.home-mock .os-tab {
background: transparent;
border: none;
color: rgba(255, 255, 255, 0.60);
font-size: 12px;
font-weight: 500;
padding: 8px 14px;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
font-family: inherit;
}
.home-mock .os-tab:hover { color: rgba(255, 255, 255, 0.85); }
.home-mock .os-tab.is-active {
color: white;
border-bottom-color: #FBBF24;
}
/* `[hidden]` UA stylesheet has lower specificity than `.install-cmd { display: flex }`,
so we need an explicit override to actually hide the inactive tab panel. */
.home-mock .install-cmd[hidden] { display: none; }
.home-mock .install-block .label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.6px;
opacity: 0.78;
margin-bottom: 10px;
font-weight: 600;
}
.home-mock .install-cmd {
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 8px;
padding: 14px 18px;
font-family: var(--ds-font-mono);
font-size: 13.5px;
color: #FBBF24;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.home-mock .install-cmd .multiline { display: block; line-height: 1.7; white-space: pre-wrap; flex: 1; }
.home-mock .install-cmd .copy-btn {
background: rgba(255, 255, 255, 0.10);
color: white;
border: 1px solid rgba(255, 255, 255, 0.18);
padding: 7px 14px;
border-radius: 6px;
font-size: 12px;
cursor: pointer;
font-weight: 500;
flex-shrink: 0;
}
.home-mock .install-cmd .copy-btn:hover { background: rgba(255, 255, 255, 0.18); }
.home-mock .install-note {
font-size: 12.5px;
color: rgba(255, 255, 255, 0.85);
margin-top: 12px;
line-height: 1.55;
}
/* Inline `<code>` chips inside the blue install-hero (lead paragraphs +
install-note prose). Previous rule was `rgba(255,255,255,0.12)` bg +
inherited near-white text — barely-visible faint-white film on the
blue gradient with low-contrast white text on top (≈2:1, fails WCAG
AA). The visual effect read as a muddy bluish blob — the user
reported the text as "dark blue/black font" because the chip blended
into the hero and the white text lost its edges.
Switched to the same amber-on-dark-navy palette as the .install-cmd
copy-button boxes below (≈9:1 contrast). Border tint matches the
amber accent so chips read as clickable affordances even with the
transparent navy bg. */
.home-mock .install-hero code,
.home-mock .install-note code,
.home-mock .install-note > code {
background: rgba(15, 23, 42, 0.75);
color: #FBBF24;
border: 1px solid rgba(251, 191, 36, 0.30);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 11.5px;
}
/* Links inside the blue install-hero need a non-blue color — the default
`<a>` style elsewhere on /home renders as `var(--ds-primary)` blue,
which is invisible against the hero's blue background. Use the same
high-contrast white-with-underline pattern the lead paragraph uses,
and bump hover to full white so the affordance stays obvious. */
.home-mock .install-hero a {
color: #ffffff;
text-decoration: underline;
text-decoration-color: rgba(255, 255, 255, 0.6);
text-underline-offset: 2px;
}
.home-mock .install-hero a:hover,
.home-mock .install-hero a:focus {
color: #ffffff;
text-decoration-color: #ffffff;
}
.home-mock .section-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--ds-text-secondary);
margin: 30px 0 12px;
}
.home-mock .grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
margin-bottom: 18px;
}
.home-mock .card {
background: white;
border: 1px solid var(--ds-border);
border-radius: 12px;
padding: 22px;
}
.home-mock .card h3 { font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.home-mock .card p { font-size: 13px; color: var(--ds-text-secondary); line-height: 1.55; margin-bottom: 12px; }
.home-mock .card-list { list-style: none; padding: 0; margin: 0; }
.home-mock .card-list li {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 8px 0;
font-size: 13px;
border-bottom: 1px solid var(--ds-border-light);
}
.home-mock .card-list li:last-child { border-bottom: none; }
.home-mock .card-list .num {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--ds-primary-light);
color: var(--ds-primary);
flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 11px;
}
.home-mock .card-list .step-text { flex: 1; line-height: 1.55; }
.home-mock .card-list .step-text strong { display: block; margin-bottom: 2px; }
.home-mock .card-list .step-text code {
font-family: var(--ds-font-mono);
font-size: 11.5px;
background: var(--ds-border-light);
padding: 1px 5px;
border-radius: 3px;
color: var(--ds-text-primary);
}
.home-mock .explore-list { list-style: none; padding: 0; margin: 0; }
.home-mock .explore-list li + li { margin-top: 8px; }
.home-mock .explore-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 14px;
background: var(--ds-border-light);
border: 1px solid transparent;
border-radius: 8px;
text-decoration: none;
color: var(--ds-text-primary);
transition: border-color 0.15s ease, background 0.15s ease;
}
.home-mock .explore-item:hover {
border-color: var(--ds-primary);
background: var(--ds-primary-light);
}
.home-mock .explore-item .ico {
font-size: 22px;
flex-shrink: 0;
width: 28px;
text-align: center;
}
.home-mock .explore-item .explore-text {
flex: 1;
font-size: 13px;
color: var(--ds-text-secondary);
line-height: 1.45;
}
.home-mock .explore-item .explore-text strong {
display: block;
color: var(--ds-text-primary);
font-size: 13.5px;
font-weight: 600;
margin-bottom: 2px;
}
.home-mock .explore-item .arrow {
color: var(--ds-primary);
font-size: 16px;
flex-shrink: 0;
font-weight: 600;
}
.home-mock .advanced-pointer {
display: flex;
align-items: center;
gap: 14px;
margin-top: 10px;
padding: 16px 22px;
background: white;
border: 1px solid var(--ds-border);
border-left: 4px solid var(--ds-primary);
border-radius: 12px;
text-decoration: none;
color: inherit;
transition: background 0.15s ease, border-color 0.15s ease;
}
.home-mock .advanced-pointer:hover {
background: var(--ds-primary-light);
border-color: var(--ds-primary);
}
.home-mock .advanced-pointer .ico {
font-size: 22px;
flex-shrink: 0;
line-height: 1;
}
.home-mock .advanced-pointer-text {
flex: 1;
font-size: 13px;
color: var(--ds-text-secondary);
line-height: 1.55;
}
.home-mock .advanced-pointer-text strong {
display: block;
color: var(--ds-text-primary);
font-size: 14px;
font-weight: 600;
margin-bottom: 2px;
}
.home-mock .advanced-pointer .arrow {
color: var(--ds-primary);
font-size: 16px;
font-weight: 600;
flex-shrink: 0;
}
.home-mock .setup-cta-lead {
font-size: 13px;
color: rgba(255, 255, 255, 0.82);
margin-bottom: 14px;
line-height: 1.55;
}
.home-mock .setup-cta-lead code {
background: rgba(255, 255, 255, 0.12);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 11.5px;
}
.home-mock .setup-cta-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 14px;
}
.home-mock .btn-setup-primary {
font-family: inherit;
font-size: 13px;
font-weight: 600;
color: var(--ds-primary);
background: #FFFFFF;
border: none;
border-radius: 6px;
padding: 10px 22px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
white-space: nowrap;
transition: background 0.15s ease;
}
.home-mock .btn-setup-primary:hover { background: var(--primary-light); }
.home-mock .btn-setup-primary.copied { background: #047857; color: #fff; }
.home-mock .btn-setup-primary[disabled] { opacity: 0.7; cursor: wait; }
.home-mock .setup-cta-meta {
display: inline-flex;
align-items: center;
gap: 14px;
flex-wrap: wrap;
}
.home-mock .setup-cta-hint {
font-size: 12px;
color: rgba(255, 255, 255, 0.65);
}
.home-mock details.manual-fallback {
margin-top: 14px;
border-top: 1px solid rgba(255, 255, 255, 0.10);
padding-top: 12px;
}
.home-mock details.manual-fallback > summary {
cursor: pointer;
list-style: none;
font-size: 12.5px;
color: rgba(255, 255, 255, 0.78);
padding: 4px 0;
user-select: none;
}
.home-mock details.manual-fallback > summary::-webkit-details-marker { display: none; }
.home-mock details.manual-fallback > summary::before {
content: "▸ ";
display: inline-block;
transition: transform 0.15s ease;
margin-right: 4px;
}
.home-mock details.manual-fallback[open] > summary::before { content: "▾ "; }
.home-mock .manual-preview-wrap { margin-top: 10px; }
.home-mock .manual-preview-wrap .setup-preview-pre {
background: #0F172A;
color: #E2E8F0;
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 8px;
padding: 14px 16px;
font-family: var(--ds-font-mono);
font-size: 12.5px;
line-height: 1.55;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-word;
margin: 0;
}
/* Override the global `code { background: var(--bg); }` rule so the inner
<code> renders white-on-navy instead of dark-on-pale (unreadable). */
.home-mock .manual-preview-wrap .setup-preview-pre code,
.home-mock .manual-preview-wrap .setup-preview-code {
background: transparent;
color: #E2E8F0;
padding: 0;
border-radius: 0;
font-family: inherit;
font-size: inherit;
}
.home-mock .manual-preview-wrap .placeholder-token {
background: rgba(251, 191, 36, 0.20);
color: #FBBF24;
padding: 0 4px;
border-radius: 3px;
font-style: italic;
}
.home-mock .manual-preview-wrap .token-revealed {
background: rgba(16, 185, 129, 0.18);
color: #6EE7B7;
padding: 0 4px;
border-radius: 3px;
font-style: normal;
word-break: break-all;
}
/* In-hero (dark) variant: shown for not-onboarded users underneath the
inline install steps inside the blue hero. */
.home-mock .self-mark {
margin-top: 16px;
font-size: 13px;
color: rgba(255, 255, 255, 0.85);
}
.home-mock .self-mark button {
background: rgba(255, 255, 255, 0.15);
color: white;
border: 1px solid rgba(255, 255, 255, 0.30);
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
margin-left: 6px;
}
.home-mock .self-mark button:hover { background: rgba(255, 255, 255, 0.25); }
.home-mock .self-mark button:disabled { opacity: 0.5; cursor: default; }
.home-mock .self-mark .status { margin-left: 10px; font-style: italic; }
/* Onboarded "steps complete" badge — shown inside the blue hero in
place of the hidden Step 1 + Step 2 install-blocks. */
.home-mock .install-done {
margin-top: 4px;
margin-bottom: 4px;
padding: 12px 16px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 10px;
color: rgba(255, 255, 255, 0.92);
font-size: 13px;
line-height: 1.55;
display: flex;
align-items: flex-start;
gap: 10px;
}
.home-mock .install-done .check {
font-size: 16px;
line-height: 1.3;
flex-shrink: 0;
}
.home-mock .install-done strong { font-weight: 600; color: white; }
/* News perex (admin-edited) — bottom of /home.
Keeps the styling within the admin-defined class vocabulary
(callout, video-embed) so authors get a predictable surface.
Full-width grid classes are intentionally NOT included here —
they live on /news where the layout has more room. */
.home-mock .home-news {
margin-top: 28px;
background: white;
border: 1px solid var(--ds-border);
border-radius: 12px;
overflow: hidden; /* keep the green strip's corners rounded */
}
.home-mock .home-news-head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
padding: 12px 22px;
background: #D1FAE5; /* same green as .callout-success */
border-bottom: 1px solid #A7F3D0;
}
.home-mock .home-news-head h2 {
font-size: 14px;
font-weight: 600;
color: #047857; /* darker green for contrast on the band */
margin: 0;
text-transform: uppercase;
letter-spacing: 0.6px;
}
.home-mock .home-news-more {
font-size: 13px;
font-weight: 500;
color: #047857;
text-decoration: none;
}
.home-mock .home-news-more:hover { text-decoration: underline; }
.home-mock .home-news-body {
font-size: 14px;
line-height: 1.55;
color: var(--ds-text-primary);
padding: 18px 22px;
}
.home-mock .home-news-body p { margin: 0 0 8px; }
.home-mock .home-news-body p:last-child { margin-bottom: 0; }
/* Callout, video-embed, news-hero, news-grid-*, news-cta — shared news
content vocabulary now lives in app/web/static/style-custom.css under
"News content vocabulary (shared)". Editing those rules in one place
updates /home perex, /news, and /admin/news preview together. */
.home-mock .install-done code {
background: rgba(15, 23, 42, 0.55);
border: 1px solid rgba(255, 255, 255, 0.18);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 12px;
color: #FBBF24;
}
/* ─────────────────────────────────────────────────────────────────
Onboarding polish — friction fixes from internal usability testing.
Each block is tagged with its priority (P0/P1/P2) — P0 resolves the
highest-frequency confusion, P2 is nice-to-have polish.
───────────────────────────────────────────────────────────────── */
/* P0-1 — "Don't have a terminal open?" disclosure inside Step 1's
blue install-block. Yellow accent matches Claude footer mode dots
so it reads as a hint, not an error. */
.home-mock details.terminal-howto {
margin-top: 10px;
padding: 8px 12px;
background: rgba(251, 191, 36, 0.10);
border: 1px solid rgba(251, 191, 36, 0.30);
border-radius: 8px;
}
.home-mock details.terminal-howto > summary {
cursor: pointer;
list-style: none;
font-size: 12.5px;
font-weight: 600;
color: #FBBF24;
user-select: none;
}
.home-mock details.terminal-howto > summary::-webkit-details-marker { display: none; }
.home-mock details.terminal-howto > summary::before { content: "▸ "; margin-right: 4px; }
.home-mock details.terminal-howto[open] > summary::before { content: "▾ "; }
.home-mock .terminal-howto-body {
margin-top: 10px;
font-size: 12.5px;
color: rgba(255, 255, 255, 0.92);
line-height: 1.6;
}
.home-mock .terminal-howto-body p { margin: 0 0 6px; }
.home-mock .terminal-howto-body kbd {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.30);
border-bottom-width: 2px;
border-radius: 4px;
padding: 1px 6px;
font-size: 11px;
font-family: var(--ds-font-mono);
color: white;
}
/* P1-6 — Auto-detect badge replaces the "Mark me as onboarded"
button as the primary affordance. Pulse dot signals it's actively
listening; the manual self-mark button stays as a fallback. */
.home-mock .auto-detect-badge {
display: inline-flex;
align-items: center;
gap: 8px;
margin-top: 16px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.20);
color: rgba(255, 255, 255, 0.92);
padding: 8px 14px;
border-radius: 8px;
font-size: 12.5px;
}
.home-mock .auto-detect-badge .pulse {
width: 8px; height: 8px;
border-radius: 50%;
background: #FBBF24;
box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7);
animation: agnes-pulse 1.6s infinite;
}
.home-mock .auto-detect-badge code {
background: rgba(0, 0, 0, 0.18);
padding: 1px 5px;
border-radius: 3px;
font-family: var(--ds-font-mono);
font-size: 11.5px;
}
@keyframes agnes-pulse {
0% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.65); }
70% { box-shadow: 0 0 0 8px rgba(251, 191, 36, 0); }
100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
}
/* P0-2 — Post-CTA modal with "where to paste" 3-step guide. Modal
markup lives at body level; this styles the backdrop + card. The
.home-mock prefix is intentionally NOT used so the modal is
render-isolated from the home page's CSS variables. */
.cta-modal-backdrop {
position: fixed;
inset: 0;
background: rgba(15, 23, 42, 0.55);
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 20px;
}
.cta-modal-backdrop.is-open { display: flex; }
.cta-modal {
background: white;
border-radius: 14px;
padding: 28px 32px;
max-width: 520px;
width: 100%;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
color: #111827;
font-family: inherit;
}
.cta-modal h2 {
font-size: 18px;
font-weight: 600;
margin: 0 0 6px;
color: #047857;
display: flex;
align-items: center;
gap: 8px;
}
.cta-modal .lead {
font-size: 13px;
color: #6B7280;
margin: 0 0 18px;
line-height: 1.55;
}
.cta-modal ol {
list-style: none;
padding: 0;
margin: 0 0 18px;
counter-reset: step;
}
.cta-modal ol li {
counter-increment: step;
display: flex;
gap: 14px;
align-items: flex-start;
padding: 12px;
background: #F9FAFB;
border-radius: 8px;
margin-bottom: 10px;
font-size: 13.5px;
line-height: 1.5;
}
.cta-modal ol li::before {
content: counter(step);
width: 26px; height: 26px;
border-radius: 50%;
background: var(--primary);
color: white;
font-weight: 700;
font-size: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.cta-modal ol li code,
.cta-modal ol li kbd {
background: #fff;
border: 1px solid #E5E7EB;
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono, ui-monospace, monospace);
font-size: 12px;
}
.cta-modal ol li kbd { border-bottom-width: 2px; }
.cta-modal ol li strong { display: block; margin-bottom: 4px; color: #111827; }
.cta-modal-foot {
display: flex; justify-content: space-between; align-items: center;
gap: 12px;
padding-top: 12px;
border-top: 1px solid #F3F4F6;
}
.cta-modal-foot .meta { font-size: 12px; color: #6B7280; }
.cta-modal-foot button {
background: var(--primary);
color: white;
border: none;
border-radius: 6px;
padding: 8px 18px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
font-family: inherit;
}
.cta-modal-foot button:hover { background: var(--ds-primary-dark); }
/* ─────────────────────────────────────────────────────────────────
Reskin overlay — value-first intro hero, pillars, progress chip,
first-session story, surfaces chrome, and browse-card upgrades.
Layered ON TOP of the existing wizard markup so the install-hero,
install-block, .home-usage, and .what-is structural classes (which
the test suite pins) keep their identities; this section adds the
new visual language around them.
───────────────────────────────────────────────────────────────── */
/* Top intro hero — dark navy card matching the design spec. Green
radial glow in the corner, white H1, rgba-white lede, green
eyebrow, green pill primary CTA on navy. Pillars row sits inside
the same card separated by a hairline border. */
.home-mock .home-hero-intro {
/* Hero gradient follows the active theme via `--ds-hero-*`. */
background: linear-gradient(135deg, var(--ds-hero-bg) 0%, var(--ds-hero-bg-deep) 100%);
color: var(--ds-hero-ink);
border-radius: 20px;
padding: 44px 44px 36px;
margin-bottom: 22px;
box-shadow: var(--ds-shadow-md);
position: relative;
overflow: hidden;
}
.home-mock .home-hero-intro::after {
content: "";
position: absolute;
top: -80px;
right: -80px;
width: 280px;
height: 280px;
background: radial-gradient(circle, rgba(84,211,160,0.25) 0%, transparent 70%);
pointer-events: none;
}
.home-mock .home-hero-intro .eyebrow {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
/* Eyebrow accent follows the theme: mint-green on navy
(default) or translucent white on blue. `--ds-hero-eyebrow`
is set per-theme in design-tokens.css. */
color: var(--ds-hero-eyebrow);
margin-bottom: 14px;
position: relative;
}
.home-mock .home-hero-intro h1 {
font-size: 44px;
font-weight: 800;
letter-spacing: -1px;
margin: 0 0 16px;
color: #ffffff;
line-height: 1.1;
position: relative;
}
.home-mock .home-hero-intro h1 .accent { color: var(--ds-brand-accent); }
.home-mock .home-hero-intro .lede {
font-size: 18px;
line-height: 1.6;
color: rgba(255, 255, 255, 0.8);
margin: 0 0 28px;
max-width: 720px;
position: relative;
}
.home-mock .home-hero-intro .lede strong { color: #ffffff; font-weight: 600; }
.home-mock .home-hero-cta {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 28px;
position: relative;
}
.home-mock .btn-intro {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 12px 22px;
border-radius: 10px;
font-size: 14.5px;
font-weight: 600;
text-decoration: none;
transition: transform 0.12s ease, background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
border: 1px solid transparent;
}
.home-mock .btn-intro-primary {
/* Primary CTA pill on the intro hero. Mint-green on navy by
default; white on blue under the "blue" theme.
`--ds-hero-cta-*` flips per theme in design-tokens.css. */
background: var(--ds-hero-cta-bg);
color: var(--ds-hero-cta-fg);
border-color: var(--ds-hero-cta-bg);
}
.home-mock .btn-intro-primary:hover {
background: var(--ds-hero-cta-bg-hover);
border-color: var(--ds-hero-cta-bg-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--ds-hero-shadow);
color: var(--ds-hero-cta-fg);
}
.home-mock .btn-intro-secondary {
background: rgba(255, 255, 255, 0.10);
color: #ffffff;
border-color: rgba(255, 255, 255, 0.20);
}
.home-mock .btn-intro-secondary:hover {
background: rgba(255, 255, 255, 0.18);
border-color: rgba(255, 255, 255, 0.32);
transform: translateY(-1px);
}
/* Pillars row — 4 columns inside the dark hero, separated from the
CTAs by a hairline top border. Each pillar header carries a green
square dot. */
.home-mock .home-hero-pillars {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 18px;
padding-top: 26px;
border-top: 1px solid rgba(255, 255, 255, 0.12);
position: relative;
}
.home-mock .pillar {
color: rgba(255, 255, 255, 0.82);
font-size: 13.5px;
background: transparent;
border: none;
padding: 0;
border-radius: 0;
}
.home-mock .pillar-h {
font-size: 14.5px;
font-weight: 600;
color: #ffffff;
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
}
.home-mock .pillar-h::before {
content: "";
display: inline-block;
width: 8px;
height: 8px;
border-radius: 2px;
background: var(--ds-brand-accent);
flex-shrink: 0;
}
.home-mock .pillar p {
font-size: 13px;
color: rgba(255, 255, 255, 0.78);
line-height: 1.55;
margin: 0;
}
@media (max-width: 880px) {
.home-mock .home-hero-intro { padding: 32px 24px 28px; }
.home-mock .home-hero-intro h1 { font-size: 26px; }
.home-mock .home-hero-pillars { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
.home-mock .home-hero-pillars { grid-template-columns: 1fr; }
}
/* Setup-wizard chrome — progress chip + step number badges, layered
ON the existing .install-hero / .install-block markup. */
.home-mock .setup-meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 10px 0 14px;
}
.home-mock .setup-chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
border-radius: 999px;
background: var(--ds-brand-accent);
color: var(--ds-hero-bg);
font-size: 11.5px;
font-weight: 600;
letter-spacing: 0.2px;
}
.home-mock .setup-chip-quiet {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.10);
color: rgba(255, 255, 255, 0.82);
font-size: 11.5px;
font-weight: 500;
border: 1px solid rgba(255, 255, 255, 0.14);
}
.home-mock .progress-bar {
height: 4px;
background: rgba(255, 255, 255, 0.10);
border-radius: 999px;
overflow: hidden;
margin-bottom: 22px;
}
.home-mock .progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--ds-brand-accent), var(--ds-primary));
border-radius: 999px;
transition: width 0.3s ease;
}
/* Step number badges inside install-block. The existing .install-block
stays as the container (test-pinned); .step-num is positioned as a
left-side circle so the existing .label/.os-tabs/.install-cmd flow
continues to the right. */
.home-mock .install-block {
position: relative;
padding-left: 56px; /* room for step badge */
}
.home-mock .install-block .step-num {
position: absolute;
top: 18px;
left: 18px;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--ds-brand-accent);
color: var(--ds-hero-bg);
font-weight: 700;
font-size: 13px;
display: flex;
align-items: center;
justify-content: center;
}
/* First-session story — bare section on the page bg (no wrapping
card). Matches the design spec where the eyebrow + h2 + lede sit
inline on the page and individual session-step rows have their
own visual rhythm via the 48px green circle on the left. */
.home-mock .first-session {
background: transparent;
border: none;
border-radius: 0;
padding: 0;
margin: 36px 0;
}
.home-mock .first-session > .eyebrow {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--ds-primary-dark);
margin-bottom: 14px;
}
/* First-session beat sizing — verbatim from the design spec. h2 28px,
lede 18px, session-step a 48px / 1fr grid, session-num a 40px
GREEN circle with WHITE text + soft green shadow, content h3 18px
+ p 15px. */
.home-mock .first-session > h2 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
line-height: 1.2;
margin: 0 0 8px;
color: var(--ds-text-primary);
}
.home-mock .first-session > .lede {
font-size: 18px;
color: var(--ds-text-secondary);
line-height: 1.55;
margin: 0 0 24px;
max-width: 720px;
}
/* Session-intro card — white surface w/ mint icon block, frames the
"five beats" tagline above the walkthrough. Per design spec. */
.home-mock .session-intro {
background: var(--ds-surface);
border: 1px solid var(--ds-border);
border-radius: 14px;
padding: 20px 24px;
margin: 4px 0 28px;
display: flex;
gap: 16px;
align-items: center;
font-size: 14.5px;
color: var(--ds-text-secondary);
line-height: 1.55;
box-shadow: var(--ds-shadow-sm);
}
.home-mock .session-intro-icon {
width: 44px;
height: 44px;
border-radius: 12px;
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
display: grid;
place-items: center;
font-size: 22px;
flex-shrink: 0;
}
.home-mock .session-intro strong { color: var(--ds-text-primary); }
.home-mock .session-walk {
display: flex;
flex-direction: column;
gap: 36px;
margin-top: 8px;
}
.home-mock .session-step {
display: grid;
grid-template-columns: 48px 1fr;
gap: 22px;
padding: 0;
border-top: none;
}
.home-mock .session-step:first-of-type { padding-top: 0; }
.home-mock .session-num {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--ds-primary);
color: #ffffff;
display: grid;
place-items: center;
font-weight: 700;
font-size: 16px;
box-shadow: 0 2px 6px rgba(46, 168, 119, 0.25);
flex-shrink: 0;
}
.home-mock .session-content { min-width: 0; }
.home-mock .session-content h3 {
margin: 0 0 6px;
font-size: 18px;
font-weight: 600;
color: var(--ds-text-primary);
}
.home-mock .session-content > p {
font-size: 15px;
color: var(--ds-text-secondary);
line-height: 1.55;
margin: 0 0 10px;
}
.home-mock .session-content > p:last-child { margin-bottom: 0; }
.home-mock .session-content .annotation {
font-size: 13.5px;
color: var(--ds-text-muted);
margin: 10px 0 0;
line-height: 1.55;
font-weight: 400;
text-transform: none;
letter-spacing: 0;
}
.home-mock .session-content .annotation strong { color: var(--ds-text-primary); }
.home-mock .session-content code {
background: var(--ds-bg);
border: 1px solid var(--ds-border);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 12.5px;
}
.home-mock .session-tldr {
background: var(--ds-primary-light);
border-left: 4px solid var(--ds-primary-dark);
padding: 20px 24px;
border-radius: 0 8px 8px 0;
margin-top: 28px;
font-size: 15px;
color: var(--ds-text-primary);
line-height: 1.6;
}
.home-mock .session-tldr strong { color: var(--ds-primary-dark); }
/* Terminal frame — exact design colors. Box-shadow uses the global
--ds-shadow-md so the frame lifts off the white first-session
surface; macOS traffic-light reds/yellows/greens match the real
colors (#ff5f57 / #febc2e / #28c840) so the framing reads as a
terminal, not a generic dark card. */
.home-mock .terminal-frame {
background: var(--ds-code-bg);
border: 1px solid #1f2a4a;
border-radius: 10px;
overflow: hidden;
box-shadow: var(--ds-shadow-md);
margin: 10px 0 4px;
}
.home-mock .terminal-bar {
display: flex;
align-items: center;
gap: 8px;
background: #182241;
padding: 8px 14px;
border-bottom: 1px solid #1f2a4a;
}
.home-mock .terminal-bar .traffic {
width: 11px;
height: 11px;
border-radius: 50%;
background: #4a5168;
display: inline-block;
}
.home-mock .terminal-bar .traffic.r { background: #ff5f57; }
.home-mock .terminal-bar .traffic.y { background: #febc2e; }
.home-mock .terminal-bar .traffic.g { background: #28c840; }
.home-mock .terminal-bar .terminal-title {
margin-left: 8px;
font-family: var(--ds-font-mono);
font-size: 12px;
color: rgba(255, 255, 255, 0.55);
}
.home-mock .terminal-body {
font-family: var(--ds-font-mono);
font-size: 13px;
line-height: 1.65;
color: var(--ds-code-ink);
padding: 16px 20px;
white-space: pre-wrap;
word-break: normal;
}
.home-mock .terminal-body .prompt {
color: var(--ds-primary);
margin-right: 8px;
user-select: none;
}
.home-mock .terminal-body .you { color: #ffd866; }
.home-mock .terminal-body .cmd { color: #ffd866; }
.home-mock .terminal-body .ai-name { color: var(--ds-primary); font-weight: 600; }
.home-mock .terminal-body .path { color: #8b9fe0; }
.home-mock .terminal-body .dim { color: rgba(215, 228, 255, 0.55); }
.home-mock .terminal-body strong { color: #ffffff; font-weight: 600; }
.home-mock .terminal-body .caret {
display: inline-block;
width: 8px;
height: 14px;
background: var(--ds-primary);
vertical-align: text-bottom;
animation: agnes-blink 1s steps(2, end) infinite;
}
@keyframes agnes-blink { 50% { opacity: 0; } }
/* ── Surfaces — 4-card layout matching the design spec verbatim. h2
28px / 700, surface-card padding 28px, .feature variant uses a
brand-light gradient + 2px brand border, .incomplete variant uses
a red-tinted gradient + 2px red border. Steps render in a tinted
panel with surface-dim bg. */
.home-mock .surfaces { padding: 24px 28px; }
.home-mock .surfaces > header { margin-bottom: 20px; }
.home-mock .surfaces > header .eyebrow {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--ds-primary-dark);
margin-bottom: 14px;
}
.home-mock .surfaces > header h2 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
line-height: 1.2;
margin: 0 0 8px;
color: var(--ds-text-primary);
}
.home-mock .surfaces > header p {
font-size: 18px;
color: var(--ds-text-secondary);
line-height: 1.55;
margin: 0 0 12px;
max-width: 760px;
}
.home-mock .surfaces-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-bottom: 14px;
}
.home-mock .surface-card {
background: var(--ds-surface);
border: 1px solid var(--ds-border);
border-radius: 14px;
padding: 28px;
box-shadow: var(--ds-shadow-sm);
display: flex;
flex-direction: column;
gap: 10px;
}
.home-mock .surface-card.feature {
border: 2px solid var(--ds-primary);
background: linear-gradient(180deg, var(--ds-primary-light) 0%, var(--ds-surface) 40%);
}
.home-mock .surface-card.incomplete {
border: 2px solid #e35e5e;
background: linear-gradient(180deg, #fdecec 0%, var(--ds-surface) 60%);
}
.home-mock .surface-icon {
font-size: 26px;
line-height: 1;
margin-bottom: 6px;
}
.home-mock .surface-card h3 {
font-size: 18px;
font-weight: 600;
margin: 0;
color: var(--ds-text-primary);
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.home-mock .surface-card .badge {
background: var(--ds-primary);
color: #ffffff;
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 3px 8px;
border-radius: 4px;
}
.home-mock .surface-card .badge-warn {
background: #e35e5e;
color: #ffffff;
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 3px 8px;
border-radius: 4px;
}
.home-mock .surface-card .what {
font-size: 14px;
color: var(--ds-text-secondary);
line-height: 1.55;
margin: 0;
}
.home-mock .surface-card .what code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
border: 1px solid rgba(46, 168, 119, 0.30);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 12px;
}
/* VS Code thumb — anchor wrapping the real screenshot. Clicking opens
the lightbox. `.thumb-fallback` is only visible when the `<img>` is
missing/errors (handled by inline onerror → `.thumb-empty`). */
.home-mock .vscode-thumb {
display: block;
position: relative;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--ds-border);
background: #0c1224;
text-decoration: none;
color: inherit;
margin: 2px 0 4px;
cursor: zoom-in;
transition: transform 0.12s, box-shadow 0.12s, border-color 0.12s;
}
.home-mock .vscode-thumb:hover {
transform: translateY(-1px);
box-shadow: 0 4px 16px rgba(15, 27, 58, 0.25);
border-color: var(--ds-brand-accent);
}
.home-mock .vscode-thumb img {
display: block;
width: 100%;
height: auto;
}
.home-mock .vscode-thumb.thumb-empty {
aspect-ratio: 16 / 9;
background: var(--ds-surface-dim);
cursor: default;
display: grid;
place-items: center;
}
.home-mock .vscode-thumb.thumb-empty:hover {
transform: none;
box-shadow: none;
border-color: var(--ds-border);
}
.home-mock .vscode-thumb .thumb-fallback {
display: none;
padding: 18px;
font-size: 12px;
color: var(--ds-text-muted);
text-align: center;
}
.home-mock .vscode-thumb.thumb-empty .thumb-fallback { display: block; }
.home-mock .vscode-thumb .thumb-fallback-row {
display: flex;
justify-content: center;
gap: 14px;
flex-wrap: wrap;
font-weight: 600;
color: #d7e4ff;
}
.home-mock .vscode-thumb .dot {
width: 10px;
height: 10px;
border-radius: 2px;
display: inline-block;
margin-right: 4px;
vertical-align: middle;
}
.home-mock .vscode-thumb .dot.d-explorer { background: #ffd866; }
.home-mock .vscode-thumb .dot.d-t1 { background: var(--ds-brand-accent); }
.home-mock .vscode-thumb .dot.d-t2 { background: #e07b3f; }
.home-mock .vscode-thumb .dot.d-t3 { background: #8b6ec7; }
.home-mock .vscode-thumb .thumb-fallback-hint {
margin-top: 10px;
font-size: 11.5px;
color: rgba(215, 228, 255, 0.6);
}
.home-mock .vscode-thumb .thumb-fallback-hint code {
font-size: 11.5px;
}
.home-mock .vscode-thumb .thumb-caption {
position: absolute;
left: 12px;
bottom: 12px;
background: rgba(15, 27, 58, 0.78);
color: white;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.3px;
padding: 4px 10px;
border-radius: 999px;
-webkit-backdrop-filter: blur(4px);
backdrop-filter: blur(4px);
}
/* Steps inner panel — surface-dim bg matching design + small caps
eyebrow on the first <strong>. */
.home-mock .surface-card .steps {
background: var(--ds-surface-dim);
border-radius: 8px;
padding: 12px 16px;
margin: 4px 0;
font-size: 13px;
color: var(--ds-text-primary);
}
.home-mock .surface-card .steps .steps-eyebrow {
font-size: 12px;
letter-spacing: 1px;
color: var(--ds-text-muted);
display: block;
margin-bottom: 8px;
font-weight: 700;
text-transform: uppercase;
}
.home-mock .surface-card .steps ol {
margin: 0;
padding-left: 18px;
list-style: decimal;
}
.home-mock .surface-card .steps li {
margin-bottom: 4px;
line-height: 1.55;
}
.home-mock .surface-card .steps li:last-child { margin-bottom: 0; }
.home-mock .surface-card .steps code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
border: 1px solid rgba(46, 168, 119, 0.30);
padding: 1px 5px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 12px;
}
.home-mock .surface-card .steps kbd {
background: var(--ds-surface);
border: 1px solid var(--ds-border);
border-bottom-width: 2px;
padding: 1px 6px;
border-radius: 4px;
font-size: 12px;
font-family: var(--ds-font-mono);
}
.home-mock .surface-card .steps a {
color: var(--ds-primary-dark);
text-decoration: underline;
}
/* `.code-output` extracted to shared
app/web/static/css/components.css — markup renamed accordingly
(`<div class="expected-output">` → `<div class="code-output">`). */
/* When-to-use footer — top-border + ink-muted body, brand-dark for
links. Per design spec. */
.home-mock .surface-card .when-to-use {
font-size: 13px;
color: var(--ds-text-muted);
border-top: 1px solid var(--ds-border);
padding-top: 12px;
margin-top: 4px;
line-height: 1.55;
}
.home-mock .surface-card .when-to-use strong { color: var(--ds-text-primary); }
.home-mock .surface-card .when-to-use a { color: var(--ds-primary-dark); text-decoration: underline; }
.home-mock .surface-card .when-to-use a:hover { color: var(--ds-primary); }
.home-mock .incomplete-callout {
background: #ffffff;
border: 1px dashed #e35e5e;
border-radius: 8px;
padding: 12px 16px;
font-size: 13px;
color: #7a1f1f;
line-height: 1.55;
}
.home-mock .incomplete-callout strong {
color: #5a0e0e;
}
.home-mock .incomplete-callout ul {
margin: 8px 0 4px 18px;
padding: 0;
color: #7a1f1f;
}
.home-mock .incomplete-callout li { margin-bottom: 4px; }
@media (max-width: 880px) {
.home-mock .surfaces-grid { grid-template-columns: 1fr; }
}
/* RECOMMENDED chip on the VS Code surface tile. Doesn't change the
.home-usage-item structure — just adds the badge. */
.home-mock .recommend-pill {
display: inline-block;
margin-left: 6px;
font-size: 10.5px;
font-weight: 700;
letter-spacing: 0.5px;
text-transform: uppercase;
padding: 2px 8px;
background: var(--ds-brand-accent);
color: var(--ds-hero-bg);
border-radius: 999px;
vertical-align: middle;
}
/* Surfaces wrapper is now bare (no white card). Padding lives on the
inner header + grid, not on .home-usage itself. The global
`header { display: flex; justify-content: space-between; ... }`
rule absorbed from style.css makes our section header lay out
the eyebrow/h2/lede side-by-side; force block + no padding/border
so the title sits on the LEFT under the eyebrow as the design has. */
.home-mock .home-usage { padding: 0; text-align: left; }
.home-mock .home-usage > header,
.home-mock .first-session > header,
.home-mock .browse-section > header,
.home-mock section > header {
display: block;
padding: 0;
margin-bottom: 20px;
border-bottom: none;
flex-wrap: initial;
gap: 0;
justify-content: initial;
align-items: initial;
}
.home-mock .home-usage > header h2,
.home-mock .home-usage > header p {
text-align: left;
width: 100%;
}
/* Browse-section — bare section on the page bg, 5-col grid, cards
with green-hover lift. Per design spec. */
.home-mock .browse-section {
margin: 36px 0;
}
.home-mock .browse-section .eyebrow {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--ds-primary-dark);
margin-bottom: 14px;
}
.home-mock .browse-section h2 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
line-height: 1.2;
margin: 0 0 8px;
color: var(--ds-text-primary);
}
.home-mock .browse-section .lede {
font-size: 18px;
color: var(--ds-text-secondary);
line-height: 1.55;
margin: 0 0 20px;
max-width: 720px;
}
.home-mock .browse-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 14px;
}
.home-mock .browse-card {
background: var(--ds-surface);
border: 1px solid var(--ds-border);
border-radius: 12px;
padding: 22px 20px;
text-decoration: none;
color: var(--ds-text-primary);
display: flex;
flex-direction: column;
gap: 6px;
transition: transform 0.1s, box-shadow 0.1s, border-color 0.1s;
box-shadow: none;
transform: none;
position: relative;
}
.home-mock .browse-card:hover {
transform: translateY(-2px);
box-shadow: var(--ds-shadow-md);
border-color: var(--ds-primary);
}
.home-mock .browse-card .browse-icon {
font-size: 28px;
margin-bottom: 4px;
line-height: 1;
}
.home-mock .browse-card .browse-title {
font-weight: 600;
font-size: 15px;
color: var(--ds-text-primary);
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.home-mock .browse-card .browse-title .arrow {
color: var(--ds-primary-dark);
font-weight: 600;
transition: transform 0.15s ease;
}
.home-mock .browse-card:hover .browse-title .arrow {
transform: translateX(2px);
}
.home-mock .browse-card .browse-desc {
font-size: 12.5px;
color: var(--ds-text-muted);
line-height: 1.45;
flex-grow: 1;
}
/* "NEW" corner badge — design spec verbatim. */
.home-mock .browse-card.new::after {
content: "NEW";
position: absolute;
top: 12px;
right: 12px;
background: var(--ds-primary);
color: #ffffff;
font-size: 10px;
font-weight: 700;
padding: 2px 6px;
border-radius: 3px;
letter-spacing: 0.5px;
}
/* Equal heights — grid stretches items by default; this just keeps
inner content laid out so titles + descs line up across cards. */
.home-mock .browse-card { align-self: stretch; }
@media (max-width: 880px) {
.home-mock .browse-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
.home-mock .browse-grid { grid-template-columns: 1fr; }
}
.home-mock .home-usage-item {
padding: 16px;
transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.home-mock a.home-usage-item:hover { transform: translateY(-1px); }
/* Browse-cards (the existing .what-is look-around-grid) — give the
tiles a bit more breathing room and a green-on-hover highlight that
matches the new palette. */
.home-mock .what-is.look-around-grid {
margin-top: 6px;
}
.home-mock .what-is-item {
padding: 20px;
}
/* Mobile tweaks for the install-hero now that the .install-block has
a 56px left-padding step badge. */
@media (max-width: 560px) {
.home-mock .install-hero { padding: 24px 18px; }
.home-mock .install-block { padding-left: 18px; }
.home-mock .install-block .step-num { position: static; margin-bottom: 8px; }
}
/* ─────────────────────────────────────────────────────────────────
Setup-wizard LIGHT theme — design spec has the install-hero as a
white surface card with light step rows, NOT a dark navy card.
This override block flips all the in-hero rules from the original
dark-navy palette to a light surface that matches the design. The
code-panel (.install-cmd) and terminal-frame mockups STAY dark
so they stand out as "what the user will type".
───────────────────────────────────────────────────────────────── */
.home-mock .install-hero {
background: var(--ds-surface);
color: var(--ds-text-primary);
border: 1px solid var(--ds-border);
border-radius: 16px;
padding: 36px;
box-shadow: var(--ds-shadow-sm);
}
/* Drop the navy gradient + sweep-shadow remnant; keep the slim green
accent strip across the top so the wizard reads as the brand CTA. */
.home-mock .install-hero::before { content: none; }
.home-mock .install-hero-close {
background: var(--ds-surface);
border: 1px solid var(--ds-border);
color: var(--ds-text-muted);
}
.home-mock .install-hero-close:hover,
.home-mock .install-hero-close:focus-visible {
background: var(--ds-bg);
color: var(--ds-text-primary);
}
.home-mock .install-hero .eyebrow {
color: var(--ds-primary);
opacity: 1;
}
.home-mock .install-hero h1 {
color: var(--ds-text-primary);
font-size: 24px;
}
.home-mock .install-hero .lead,
.home-mock .install-hero .lead-privacy {
color: var(--ds-text-secondary);
opacity: 1;
}
.home-mock .install-hero .lead strong { color: var(--ds-text-primary); }
.home-mock .install-hero a {
color: var(--ds-primary);
text-decoration: underline;
text-decoration-color: rgba(46, 168, 119, 0.4);
}
.home-mock .install-hero a:hover,
.home-mock .install-hero a:focus {
color: var(--ds-primary-dark);
text-decoration-color: var(--ds-primary-dark);
}
/* In-lead `<code>` chips — light variant (design uses brand-light bg). */
.home-mock .install-hero code,
.home-mock .install-note code,
.home-mock .install-note > code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
border-color: rgba(46, 168, 119, 0.30);
}
/* Setup-meta chips on light bg — primary chip uses brand-light pill,
secondary chips lose the white-on-dark treatment for ink-muted. */
.home-mock .setup-chip {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
}
.home-mock .setup-chip-quiet {
background: var(--ds-bg);
color: var(--ds-text-secondary);
border-color: var(--ds-border);
}
.home-mock .progress-bar {
height: 6px;
background: var(--ds-bg);
}
.home-mock .progress-fill {
background: var(--ds-primary);
}
/* Step rows — grid layout with a light circle for the step number,
borders between rows, no dark card. */
.home-mock .install-block {
background: transparent;
border: none;
border-top: 1px solid var(--ds-border);
border-radius: 0;
padding: 22px 0 22px 64px;
margin-top: 0 !important;
}
.home-mock .install-block:first-of-type {
border-top: none;
padding-top: 6px;
}
.home-mock .install-block + .install-block { margin-top: 0; }
.home-mock .install-block .step-num {
top: 22px;
left: 8px;
width: 40px;
height: 40px;
background: var(--ds-surface-dim);
color: var(--ds-text-secondary);
font-size: 16px;
font-weight: 700;
}
.home-mock .install-block .label {
color: var(--ds-text-primary);
font-size: 17px;
font-weight: 700;
text-transform: none;
letter-spacing: 0;
opacity: 1;
margin-bottom: 6px;
line-height: 1.35;
}
/* Subhead under each step label — short body type explaining what
the step accomplishes before the OS tabs / code panel appear. */
.home-mock .install-block .step-lede {
color: var(--ds-text-secondary);
font-size: 14.5px;
line-height: 1.55;
margin: 0 0 12px;
max-width: 720px;
}
.home-mock .install-block .step-lede strong { color: var(--ds-text-primary); font-weight: 600; }
.home-mock .install-block .step-lede code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
border: 1px solid rgba(46, 168, 119, 0.30);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 12px;
}
/* OS tabs sit on white now — borders + colors flip to ink. */
.home-mock .os-tabs {
border-bottom-color: var(--ds-border);
}
.home-mock .os-tab {
color: var(--ds-text-muted);
}
.home-mock .os-tab:hover { color: var(--ds-text-primary); }
.home-mock .os-tab.is-active {
color: var(--ds-primary-dark);
border-bottom-color: var(--ds-primary-dark);
}
/* Code panel (.install-cmd) STAYS dark — it's the "type this" surface.
Just adjust spacing + ensure it pops on the white step row. */
.home-mock .install-cmd {
background: var(--ds-code-bg);
border-color: rgba(0, 0, 0, 0.08);
color: var(--ds-code-yellow);
}
/* Install-note prose — ink-soft secondary on white, 14px to match
design's body type. */
.home-mock .install-note {
color: var(--ds-text-secondary);
font-size: 14px;
line-height: 1.55;
margin-top: 10px;
}
/* `.callout-rec` and `.callout-hint` extracted to shared
app/web/static/css/components.css — markup renamed accordingly
(`<div class="rec">` → `<div class="callout-rec">`). */
/* Mode-tabs — Auto / YOLO toggle in Step 6 selecting which shell
function gets installed. Visually mirrors `.os-tabs` but with a
labeled heading above. */
.home-mock .install-block .step-mode-heading {
font-weight: 600;
margin: 14px 0 6px;
color: var(--ds-text-primary);
}
.home-mock .install-block .mode-tabs {
display: flex;
gap: 4px;
margin-bottom: 8px;
border-bottom: 1px solid var(--ds-border);
}
.home-mock .install-block .mode-tab {
background: transparent;
border: none;
color: var(--ds-text-muted);
font-size: 13px;
font-weight: 600;
padding: 8px 14px;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
font-family: inherit;
}
.home-mock .install-block .mode-tab.is-active {
color: var(--ds-primary-dark);
border-bottom-color: var(--ds-primary-dark);
}
/* Single-line description below the mode-tab — kept on one row.
The text is tight enough to fit at typical widths; on narrow
viewports it wraps gracefully. */
.home-mock .install-block .mode-panel-lede {
font-size: 13.5px;
line-height: 1.5;
color: var(--ds-text-secondary);
margin: 10px 0 12px;
}
.home-mock .install-block .mode-panel-lede code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 12px;
}
/* `.setup-section-header` (eyebrow + heading + lede above a wizard
card) extracted to shared app/web/static/css/components.css. */
.setup-section-header .lead.lead-privacy {
font-size: 13.5px;
color: var(--ds-text-muted);
margin-bottom: 0;
}
.setup-section-header .lead.lead-privacy strong { color: var(--ds-text-secondary); }
/* Step 5 manual-fallback details — inline with the copy button on the
right of the cta row. When closed, just the summary is visible;
when opened, the expanded preview spans the full row width. */
.home-mock .install-block .setup-cta-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px 16px;
margin-top: 4px;
}
.home-mock .install-block .setup-cta-row .manual-fallback {
margin-left: auto;
font-size: 13px;
}
.home-mock .install-block .setup-cta-row .manual-fallback[open] {
flex-basis: 100%;
margin-left: 0;
}
.home-mock .install-block .setup-cta-row .manual-fallback > summary {
color: var(--ds-text-muted);
cursor: pointer;
list-style: none;
}
.home-mock .install-block .setup-cta-row .manual-fallback > summary::-webkit-details-marker { display: none; }
.home-mock .install-block .setup-cta-row .manual-fallback > summary::before {
content: "\25B8 ";
color: var(--ds-text-muted);
}
.home-mock .install-block .setup-cta-row .manual-fallback[open] > summary::before { content: "\25BE "; }
.home-mock .install-block .setup-cta-row .manual-fallback > summary:hover { color: var(--ds-text-primary); }
/* Setup-finish strip — flex row separating "waiting for agnes pull"
status from the right-aligned "Mark me as onboarded" fallback link.
Matches design spec's footer row on the setup card. */
.home-mock .install-hero .setup-finish-strip {
border-top: 1px solid var(--ds-border);
padding-top: 16px;
margin-top: 20px;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
font-size: 13px;
color: var(--ds-text-muted);
}
.home-mock .install-hero .setup-finish-text code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 11.5px;
}
.home-mock .install-hero .setup-finish-link {
color: var(--ds-text-muted);
text-decoration: underline;
cursor: pointer;
}
.home-mock .install-hero .setup-finish-link:hover { color: var(--ds-text-primary); }
.home-mock .install-hero .setup-finish-strip .status {
width: 100%;
font-style: italic;
margin-top: 4px;
}
/* Setup-CTA inside Step 4 — green primary button on light. */
.home-mock .setup-cta-lead {
color: var(--ds-text-secondary);
}
.home-mock .setup-cta-lead code {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
}
.home-mock .btn-setup-primary {
background: var(--ds-primary);
color: #ffffff;
}
.home-mock .btn-setup-primary:hover { background: var(--ds-primary-dark); }
.home-mock .setup-cta-hint { color: var(--ds-text-muted); }
.home-mock details.manual-fallback {
border-top-color: var(--ds-border);
}
.home-mock details.manual-fallback > summary {
color: var(--ds-text-secondary);
}
/* Self-mark + auto-detect badge — light variants. */
.home-mock .self-mark { color: var(--ds-text-secondary); }
.home-mock .self-mark button {
background: var(--ds-surface);
color: var(--ds-text-primary);
border: 1px solid var(--ds-border);
}
.home-mock .self-mark button:hover { background: var(--ds-bg); }
.home-mock .auto-detect-badge {
background: var(--ds-primary-light);
color: var(--ds-primary-dark);
border: 1px solid rgba(46, 168, 119, 0.30);
}
.home-mock .auto-detect-badge .pulse { background: var(--ds-primary); }
.home-mock .auto-detect-badge code {
background: rgba(46, 168, 119, 0.18);
color: var(--ds-primary-dark);
}
/* Terminal-howto disclosure — blue info-hint box matching the design's
`.step-body .hint` vocabulary (light blue bg, blue left-border,
blue ink, white kbd chips with thin border). */
.home-mock details.terminal-howto {
background: var(--ds-info-bg);
border: none;
border-left: 3px solid var(--ds-info-line);
border-radius: 8px;
padding: 12px 16px;
margin-top: 10px;
}
.home-mock details.terminal-howto > summary {
color: var(--ds-info-ink);
font-weight: 700;
font-size: 14px;
}
.home-mock details.terminal-howto > summary::before { color: var(--ds-info-ink); }
.home-mock .terminal-howto-body {
color: var(--ds-info-ink);
margin-top: 8px;
font-size: 14px;
}
.home-mock .terminal-howto-body p { margin: 0 0 6px; }
.home-mock .terminal-howto-body p:last-child { margin: 0; }
.home-mock .terminal-howto-body strong { color: var(--ds-info-ink); }
.home-mock .terminal-howto-body kbd {
background: var(--ds-surface);
color: var(--ds-text-primary);
border: 1px solid var(--ds-border);
border-bottom-width: 2px;
padding: 1px 6px;
border-radius: 4px;
font-size: 12px;
font-family: var(--ds-font-mono);
}
/* Step 3 (home_automode) extra .install-cmd nested inside — already
dark via .install-cmd rule above. Notes around it use ink-soft. */
.home-mock .install-cmd .copy-btn {
background: rgba(255, 255, 255, 0.08);
color: #ffffff;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.home-mock .install-cmd .copy-btn:hover { background: rgba(255, 255, 255, 0.15); }
/* Manual-preview-pre stays dark (rendered already) — no change needed. */
@media (max-width: 560px) {
.home-mock .install-block { padding-left: 0; }
.home-mock .install-block .step-num { position: static; margin-bottom: 8px; }
}
</style>
<div class="home-mock">
{# Value-first intro hero — explains *what* {{ instance_brand }} is
before any install step. Renders for both onboarded and
not-onboarded users: onboarded analysts get the same product
narrative on every visit, just without the "Set up in ~15 min"
CTA. Pillars row mirrors the four primary nav destinations
(catalog / marketplace / corporate-memory / marketplace?skills)
so the value proposition aligns with where the user can act on
it. #}
{% set display_name = (user.name or (user.email or "").split("@")[0] or "there") %}
<section class="home-hero-intro">
<div class="eyebrow">Welcome, {{ display_name }}</div>
<h1>{{ instance_brand }} is your team's <span class="accent">AI workspace.</span></h1>
<p class="lede">
One place to reach {{ instance_brand }}'s curated data, plugins, skills, and shared memory &mdash;
so your AI agent stops guessing and starts answering. Curated, versioned, kept current.
The system learns from every session and extends coverage so the next question doesn't
trip on the same gap.
</p>
<p class="lede">
Think of it as your <em>AI Chief of Staff</em> &mdash; it lives in a folder on your computer,
gives you access to company data and curated skills, and lets you share your own skills
and plugins back to the team.
</p>
<div class="home-hero-cta">
{% if not onboarded %}
<a class="btn-intro btn-intro-primary" href="#install-hero">Set up in ~15&nbsp;min &rarr;</a>
{% endif %}
<a class="btn-intro btn-intro-secondary" href="#look-around">Just browse &mdash; no install needed</a>
</div>
<div class="home-hero-pillars">
<div class="pillar">
<div class="pillar-h">Data packages</div>
<p>Tables, schema, metric definitions your team has registered &mdash; documented business rules.</p>
</div>
<div class="pillar">
<div class="pillar-h">Plugins</div>
<p>Asana, Jira, Google Workspace, Atlassian, GitHub. Curated &amp; community-built.</p>
</div>
<div class="pillar">
<div class="pillar-h">Skills</div>
<p>Reusable workflow templates Claude follows &mdash; brainstorming, planning, review, debugging. Curated company-wide plus a flea market to share yours.</p>
</div>
<div class="pillar">
<div class="pillar-h">Memory</div>
<p>Shared analyst knowledge and prior solutions, fed back into Claude's context on demand.</p>
</div>
</div>
</section>
{# Homepage status frame — five counters with 24h/7d toggle.
Two gates: (a) operator flag instance.home.show_status_frame /
AGNES_HOME_SHOW_STATUS_FRAME (default on, evaluated in router and
passed as `status_frame_enabled`); (b) the user being onboarded —
fresh users see a clean install-hero before zero-value stats.
Router skips `compute_home_stats` (saves the DB hit) when either
gate is closed, so `home_stats` is None in that branch. #}
{% if status_frame_enabled and onboarded and home_stats %}
{% include "_home_stats.html" %}
{% endif %}
{% set display_name = (user.name or (user.email or "").split("@")[0] or "there") %}
{# Install-hero renders only for not-onboarded users. Once `agnes init`
POSTs /api/me/onboarded (or the user clicks the in-hero X) the hero
disappears entirely — the rest of /home (connector tiles, news,
etc.) stays. Offboarding escape hatch moved to a discrete strip
below; see `.offboard-strip`. #}
{% if not onboarded %}
<div class="setup-section-header" id="install-hero">
<div class="eyebrow">First time here</div>
<h2 class="setup-heading">Set up {{ instance_brand }} on your machine</h2>
<p class="lead">
~15&nbsp;minutes, one time. You'll install one CLI tool, pick a folder, and paste a script we generate for you. After that you have a working AI workspace that knows your team's data. Everything lives in <code>~/Desktop/{{ workspace_dir }}</code> and can be removed in one command.
</p>
</div>
<div class="install-hero">
<button type="button" class="install-hero-close" id="installHeroClose"
data-target-source="self_acknowledged"
aria-label="I'm already set up — close this setup hero">&times;</button>
{# Progress meta — visual hint that the wizard is bounded ("~15 min,
one-time, reversible"). Six steps total when home_automode is
enabled, five when it's disabled (the "Launch Claude with
auto-approve" step hides via {% if home_automode.show %}).
Pre-empt: when more steps land in future iterations, just
bump the total_steps default; per-step numbering inside
.install-block carries its own count already. #}
{% set total_steps = 6 if home_automode.show else 5 %}
<div class="setup-meta" aria-label="Setup overview">
<span class="setup-chip">Step 1 of {{ total_steps }}</span>
<span class="setup-chip-quiet">~15 min total</span>
<span class="setup-chip-quiet">One-time setup</span>
<span class="setup-chip-quiet">Reversible &mdash; remove with one command</span>
</div>
<div class="progress-bar" aria-hidden="true">
<div class="progress-fill" style="width: {{ (100 // total_steps) }}%"></div>
</div>
<div class="install-block">
<div class="step-num" aria-hidden="true"><span>1</span></div>
<div class="label">Install Claude Code on your computer</div>
<p class="step-lede">Claude Code is the CLI tool that runs Claude on your machine. {{ instance_brand }} plugs into it. <strong>~3&nbsp;min.</strong></p>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux</button>
<button type="button" role="tab" class="os-tab"
data-os-tab="windows" aria-selected="false">Windows (PowerShell)</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="unix">
<span class="multiline" id="install-cmd-claude-unix">curl -fsSL https://claude.ai/install.sh | bash</span>
<button class="copy-btn" data-copy-target="install-cmd-claude-unix">Copy</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="windows" hidden>
<span class="multiline" id="install-cmd-claude-windows">irm https://claude.ai/install.ps1 | iex</span>
<button class="copy-btn" data-copy-target="install-cmd-claude-windows">Copy</button>
</div>
<div class="callout-hint">
<strong>Don't have a terminal open yet?</strong>
On macOS, press <kbd></kbd> + <kbd>Space</kbd>, type <em>Terminal</em>, hit Enter.
On Windows, press the <kbd></kbd> key, type <em>PowerShell</em>, hit Enter.
</div>
<p class="step-lede" style="margin-top: 14px;">
Once it finishes, verify with <code>claude --version</code>, then sign in with <code>claude</code>
(one-time OAuth in your browser). Don't have a Claude license yet?
<a href="/setup-advanced#claude-plan">Here's how to get one</a>
(Pro&nbsp;/&nbsp;Max&nbsp;5×&nbsp;/&nbsp;Max&nbsp;20×&nbsp;/&nbsp;Enterprise &mdash; Enterprise is the option for Finance and Legal).
</p>
</div>
<div class="install-block">
<div class="step-num" aria-hidden="true"><span>2</span></div>
<div class="label">Pick a folder for {{ instance_brand }}</div>
<p class="step-lede">This is where {{ instance_brand }} &mdash; and all your AI projects &mdash; will live. <strong>~1&nbsp;min.</strong></p>
<div class="callout-rec">
<strong>My recommendation: put it on your Desktop.</strong>
Desktop is easy to see in Finder/Explorer and easy to find from anywhere
(<code>~/Desktop/{{ workspace_dir }}</code> on macOS, <code>%USERPROFILE%\Desktop\{{ workspace_dir }}</code> on Windows).
I keep mine there because I open it 10&times; a day. Your home folder is fine too &mdash;
the install will work anywhere.
</div>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux</button>
<button type="button" role="tab" class="os-tab"
data-os-tab="windows" aria-selected="false">Windows (PowerShell)</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="unix">
<span class="multiline" id="install-cmd-mkdir-unix">mkdir -p ~/Desktop/{{ workspace_dir }} &amp;&amp; cd ~/Desktop/{{ workspace_dir }}</span>
<button class="copy-btn" data-copy-target="install-cmd-mkdir-unix">Copy</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="windows" hidden>
<span class="multiline" id="install-cmd-mkdir-windows">New-Item -ItemType Directory -Force -Path "$HOME\Desktop\{{ workspace_dir }}" | Out-Null
Set-Location "$HOME\Desktop\{{ workspace_dir }}"</span>
<button class="copy-btn" data-copy-target="install-cmd-mkdir-windows">Copy</button>
</div>
<div class="callout-hint">
<strong>What does <code>mkdir -p</code> do?</strong>
It creates a folder. The <code>-p</code> just means "don't complain if it already exists."
After this command, you have an empty folder called <code>{{ workspace_dir }}</code> on your Desktop.
You can verify by opening Finder/Explorer and looking on your Desktop &mdash; it'll be there.
</div>
</div>
{# Step 3 — open a terminal inside the workspace folder. No
shell command here: this step is just the OS-level "you are
now standing in the right directory" reassurance, mirroring
the design spec's Step 3. Step 2's `cd` already lands the
current shell here; this step covers the case where the
analyst closes that terminal between steps. #}
<div class="install-block">
<div class="step-num" aria-hidden="true"><span>3</span></div>
<div class="label">Open a terminal inside that folder</div>
<p class="step-lede">The terminal is how you tell Claude what to do. You need to "be in" the <code>{{ workspace_dir }}</code> folder before you launch Claude. <strong>~1&nbsp;min.</strong></p>
<div class="callout-hint">
<strong>Two ways to get there.</strong> Pick whichever feels easier.
<ol>
<li><strong>Drag-and-drop (easy).</strong> Open Terminal. Type <code>cd</code> followed by a space. Then drag the <code>{{ workspace_dir }}</code> folder from your file browser right onto the Terminal window &mdash; it pastes the path for you. Hit Enter.</li>
<li><strong>Type the path (faster).</strong> See the command below.</li>
</ol>
</div>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux</button>
<button type="button" role="tab" class="os-tab"
data-os-tab="windows" aria-selected="false">Windows (PowerShell)</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="unix">
<span class="multiline" id="install-cmd-cd-unix">cd ~/Desktop/{{ workspace_dir }}</span>
<button class="copy-btn" data-copy-target="install-cmd-cd-unix">Copy</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="windows" hidden>
<span class="multiline" id="install-cmd-cd-windows">Set-Location "$HOME\Desktop\{{ workspace_dir }}"</span>
<button class="copy-btn" data-copy-target="install-cmd-cd-windows">Copy</button>
</div>
<div class="callout-hint">
<strong>What does <code>cd</code> mean?</strong>
"Change directory" &mdash; like double-clicking into a folder, but in the terminal.
After this command, every command you type happens <em>inside</em> the <code>{{ workspace_dir }}</code> folder.
</div>
<div class="code-output">$ pwd
/Users/yourname/Desktop/{{ workspace_dir }}</div>
<p class="step-lede" style="font-size: 13px; color: var(--ds-text-muted); margin-top: 6px;">
(Optional: run <code>pwd</code> to print the path you're currently in. If it ends in <code>/Desktop/{{ workspace_dir }}</code>, you're in the right place.)
</p>
</div>
{% if home_automode.show %}
<div class="install-block">
<div class="step-num" aria-hidden="true"><span>4</span></div>
<div class="label">Launch Claude with auto-approve on</div>
<p class="step-lede">The next step pastes a setup script that runs ~20 shell commands. Launching Claude with the permission-skip flag lets it complete without per-command Yes/No prompts.</p>
<div class="install-cmd">
<span class="multiline" id="install-cmd-claude-yolo">claude --dangerously-skip-permissions</span>
<button class="copy-btn" data-copy-target="install-cmd-claude-yolo">Copy</button>
</div>
<div class="install-note">
Session-scoped — drops on next plain <code>claude</code>. Safe here because the script you paste in the next step is generated by this server and ends after a fixed sequence; the flag does not weaken future Claude sessions. Prefer reviewing each command? Run plain <code>claude</code> and press <strong>Shift + Tab</strong> to cycle on <strong>auto-accept edits</strong> (default → auto-accept edits → plan mode; footer shows <code>⏵⏵</code>). Covers file edits, not Bash — expect ~20 prompt clicks during the next step.
<br><br>
Persistent YOLO (allowlisted): see <a href="/setup-advanced#yolo" target="_blank" rel="noopener">YOLO mode</a> on /setup-advanced — pairs <code>--dangerously-skip-permissions</code> with a reviewed <code>~/.claude/settings.local.json</code> allowlist.
</div>
<div class="code-output">Welcome to Claude Code!
What can I help you with?
&gt;</div>
<p class="step-lede" style="margin-top: 12px;">
When you see the <code>&gt;</code> prompt, you're ready for the next step.
</p>
</div>
{% endif %}
<div class="install-block">
<div class="step-num" aria-hidden="true"><span>{% if home_automode.show %}5{% else %}4{% endif %}</span></div>
<div class="label">Get the install script and paste it into Claude</div>
<p class="step-lede">
Click the button below. {{ instance_brand }} generates a one-time install script
(with a 90-day login token) and copies it to your clipboard. Then paste it into the
Claude prompt from Step&nbsp;4 (<kbd></kbd>+<kbd>V</kbd> on macOS,
<kbd>Ctrl</kbd>+<kbd>V</kbd> on Windows) and hit Enter. The script installs ~20 things
(the marketplace, your team's plugins, data package definitions, hooks that keep
everything in sync) into <code>~/Desktop/{{ workspace_dir }}</code>.
<strong>~30&nbsp;sec to copy; ~5&nbsp;min to run.</strong>
</p>
<div class="setup-cta-row">
<button type="button" id="setupClaudeBtn" class="btn-setup-primary" onclick="setupNewClaude(this)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
Copy install script to clipboard
</button>
<span class="setup-cta-meta">
<span class="setup-cta-hint">Token valid 90 days · stays in clipboard only</span>
</span>
<details class="manual-fallback">
<summary>Or paste manually (preview the script)</summary>
<div class="manual-preview-wrap">
{% with preview_mode=True %}
{% include "_claude_setup_instructions.jinja" %}
{% endwith %}
</div>
<div class="install-note">
The preview above is the exact text the button copies; the placeholder is replaced with a real token at click time. Don't create <code>~/{{ workspace_dir }}/Projects/</code> manually — the bundled plugin offers to set it up after install.
</div>
</details>
</div>
<div id="setupClaudeError" class="setup-error" role="alert" style="display:none;"></div>
<div class="callout-hint">
<strong>You're done when</strong> the script finishes and {{ instance_brand }} auto-detects
your first <code>agnes pull</code> (~30 seconds after the script ends). This page will
update on its own.
</div>
</div>
{# Step 6 — Optional one-word shortcut. Mirrors the design spec's
final step: a shell alias that drops the analyst into the
workspace folder and launches Claude with a single keyword.
Pure quality-of-life polish, gated by an inline <details>
so the wizard stays compact for analysts who just want the
default `claude` invocation. #}
<div class="install-block">
<div class="step-num" aria-hidden="true"><span>{% if home_automode.show %}6{% else %}5{% endif %}</span></div>
<div class="label">Optional: create a one-word shortcut for next time</div>
<p class="step-lede">
So you can stop retyping the long flag and stop typing <code>cd</code>. Adds a shell
function that <em>both</em> changes into your <code>{{ workspace_dir }}</code> folder
<em>and</em> launches Claude &mdash; one word, anywhere on your machine. <strong>~30&nbsp;seconds.</strong>
</p>
<p class="step-mode-heading">Pick a permission level:</p>
<div class="mode-tabs" role="tablist" aria-label="Permission level">
<button type="button" role="tab" class="mode-tab is-active"
data-mode-tab="auto" aria-selected="true">Auto (safer &mdash; recommended)</button>
<button type="button" role="tab" class="mode-tab"
data-mode-tab="yolo" aria-selected="false">YOLO (faster, broader)</button>
</div>
{# AUTO mode panel — `--permission-mode auto` is the right default. #}
<div data-mode-panel="auto">
<p class="mode-panel-lede"><code>--permission-mode auto</code> &mdash; auto-approves edits and safe read-only commands; still asks before anything destructive. Right default for most people.</p>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux (zsh)</button>
<button type="button" role="tab" class="os-tab"
data-os-tab="windows" aria-selected="false">Windows (PowerShell)</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="unix">
<span class="multiline" id="install-cmd-shortcut-auto-unix">echo '{{ workspace_dir | lower }}() { cd ~/Desktop/{{ workspace_dir }} &amp;&amp; claude --permission-mode auto "$@"; }' &gt;&gt; ~/.zshrc &amp;&amp; source ~/.zshrc</span>
<button class="copy-btn" data-copy-target="install-cmd-shortcut-auto-unix">Copy</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="windows" hidden>
<span class="multiline" id="install-cmd-shortcut-auto-windows">if (!(Test-Path $PROFILE)) { New-Item $PROFILE -Force }; Add-Content $PROFILE 'function {{ workspace_dir | lower }} { Push-Location "$env:USERPROFILE\Desktop\{{ workspace_dir }}"; claude --permission-mode auto @args }'</span>
<button class="copy-btn" data-copy-target="install-cmd-shortcut-auto-windows">Copy</button>
</div>
<p class="step-lede" style="margin-top: 8px;">
Now typing <code>{{ workspace_dir | lower }}</code> from any terminal hops into the
<code>{{ workspace_dir }}</code> folder and launches Claude in auto mode. Same on
day&nbsp;1 as day&nbsp;100.
</p>
</div>
{# YOLO mode panel — `--dangerously-skip-permissions` skips every prompt. #}
<div data-mode-panel="yolo" hidden>
<p class="mode-panel-lede"><code>--dangerously-skip-permissions</code> &mdash; auto-approves <em>everything</em>, no prompts. Faster, broader blast radius. Read the security callout below first.</p>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux (zsh)</button>
<button type="button" role="tab" class="os-tab"
data-os-tab="windows" aria-selected="false">Windows (PowerShell)</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="unix">
<span class="multiline" id="install-cmd-shortcut-yolo-unix">echo 'yolo() { cd ~/Desktop/{{ workspace_dir }} &amp;&amp; claude --dangerously-skip-permissions "$@"; }' &gt;&gt; ~/.zshrc &amp;&amp; source ~/.zshrc</span>
<button class="copy-btn" data-copy-target="install-cmd-shortcut-yolo-unix">Copy</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="windows" hidden>
<span class="multiline" id="install-cmd-shortcut-yolo-windows">if (!(Test-Path $PROFILE)) { New-Item $PROFILE -Force }; Add-Content $PROFILE 'function yolo { Push-Location "$env:USERPROFILE\Desktop\{{ workspace_dir }}"; claude --dangerously-skip-permissions @args }'</span>
<button class="copy-btn" data-copy-target="install-cmd-shortcut-yolo-windows">Copy</button>
</div>
<p class="step-lede" style="margin-top: 8px;">
Now typing <code>yolo</code> from any terminal hops into the
<code>{{ workspace_dir }}</code> folder and launches Claude in full auto-approve.
Use it when you trust the work; switch back to <code>{{ workspace_dir | lower }}</code>
(auto mode) when you don't.
</p>
</div>
<div class="install-note">
Bash users: swap <code>~/.zshrc</code> for <code>~/.bashrc</code>. The shortcut is reversible &mdash; open the rc file and delete the function line to remove it.
</div>
<div class="callout-rec">
<strong>The install bundled a curated security allowlist &mdash; review it before going further.</strong>
{{ instance_brand }}'s setup script installed a reviewed <code>~/.claude/settings.local.json</code> for you,
with sensible defaults: read freely, run common dev tools, gate destructive ops. This is your
actual safety net &mdash; the auto / YOLO mode is only safe because of it.
<br><br>
Open the file (<code>open ~/.claude/settings.local.json</code> on macOS, or in VS Code) and
skim what's allowed and what's gated. Add or remove rules as you learn what you trust.
<a href="/setup-advanced#yolo">More on the allowlist &rarr;</a>
</div>
</div>
{# Setup-finish strip — flex row matching design spec: hourglass +
"Waiting for first agnes pull" on the left, "Already set up?
Mark me as onboarded →" link on the right. Auto-detect lands
via agnes-init's POST to /api/me/onboarded; the right-aligned
link is the manual fallback. JS hooks `self-mark-btn`. #}
<div class="setup-finish-strip" role="status" aria-live="polite">
<span class="setup-finish-text">
<span aria-hidden="true"></span>
Waiting for your first <code>agnes pull</code> &mdash; auto-detects within ~30&nbsp;sec of the install script finishing.
</span>
<a href="#" id="self-mark-btn" class="setup-finish-link"
data-target-onboarded="true"
data-target-source="self_acknowledged">Already set up? Mark me as onboarded &rarr;</a>
<span id="self-mark-status" class="status" role="status" aria-live="polite"></span>
</div>
</div>
{% endif %}
{% if onboarded %}
{# Offboarding escape hatch shown only after the hero has disappeared.
Lets the analyst (e.g. after wiping ~/{{ workspace_dir }}) flip the
users.onboarded boolean back to false so the full install hero
renders again on next reload. Discrete by design — onboarded
users land on /home expecting the nav hub, not a setup screen. #}
<div class="offboard-strip">
<span>Workspace ready — wiped it and need the full setup view back?</span>
<button id="offboard-btn" type="button"
data-target-source="self_unmark">Mark me as offboarded</button>
<span id="offboard-status" class="status" role="status" aria-live="polite"></span>
</div>
{% endif %}
{# Auto-mode card used to live here as a `<details>` reference block;
moved into the install-hero as the new Step 2 so users enable it
BEFORE Step 3's install runs ~20 commands. Gated by the same
`home_automode.show` flag at the call site. #}
{# Getting Started was previously rendered HERE (between the offboard
strip and Overview) as a full-card <section>. Moved up to render
BEFORE the install-hero as a collapsed-by-default <details> — see
the block right after `{% if not onboarded %}` near line ~1357. #}
{# First-session story — five-beat narrative showing what the analyst
will actually see on their first run. Terminal frames design the
real output. Renders for both onboarded (reference / refresher)
and not-onboarded (preview of what's coming) so the visual
language stays consistent across visits. #}
<section class="first-session" id="first-session">
<div class="eyebrow">Your first session</div>
<h2>What happens when you launch {{ instance_brand }}</h2>
<p class="lede">A real session, end-to-end. You'll see exactly what appears on screen and what to type at each step. No prior terminal experience needed.</p>
<div class="session-intro">
<span class="session-intro-icon" aria-hidden="true">&#x1F9ED;</span>
<span>The whole loop is <strong>five beats</strong>: launch &rarr; pick a project &rarr; Claude loads its memory &rarr; ask anything &rarr; close when done. Every part of {{ instance_brand }} &mdash; plugins, data packages, skills, shared memory &mdash; quietly does its job inside this loop. You don't have to manage them.</span>
</div>
<div class="session-walk">
<div class="session-step">
<div class="session-num">1</div>
<div class="session-content">
<h3>Launch your workspace</h3>
<p><strong>Open a terminal</strong> &mdash; in VS Code, press <kbd></kbd>+<kbd>`</kbd> (Mac) or <kbd>Ctrl</kbd>+<kbd>`</kbd> (Windows). On macOS you can also open the standalone Terminal app from Spotlight.</p>
<p><strong>Type one word</strong> &mdash; <code>{{ workspace_dir | lower }}</code> (or <code>claude</code> if you skipped Step&nbsp;6) &mdash; and hit Enter.</p>
<div class="terminal-frame">
<div class="terminal-bar"><span class="traffic r"></span><span class="traffic y"></span><span class="traffic g"></span><span class="terminal-title">~/Desktop/{{ workspace_dir }} &nbsp;&mdash;&nbsp; zsh</span></div>
<div class="terminal-body"><span class="prompt">$</span><span class="you">{{ workspace_dir | lower }}</span></div>
</div>
<p class="annotation">That single word jumps into your <code>~/Desktop/{{ workspace_dir }}</code> folder <em>and</em> launches Claude in one go &mdash; same on day&nbsp;1 as day&nbsp;100. No <code>cd</code>, no flags, no setup to remember. (The shortcut was installed in Step&nbsp;6 of the setup above.)</p>
</div>
</div>
<div class="session-step">
<div class="session-num">2</div>
<div class="session-content">
<h3>{{ instance_brand }} greets you with today's menu</h3>
<p>Claude reads your recent activity and shows the five projects you've touched most recently. Your screen looks something like this:</p>
<div class="terminal-frame">
<div class="terminal-bar"><span class="traffic r"></span><span class="traffic y"></span><span class="traffic g"></span><span class="terminal-title">claude&nbsp;&mdash;&nbsp;{{ instance_brand }}</span></div>
<div class="terminal-body">2026-05-20
What would you like to do?
<strong>[1]</strong> Talk to {{ instance_brand }} &mdash; workspace questions, setup, admin
<strong>[2]</strong> New project &mdash; scaffold a new project
<strong>[3]</strong> Switch to recent project:
a. RevenueAnalysis <span class="dim">(2 hours ago)</span>
b. WeeklyReview <span class="dim">(today)</span>
c. Onboarding <span class="dim">(1 day ago)</span>
d. OpsDb <span class="dim">(4 days ago)</span>
e. HRHandShake <span class="dim">(5 days ago)</span>
<strong>[4]</strong> Switch to another project &mdash; browse the full registry
<span class="prompt">&gt;</span><span class="caret"></span></div>
</div>
<p class="annotation">The recent-projects list updates every session based on what you actually worked on. Pick a code (like <code>3a</code>) or just type free text &mdash; <em>"open the news project"</em> or <em>"keep working on the marketing plan"</em> work the same way. Claude figures out the intent.</p>
</div>
</div>
<div class="session-step">
<div class="session-num">3</div>
<div class="session-content">
<h3>Pick a project &mdash; Claude loads its memory</h3>
<p>Type your choice and hit Enter. Claude switches into that project's folder, reads its <code>CLAUDE.md</code> (the project's living briefing doc), checks for new inputs you've dropped in, and tells you the state of play.</p>
<div class="terminal-frame">
<div class="terminal-bar"><span class="traffic r"></span><span class="traffic y"></span><span class="traffic g"></span><span class="terminal-title">claude&nbsp;&mdash;&nbsp;{{ instance_brand }}</span></div>
<div class="terminal-body"><span class="prompt">&gt;</span><span class="you">3a</span>
Switched to <strong>RevenueAnalysis</strong> &mdash; quarterly revenue
review program.
<span class="dim">Loaded: CLAUDE.md, 8 knowledge files, 4 active decisions</span>
<span class="dim">Last session: yesterday, 4:12 PM &mdash; "Q1 close review"</span>
One unprocessed input detected:
<span class="path">inputs/Q1_close_DRAFT.pdf</span> (3.4&nbsp;MB)
Want me to process it into <span class="path">knowledge/</span> now?
<span class="prompt">&gt;</span><span class="caret"></span></div>
</div>
<p class="annotation">Claude now has full project context loaded &mdash; past decisions, key numbers, ongoing work, who's involved. You don't have to re-explain anything every session. New files in <code>inputs/</code> are auto-detected so nothing gets forgotten on your hard drive.</p>
</div>
</div>
<div class="session-step">
<div class="session-num">4</div>
<div class="session-content">
<h3>Ask anything &mdash; Claude is now scoped to that project</h3>
<p>Plain English. No commands to memorise. Claude pulls from the project's files, your registered data packages, installed plugins, and the team's shared memory &mdash; quoting exact sources as it goes.</p>
<div class="terminal-frame">
<div class="terminal-bar"><span class="traffic r"></span><span class="traffic y"></span><span class="traffic g"></span><span class="terminal-title">claude&nbsp;&mdash;&nbsp;{{ instance_brand }}</span></div>
<div class="terminal-body"><span class="prompt">&gt;</span><span class="you">what's the latest on the Q1 close? Give me the
headline numbers and the open risks.</span>
<span class="dim">Reading <span class="path">knowledge/q1-close-input.md</span></span>
<span class="dim">Reading <span class="path">temp/v4/close.md</span></span>
<strong>Q1 close summary &mdash; v4, Apr 2026</strong>
• Revenue: $124.3M &rarr; $131.0M (+5.4% QoQ)
• Gross margin: 62.1% &rarr; 63.4%
• 4 markets above plan, 2 below
• Customer churn flat at 6.1%
<strong>Open risks</strong>
• FX hedging assumption is 6 weeks old &mdash; needs refresh
• No DRI yet on the EMEA segmentation prerequisite
• Q2 forecast model still in review
Want me to draft a 1-page brief, or dig into one of these?
<span class="prompt">&gt;</span><span class="caret"></span></div>
</div>
<p class="annotation"><strong>Cited sources are clickable paths</strong> &mdash; tap to open the actual file in your editor. If Claude needs data from a remote system, your registered plugins kick in silently. No copy-pasting between tabs.</p>
</div>
</div>
<div class="session-step">
<div class="session-num">5</div>
<div class="session-content">
<h3>When you're done, just close &mdash; everything's saved</h3>
<p>Type <code>/exit</code> or close the terminal window. {{ instance_brand }} saves the session, captures any new knowledge into the project's memory, and puts today's project at the top of tomorrow's menu.</p>
<div class="terminal-frame">
<div class="terminal-bar"><span class="traffic r"></span><span class="traffic y"></span><span class="traffic g"></span><span class="terminal-title">claude&nbsp;&mdash;&nbsp;{{ instance_brand }}</span></div>
<div class="terminal-body"><span class="prompt">&gt;</span><span class="you">/exit</span>
<span class="dim">Session saved &mdash; 12 prompts, 4 files referenced.</span>
<span class="dim">RevenueAnalysis will appear as "today" in your menu tomorrow.</span>
<span class="ai-name">See you next time.</span>
<span class="prompt">$</span><span class="caret"></span></div>
</div>
<p class="annotation">Nothing to clean up, no "save your work" prompt, no version to remember. Next time you type <code>{{ workspace_dir | lower }}</code>, this project is right at the top of the recent list &mdash; and Claude remembers every decision, file, and follow-up from today.</p>
<p class="annotation session-privacy">
<strong>What leaves your machine.</strong> Session telemetry &mdash; prompts, tool calls, and tool responses &mdash; flows back to the central catalog so the team can analyse failure patterns. Raw data rows you query locally stay on your machine; only the prompt/response transcript travels. Need a session off the record? Toggle Private in Claude Code (type <code>/agnes-private</code>) to disable telemetry for that chat &mdash; nothing from that session reaches the catalog.
</p>
</div>
</div>
</div>
<div class="session-tldr">
<strong>That's the whole loop.</strong> One word to launch &mdash; pick a project &mdash; ask &mdash; close. Everything else (plugins, data packages, skills, shared memory) is Claude doing more for you inside the same five-beat rhythm. You learn it once on day&nbsp;1 and never re-learn it.
</div>
</section>
{# Overview section — operator-owned, opt-in. Body comes from the
`instance.overview` yaml field via get_instance_overview()
(`AGNES_INSTANCE_OVERVIEW` env override). Empty value hides the
whole section, keeping the OSS vendor-neutral. #}
{# Overview is operator-owned reference content, not per-user
chrome — no dismiss button on purpose. A one-time per-device
hide would mean returning users who wanted to re-read the
privacy posture / telemetry policy can't get back to it
without clearing localStorage. The whole section is opt-in at
the operator level (empty yaml → section absent), which is
the right axis of control. #}
{% if config.INSTANCE_OVERVIEW %}
<section class="home-overview">
<h2>Overview</h2>
<div class="home-overview-body">{{ config.INSTANCE_OVERVIEW | safe }}</div>
</section>
{% endif %}
{# Surfaces — four places to use {{ instance_brand }}. Mirrors the
design spec's "Where you can use it" section: VS Code (RECOMMENDED),
Terminal, Claude Desktop, Cowork (claude.ai). Each card carries
a short pitch + an uppercase eyebrow (DAILY USE / QUICK ACCESS /
CONNECT IT) + a numbered step list + a one-liner "Best for".
The .home-usage class is kept on the wrapper so existing test
assertions and the legacy `.home-usage-grid` mobile media query
still apply. #}
<section class="home-usage surfaces" id="where-you-can-use-it">
<header>
<div class="eyebrow">Where you can use it</div>
<h2>Four places, one workspace</h2>
<p class="lede">Same plugins, same data access, same credentials &mdash; pick whichever fits the moment. VS Code is the most comfortable for most people; the others are useful when the situation calls for it.</p>
</header>
<div class="surfaces-grid">
<article class="surface-card feature">
<div class="surface-icon" aria-hidden="true">&#x1F4DD;</div>
<h3>VS Code <span class="badge">RECOMMENDED</span></h3>
<p class="what">The best place to live in {{ instance_brand }}. Multi-panel layout, built-in file editor, diff viewer, and a terminal Claude runs in &mdash; all in one window. Easier than a bare terminal for most people.</p>
<a href="#" id="vscode-screenshot-trigger" class="vscode-thumb">
<img src="/static/img/vscode-layout.png" alt="VS Code with terminal-centric layout"
onerror="this.parentElement.classList.add('thumb-empty');this.remove();">
<div class="thumb-fallback">
<div class="thumb-fallback-inner">
<div class="thumb-fallback-row">
<span class="dot d-explorer"></span>EXPLORER
<span class="dot d-t1"></span>TERMINAL&nbsp;1
<span class="dot d-t2"></span>TERMINAL&nbsp;2
<span class="dot d-t3"></span>TERMINAL&nbsp;3
</div>
<div class="thumb-fallback-hint">Screenshot pending &mdash; drop at <code>app/web/static/img/vscode-layout.png</code></div>
</div>
</div>
<span class="thumb-caption">Click to enlarge &mdash; recommended layout</span>
</a>
<div class="steps">
<strong class="steps-eyebrow">DAILY USE</strong>
<ol>
<li>Open VS Code &rarr; <strong>File &rarr; Open Folder</strong> &rarr; select your <code>~/Desktop/{{ workspace_dir }}</code> folder.</li>
<li>Open terminal: <kbd></kbd>+<kbd>`</kbd> (macOS) or <kbd>Ctrl</kbd>+<kbd>`</kbd> (Windows).</li>
<li>Right-click the terminal tab &rarr; <em>"Move Terminal into Editor Area"</em>. Split with <kbd></kbd>+<kbd>\</kbd> &mdash; one panel for the conversation, one for diffs.</li>
<li>Type <code>claude</code> (or <code>{{ workspace_dir | lower }}</code> if you set the Step&nbsp;6 shortcut). The welcome menu fires &mdash; pick a project or describe what you want.</li>
</ol>
</div>
<div class="when-to-use">
<strong>Full step-by-step guide:</strong> <a href="/setup-advanced#vscode">Open VS Code setup guide &rarr;</a>
</div>
</article>
<article class="surface-card">
<div class="surface-icon" aria-hidden="true">&#x2328;&#xFE0F;</div>
<h3>Terminal</h3>
<p class="what">Quick access &mdash; when you don't want a whole IDE open. Same Claude, same plugins, just bare. Best for short questions and one-off scripts.</p>
<div class="steps">
<strong class="steps-eyebrow">QUICK ACCESS</strong>
<ol>
<li>Open <strong>Terminal</strong> (macOS: <kbd></kbd>+<kbd>Space</kbd>, type <em>Terminal</em>) or <strong>PowerShell</strong> (Windows: <kbd></kbd>, type <em>PowerShell</em>).</li>
<li>Go to your folder: <code>cd ~/Desktop/{{ workspace_dir }}</code></li>
<li>Type <code>claude</code> (or <code>{{ workspace_dir | lower }}</code>) and hit Enter.</li>
<li>Welcome menu fires &mdash; same as in VS Code.</li>
</ol>
</div>
<div class="code-output">2026-05-20
What would you like to do?
[1] Talk to {{ instance_brand }} &mdash; workspace questions
[2] New project &mdash; scaffold a new project
[3] Switch to recent project:
a. RevenueAnalysis (2 hours ago)
b. WeeklyReview (1 day ago)
c. Onboarding (3 days ago)
[4] Browse full registry</div>
<div class="when-to-use"><strong>Best for:</strong> quick questions, scripts, when you already have a terminal open from something else.</div>
</article>
<article class="surface-card">
<div class="surface-icon" aria-hidden="true">&#x1F5A5;&#xFE0F;</div>
<h3>Claude Code (Desktop app)</h3>
<p class="what">The Claude Code agent running inside the Claude Desktop app instead of in a terminal. You point it at your <code>{{ workspace_dir }}</code> folder and work from there with a native UI for diffs, file tree, and chat.</p>
<div class="steps">
<strong class="steps-eyebrow">CONNECT IT</strong>
<ol>
<li>Install Claude Desktop from <a href="https://claude.ai/download" target="_blank" rel="noopener">claude.ai/download</a>.</li>
<li>Sign in with the same account you use for Claude Code.</li>
<li>Open the <code>{{ workspace_dir }}</code> folder on your Desktop in Claude Code (<strong>File &rarr; Open Folder</strong>).</li>
<li>Everything in the workspace &mdash; plugins, skills, data packages, memory &mdash; is available there automatically.</li>
</ol>
</div>
<div class="when-to-use"><strong>Best for:</strong> people who prefer a native UI to a terminal. Same Claude Code engine, same workspace.</div>
</article>
<article class="surface-card incomplete">
<div class="surface-icon" aria-hidden="true">&#x1F91D;</div>
<h3>Cowork (claude.ai) <span class="badge-warn">INSTRUCTIONS NEEDED</span></h3>
<p class="what">Claude Cowork &mdash; the collaborative workspace on <a href="https://claude.ai/" target="_blank" rel="noopener">claude.ai</a>. Currently {{ instance_brand }} supports <strong>skills only</strong> here (no data packages or plugins yet).</p>
<div class="incomplete-callout">
&#x26A0;&#xFE0F; <strong>This section is missing detailed instructions.</strong> Add the step-by-step here:
<ul>
<li>How to enable {{ instance_brand }}'s skills in Cowork (URL, sign-in, where to paste config)</li>
<li>What does and doesn't sync (skills &#x2705;, plugins &#x274C;, data packages &#x274C;, memory &#x274C;)</li>
<li>When to use Cowork vs the other surfaces</li>
<li>Known limits / roadmap for plugin + data package support</li>
</ul>
</div>
<div class="when-to-use"><strong>Status:</strong> partial support &mdash; skills only. Full instructions to be written.</div>
</article>
</div>
<p class="home-usage-foot">For the deepest integration, create every project under <code>~/Desktop/{{ workspace_dir }}/Projects/</code> &mdash; existing or new. The bundled plugin keeps each project in sync with the central catalog automatically, and the session-analysis loop is scoped to that root. Anything outside <code>{{ workspace_dir }}/</code> is invisible to the platform.</p>
</section>
{# Connectors `<details data-section="connectors">` block removed —
the install-hero's Step 4 clipboard payload (rendered via
`_claude_setup_instructions.jinja` inside the "Or paste manually"
fallback) already inlines the same Asana / GWS / Atlassian
prompts from app/web/connector_prompts.py via
app/web/setup_instructions.py::_connectors_block. Showing them
a second time as standalone cards duplicated UX without adding
reach — the install script visits them all in sequence. Brief
mention in the install-hero lead paragraph above covers the
benefits ("third-party tools (Asana, Google Workspace,
Atlassian)"); deep ops live in /setup-advanced. #}
<section class="browse-section" id="look-around">
<div class="eyebrow">{{ instance_brand }} workspace</div>
<h2>Explore your workspace</h2>
<p class="lede">Jump into any part of {{ instance_brand }} &mdash; what your team has registered, what's curated company-wide, and what's shared by your colleagues.</p>
<div class="browse-grid what-is look-around-grid">
<a class="browse-card what-is-item" href="/marketplace">
<span class="browse-icon ico" aria-hidden="true">&#x1F9E9;</span>
<span class="browse-title ttl">Plugin marketplace <span class="arrow">&rarr;</span></span>
<span class="browse-desc desc">Two tiers: <strong>Curated</strong> (official, vetted &mdash; Asana, Jira, GWS, GitHub) and <strong>Flea Market</strong> (team-shared, lower bar &mdash; anyone can publish for the team).</span>
</a>
<a class="browse-card what-is-item" href="/catalog">
<span class="browse-icon ico" aria-hidden="true">&#x1F4E6;</span>
<span class="browse-title ttl">Data packages <span class="arrow">&rarr;</span></span>
<span class="browse-desc desc">Tables, schema, metric definitions registered by your team. Subscribe + query.</span>
</a>
<a class="browse-card new what-is-item" href="/marketplace?type=skills">
<span class="browse-icon ico" aria-hidden="true">&#x26A1;</span>
<span class="browse-title ttl">Skills <span class="arrow">&rarr;</span></span>
<span class="browse-desc desc">Two tiers: <strong>Curated</strong> (official workflow templates &mdash; brainstorming, planning, review) and <strong>Flea Market</strong> (team-shared skills you and your colleagues publish).</span>
</a>
{# Curated Memory is user-facing — the /corporate-memory route runs
on get_current_user, so the tile shows for everyone, matching
its primary-nav placement. #}
<a class="browse-card what-is-item" href="/corporate-memory">
<span class="browse-icon ico" aria-hidden="true">&#x1F9E0;</span>
<span class="browse-title ttl">Memory <span class="arrow">&rarr;</span></span>
<span class="browse-desc desc">Shared analyst knowledge and prior solutions. Searchable, versioned.</span>
</a>
{# Activity center admin-only — matches the top-nav gating logic. #}
{% if is_admin %}
<a class="browse-card what-is-item" href="/activity-center">
<span class="browse-icon ico" aria-hidden="true">&#x1F4C8;</span>
<span class="browse-title ttl">Activity center <span class="arrow">&rarr;</span></span>
<span class="browse-desc desc">Adoption analytics across your team. Sessions, plugins, prompt patterns.</span>
</a>
{% endif %}
</div>
</section>
{# Legacy `.advanced-pointer` row removed — same link now lives in
the Getting Started card at the top of /home. `.advanced-pointer`
CSS (~line 721) is harmless dead style; left in place to keep
this diff focused. #}
{% if news_intro %}
<section class="home-news">
<header class="home-news-head">
<h2>What's new</h2>
<a class="home-news-more" href="/news">Read more &rarr;</a>
</header>
<div class="home-news-body">{{ news_intro | safe }}</div>
</section>
{% endif %}
</div>
{# P0-2 — Post-CTA modal. Opens after the shared CTA include below has
created the token + copied the script. _claude_setup_cta.jinja still
owns the token request + clipboard write; this modal layers on top
with a 3-step "where to paste" guide. Lives at body level so the
home-mock styles don't bleed into it. #}
{% if not onboarded %}
<div class="cta-modal-backdrop" id="cta-modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="cta-modal-title" hidden>
<div class="cta-modal">
<h2 id="cta-modal-title"><span aria-hidden="true">&#x2705;</span> Setup script copied to clipboard</h2>
<p class="lead">Now paste it into Claude Code on your machine — three steps:</p>
<ol>
<li>
<div>
<strong>Open a terminal</strong>
macOS: <kbd></kbd>+<kbd>Space</kbd>, type "Terminal". Windows: <kbd>Win</kbd>+<kbd>R</kbd>, type <code>powershell</code>. Linux: <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>T</kbd>.
</div>
</li>
<li>
<div>
<strong>Start Claude Code</strong>
Type <code>claude</code> and press <kbd>Enter</kbd>. You'll see a prompt waiting for input.
</div>
</li>
<li>
<div>
<strong>Paste &amp; press Enter</strong>
macOS: <kbd></kbd>+<kbd>V</kbd>. Windows/Linux: <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd>. Claude runs the setup and tells you when it's done.
</div>
</li>
</ol>
<div class="cta-modal-foot">
<span class="meta">Token is in clipboard only — never displayed here.</span>
<button type="button" id="cta-modal-close">Got it</button>
</div>
</div>
</div>
{% endif %}
{# Shared "Setup a new Claude Code" CTA behaviour — provides the JS that
POSTs /auth/tokens, copies the rendered instructions to the clipboard,
and falls back to a modal when the clipboard API is blocked. The button
above (id="setupClaudeBtn") is the primary trigger. #}
{% include "_claude_setup_cta.jinja" %}
{# VS Code screenshot lightbox — full-bleed overlay; click to close. #}
<div class="lightbox" id="vscode-lightbox" aria-hidden="true">
<img src="/static/img/vscode-layout.png" alt="VS Code with terminal-centric layout">
</div>
<script>
(function () {
function wireCopy(btn) {
btn.addEventListener('click', function () {
var src = document.getElementById(btn.getAttribute('data-copy-target'));
if (!src) return;
// textContent (not innerText) so collapsed <details> content still
// copies — innerText returns "" for nodes whose ancestor has
// display:none (which is what closed <details> applies).
var raw = src.textContent || '';
var text = raw.replace(/ /g, ' ');
navigator.clipboard.writeText(text).then(function () {
var orig = btn.textContent;
btn.textContent = 'Copied';
setTimeout(function () { btn.textContent = orig; }, 1500);
}).catch(function () { btn.textContent = 'Copy failed'; });
});
}
document.querySelectorAll('.copy-btn[data-copy-target]').forEach(wireCopy);
// OS tab switching for Step 1. Flips both the command panel AND the
// P0-1 terminal-howto body so the howto matches the active OS.
document.querySelectorAll('.os-tab[data-os-tab]').forEach(function (tab) {
tab.addEventListener('click', function () {
var target = tab.getAttribute('data-os-tab');
// Scope OS-tab switching to the nearest mode-panel when nested
// inside one (Step 6's Auto/YOLO panels each have their own
// OS toggle); otherwise scope to the install-block.
var scope = tab.closest('[data-mode-panel]') || tab.closest('.install-block') || document;
scope.querySelectorAll('.os-tab[data-os-tab]').forEach(function (t) {
var on = t.getAttribute('data-os-tab') === target;
t.classList.toggle('is-active', on);
t.setAttribute('aria-selected', on ? 'true' : 'false');
});
scope.querySelectorAll('[data-os-panel]').forEach(function (p) {
if (p.getAttribute('data-os-panel') === target) {
p.removeAttribute('hidden');
} else {
p.setAttribute('hidden', '');
}
});
// P0-1 — flip the howto bodies in lockstep.
scope.querySelectorAll('[data-howto-panel]').forEach(function (p) {
if (p.getAttribute('data-howto-panel') === target) {
p.removeAttribute('hidden');
} else {
p.setAttribute('hidden', '');
}
});
});
});
// Mode tabs — Step 6's Auto / YOLO toggle. Mirrors os-tab handler
// but switches `[data-mode-panel]` siblings.
document.querySelectorAll('.mode-tab[data-mode-tab]').forEach(function (tab) {
tab.addEventListener('click', function () {
var target = tab.getAttribute('data-mode-tab');
var scope = tab.closest('.install-block') || document;
scope.querySelectorAll('.mode-tab[data-mode-tab]').forEach(function (t) {
var on = t.getAttribute('data-mode-tab') === target;
t.classList.toggle('is-active', on);
t.setAttribute('aria-selected', on ? 'true' : 'false');
});
scope.querySelectorAll('[data-mode-panel]').forEach(function (p) {
if (p.getAttribute('data-mode-panel') === target) {
p.removeAttribute('hidden');
} else {
p.setAttribute('hidden', '');
}
});
});
});
// P0-2 — Post-CTA modal. _claude_setup_cta.jinja owns the click
// handler that POSTs /auth/tokens + copies the script; we wait for
// its success signal (agnes:setup-script-copied custom event) and
// then open the "where to paste" guide. Without the event the modal
// simply never opens — the include's own fallback paths handle
// older browsers / blocked clipboard.
var ctaModal = document.getElementById('cta-modal-backdrop');
var ctaModalClose = document.getElementById('cta-modal-close');
function openCtaModal() {
if (!ctaModal) return;
ctaModal.removeAttribute('hidden');
ctaModal.classList.add('is-open');
if (ctaModalClose) ctaModalClose.focus();
}
function closeCtaModal() {
if (!ctaModal) return;
ctaModal.classList.remove('is-open');
ctaModal.setAttribute('hidden', '');
var setupBtn = document.getElementById('setupClaudeBtn');
if (setupBtn) setupBtn.focus();
}
if (ctaModal) {
document.addEventListener('agnes:setup-script-copied', openCtaModal);
if (ctaModalClose) ctaModalClose.addEventListener('click', closeCtaModal);
ctaModal.addEventListener('click', function (ev) {
if (ev.target === ctaModal) closeCtaModal();
});
document.addEventListener('keydown', function (ev) {
if (ev.key === 'Escape' && ctaModal.classList.contains('is-open')) closeCtaModal();
});
}
// Shared poster for /api/me/onboarded — reused by every UI surface
// that flips users.onboarded (in-hero X close, "Mark me as onboarded"
// fallback button, the offboard strip). Reloads on success so the
// template re-renders with the new state.
function postOnboarded(triggerBtn, statusEl, targetOnboarded, targetSource) {
if (triggerBtn) triggerBtn.disabled = true;
if (statusEl) statusEl.textContent = targetOnboarded ? 'Marking…' : 'Resetting…';
fetch('/api/me/onboarded', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ source: targetSource, onboarded: targetOnboarded }),
}).then(function (resp) {
if (resp.ok) {
if (statusEl) statusEl.textContent = 'Done. Reloading…';
window.location.reload();
} else {
if (statusEl) statusEl.textContent = 'Failed (' + resp.status + '). Try again.';
if (triggerBtn) triggerBtn.disabled = false;
}
}).catch(function () {
if (statusEl) statusEl.textContent = 'Network error. Try again.';
if (triggerBtn) triggerBtn.disabled = false;
});
}
// "Mark me as onboarded" fallback button inside the hero (rendered
// only when not-onboarded — the X close button is the primary path).
var btn = document.getElementById('self-mark-btn');
var status = document.getElementById('self-mark-status');
if (btn) {
btn.addEventListener('click', function (e) {
if (btn.tagName === 'A') e.preventDefault();
postOnboarded(
btn, status, true,
btn.getAttribute('data-target-source') || 'self_acknowledged'
);
});
}
// Hero X close — confirm first so a stray click doesn't flip state.
var heroClose = document.getElementById('installHeroClose');
if (heroClose) {
heroClose.addEventListener('click', function () {
var ok = window.confirm(
"Are you already onboarded? Closing this will mark your account as onboarded " +
"and hide the setup steps. You can revert later from the strip below the hero."
);
if (!ok) return;
postOnboarded(
heroClose, status, true,
heroClose.getAttribute('data-target-source') || 'self_acknowledged'
);
});
}
// Offboarding strip — only rendered when onboarded. Flips back to
// the install hero on next reload.
var offBtn = document.getElementById('offboard-btn');
var offStatus = document.getElementById('offboard-status');
if (offBtn) {
offBtn.addEventListener('click', function () {
postOnboarded(
offBtn, offStatus, false,
offBtn.getAttribute('data-target-source') || 'self_unmark'
);
});
}
// ── Generic dismiss-card handler ─────────────────────────────────
// Any `<button class="home-card-close" data-dismiss-key="...">`
// inside a `<section>` becomes dismissible: clicking sets the
// localStorage key to '1' and hides the section; on next page
// load the section starts hidden if the key is set. Used by the
// Getting Started card; future dismissible cards drop in with
// zero per-card JS.
document.querySelectorAll('.home-card-close[data-dismiss-key]').forEach(function (btn) {
var key = btn.getAttribute('data-dismiss-key');
var section = btn.closest('section, details');
if (!section || !key) return;
try {
if (localStorage.getItem(key) === '1') {
section.hidden = true;
return;
}
} catch (e) { /* private-mode: render visible, no-op */ }
btn.addEventListener('click', function () {
try { localStorage.setItem(key, '1'); } catch (e) { /* ignore */ }
section.hidden = true;
});
});
// ── VS Code screenshot lightbox ──────────────────────────────────
// Anchor `.vscode-thumb` opens `#vscode-lightbox`. Skips wiring when
// the screenshot is missing (`.thumb-empty` set by the <img> onerror).
var vsLightbox = document.getElementById('vscode-lightbox');
var vsThumb = document.getElementById('vscode-screenshot-trigger');
if (vsThumb && vsLightbox && !vsThumb.classList.contains('thumb-empty')) {
vsThumb.addEventListener('click', function (e) {
e.preventDefault();
vsLightbox.classList.add('open');
document.body.style.overflow = 'hidden';
});
vsLightbox.addEventListener('click', function () {
vsLightbox.classList.remove('open');
document.body.style.overflow = '';
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && vsLightbox.classList.contains('open')) {
vsLightbox.classList.remove('open');
document.body.style.overflow = '';
}
});
}
})();
</script>
{% endblock %}