* Make /home install-hero links readable against blue background The Claude license-options link added in the previous commit inherited the default `<a>` style (`var(--hp-primary)` blue), which renders as blue-on-blue and is unreadable inside the blue install-hero. Add a scoped `.install-hero a` rule that uses white with an underline (matching the existing lead-paragraph contrast pattern) so any link nested in the hero stays legible. * Reorder /home install flow: auto-mode is now Step 2, Agnes install becomes Step 3 Step 3 (was Step 2) pastes a ~20-command bash bootstrap into a fresh Claude Code session. Without auto-mode enabled first, each Bash/edit command needs a manual approve click — bad UX for first-time users. Move auto-mode from the outside-hero `<details>` reference block into the install-hero as a real Step 2, between "install Claude Code" and "install Agnes". Content is the persistent `acceptEdits` snippet (write to ~/.claude/settings.json) plus a one-liner pointing at Shift+Tab for users who are already inside a running Claude Code session. YOLO mode for full Bash auto-approve stays on /setup-advanced behind the existing link. The outside-hero `setup-collapsible[data-section="step3"]` block is dropped — auto-mode is no longer reference content, it's a real install step, and duplicating it would just diverge over time. Onboarded users no longer see the auto-mode block at all (consistent with Steps 1 + 3 also hiding post-onboarding). Completion banner copy updated: "Step 1, 2 & 3 done — Claude Code installed, auto-mode set, Agnes ready". Dashboard CTA partial and other templates don't reference step numbers for this flow, so no adaptation needed there. * Simplify /home Step 2 to Shift+Tab only — drop the JSON snippet Operator pointed out two issues with the prior Step 2: 1. The settings.json snippet is redundant. Claude Code's first Shift+Tab cycle to auto-accept mode already prompts the user whether to persist it as default — Claude writes the config itself, no manual file edit needed. 2. The snippet only showed the POSIX path `~/.claude/settings.json`, which doesn't translate to native Windows. Replace the snippet + copy button with a plain Shift+Tab instruction, explicitly call out the first-time "make this the default?" prompt, and note that Claude handles the config write itself — same flow on macOS / Linux / WSL / Windows. Adds a fallback line for users who already closed the post-OAuth session. * Tighten /home Step 2 install-note to two paragraphs Operator: drop the 'Claude writes the setting itself, so this works the same on macOS / Linux / WSL / Windows...' line plus the 'auto-approves file edits going forward; Bash commands stay gated — that's the safe default' line. Both were filler — the make-default prompt already implies persistence, and gated Bash is the obvious default users won't be surprised by. Result: paragraph 1 carries Shift+Tab + first-time make-default say-yes + closed-session fallback in one breath; paragraph 2 keeps the verbatim YOLO link. Same affordances, less vertical space.
1691 lines
62 KiB
HTML
1691 lines
62 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Setup — {{ instance_name or "AI Data Analyst" }}{% endblock %}
|
||
|
||
{% block content %}
|
||
{% include "_page_chrome.html" %}
|
||
<style>
|
||
.home-mock {
|
||
--hp-primary: #0073D1;
|
||
--hp-primary-dark: #0056A3;
|
||
--hp-primary-light: #E6F3FC;
|
||
--hp-border: #E5E7EB;
|
||
--hp-border-light: #F3F4F6;
|
||
--hp-text-primary: #111827;
|
||
--hp-text-secondary: #6B7280;
|
||
--hp-text-muted: #9CA3AF;
|
||
--hp-orange: #C2410C;
|
||
--hp-orange-light: #FED7AA;
|
||
--hp-font-mono: ui-monospace, "SF Mono", Consolas, monospace;
|
||
color: var(--hp-text-primary);
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
}
|
||
.home-mock * { box-sizing: border-box; }
|
||
|
||
.home-mock .install-hero {
|
||
background: linear-gradient(135deg, #0073D1 0%, #0056A3 100%);
|
||
color: white;
|
||
border-radius: 16px;
|
||
padding: 38px 40px;
|
||
margin-bottom: 22px;
|
||
box-shadow: 0 8px 24px rgba(0, 86, 163, 0.18);
|
||
}
|
||
.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; }
|
||
|
||
.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(--hp-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(--hp-primary);
|
||
box-shadow: 0 4px 12px rgba(0, 115, 209, 0.10);
|
||
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(--hp-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(--hp-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(--hp-text-secondary);
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.home-mock .look-around-lead {
|
||
font-size: 13px;
|
||
color: var(--hp-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 .connector-tiles {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||
gap: 16px;
|
||
margin-bottom: 26px;
|
||
}
|
||
.home-mock .connector-tile {
|
||
background: white;
|
||
border: 1px solid var(--hp-border);
|
||
border-radius: 12px;
|
||
padding: 20px 22px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.home-mock .connector-tile .ico {
|
||
font-size: 24px;
|
||
margin-bottom: 10px;
|
||
line-height: 1;
|
||
}
|
||
.home-mock .connector-tile .ttl {
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: var(--hp-text-primary);
|
||
margin-bottom: 6px;
|
||
}
|
||
.home-mock .connector-tile .desc {
|
||
font-size: 13px;
|
||
color: var(--hp-text-secondary);
|
||
line-height: 1.55;
|
||
margin-bottom: 14px;
|
||
flex: 1;
|
||
}
|
||
.home-mock .connector-tile .connector-actions {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
.home-mock .connector-tile .connector-copy {
|
||
align-self: flex-start;
|
||
}
|
||
|
||
.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(--hp-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;
|
||
}
|
||
.home-mock .install-note code,
|
||
.home-mock .install-note > code {
|
||
background: rgba(255, 255, 255, 0.12);
|
||
padding: 1px 6px;
|
||
border-radius: 4px;
|
||
font-family: var(--hp-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(--hp-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 .automode-card {
|
||
margin: 22px 0;
|
||
background: white;
|
||
border: 1px solid var(--hp-border);
|
||
border-radius: 12px;
|
||
padding: 18px 22px;
|
||
}
|
||
.home-mock .automode-head {
|
||
display: flex;
|
||
gap: 14px;
|
||
align-items: flex-start;
|
||
margin-bottom: 14px;
|
||
}
|
||
.home-mock .automode-head .ico {
|
||
font-size: 22px;
|
||
flex-shrink: 0;
|
||
line-height: 1;
|
||
}
|
||
.home-mock .automode-head h3 {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
color: var(--hp-text-primary);
|
||
}
|
||
.home-mock .automode-head p {
|
||
font-size: 13px;
|
||
color: var(--hp-text-secondary);
|
||
line-height: 1.55;
|
||
margin: 0;
|
||
}
|
||
.home-mock .automode-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 14px;
|
||
}
|
||
.home-mock .automode-step {
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: flex-start;
|
||
padding: 12px;
|
||
background: var(--hp-border-light);
|
||
border-radius: 8px;
|
||
}
|
||
.home-mock .automode-step .num {
|
||
width: 22px; height: 22px;
|
||
border-radius: 50%;
|
||
background: var(--hp-primary-light);
|
||
color: var(--hp-primary);
|
||
flex-shrink: 0;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-weight: 700; font-size: 11px;
|
||
}
|
||
.home-mock .automode-step .step-text {
|
||
flex: 1;
|
||
font-size: 12.5px;
|
||
line-height: 1.5;
|
||
color: var(--hp-text-secondary);
|
||
}
|
||
.home-mock .automode-step .step-text strong {
|
||
display: block;
|
||
color: var(--hp-text-primary);
|
||
margin-bottom: 4px;
|
||
font-size: 13px;
|
||
}
|
||
.home-mock .automode-step kbd {
|
||
background: white;
|
||
border: 1px solid var(--hp-border);
|
||
border-bottom-width: 2px;
|
||
border-radius: 4px;
|
||
padding: 1px 6px;
|
||
font-size: 11px;
|
||
font-family: var(--hp-font-mono);
|
||
color: var(--hp-text-primary);
|
||
}
|
||
.home-mock .automode-step code {
|
||
font-family: var(--hp-font-mono);
|
||
font-size: 11.5px;
|
||
background: white;
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
color: var(--hp-text-primary);
|
||
border: 1px solid var(--hp-border);
|
||
}
|
||
.home-mock .automode-code {
|
||
background: #0F172A;
|
||
color: #FBBF24;
|
||
border-radius: 6px;
|
||
padding: 8px 10px;
|
||
margin-top: 6px;
|
||
font-family: var(--hp-font-mono);
|
||
font-size: 11.5px;
|
||
line-height: 1.5;
|
||
overflow-x: auto;
|
||
white-space: pre;
|
||
}
|
||
.home-mock .automode-foot {
|
||
margin-top: 12px;
|
||
padding-top: 10px;
|
||
border-top: 1px solid var(--hp-border-light);
|
||
font-size: 12px;
|
||
color: var(--hp-text-secondary);
|
||
line-height: 1.5;
|
||
}
|
||
.home-mock .automode-foot a { color: var(--hp-primary); text-decoration: underline; }
|
||
.home-mock .automode-foot code {
|
||
font-family: var(--hp-font-mono);
|
||
font-size: 11px;
|
||
background: var(--hp-border-light);
|
||
padding: 1px 4px;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.home-mock .section-label {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.6px;
|
||
color: var(--hp-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(--hp-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(--hp-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(--hp-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(--hp-primary-light);
|
||
color: var(--hp-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,
|
||
.home-mock .card-mini-cmd code {
|
||
font-family: var(--hp-font-mono);
|
||
font-size: 11.5px;
|
||
background: var(--hp-border-light);
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
color: var(--hp-text-primary);
|
||
}
|
||
|
||
.home-mock .card-mini-cmd {
|
||
margin-top: 6px;
|
||
padding: 8px 10px;
|
||
background: #0F172A;
|
||
color: #FBBF24;
|
||
border-radius: 6px;
|
||
font-family: var(--hp-font-mono);
|
||
font-size: 11.5px;
|
||
line-height: 1.5;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
.home-mock .card-mini-cmd code {
|
||
background: transparent;
|
||
color: inherit;
|
||
padding: 0;
|
||
flex: 1;
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
}
|
||
.home-mock .connector-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
.home-mock .connector-head strong {
|
||
display: inline;
|
||
margin-bottom: 0;
|
||
}
|
||
.home-mock .connector-copy {
|
||
background: var(--hp-primary);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
padding: 5px 12px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
flex-shrink: 0;
|
||
}
|
||
.home-mock .connector-copy:hover { background: var(--hp-primary-dark); }
|
||
.home-mock .connector-copy.copied { background: #047857; }
|
||
.home-mock details.connector-preview {
|
||
margin-top: 6px;
|
||
}
|
||
.home-mock details.connector-preview > summary {
|
||
cursor: pointer;
|
||
list-style: none;
|
||
font-size: 11.5px;
|
||
color: var(--hp-text-secondary);
|
||
padding: 2px 0;
|
||
user-select: none;
|
||
}
|
||
.home-mock details.connector-preview > summary::-webkit-details-marker { display: none; }
|
||
.home-mock details.connector-preview > summary::before {
|
||
content: "▸ ";
|
||
margin-right: 2px;
|
||
}
|
||
.home-mock details.connector-preview[open] > summary::before { content: "▾ "; }
|
||
.home-mock details.connector-preview > summary:hover { color: var(--hp-text-primary); }
|
||
.home-mock details.connector-preview .card-mini-cmd { margin-top: 6px; }
|
||
|
||
.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(--hp-border-light);
|
||
border: 1px solid transparent;
|
||
border-radius: 8px;
|
||
text-decoration: none;
|
||
color: var(--hp-text-primary);
|
||
transition: border-color 0.15s ease, background 0.15s ease;
|
||
}
|
||
.home-mock .explore-item:hover {
|
||
border-color: var(--hp-primary);
|
||
background: var(--hp-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(--hp-text-secondary);
|
||
line-height: 1.45;
|
||
}
|
||
.home-mock .explore-item .explore-text strong {
|
||
display: block;
|
||
color: var(--hp-text-primary);
|
||
font-size: 13.5px;
|
||
font-weight: 600;
|
||
margin-bottom: 2px;
|
||
}
|
||
.home-mock .explore-item .arrow {
|
||
color: var(--hp-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(--hp-border);
|
||
border-left: 4px solid var(--hp-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(--hp-primary-light);
|
||
border-color: var(--hp-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(--hp-text-secondary);
|
||
line-height: 1.55;
|
||
}
|
||
.home-mock .advanced-pointer-text strong {
|
||
display: block;
|
||
color: var(--hp-text-primary);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
margin-bottom: 2px;
|
||
}
|
||
.home-mock .advanced-pointer .arrow {
|
||
color: var(--hp-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(--hp-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(--hp-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: #F0F7FF; }
|
||
.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(--hp-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(--hp-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(--hp-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; }
|
||
|
||
/* Setup-collapsible: each post-install section (Step 3 auto-mode,
|
||
Connect-your-tools) is wrapped in a <details open> so it keyboard-
|
||
collapses without JS. Default state on /home: summary hidden, body
|
||
flat — visually identical to the pre-collapse layout.
|
||
|
||
When the user clicks "Minimize setup view" in the hero, JS sets
|
||
`data-setup-minimized="1"` on `.home-mock` and removes the `open`
|
||
attribute on each <details>. The summary then appears as a slim
|
||
gray bar; the body collapses; clicking the bar re-opens that one
|
||
section. localStorage persists the minimize state per device. */
|
||
.home-mock .setup-collapsible { margin-top: 22px; }
|
||
.home-mock .setup-collapsible > summary {
|
||
/* Default: summary is structural-only. The "flat" rendering is
|
||
handled by the inner blocks (.automode-card already provides its
|
||
own padding/border/background; the connect-your-tools section
|
||
starts with a .section-label-flat). */
|
||
display: none;
|
||
}
|
||
.home-mock .setup-collapsible > summary::-webkit-details-marker { display: none; }
|
||
|
||
/* Minimize ON: summary becomes a slim clickable bar; the inner body
|
||
inherits the existing block styling but tucks under the summary
|
||
when the <details> is closed. */
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible {
|
||
border: 1px solid var(--hp-border);
|
||
border-radius: 12px;
|
||
background: white;
|
||
overflow: hidden;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary {
|
||
list-style: none;
|
||
cursor: pointer;
|
||
padding: 14px 22px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: var(--hp-text-primary);
|
||
background: #F9FAFB;
|
||
border-bottom: 1px solid transparent;
|
||
transition: background 120ms ease;
|
||
user-select: none;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary:hover {
|
||
background: #F3F4F6;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ico {
|
||
font-size: 18px;
|
||
line-height: 1;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ttl { flex: 1; }
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ttl small {
|
||
color: var(--hp-text-secondary);
|
||
font-weight: 400;
|
||
margin-left: 6px;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .chev {
|
||
font-size: 18px;
|
||
color: var(--hp-text-secondary);
|
||
transition: transform 160ms ease;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > summary {
|
||
border-bottom-color: var(--hp-border);
|
||
background: #F3F4F6;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > summary .chev {
|
||
transform: rotate(90deg);
|
||
}
|
||
/* Tighten the body padding so collapsed sections don't gain margin
|
||
when inside the white wrapper card. */
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .automode-card,
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .connector-tiles {
|
||
margin: 18px 22px 22px;
|
||
}
|
||
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .section-label-flat {
|
||
padding: 14px 22px 0;
|
||
}
|
||
/* When a section's <details> is closed in minimize mode, the body
|
||
already auto-hides via the browser's <details> behaviour — no extra
|
||
rule needed. */
|
||
|
||
/* Minimize toggle in the blue hero, only present when onboarded. */
|
||
.home-mock .setup-minimize {
|
||
margin-top: 14px;
|
||
font-size: 13px;
|
||
color: rgba(255, 255, 255, 0.85);
|
||
}
|
||
.home-mock .setup-minimize button {
|
||
background: rgba(255, 255, 255, 0.10);
|
||
color: white;
|
||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||
padding: 6px 14px;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
}
|
||
.home-mock .setup-minimize button:hover { background: rgba(255, 255, 255, 0.18); }
|
||
|
||
/* 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(--hp-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(--hp-font-mono);
|
||
color: white;
|
||
}
|
||
|
||
/* P0-3 — connector card time badge ("~5 min · self-serve") and the
|
||
post-copy "now paste into Step 2" hint with arrow back. */
|
||
.home-mock .connector-tile .ttl-row {
|
||
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
||
margin-bottom: 6px;
|
||
}
|
||
.home-mock .time-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
padding: 2px 8px;
|
||
border-radius: 999px;
|
||
background: var(--hp-primary-light);
|
||
color: var(--hp-primary-dark);
|
||
flex-shrink: 0;
|
||
}
|
||
.home-mock .time-badge.is-warn {
|
||
background: #FEF3C7;
|
||
color: #92400E;
|
||
}
|
||
.home-mock .copy-next-hint {
|
||
font-size: 12px;
|
||
color: var(--hp-primary-dark);
|
||
background: var(--hp-primary-light);
|
||
padding: 6px 10px;
|
||
border-radius: 6px;
|
||
margin-top: 6px;
|
||
display: none;
|
||
align-items: center;
|
||
gap: 6px;
|
||
line-height: 1.45;
|
||
}
|
||
.home-mock .copy-next-hint.is-visible { display: inline-flex; }
|
||
.home-mock .copy-next-hint code {
|
||
background: rgba(0, 0, 0, 0.06);
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
font-family: var(--hp-font-mono);
|
||
font-size: 11px;
|
||
}
|
||
|
||
/* P1-8 — GWS gating note + Email-admin button. Yellow background
|
||
matches the same friction-level used by other "admin help likely"
|
||
surfaces (advanced setup warnings). */
|
||
.home-mock .gating-note {
|
||
font-size: 12px;
|
||
color: #92400E;
|
||
background: #FEF3C7;
|
||
border: 1px solid #FCD34D;
|
||
border-radius: 6px;
|
||
padding: 8px 10px;
|
||
margin-bottom: 10px;
|
||
line-height: 1.5;
|
||
}
|
||
.home-mock .email-admin {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
background: white;
|
||
border: 1px solid var(--hp-border);
|
||
color: var(--hp-text-primary);
|
||
padding: 5px 12px;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
text-decoration: none;
|
||
cursor: pointer;
|
||
align-self: flex-start;
|
||
margin-top: 6px;
|
||
}
|
||
.home-mock .email-admin:hover {
|
||
text-decoration: none;
|
||
border-color: var(--hp-primary);
|
||
color: var(--hp-primary-dark);
|
||
}
|
||
|
||
/* 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(--hp-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: #0073D1;
|
||
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(--hp-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: #0073D1;
|
||
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: #0056A3; }
|
||
</style>
|
||
|
||
<div class="home-mock">
|
||
|
||
{% set display_name = (user.name or (user.email or "").split("@")[0] or "there") %}
|
||
|
||
<div class="install-hero">
|
||
{% if onboarded %}
|
||
<div class="eyebrow">Welcome back, {{ display_name }} — your workspace is ready</div>
|
||
<h1>You're set up — keep this page handy</h1>
|
||
<p class="lead">
|
||
Your local Agnes install is confirmed. The steps below stay useful for <strong>adding another machine</strong>, <strong>connecting more services</strong>, or <strong>turning on auto-accept mode</strong>. Skip whatever you don't need; nothing here re-runs unless you click it.
|
||
</p>
|
||
{% else %}
|
||
<div class="eyebrow">Welcome, {{ display_name }} — let's get you set up</div>
|
||
<h1>Connect Claude Code on your machine to your team's data</h1>
|
||
<p class="lead">
|
||
{{ instance_name or "Agnes" }} gives <strong>Claude Code</strong> on your computer access to your team's <strong>curated data, plugins, and shared knowledge</strong> — so you can ask questions and get answers in plain language, right from your terminal. This page walks you through the <strong>one-time setup (~10 minutes)</strong>. Everything it installs lives in your home folder (<code style="background: rgba(255,255,255,0.12); padding: 1px 6px; border-radius: 4px; font-family: var(--hp-font-mono); font-size: 12.5px;">~/Agnes</code>) and can be removed in one command.
|
||
</p>
|
||
{% endif %}
|
||
|
||
{% if onboarded %}
|
||
<div class="install-done" role="status" aria-live="polite">
|
||
<span class="check" aria-hidden="true">✅</span>
|
||
<span><strong>Step 1, 2 & 3 done</strong> — Claude Code installed, auto-mode set, Agnes ready in <code>~/Agnes</code>. The full install steps stay one click away under the offboard control below.</span>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{% if not onboarded %}
|
||
<div class="install-block">
|
||
<div class="label">Step 1 — install Claude Code</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 / WSL</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>
|
||
|
||
{# P0-1 — terminal-howto disclosure. Two panels (unix / windows)
|
||
that flip in lockstep with the install-cmd OS tabs above. #}
|
||
<details class="terminal-howto">
|
||
<summary>Don't have a terminal open? — show how</summary>
|
||
<div class="terminal-howto-body" data-howto-panel="unix">
|
||
<p><strong>macOS:</strong> press <kbd>⌘</kbd> + <kbd>Space</kbd>, type <kbd>Terminal</kbd>, press <kbd>Enter</kbd>.</p>
|
||
<p><strong>Linux:</strong> press <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>T</kbd> (most distros), or open the apps menu and search "Terminal".</p>
|
||
<p><strong>WSL:</strong> open the Windows Start menu, search "Ubuntu" (or your installed distro), press <kbd>Enter</kbd>.</p>
|
||
<p>Paste the command above with <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>V</kbd> (Linux/WSL) or <kbd>⌘</kbd> + <kbd>V</kbd> (macOS), then press <kbd>Enter</kbd>.</p>
|
||
</div>
|
||
<div class="terminal-howto-body" data-howto-panel="windows" hidden>
|
||
<p><strong>Windows:</strong> press <kbd>Win</kbd> + <kbd>R</kbd>, type <kbd>powershell</kbd>, press <kbd>Enter</kbd>. (Or: open Start menu, type "PowerShell".)</p>
|
||
<p>Paste the command above with <kbd>Ctrl</kbd> + <kbd>V</kbd> and press <kbd>Enter</kbd>.</p>
|
||
</div>
|
||
</details>
|
||
|
||
<div class="install-note">
|
||
Verify with <code>claude --version</code>. Sign in once with <code>claude</code> and complete the OAuth flow.
|
||
Don't have a Claude license yet? See <a href="/setup-advanced#claude-plan">plan options on /setup-advanced</a> (Pro / Max 5× / Max 20×).
|
||
</div>
|
||
</div>
|
||
|
||
{% if home_automode.show %}
|
||
<div class="install-block">
|
||
<div class="label">Step 2 — turn on auto-mode (recommended before Step 3)</div>
|
||
<div class="install-note">
|
||
In the Claude Code session you just signed into, press <strong>Shift + Tab</strong>. Claude cycles modes: default → <strong>auto-accept edits</strong> → plan mode → default; the footer shows <code>⏵⏵</code> when auto-accept is on. On the first cycle to auto-accept, Claude asks whether to make it the default — say <strong>yes</strong>. Closed the session already? Run <code>claude</code> again, then press <strong>Shift + Tab</strong>.
|
||
<br><br>
|
||
Want full auto-approve including Bash? See <a href="/setup-advanced#yolo">YOLO mode</a> on /setup-advanced — pairs <code>--dangerously-skip-permissions</code> with a reviewed <code>~/.claude/settings.local.json</code> allowlist. Skip if you're not sure.
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div class="install-block">
|
||
<div class="label">Step 3 — install Agnes from inside Claude Code</div>
|
||
<p class="setup-cta-lead">
|
||
Click the button — {{ instance_name or "Agnes" }} <strong>creates a 90-day login token</strong>, copies a ready-to-paste setup script to your clipboard, and a follow-up popup tells you exactly where to paste it. The script bootstraps everything in <code>~/Agnes</code> once Claude Code receives it.
|
||
</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>
|
||
Setup a new Claude Code
|
||
</button>
|
||
<span class="setup-cta-meta">
|
||
<span class="setup-cta-hint">Valid 90 days · token stays in clipboard only</span>
|
||
</span>
|
||
</div>
|
||
<div id="setupClaudeError" class="setup-error" role="alert" style="display:none;"></div>
|
||
|
||
<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>~/Agnes/Projects/</code> manually — the bundled plugin offers to set it up after install.
|
||
</div>
|
||
</details>
|
||
|
||
</div>
|
||
{% endif %}
|
||
|
||
{# P1-6 — auto-detect badge is the PRIMARY affordance after the
|
||
install-script copy: agnes-init's first POST to
|
||
/api/me/onboarded flips state automatically and the page
|
||
reloads. The manual "Mark me as onboarded" button below it
|
||
stays as a fallback when auto-flip never lands. #}
|
||
{% if not onboarded %}
|
||
<div class="auto-detect-badge" role="status" aria-live="polite">
|
||
<span class="pulse" aria-hidden="true"></span>
|
||
<span>Waiting for your first <code>agnes pull</code> — auto-detects within ~30 s of the setup script finishing.</span>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{# Self-mark control lives inside the blue hero in both states.
|
||
When onboarded, the install steps above are hidden so this is
|
||
the only thing rendered below the lead paragraph. #}
|
||
<div class="self-mark">
|
||
{% if onboarded %}
|
||
Wiped your workspace or want the full setup view back?
|
||
<button id="self-mark-btn" type="button"
|
||
data-target-onboarded="false"
|
||
data-target-source="self_unmark">Mark me as offboarded</button>
|
||
{% else %}
|
||
Already set this up?
|
||
<button id="self-mark-btn" type="button"
|
||
data-target-onboarded="true"
|
||
data-target-source="self_acknowledged">Mark me as onboarded</button>
|
||
{% endif %}
|
||
<span id="self-mark-status" class="status" role="status" aria-live="polite"></span>
|
||
</div>
|
||
|
||
{% if onboarded %}
|
||
{# User-controlled minimize toggle for Connect-your-tools.
|
||
Default OFF (section renders flat). State persists in
|
||
localStorage so the choice is per-device. The agnes-init
|
||
auto-flip of users.onboarded never triggers a collapse on
|
||
its own — only an explicit click here does. The auto-mode
|
||
block used to be a peer collapsible (`step3`); it now lives
|
||
inside the install-hero as Step 2 and is not collapsible. #}
|
||
<div class="setup-minimize">
|
||
<button id="setupMinimizeToggle" type="button" aria-pressed="false">
|
||
Minimize setup view
|
||
</button>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
{# 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. #}
|
||
|
||
<details class="setup-collapsible" data-section="connectors" open>
|
||
<summary>
|
||
<span class="ico" aria-hidden="true">🔗</span>
|
||
<span class="ttl">Connect your tools <small>(Asana / Google Workspace / Atlassian)</small></span>
|
||
<span class="chev" aria-hidden="true">›</span>
|
||
</summary>
|
||
<div class="section-label section-label-flat">Once Agnes is installed — connect your tools</div>
|
||
|
||
<div class="connector-tiles">
|
||
<div class="connector-tile">
|
||
<span class="ico">✅</span>
|
||
{# P0-3 — title row + time-badge + post-copy hint. The hint
|
||
container is rendered hidden; the JS reveals it after the
|
||
copy succeeds, then auto-hides after 8 s. #}
|
||
<div class="ttl-row">
|
||
<span class="ttl">Asana</span>
|
||
<span class="time-badge">~5 min · self-serve</span>
|
||
</div>
|
||
<div class="desc">Read tasks and projects, comment, create updates — Claude works alongside your project boards without leaving the terminal.</div>
|
||
<div class="connector-actions">
|
||
<button class="connector-copy" data-copy-target="asana-prompt" data-connector="Asana">Copy prompt</button>
|
||
<div class="copy-next-hint" data-hint-for="Asana">
|
||
<span>✅ Copied. Now paste into Claude Code — run <code>claude</code> in your terminal, then paste & press Enter.</span>
|
||
</div>
|
||
<details class="connector-preview">
|
||
<summary>Show prompt</summary>
|
||
{# Asana prompt body sourced from app/web/connector_prompts.py
|
||
(`asana_prompt()`). Same string the main setup script
|
||
inlines in step 9, so the two surfaces stay in lockstep. #}
|
||
<div class="card-mini-cmd"><code id="asana-prompt">{{ connector_prompts.asana }}</code></div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="connector-tile">
|
||
<span class="ico">📚</span>
|
||
{# P0-3 + P1-8 — Google Workspace tile. Time badge warns when
|
||
the operator hasn't provisioned a shared OAuth app (forces
|
||
the user to set up GCP themselves, which is a ~20-min
|
||
clickops detour). The gating-note + email-admin button
|
||
appear in that same un-configured branch so the user has
|
||
a way out before copying. #}
|
||
<div class="ttl-row">
|
||
<span class="ttl">Google Workspace</span>
|
||
{% if gws_oauth.configured %}
|
||
<span class="time-badge">~5 min · self-serve</span>
|
||
{% else %}
|
||
<span class="time-badge is-warn">~20 min · admin help likely</span>
|
||
{% endif %}
|
||
</div>
|
||
<div class="desc">Drive, Calendar, Gmail, Docs, Sheets, Chat — Claude reads and acts across your work account via the official <code>gws</code> CLI.</div>
|
||
{% if not gws_oauth.configured %}
|
||
<div class="gating-note">
|
||
<strong>Heads up:</strong> your Agnes admin hasn't provisioned a shared Google Cloud OAuth app yet, so this connector needs GCP project setup (creating an OAuth client, enabling APIs). It's fastest to ask your admin first — the button below pre-fills the email.
|
||
</div>
|
||
{% endif %}
|
||
<div class="connector-actions">
|
||
<button class="connector-copy" data-copy-target="gws-prompt" data-connector="Google Workspace">Copy prompt</button>
|
||
{% if not gws_oauth.configured and instance_admin_email %}
|
||
<a class="email-admin" href="mailto:{{ instance_admin_email }}?subject=Agnes%20%E2%80%94%20Google%20Workspace%20OAuth%20setup&body=Hi%20%E2%80%94%20I'd%20like%20to%20connect%20Google%20Workspace%20in%20Agnes%20but%20it%20looks%20like%20a%20shared%20OAuth%20app%20isn't%20provisioned%20yet.%20Could%20you%20set%20it%20up%20for%20our%20instance%3F%20Thanks!">
|
||
✉️ Email admin
|
||
</a>
|
||
{% endif %}
|
||
<div class="copy-next-hint" data-hint-for="Google Workspace">
|
||
<span>✅ Copied. Now paste into Claude Code — run <code>claude</code> in your terminal, then paste & press Enter.</span>
|
||
</div>
|
||
<details class="connector-preview">
|
||
<summary>Show prompt</summary>
|
||
<div class="card-mini-cmd"><code id="gws-prompt">{{ connector_prompts.gws }}</code></div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="connector-tile">
|
||
<span class="ico">🎟️</span>
|
||
<div class="ttl-row">
|
||
<span class="ttl">Atlassian (Jira / Confluence)</span>
|
||
<span class="time-badge">~7 min · self-serve</span>
|
||
</div>
|
||
<div class="desc">Read and write Jira issues, search Confluence pages — Claude pulls ticket context and posts updates without leaving the workspace.</div>
|
||
<div class="connector-actions">
|
||
<button class="connector-copy" data-copy-target="jira-prompt" data-connector="Atlassian">Copy prompt</button>
|
||
<div class="copy-next-hint" data-hint-for="Atlassian">
|
||
<span>✅ Copied. Now paste into Claude Code — run <code>claude</code> in your terminal, then paste & press Enter.</span>
|
||
</div>
|
||
<details class="connector-preview">
|
||
<summary>Show prompt</summary>
|
||
<div class="card-mini-cmd"><code id="jira-prompt">{{ connector_prompts.atlassian }}</code></div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<div class="section-label">Want to look around first?</div>
|
||
<p class="look-around-lead">You don't need Agnes installed locally to browse what's available. Anything you bookmark or subscribe to will be there waiting after you set Agnes up.</p>
|
||
|
||
<div class="what-is look-around-grid">
|
||
<a class="what-is-item" href="/marketplace">
|
||
<span class="ico">🧩</span>
|
||
<div class="ttl">Plugin marketplace <span class="arrow">→</span></div>
|
||
<div class="desc">Curated and community-built plugins for Claude Code — Asana, Jira, Google Workspace, and more. Browse, install, sync.</div>
|
||
</a>
|
||
<a class="what-is-item" href="/catalog">
|
||
<span class="ico">📦</span>
|
||
<div class="ttl">Curated data packages <span class="arrow">→</span></div>
|
||
<div class="desc">Tables, schema, and metric definitions your team has registered. Subscribe and Claude can query them with documented business rules.</div>
|
||
</a>
|
||
{# Corporate memory + Activity center are both admin-only — matches
|
||
the top-nav gating logic (the "Memory" link is hidden for
|
||
non-admin in _app_header.html, and the /corporate-memory route
|
||
is `require_admin`). Without this gate non-admin users would
|
||
see a Corporate memory tile that 403s when clicked. #}
|
||
{% if is_admin %}
|
||
<a class="what-is-item" href="/corporate-memory">
|
||
<span class="ico">🧠</span>
|
||
<div class="ttl">Corporate memory <span class="arrow">→</span></div>
|
||
<div class="desc">Shared analyst knowledge and prior solutions to draw from. Searchable, versioned, fed back into Claude's context on demand.</div>
|
||
</a>
|
||
<a class="what-is-item" href="/activity-center">
|
||
<span class="ico">📈</span>
|
||
<div class="ttl">Activity center <span class="arrow">→</span></div>
|
||
<div class="desc">Per-user analytics on Agnes adoption across your team. Sessions, plugin installs, prompt patterns.</div>
|
||
</a>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<a class="advanced-pointer" href="/setup-advanced">
|
||
<span class="ico">🛠️</span>
|
||
<div class="advanced-pointer-text">
|
||
<strong>Going deeper — Advanced setup</strong>
|
||
VS Code split-terminal layout, recommended Claude Code plugins (with copy-able install commands), multi-model second opinions (Codex + Gemini), custom skills + rules + hooks, project workflows, plan tier guidance.
|
||
</div>
|
||
<span class="arrow">→</span>
|
||
</a>
|
||
|
||
{% 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 →</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">✅</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 & 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" %}
|
||
|
||
<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);
|
||
|
||
// P0-3 + P2-12 — Connector copy buttons. Three things on click:
|
||
// 1) copy the prompt (same textContent trick so closed <details>
|
||
// still copies);
|
||
// 2) flip the button to "✓ Copied" + disabled for 8 s so the user
|
||
// stops mashing it while figuring out where to paste;
|
||
// 3) reveal a paste hint pointing the user at Claude Code.
|
||
document.querySelectorAll('.connector-copy[data-copy-target]').forEach(function (btn) {
|
||
btn.addEventListener('click', function () {
|
||
var src = document.getElementById(btn.getAttribute('data-copy-target'));
|
||
if (!src) return;
|
||
var raw = src.textContent || '';
|
||
var connector = btn.getAttribute('data-connector') || '';
|
||
var hint = connector
|
||
? document.querySelector('.copy-next-hint[data-hint-for="' + connector + '"]')
|
||
: null;
|
||
navigator.clipboard.writeText(raw).then(function () {
|
||
var orig = btn.textContent;
|
||
btn.classList.add('copied');
|
||
btn.textContent = '✓ Copied';
|
||
btn.disabled = true;
|
||
if (hint) hint.classList.add('is-visible');
|
||
setTimeout(function () {
|
||
btn.classList.remove('copied');
|
||
btn.textContent = orig;
|
||
btn.disabled = false;
|
||
if (hint) hint.classList.remove('is-visible');
|
||
}, 8000);
|
||
}).catch(function () { btn.textContent = 'Copy failed'; });
|
||
});
|
||
});
|
||
|
||
// 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');
|
||
var scope = 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', '');
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
// 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();
|
||
});
|
||
}
|
||
|
||
var btn = document.getElementById('self-mark-btn');
|
||
var status = document.getElementById('self-mark-status');
|
||
if (!btn) return;
|
||
btn.addEventListener('click', function () {
|
||
// Direction comes from data-attrs the template sets per render —
|
||
// onboarded view → flip to FALSE (offboard), not-onboarded → flip to TRUE.
|
||
var targetOnboarded = btn.getAttribute('data-target-onboarded') === 'true';
|
||
var targetSource = btn.getAttribute('data-target-source') || 'self_acknowledged';
|
||
btn.disabled = true;
|
||
status.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) {
|
||
status.textContent = 'Done. Reloading…';
|
||
window.location.reload();
|
||
} else {
|
||
status.textContent = 'Failed (' + resp.status + '). Try again.';
|
||
btn.disabled = false;
|
||
}
|
||
}).catch(function () {
|
||
status.textContent = 'Network error. Try again.';
|
||
btn.disabled = false;
|
||
});
|
||
});
|
||
|
||
// ── Minimize-setup toggle ────────────────────────────────────────
|
||
// Default OFF: sections render flat (no <summary> visible).
|
||
// ON: data-setup-minimized="1" on .home-mock activates the slim
|
||
// gray summary bars; <details> open/close handles per-section
|
||
// expansion. Per-device via localStorage; survives reloads but
|
||
// resets on a new machine — which is correct (the user might
|
||
// want the full reference there).
|
||
var KEY = 'agnes_home_setup_minimized';
|
||
var mockEl = document.querySelector('.home-mock');
|
||
var minToggle = document.getElementById('setupMinimizeToggle');
|
||
var collapsibles = document.querySelectorAll('.setup-collapsible');
|
||
|
||
function applyMinimize(on) {
|
||
if (!mockEl) return;
|
||
if (on) {
|
||
mockEl.setAttribute('data-setup-minimized', '1');
|
||
collapsibles.forEach(function (d) { d.removeAttribute('open'); });
|
||
if (minToggle) {
|
||
minToggle.textContent = 'Show full setup view';
|
||
minToggle.setAttribute('aria-pressed', 'true');
|
||
}
|
||
} else {
|
||
mockEl.removeAttribute('data-setup-minimized');
|
||
collapsibles.forEach(function (d) { d.setAttribute('open', ''); });
|
||
if (minToggle) {
|
||
minToggle.textContent = 'Minimize setup view';
|
||
minToggle.setAttribute('aria-pressed', 'false');
|
||
}
|
||
}
|
||
}
|
||
|
||
// Initial state — only when the toggle exists (= onboarded view).
|
||
if (minToggle) {
|
||
try { applyMinimize(localStorage.getItem(KEY) === '1'); }
|
||
catch (e) { /* ignore localStorage failures (private mode) */ }
|
||
minToggle.addEventListener('click', function () {
|
||
var nowOn = mockEl.getAttribute('data-setup-minimized') !== '1';
|
||
try { localStorage.setItem(KEY, nowOn ? '1' : '0'); } catch (e) {}
|
||
applyMinimize(nowOn);
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
{% endblock %}
|