opencastle 0.32.3 → 0.32.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/cli/bootstrap.js +1 -1
  2. package/dist/cli/bootstrap.js.map +1 -1
  3. package/dist/cli/bootstrap.test.js +16 -0
  4. package/dist/cli/bootstrap.test.js.map +1 -1
  5. package/dist/cli/convoy/engine.d.ts +1 -0
  6. package/dist/cli/convoy/engine.d.ts.map +1 -1
  7. package/dist/cli/convoy/engine.js +17 -2
  8. package/dist/cli/convoy/engine.js.map +1 -1
  9. package/dist/cli/convoy/pipeline.d.ts +1 -0
  10. package/dist/cli/convoy/pipeline.d.ts.map +1 -1
  11. package/dist/cli/convoy/pricing.d.ts +3 -0
  12. package/dist/cli/convoy/pricing.d.ts.map +1 -0
  13. package/dist/cli/convoy/pricing.js +52 -0
  14. package/dist/cli/convoy/pricing.js.map +1 -0
  15. package/dist/cli/convoy/pricing.test.d.ts +2 -0
  16. package/dist/cli/convoy/pricing.test.d.ts.map +1 -0
  17. package/dist/cli/convoy/pricing.test.js +63 -0
  18. package/dist/cli/convoy/pricing.test.js.map +1 -0
  19. package/dist/cli/convoy/store.d.ts +1 -1
  20. package/dist/cli/convoy/store.d.ts.map +1 -1
  21. package/dist/cli/convoy/store.js +1 -1
  22. package/dist/cli/convoy/store.js.map +1 -1
  23. package/dist/cli/init.test.js +38 -0
  24. package/dist/cli/init.test.js.map +1 -1
  25. package/dist/cli/run/adapters/opencode.js +1 -1
  26. package/dist/cli/run/adapters/opencode.js.map +1 -1
  27. package/dist/cli/run.d.ts.map +1 -1
  28. package/dist/cli/run.js +10 -2
  29. package/dist/cli/run.js.map +1 -1
  30. package/dist/cli/stack-config-update.test.js +18 -0
  31. package/dist/cli/stack-config-update.test.js.map +1 -1
  32. package/dist/cli/stack-config.d.ts.map +1 -1
  33. package/dist/cli/stack-config.js +1 -0
  34. package/dist/cli/stack-config.js.map +1 -1
  35. package/dist/cli/types.d.ts +1 -1
  36. package/dist/cli/types.d.ts.map +1 -1
  37. package/dist/orchestrator/plugins/index.d.ts.map +1 -1
  38. package/dist/orchestrator/plugins/index.js +4 -0
  39. package/dist/orchestrator/plugins/index.js.map +1 -1
  40. package/dist/orchestrator/plugins/notion/config.d.ts +3 -0
  41. package/dist/orchestrator/plugins/notion/config.d.ts.map +1 -0
  42. package/dist/orchestrator/plugins/notion/config.js +46 -0
  43. package/dist/orchestrator/plugins/notion/config.js.map +1 -0
  44. package/dist/orchestrator/plugins/trello/config.d.ts +3 -0
  45. package/dist/orchestrator/plugins/trello/config.d.ts.map +1 -0
  46. package/dist/orchestrator/plugins/trello/config.js +43 -0
  47. package/dist/orchestrator/plugins/trello/config.js.map +1 -0
  48. package/dist/orchestrator/plugins/types.d.ts +1 -1
  49. package/dist/orchestrator/plugins/types.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/cli/bootstrap.test.ts +21 -0
  52. package/src/cli/bootstrap.ts +1 -1
  53. package/src/cli/convoy/engine.ts +18 -3
  54. package/src/cli/convoy/pipeline.ts +1 -1
  55. package/src/cli/convoy/pricing.test.ts +78 -0
  56. package/src/cli/convoy/pricing.ts +62 -0
  57. package/src/cli/convoy/store.ts +3 -3
  58. package/src/cli/init.test.ts +46 -0
  59. package/src/cli/run/adapters/opencode.ts +1 -1
  60. package/src/cli/run.ts +10 -2
  61. package/src/cli/stack-config-update.test.ts +20 -0
  62. package/src/cli/stack-config.ts +1 -0
  63. package/src/cli/types.ts +1 -1
  64. package/src/dashboard/dist/_astro/index.wyN9vmjZ.css +1 -0
  65. package/src/dashboard/dist/index.html +4 -4
  66. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  67. package/src/dashboard/src/pages/index.astro +5 -3
  68. package/src/dashboard/src/styles/dashboard.css +6 -0
  69. package/src/orchestrator/customizations/agents/skill-matrix.json +8 -4
  70. package/src/orchestrator/customizations/agents/skill-matrix.md +20 -0
  71. package/src/orchestrator/plugins/index.ts +4 -0
  72. package/src/orchestrator/plugins/notion/SKILL.md +205 -0
  73. package/src/orchestrator/plugins/notion/config.ts +47 -0
  74. package/src/orchestrator/plugins/trello/SKILL.md +151 -0
  75. package/src/orchestrator/plugins/trello/config.ts +44 -0
  76. package/src/orchestrator/plugins/types.ts +1 -1
  77. package/src/dashboard/dist/_astro/index.D6quLrA6.css +0 -1
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: notion-knowledge-management
3
+ description: "Notion workspace patterns for knowledge capture, research documentation, architectural decisions, and spec management. Use when capturing research findings, writing specs, documenting decisions, or managing a team knowledge base."
4
+ ---
5
+
6
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
7
+
8
+ # Knowledge Management with Notion
9
+
10
+ Conventions for working with the team's Notion workspace via the official Notion MCP server. Covers page and database operations, research capture, decision documentation, and permission-aware workflows.
11
+
12
+ ## MCP Server
13
+
14
+ | Field | Value |
15
+ |-------|-------|
16
+ | **Endpoint** | `https://mcp.notion.com/mcp` (HTTP, remote) |
17
+ | **Auth** | OAuth — users authenticate via Notion account when the MCP connection is established |
18
+ | **Type** | HTTP MCP (no local process to spawn) |
19
+
20
+ ### Authentication
21
+
22
+ The Notion MCP server uses OAuth. When the MCP connection is first opened in your IDE, you will be prompted to authorise access to your Notion workspace. No API key or token is required in `.env`.
23
+
24
+ > **Scope:** The integration is granted access only to pages and databases explicitly shared with it. Before using MCP tools, ensure the relevant pages/databases are shared with the OpenCastle integration in Notion.
25
+
26
+ ## Available MCP Tools
27
+
28
+ | Tool | Description |
29
+ |------|-------------|
30
+ | `search` | Search pages and databases across the workspace by keyword |
31
+ | `create_page` | Create a new page (standalone or inside a parent page/database) |
32
+ | `update_page` | Update page properties or archive a page |
33
+ | `append_block_children` | Append content blocks (paragraphs, headings, bullets, code) to a page |
34
+ | `query_database` | Query a Notion database with filters and sorts |
35
+
36
+ ## Working with Pages and Databases
37
+
38
+ ### Page Hierarchy Hygiene
39
+
40
+ Keep the workspace navigable by placing new pages in the right location:
41
+
42
+ ```
43
+ Workspace root
44
+ ├── Engineering/
45
+ │ ├── Architecture Decisions/ ← ADRs go here
46
+ │ ├── Specs/ ← Feature specs go here
47
+ │ └── Research/ ← Research notes go here
48
+ ├── Team/
49
+ │ ├── Meeting Notes/ ← Meeting intelligence
50
+ │ └── Decisions Log/ ← Key team decisions
51
+ └── Project: <name>/ ← Per-project space
52
+ ├── Roadmap
53
+ ├── Known Issues
54
+ └── Release Notes/
55
+ ```
56
+
57
+ - Always use `search` first to check if a page already exists before creating a new one.
58
+ - Create pages as children of the appropriate parent — never at the workspace root unless explicitly requested.
59
+ - Use databases (not flat pages) for collections that need filtering, sorting, or status tracking (e.g., ADRs, specs).
60
+
61
+ ### Page Creation Pattern
62
+
63
+ When creating a page:
64
+
65
+ 1. `search` for an existing page with a similar title to avoid duplicates
66
+ 2. `create_page` with `parent` set to the correct parent page or database
67
+ 3. `append_block_children` to add structured content
68
+
69
+ ```json
70
+ // Example: Create a spec page
71
+ {
72
+ "parent": { "page_id": "<Engineering/Specs parent ID>" },
73
+ "properties": {
74
+ "title": [{ "type": "text", "text": { "content": "[Spec] Price Range Filter" } }]
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## Capturing Research and Decisions
80
+
81
+ ### Research Note Structure
82
+
83
+ Use this outline when capturing research findings:
84
+
85
+ ```
86
+ # [Research] <Topic>
87
+
88
+ ## Summary
89
+ One-paragraph overview of findings.
90
+
91
+ ## Sources
92
+ - <URL or reference> — <why it is relevant>
93
+
94
+ ## Key Findings
95
+ - Finding 1
96
+ - Finding 2
97
+
98
+ ## Implications
99
+ How these findings affect the current task or architecture.
100
+
101
+ ## Open Questions
102
+ - Question 1
103
+ ```
104
+
105
+ ### Architectural Decision Record (ADR) Structure
106
+
107
+ ```
108
+ # ADR-NNN: <Short title>
109
+
110
+ **Status:** Proposed | Accepted | Deprecated | Superseded
111
+ **Date:** YYYY-MM-DD
112
+
113
+ ## Context
114
+ What is the problem or decision to be made?
115
+
116
+ ## Decision
117
+ What was decided?
118
+
119
+ ## Consequences
120
+ What tradeoffs or follow-on work does this create?
121
+
122
+ ## Alternatives Considered
123
+ - Option A — why rejected
124
+ - Option B — why rejected
125
+ ```
126
+
127
+ ### Spec-to-Implementation Link
128
+
129
+ When a spec page drives implementation, add an **Implementation** section at the bottom:
130
+
131
+ ```
132
+ ## Implementation
133
+ - **Branch:** `feat/price-range-filter`
134
+ - **PR:** <link>
135
+ - **Tracker:** <Linear/Jira/Trello card link>
136
+ - **Status:** In Progress / Done
137
+ ```
138
+
139
+ This closes the loop between the knowledge base and the task tracker.
140
+
141
+ ## Meeting Intelligence
142
+
143
+ When capturing meeting notes, use the following structure:
144
+
145
+ ```
146
+ # Meeting: <Title> — YYYY-MM-DD
147
+
148
+ **Attendees:** Name1, Name2
149
+ **Type:** Planning / Review / Retrospective / Decision
150
+
151
+ ## Summary
152
+
153
+ ## Decisions Made
154
+ - Decision 1 (owner: Name)
155
+
156
+ ## Action Items
157
+ - [ ] Action item (owner: Name, due: YYYY-MM-DD)
158
+
159
+ ## Context / Discussion Notes
160
+ ```
161
+
162
+ After the meeting, add action items to the task tracker.
163
+
164
+ ## Permission-Aware Workflows
165
+
166
+ Notion access is page-scoped. Follow these rules to avoid permission errors:
167
+
168
+ 1. **Before writing** — run `search` to verify you can see the target page. If it does not appear, the integration has not been granted access.
169
+ 2. **Sharing** — ask the user to share the relevant page or database with the OpenCastle integration before running MCP tools against it.
170
+ 3. **Databases vs pages** — use `query_database` only on pages that are databases. Use `append_block_children` to add content to regular pages.
171
+ 4. **Archived pages** — `search` does not return archived pages. If a page is missing, it may have been archived. Ask the user to restore it.
172
+
173
+ ## Database Query Patterns
174
+
175
+ ### Filter by Status
176
+
177
+ ```json
178
+ {
179
+ "filter": {
180
+ "property": "Status",
181
+ "select": { "equals": "In Progress" }
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### Sort by Last Edited
187
+
188
+ ```json
189
+ {
190
+ "sorts": [
191
+ { "timestamp": "last_edited_time", "direction": "descending" }
192
+ ]
193
+ }
194
+ ```
195
+
196
+ ## Agent Usage Guidelines
197
+
198
+ | Agent | Primary Use |
199
+ |-------|-------------|
200
+ | **Team Lead** | Create spec pages, capture decisions, link tracker issues to specs |
201
+ | **Researcher** | Capture research notes, query databases for prior art, document findings |
202
+ | **Documentation Writer** | Write and update documentation pages, maintain page hierarchy |
203
+ | **Architect** | Write ADRs, create technical specs, link specs to implementation PRs |
204
+
205
+ **Never** delete pages via MCP — use `update_page` with `archived: true` if a page needs to be removed, and confirm with the user first.
@@ -0,0 +1,47 @@
1
+ import type { PluginConfig } from '../types.js';
2
+
3
+ export const config: PluginConfig = {
4
+ id: 'notion',
5
+ name: 'Notion',
6
+ category: 'team',
7
+ subCategory: 'knowledge-management',
8
+ label: 'Notion',
9
+ hint: 'Workspace knowledge base and documentation hub',
10
+ skillName: 'notion-knowledge-management',
11
+ mcpServerKey: 'Notion',
12
+ mcpConfig: {
13
+ type: 'http',
14
+ url: 'https://mcp.notion.com/mcp',
15
+ },
16
+ authType: 'oauth',
17
+ envVars: [],
18
+ agentToolMap: {
19
+ 'team-lead': [
20
+ 'Notion/search',
21
+ 'Notion/create_page',
22
+ 'Notion/update_page',
23
+ 'Notion/query_database',
24
+ 'Notion/append_block_children',
25
+ ],
26
+ 'researcher': [
27
+ 'Notion/search',
28
+ 'Notion/create_page',
29
+ 'Notion/append_block_children',
30
+ 'Notion/query_database',
31
+ ],
32
+ 'documentation-writer': [
33
+ 'Notion/search',
34
+ 'Notion/create_page',
35
+ 'Notion/update_page',
36
+ 'Notion/append_block_children',
37
+ ],
38
+ 'architect': [
39
+ 'Notion/search',
40
+ 'Notion/create_page',
41
+ 'Notion/update_page',
42
+ 'Notion/query_database',
43
+ ],
44
+ },
45
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#notion',
46
+ officialDocs: 'https://developers.notion.com/docs/mcp',
47
+ };
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: trello-task-management
3
+ description: "Trello board conventions for tracking feature work — board/list/card workflow, checklist-driven task breakdown, due dates, and when to use comments vs checklist items. Use when decomposing features into cards or resuming interrupted sessions."
4
+ ---
5
+
6
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
7
+
8
+ # Task Management with Trello
9
+
10
+ Conventions for tracking feature work on Trello boards via MCP tools. For project-specific board IDs and list IDs, see [tracker-config.md](../../.opencastle/project/tracker-config.md).
11
+
12
+ ## MCP Server
13
+
14
+ | Field | Value |
15
+ |-------|-------|
16
+ | **Package** | [`@delorenj/mcp-server-trello`](https://www.npmjs.com/package/@delorenj/mcp-server-trello) |
17
+ | **Type** | stdio (spawned via `npx -y @delorenj/mcp-server-trello`) |
18
+ | **Auth** | API key + token via `TRELLO_API_KEY` and `TRELLO_TOKEN` env vars |
19
+
20
+ ### Authentication
21
+
22
+ 1. Get your API key at [trello.com/app-key](https://trello.com/app-key) → **API Key**
23
+ 2. On the same page, click **"Generate a Token"** to get your token
24
+ 3. Add both to your `.env` file:
25
+
26
+ ```
27
+ TRELLO_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
28
+ TRELLO_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
29
+ ```
30
+
31
+ ## Available MCP Tools
32
+
33
+ | Tool | Description |
34
+ |------|-------------|
35
+ | `get_boards` | List all boards accessible to the authenticated user |
36
+ | `get_lists` | Get all lists on a board (by board ID) |
37
+ | `get_cards_by_list_id` | Get all cards in a specific list |
38
+ | `get_card_details` | Get full details of a single card |
39
+ | `create_card` | Create a new card in a list |
40
+ | `update_card` | Update card fields (name, description, due date, list) |
41
+ | `add_checklist_to_card` | Add a checklist with items to a card |
42
+ | `add_comment_to_card` | Post a comment on a card |
43
+
44
+ ## Discovered Issues (Bug Tickets)
45
+
46
+ When an agent encounters a pre-existing bug or issue unrelated to the current task, it must be tracked:
47
+
48
+ 1. **Check** existing cards on the board to see if it is already tracked
49
+ 2. **If tracked** — skip it, continue with current work
50
+ 3. **If NOT tracked:**
51
+ - **Unfixable limitation** — add to known issues with severity, evidence, and root cause
52
+ - **Fixable bug** — create a Trello card:
53
+ - **Name:** `[Bug] Short description of the symptom`
54
+ - **List:** `Backlog` (or the equivalent list in your project)
55
+ - **Description:** Include symptoms, reproduction steps, affected files, and any error messages
56
+ - **Due date:** Set only if it is blocking current work
57
+
58
+ ## Card Naming
59
+
60
+ Use `[Area] Short description` format:
61
+
62
+ ```
63
+ [Schema] Add priceRange field to place type
64
+ [DB] Add price_range column and migration
65
+ [UI] Build PriceRangeFilter component
66
+ [API] Add price filter endpoint
67
+ [Test] Unit tests for price filter
68
+ [Docs] Update data model documentation
69
+ ```
70
+
71
+ **Area prefixes:** `[Schema]`, `[DB]`, `[Query]`, `[UI]`, `[Page]`, `[API]`, `[Auth]`, `[Test]`, `[Docs]`, `[Deploy]`, `[Data]`, `[Perf]`, `[Security]`, `[Bug]`
72
+
73
+ ## Board and List Workflow
74
+
75
+ ### Typical List Structure
76
+
77
+ ```
78
+ Backlog → To Do → In Progress → In Review → Done
79
+ ```
80
+
81
+ - **Backlog** — Captured but not yet planned
82
+ - **To Do** — Planned and ready to start
83
+ - **In Progress** — Actively being worked on
84
+ - **In Review** — PR open, awaiting review or merge
85
+ - **Done** — Completed and verified
86
+
87
+ ### Agent-Driven Card Transitions (via MCP)
88
+
89
+ | From | To | When |
90
+ |------|----|------|
91
+ | Backlog / To Do | In Progress | Agent starts working on the card |
92
+ | In Progress | Done | Non-PR task is verified (docs, config) |
93
+ | Any | Backlog | Task is deferred |
94
+
95
+ ## Checklist-Driven Task Breakdown
96
+
97
+ Use checklists for **subtask decomposition within a single card**. This keeps related work together without cluttering the board with micro-cards.
98
+
99
+ ### When to Use a Checklist vs a Separate Card
100
+
101
+ | Use a **checklist item** when… | Use a **separate card** when… |
102
+ |-------------------------------|------------------------------|
103
+ | Steps are sequential and tightly coupled | Work can be assigned independently |
104
+ | Total effort fits in one session | Each step spans multiple sessions |
105
+ | Steps share the same assignee | Steps need different labels/due dates |
106
+ | Internal implementation details | Distinct deliverables that need review |
107
+
108
+ ### Checklist Pattern for Feature Decomposition
109
+
110
+ ```
111
+ Card: [Feature] Add price range filter
112
+ Checklist: Implementation Steps
113
+ ☐ Add priceRange field to schema
114
+ ☐ Create DB migration
115
+ ☐ Update GROQ/API query
116
+ ☐ Build UI component
117
+ ☐ Wire into page
118
+ ☐ Write unit tests
119
+ ☐ Update documentation
120
+ ```
121
+
122
+ ## Due and Start Dates
123
+
124
+ Trello cards support both a **start date** and a **due date**.
125
+
126
+ - **Due date** — The deadline for the card to move to Done. Set for tasks on the critical path.
127
+ - **Start date** — When work is expected to begin. Useful for pipeline planning.
128
+ - **Due time** — Be explicit with time only for time-sensitive deliverables (e.g., scheduled releases).
129
+ - **Format:** Trello API uses ISO 8601: `2026-03-20T14:00:00.000Z`
130
+
131
+ ## Comments vs Checklist Items
132
+
133
+ | Use **comments** for… | Use **checklist items** for… |
134
+ |-----------------------|------------------------------|
135
+ | Progress updates visible to the team | Actionable steps with completion state |
136
+ | Blocking issues or decisions | Pre-defined subtask decomposition |
137
+ | Links to PRs, builds, external docs | Typed acceptance criteria |
138
+ | Questions or async approvals | Implementation sub-steps |
139
+ | Post-implementation notes | QA verification steps |
140
+
141
+ **Rule of thumb:** If it needs to be *checked off*, it's a checklist item. If it needs to be *read*, it's a comment.
142
+
143
+ ## Session Continuity
144
+
145
+ At the start of each work session:
146
+
147
+ 1. `get_boards` — confirm the right board is active
148
+ 2. `get_lists` — identify current list structure
149
+ 3. `get_cards_by_list_id` for **In Progress** — find cards already in flight
150
+ 4. Resume work on the relevant card, updating the checklist as steps complete
151
+ 5. Move the card to the next list when the current phase is done
@@ -0,0 +1,44 @@
1
+ import type { PluginConfig } from '../types.js';
2
+
3
+ export const config: PluginConfig = {
4
+ id: 'trello',
5
+ name: 'Trello',
6
+ category: 'team',
7
+ subCategory: 'task-management',
8
+ label: 'Trello',
9
+ hint: 'Visual board task management via MCP',
10
+ skillName: 'trello-task-management',
11
+ mcpServerKey: 'Trello',
12
+ mcpConfig: {
13
+ type: 'stdio',
14
+ command: 'npx',
15
+ args: ['-y', '@delorenj/mcp-server-trello'],
16
+ envFile: '${workspaceFolder}/.env',
17
+ },
18
+ authType: 'env-token',
19
+ envVars: [
20
+ {
21
+ name: 'TRELLO_API_KEY',
22
+ hint: 'Create at trello.com/app-key -> API Key',
23
+ },
24
+ {
25
+ name: 'TRELLO_TOKEN',
26
+ hint: 'Generate at trello.com/app-key -> Token (click "Generate a Token")',
27
+ },
28
+ ],
29
+ agentToolMap: {
30
+ 'team-lead': [
31
+ 'Trello/get_boards',
32
+ 'Trello/get_lists',
33
+ 'Trello/get_cards_by_list_id',
34
+ 'Trello/get_card_details',
35
+ 'Trello/create_card',
36
+ 'Trello/update_card',
37
+ 'Trello/add_checklist_to_card',
38
+ 'Trello/add_comment_to_card',
39
+ ],
40
+ },
41
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#trello',
42
+ officialDocs: 'https://developer.atlassian.com/cloud/trello/',
43
+ mcpPackage: '@delorenj/mcp-server-trello',
44
+ };
@@ -13,7 +13,7 @@ export interface PluginConfig {
13
13
  category: 'tech' | 'team';
14
14
 
15
15
  /** Sub-category for grouping */
16
- subCategory: 'cms' | 'database' | 'deployment' | 'framework' | 'codebase-tool' | 'task-management' | 'notifications' | 'testing' | 'e2e-testing' | 'design' | 'email';
16
+ subCategory: 'cms' | 'database' | 'deployment' | 'framework' | 'codebase-tool' | 'task-management' | 'knowledge-management' | 'notifications' | 'testing' | 'e2e-testing' | 'design' | 'email';
17
17
 
18
18
  /** Label shown in the `npx opencastle init` multiselect */
19
19
  label: string;
@@ -1 +0,0 @@
1
- :root{--bg-primary: #0a0a0f;--bg-secondary: #111118;--bg-tertiary: #1a1a24;--bg-card: rgba(255, 255, 255, .03);--bg-card-hover: rgba(255, 255, 255, .06);--text-primary: #f0f0f5;--text-secondary: #8a8a9a;--text-tertiary: #7a7a8e;--text-accent: #a78bfa;--gradient-accent: linear-gradient(135deg, #a78bfa 0%, #6366f1 50%, #3b82f6 100%);--gradient-glow: radial-gradient(ellipse 800px 400px at 50% 0%, rgba(99, 102, 241, .12) 0%, transparent 70%);--border-color: rgba(255, 255, 255, .06);--border-accent: rgba(167, 139, 250, .3);--color-success: #22c55e;--color-partial: #f59e0b;--color-failed: #ef4444;--color-redirected: #64748b;--color-premium: #f59e0b;--color-standard: #a78bfa;--color-utility: #3b82f6;--color-economy: #64748b;--accent-blue: #3b82f6;--accent-purple: #a78bfa;--accent-indigo: #6366f1;--max-width: 1280px;--transition-fast: .15s cubic-bezier(.4, 0, .2, 1);--transition-base: .3s cubic-bezier(.4, 0, .2, 1)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Inter,Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;overflow-x:hidden;min-height:100vh}.dash-header{position:sticky;top:0;z-index:50;background:#0a0a0fd9;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border-color)}.dash-header__inner{max-width:var(--max-width);margin:0 auto;padding:0 24px;height:56px;display:flex;align-items:center;justify-content:space-between}.dash-header__brand{display:flex;align-items:center;gap:10px}.dash-header__icon{width:32px;height:32px;border-radius:8px;object-fit:contain}.dash-header__title{font-size:1rem;font-weight:600;color:var(--text-primary)}.dash-layout{display:flex;max-width:var(--max-width);margin:0 auto;position:relative}.dash-sidebar{position:sticky;top:56px;height:calc(100vh - 56px);width:180px;flex-shrink:0;padding:24px 0 24px 24px;overflow-y:auto;display:none}@media(min-width:1024px){.dash-sidebar{display:block}}.dash-sidebar__list{list-style:none;display:flex;flex-direction:column;gap:2px}.dash-sidebar__link{display:block;padding:8px 16px;font-size:.8125rem;font-weight:500;color:var(--text-tertiary);text-decoration:none;border-radius:8px;transition:color var(--transition-fast),background var(--transition-fast)}.dash-sidebar__link:hover{color:var(--text-secondary);background:#ffffff0a}.dash-sidebar__link--active{color:var(--text-accent);background:#a78bfa14;font-weight:600}.dash-main{flex:1;min-width:0;max-width:var(--max-width);margin:0 auto;padding:24px;display:flex;flex-direction:column;gap:20px;position:relative}.dash-main:before{content:"";position:fixed;top:0;left:50%;transform:translate(-50%);width:100%;height:600px;background:var(--gradient-glow);pointer-events:none;z-index:0}.dash-main>*{position:relative;z-index:1}[data-nav-section]{scroll-margin-top:72px}.kpi-row{display:grid;grid-template-columns:1fr;gap:12px}@media(min-width:480px){.kpi-row{grid-template-columns:repeat(2,1fr)}}@media(min-width:960px){.kpi-row{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}}.kpi-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;padding:20px 24px;display:flex;flex-direction:column;gap:4px;transition:border-color var(--transition-fast)}.kpi-card:hover{border-color:#ffffff1a}.kpi-card__label{font-size:.75rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.kpi-card__value{font-size:2rem;font-weight:700;color:var(--text-primary);line-height:1.2;letter-spacing:-.02em}.kpi-card__sub{font-size:.75rem;color:var(--text-secondary);display:flex;align-items:center;gap:4px}.kpi-trend{font-weight:600}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-failed)}.kpi-trend--neutral{color:var(--text-tertiary)}.chart-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.chart-card:hover{border-color:#ffffff1a}.chart-card__header{padding:20px 24px 8px;display:flex;flex-wrap:wrap;align-items:baseline;gap:6px}.chart-card__title{font-size:.9375rem;font-weight:600;color:var(--text-primary)}.chart-card__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px;width:100%}.chart-card__body{padding:16px 24px 24px;min-height:120px}.chart-card__body--table{padding:0}.charts-row{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width:768px){.charts-row{grid-template-columns:repeat(2,1fr)}}.bar-row{display:flex;align-items:center;gap:12px;padding:6px 0}.bar-row+.bar-row{border-top:1px solid rgba(255,255,255,.03)}.bar-label{font-size:.8125rem;color:var(--text-secondary);width:130px;flex-shrink:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bar-track{flex:1;height:24px;background:var(--bg-tertiary);border-radius:6px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:width .8s cubic-bezier(.4,0,.2,1);min-width:0}.bar--success{background:var(--color-success)}.bar--partial{background:var(--color-partial)}.bar--failed{background:var(--color-failed)}.bar--premium{background:var(--color-premium)}.bar--standard{background:var(--color-standard)}.bar--utility{background:var(--color-utility)}.bar--economy{background:var(--color-economy)}.bar--accent{background:var(--accent-blue)}.bar-value{font-size:.8125rem;font-weight:600;color:var(--text-primary);width:36px;text-align:right;flex-shrink:0;font-variant-numeric:tabular-nums}.donut-container{display:flex;align-items:center;justify-content:center;gap:32px;flex-wrap:wrap}.donut-wrap{position:relative;width:180px;height:180px;flex-shrink:0}.donut-svg{width:100%;height:100%}.donut-svg circle{transition:stroke-dasharray .8s cubic-bezier(.4,0,.2,1),stroke-dashoffset .8s cubic-bezier(.4,0,.2,1)}.donut-center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center}.donut-total{display:block;font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.donut-total-label{display:block;font-size:.6875rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.08em;margin-top:2px}.donut-legend{display:flex;flex-direction:column;gap:10px}.legend-item{display:flex;align-items:center;gap:8px;font-size:.8125rem}.legend-dot{width:10px;height:10px;border-radius:3px;flex-shrink:0}.legend-name{color:var(--text-secondary);text-transform:capitalize}.legend-count{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-left:auto}.timeline-svg{width:100%;height:auto;display:block}.timeline-svg text{font-family:inherit}.timeline-legend{display:flex;gap:16px;justify-content:center;margin-top:12px}.timeline-legend__item{display:flex;align-items:center;gap:6px;font-size:.75rem;color:var(--text-tertiary)}.timeline-legend__dot{width:8px;height:8px;border-radius:2px}.pipeline{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:8px 0}.pipeline-stage{flex:1;min-width:140px;display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px;position:relative}.pipeline-stage:not(:last-child):after{content:"";position:absolute;right:-1px;top:50%;transform:translateY(-50%);width:2px;height:40%;background:var(--border-color)}.pipeline-stage__icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem}.pipeline-stage__icon--pending{background:#64748b26;color:#94a3b8;border:1px solid rgba(100,116,139,.2)}.pipeline-stage__icon--active{background:#3b82f626;color:#60a5fa;border:1px solid rgba(59,130,246,.3);animation:pulse-glow 2s ease-in-out infinite}.pipeline-stage__icon--review{background:#f59e0b26;color:#fbbf24;border:1px solid rgba(245,158,11,.3)}.pipeline-stage__icon--done{background:#22c55e26;color:#4ade80;border:1px solid rgba(34,197,94,.3)}@keyframes pulse-glow{0%,to{box-shadow:0 0 #3b82f633}50%{box-shadow:0 0 12px 4px #3b82f626}}.pipeline-stage__count{font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.pipeline-stage__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;font-weight:500}.pipeline-arrow{display:flex;align-items:center;color:var(--text-tertiary);font-size:1.25rem;padding:0 4px;flex-shrink:0}.exec-log{display:flex;flex-direction:column}.exec-step{display:flex;gap:16px;padding:14px 0;position:relative}.exec-step+.exec-step{border-top:1px solid rgba(255,255,255,.03)}.exec-step__indicator{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:32px}.exec-step__dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:700;flex-shrink:0}.exec-step__dot--success{background:#22c55e26;color:var(--color-success);border:1.5px solid rgba(34,197,94,.3)}.exec-step__dot--partial{background:#f59e0b26;color:var(--color-partial);border:1.5px solid rgba(245,158,11,.3)}.exec-step__dot--failed{background:#ef444426;color:var(--color-failed);border:1.5px solid rgba(239,68,68,.3)}.exec-step__line{flex:1;width:1.5px;background:var(--border-color);margin-top:4px}.exec-step__content{flex:1;min-width:0}.exec-step__header{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.exec-step__agent{font-size:.875rem;font-weight:600;color:var(--text-primary)}.exec-step__badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.exec-step__badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.exec-step__badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.exec-step__badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.exec-step__task{font-size:.8125rem;color:var(--text-secondary);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.exec-step__meta{display:flex;gap:16px;margin-top:6px;font-size:.6875rem;color:var(--text-tertiary)}.exec-step__meta-item{display:flex;align-items:center;gap:4px}.panel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}.panel-item{background:var(--bg-tertiary);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px;border:1px solid transparent;transition:border-color var(--transition-fast)}.panel-item:hover{border-color:var(--border-color)}.panel-item__header{display:flex;align-items:center;justify-content:space-between}.panel-item__key{font-size:.8125rem;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-item__verdict{font-size:.6875rem;font-weight:700;padding:2px 8px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em}.panel-item__verdict--pass{background:#22c55e26;color:var(--color-success)}.panel-item__verdict--block{background:#ef444426;color:var(--color-failed)}.panel-item__votes{display:flex;gap:4px}.panel-item__vote{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.625rem;font-weight:700}.panel-item__vote--pass{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.panel-item__vote--block{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.panel-item__fixes{font-size:.6875rem;color:var(--text-tertiary)}.panel-item__meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-color)}.panel-item__meta-item{font-size:.625rem;color:var(--text-tertiary);white-space:nowrap}.sessions-table{width:100%;border-collapse:collapse;font-size:.8125rem}.sessions-table thead{position:sticky;top:0}.sessions-table th{padding:12px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.sessions-table th:last-child,.sessions-table td:last-child{text-align:right}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5){text-align:right}.sessions-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.sessions-table tr:hover td{background:#ffffff05}.sessions-table .td-agent{font-weight:500;color:var(--text-primary)}.sessions-table .td-task{max-width:260px;overflow:hidden;text-overflow:ellipsis}.outcome-badge{display:inline-flex;align-items:center;padding:3px 10px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.outcome-badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.outcome-badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.outcome-badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.td-num{font-variant-numeric:tabular-nums;text-align:right}.td-issue{font-size:.75rem;color:var(--text-accent);font-weight:500;font-variant-numeric:tabular-nums}.loading-skeleton{display:flex;align-items:center;justify-content:center;min-height:200px;color:var(--text-tertiary);font-size:.8125rem}.loading-skeleton:after{content:"Loading data…";animation:fade-pulse 1.5s ease-in-out infinite}@keyframes fade-pulse{0%,to{opacity:.4}50%{opacity:1}}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;text-align:center;gap:12px}.empty-state__icon{font-size:2rem;opacity:.4}.empty-state__text{font-size:.875rem;color:var(--text-tertiary);max-width:320px}.empty-state--enhanced{padding:56px 32px;gap:16px;border:1px dashed rgba(167,139,250,.15);border-radius:12px;background:radial-gradient(ellipse 300px 200px at 50% 30%,rgba(99,102,241,.04) 0%,transparent 70%),var(--bg-tertiary);position:relative;overflow:hidden}.empty-state--enhanced:before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 23px,rgba(255,255,255,.015) 23px,rgba(255,255,255,.015) 24px);pointer-events:none}.empty-state__icon-wrap{width:64px;height:64px;display:flex;align-items:center;justify-content:center;border-radius:16px;background:#a78bfa0f;border:1px solid rgba(167,139,250,.12);color:var(--text-accent);animation:empty-breathe 4s ease-in-out infinite}@keyframes empty-breathe{0%,to{box-shadow:0 0 #a78bfa14;transform:scale(1)}50%{box-shadow:0 0 20px 4px #a78bfa0f;transform:scale(1.03)}}.empty-state__title{font-size:.9375rem;font-weight:600;color:var(--text-secondary);letter-spacing:-.01em}.empty-state__desc{font-size:.8125rem;color:var(--text-tertiary);max-width:380px;line-height:1.55}.kpi-card__hint{color:var(--text-tertiary);font-style:italic;font-size:.6875rem}.kpi-row--empty .kpi-card{border-style:dashed;border-color:#ffffff0a}.kpi-row--empty .kpi-card__value{color:var(--text-tertiary);opacity:.5}.welcome-banner{position:relative;background:var(--bg-secondary);border:1px solid transparent;border-radius:16px;padding:48px 40px;overflow:hidden;z-index:1}.welcome-banner:before{content:"";position:absolute;inset:-1px;border-radius:16px;padding:1px;background:linear-gradient(135deg,#a78bfa4d,#6366f126,#3b82f61a 60%,#a78bfa33);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;z-index:0}.welcome-banner__glow{position:absolute;top:-60px;left:50%;transform:translate(-50%);width:500px;height:300px;background:radial-gradient(ellipse at center,rgba(167,139,250,.08) 0%,rgba(99,102,241,.04) 40%,transparent 70%);pointer-events:none;z-index:0}.welcome-banner__content{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;text-align:center;gap:20px}.welcome-banner__icon{width:72px;height:72px;display:flex;align-items:center;justify-content:center;border-radius:20px;background:#a78bfa14;border:1px solid rgba(167,139,250,.15);color:var(--text-accent);animation:welcome-float 6s ease-in-out infinite}@keyframes welcome-float{0%,to{transform:translateY(0);box-shadow:0 8px 32px #a78bfa14}50%{transform:translateY(-6px);box-shadow:0 16px 48px #a78bfa1f}}.welcome-banner__title{font-size:1.375rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.3}.welcome-banner__subtitle{font-size:.9375rem;color:var(--text-secondary);max-width:480px;line-height:1.6}.welcome-banner__steps{display:flex;gap:20px;margin-top:12px;flex-wrap:wrap;justify-content:center}.welcome-step{display:flex;align-items:flex-start;gap:12px;text-align:left;padding:16px 20px;background:#ffffff05;border:1px solid rgba(255,255,255,.05);border-radius:12px;min-width:200px;max-width:220px;transition:border-color var(--transition-fast),background var(--transition-fast)}.welcome-step:hover{border-color:#a78bfa26;background:#ffffff08}.welcome-step__num{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;color:var(--text-accent);background:#a78bfa1a;border:1px solid rgba(167,139,250,.2);flex-shrink:0}.welcome-step__text{display:flex;flex-direction:column;gap:3px}.welcome-step__text strong{font-size:.8125rem;font-weight:600;color:var(--text-primary)}.welcome-step__text span{font-size:.75rem;color:var(--text-tertiary);line-height:1.4}@media(max-width:640px){.welcome-banner{padding:32px 24px}.welcome-banner__steps{flex-direction:column;align-items:center}.welcome-step{max-width:100%;width:100%}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.dash-main>*{animation:slide-up .5s ease-out backwards}.dash-main>*:nth-child(1){animation-delay:0ms}.dash-main>*:nth-child(2){animation-delay:60ms}.dash-main>*:nth-child(3){animation-delay:.12s}.dash-main>*:nth-child(4){animation-delay:.18s}.dash-main>*:nth-child(5){animation-delay:.24s}.dash-main>*:nth-child(6){animation-delay:.3s}.dash-main>*:nth-child(7){animation-delay:.36s}.dash-main>*:nth-child(8){animation-delay:.42s}.dash-main>*:nth-child(9){animation-delay:.48s}.dash-main>*:nth-child(10){animation-delay:.54s}.dash-main>*:nth-child(11){animation-delay:.6s}@media(max-width:640px){.bar-label{width:90px;font-size:.75rem}.donut-container{flex-direction:column;align-items:center}.donut-wrap{width:150px;height:150px}.pipeline{gap:0}.pipeline-stage{min-width:100px;padding:12px 8px}.panel-grid{grid-template-columns:1fr}.sessions-table th:nth-child(3),.sessions-table td:nth-child(3){display:none}}.filter-bar{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;padding:16px 20px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px}.filter-group{display:flex;flex-direction:column;gap:4px;min-width:0}.filter-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.filter-input,.filter-select{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;transition:border-color var(--transition-fast);font-family:inherit}.filter-input:focus,.filter-select:focus{border-color:var(--border-accent)}.filter-input{width:140px;color-scheme:dark}.filter-select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.filter-reset{height:34px;font-size:.75rem}.dash-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;font-size:.8125rem;font-weight:500;font-family:inherit;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.dash-btn--ghost{color:var(--text-secondary);background:#ffffff0f}.dash-btn--ghost:hover{color:var(--text-primary);background:#ffffff1a}.dash-header__actions{display:flex;align-items:center;gap:8px}@media(max-width:480px){.dash-header__inner{padding:0 12px}.dash-main{padding:12px;gap:12px}.kpi-card,.chart-card__header{padding:14px 16px}.chart-card__body{padding:12px 16px 16px}.filter-bar{padding:12px;gap:8px}.filter-input,.filter-select{width:100%;min-width:unset}.filter-group{flex:1 1 calc(50% - 4px)}.filter-reset{width:100%}.dash-header__title{font-size:.875rem}.exec-step__meta{flex-direction:column;gap:2px}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5),.sessions-table th:nth-child(6),.sessions-table td:nth-child(6),.sessions-table th:nth-child(7),.sessions-table td:nth-child(7),.sessions-table th:nth-child(8),.sessions-table td:nth-child(8){display:none}}@media(max-width:768px){.charts-row{grid-template-columns:1fr}.pipeline{flex-wrap:wrap;gap:8px}.pipeline-arrow{display:none}.pipeline-stage{flex:1 1 calc(50% - 4px);min-width:100px}.tier-chart .donut-container,.donut-container{flex-direction:column;align-items:center}.sessions-table{font-size:.75rem}.sessions-table th,.sessions-table td{padding:8px 6px}}.convoy-overview{display:flex;flex-wrap:wrap;gap:24px;margin-bottom:20px}.convoy-stat{display:flex;flex-direction:column;gap:4px}.convoy-stat__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-stat__value{font-size:.95rem;color:var(--text-primary)}.convoy-stat__value--error{color:var(--color-failed)}.convoy-progress{display:flex;align-items:center;gap:12px;margin-bottom:20px}.convoy-progress__bar{flex:1;height:8px;background:var(--bg-tertiary);border-radius:4px;overflow:hidden}.convoy-progress__fill{height:100%;background:var(--gradient-accent);border-radius:4px;transition:width var(--transition-base)}.convoy-progress__label{font-size:.8rem;color:var(--text-secondary);white-space:nowrap}.convoy-tasks{margin-top:8px}.convoy-chain{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:1rem 0 1.5rem;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.convoy-chain::-webkit-scrollbar{height:4px}.convoy-chain::-webkit-scrollbar-track{background:transparent}.convoy-chain::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:2px}.convoy-chain__connector{display:flex;align-items:center;padding:0 .5rem;color:var(--text-tertiary);font-size:1.1rem;flex-shrink:0}.convoy-chain__node{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:10px;min-width:140px;cursor:pointer;transition:background var(--transition-fast),border-color var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast);flex-shrink:0}.convoy-chain__node:hover{background:var(--bg-card-hover);transform:translateY(-2px);box-shadow:0 4px 12px #0000004d}.convoy-chain__node-name{font-size:.8rem;font-weight:600;color:var(--text-primary);text-align:center;word-break:break-word;max-width:120px}.convoy-chain__node-meta{font-size:.72rem;color:var(--text-tertiary);text-align:center}.convoy-chain__node--active{border-color:var(--accent-purple);box-shadow:0 0 0 1px var(--accent-purple),0 0 12px #a78bfa33;animation:convoy-pulse 2s ease-in-out infinite}.convoy-chain__node--done{border-color:#22c55e4d}.convoy-chain__node--failed{border-color:#ef44444d}.convoy-chain__node--pending{opacity:.6}@keyframes convoy-pulse{0%,to{box-shadow:0 0 0 1px var(--accent-purple),0 0 8px #a78bfa26}50%{box-shadow:0 0 0 1px var(--accent-purple),0 0 18px #a78bfa59}}@media(max-width:768px){.convoy-chain{flex-wrap:wrap;gap:8px}.convoy-chain__connector{display:none}.convoy-chain__node{flex:1 1 calc(50% - 4px);min-width:120px}}.convoy-selector{display:flex;align-items:center;gap:.5rem}.convoy-selector__label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}.convoy-selector__select{appearance:none;background:var(--bg-tertiary);border:1px solid rgba(255,255,255,.08);border-radius:6px;color:var(--text-primary);font-size:.8125rem;padding:.375rem 2rem .375rem .75rem;cursor:pointer;max-width:320px;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a8a9a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .75rem center;transition:border-color .15s}.convoy-selector__select:hover{border-color:#ffffff26}.convoy-selector__select:focus{outline:2px solid var(--accent-purple);outline-offset:2px}.overall-stats{margin-bottom:0;padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.overall-stats__header{display:flex;align-items:center;gap:.5rem;margin-bottom:1rem}.overall-stats__title{font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}.overall-stats__grid{display:grid;grid-template-columns:repeat(6,1fr);gap:.75rem}.overall-kpi{display:flex;flex-direction:column;gap:.25rem;padding:.75rem;background:var(--bg-tertiary);border-radius:8px;border:1px solid rgba(255,255,255,.04);transition:border-color .15s}.overall-kpi:hover{border-color:#ffffff1a}.overall-kpi__label{font-size:.6875rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);display:flex;align-items:center;gap:.25rem}.overall-kpi__value{font-size:1.375rem;font-weight:700;color:var(--text-primary);font-variant-numeric:tabular-nums}.convoy-detail-header{padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.convoy-detail-header__top{display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem}.convoy-detail-header__name{font-size:1.25rem;font-weight:700;color:var(--text-primary);margin:0}.convoy-detail-header__meta{display:flex;flex-wrap:wrap;gap:1rem}.convoy-meta__item{font-size:.8125rem;color:var(--text-secondary)}.status-badge{display:inline-flex;align-items:center;padding:.125rem .625rem;border-radius:999px;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}.status-badge--done{background:#22c55e26;color:var(--color-success)}.status-badge--running{background:#3b82f626;color:var(--accent-blue)}.status-badge--failed{background:#ef444426;color:var(--color-failed)}.status-badge--gate-failed,.status-badge--gate_failed{background:#f59e0b26;color:var(--color-partial)}.tooltip-trigger{position:relative;cursor:help;font-size:.75rem;opacity:.5;transition:opacity .15s}.tooltip-trigger:hover{opacity:1}.tooltip-trigger:hover:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006;text-transform:none}.tooltip-trigger:focus{opacity:1;outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.tooltip-trigger:focus:after,.tooltip-trigger:focus-visible:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006;text-transform:none}.status-badge--pending{background:#64748b26;color:#94a3b8}.status-badge--assigned{background:#3b82f61a;color:#60a5fa}.status-badge--timed-out{background:#ef44441f;color:#f87171}.status-badge--review-blocked{background:#f59e0b1f;color:#fbbf24}.status-badge--skipped{background:#64748b1a;color:#64748b}.status-badge--hook-failed{background:#ef44441a;color:#f87171}.status-badge--disputed{background:#a78bfa26;color:var(--accent-purple)}.status-badge--wait-for-input{background:#f59e0b1a;color:var(--color-partial)}.task-summary-cards{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:20px}.task-summary-card{flex:1 1 140px;display:flex;flex-direction:column;gap:8px;padding:14px 16px;background:var(--bg-card);border:1px solid var(--border-color);border-radius:10px;transition:border-color .15s}.task-summary-card:hover{border-color:#ffffff1f}.task-summary-card__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-tertiary)}.task-summary-card__value{font-size:1.75rem;font-weight:700;line-height:1;color:var(--text-primary)}.task-summary-card--done{border-left:3px solid var(--color-success)}.task-summary-card--running{border-left:3px solid var(--accent-blue)}.task-summary-card--errors{border-left:3px solid var(--color-failed)}.task-summary-card--waiting{border-left:3px solid #94a3b8}.task-summary-card--input{border-left:3px solid var(--color-partial)}.task-table-wrap{overflow-x:auto}.task-table .td-num{text-align:right}.sortable-th{cursor:pointer;user-select:none}.sortable-th:hover{color:var(--text-secondary)}.sortable-th--active{color:var(--text-primary)}.sort-indicator{margin-left:4px;font-size:.5625rem;opacity:.5}.sortable-th--active .sort-indicator{opacity:1;color:var(--accent-blue)}.phase-breakdown{display:flex;flex-direction:column;gap:8px;margin-bottom:20px}.phase-breakdown__row{display:flex;align-items:center;gap:12px}.phase-breakdown__label{font-size:.75rem;font-weight:600;color:var(--text-tertiary);min-width:60px}.phase-breakdown__bar{flex:1;height:10px;background:#ffffff0a;border-radius:5px;overflow:hidden;display:flex}.phase-breakdown__seg{height:100%;transition:width .3s ease}.phase-breakdown__seg--done{background:var(--color-success)}.phase-breakdown__seg--running{background:var(--accent-blue)}.phase-breakdown__seg--waiting{background:#475569}.phase-breakdown__seg--failed{background:var(--color-failed)}.phase-breakdown__count{font-size:.6875rem;color:var(--text-tertiary);min-width:52px;text-align:right}@media(max-width:960px){.overall-stats__grid{grid-template-columns:repeat(3,1fr)}}@media(max-width:640px){.overall-stats__grid{grid-template-columns:repeat(2,1fr)}.convoy-detail-header__name{font-size:1rem}.convoy-selector__select{max-width:200px}}@media(max-width:480px){.overall-stats__grid{grid-template-columns:1fr}}.reliability-empty{font-size:.875rem;color:var(--text-tertiary);padding:12px 0;margin:0}.secret-leak-banner{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;background:#f59e0b1a;border:1px solid rgba(245,158,11,.3);border-radius:8px;margin-top:16px}.secret-leak-banner__icon{font-size:1.25rem;flex-shrink:0;line-height:1.4}.secret-leak-banner__text{display:flex;flex-direction:column;gap:4px}.secret-leak-banner__text strong{font-size:.875rem;font-weight:600;color:var(--color-partial)}.secret-leak-banner__text span{font-size:.8125rem;color:var(--text-secondary)}.artifact-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.75rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.timeline-filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}.timeline-filter-chip{display:inline-flex;align-items:center;padding:6px 14px;border-radius:20px;border:1px solid var(--border);background:transparent;color:var(--text-secondary);font-size:.8125rem;font-weight:500;cursor:pointer;transition:all .15s ease}.timeline-filter-chip:hover{border-color:var(--accent);color:var(--text-primary)}.timeline-filter-chip--active{background:var(--accent);border-color:var(--accent);color:#fff}.event-timeline-row{padding:12px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s ease}.event-timeline-row:hover{background:#a78bfa0d}.event-timeline-row--expanded{background:#a78bfa14}.event-timeline-row__main{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.event-timeline-ts{font-size:.8125rem;color:var(--text-secondary);min-width:140px;font-variant-numeric:tabular-nums}.event-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.6875rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.event-timeline-context{font-size:.8125rem;color:var(--text-tertiary, #6b7280);font-family:var(--font-mono, "SF Mono", "Fira Code", monospace)}.event-timeline-detail{margin-top:8px;padding:12px;background:var(--bg-card, #111118);border-radius:6px;border:1px solid var(--border)}.event-timeline-json{font-size:.75rem;color:var(--text-secondary);white-space:pre-wrap;word-break:break-all;margin:0;font-family:var(--font-mono, "SF Mono", "Fira Code", monospace);max-height:300px;overflow-y:auto}@media(max-width:640px){.event-timeline-ts{min-width:auto;font-size:.75rem}.event-timeline-row__main{gap:8px}.timeline-filter-chip{padding:4px 10px;font-size:.75rem}}.dash-btn:focus-visible,.convoy-selector__select:focus-visible,.filter-select:focus-visible,.filter-input:focus-visible,.dash-sidebar__link:focus-visible,.timeline-filter-chip:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-status-explanation{font-size:.8125rem;color:var(--text-secondary);margin-top:.25rem;margin-bottom:.5rem;font-style:italic}.view-home,.view-convoy-detail{display:flex;flex-direction:column;gap:20px}[data-view-hidden]{display:none!important}.breadcrumbs{display:flex;align-items:center;gap:6px;font-size:.8125rem;color:var(--text-tertiary);flex-wrap:wrap;padding:0;margin-bottom:-8px}.breadcrumbs__link{color:var(--text-secondary);text-decoration:none;transition:color var(--transition-fast);border-bottom:1px solid transparent}.breadcrumbs__link:hover{color:var(--text-accent);border-bottom-color:#a78bfa66}.breadcrumbs__link:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.breadcrumbs__separator{color:var(--text-tertiary);opacity:.5;user-select:none;font-size:.75rem}.breadcrumbs__current{color:var(--text-accent);font-weight:500;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.convoy-list-section{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.convoy-list-section:hover{border-color:#ffffff1a}.convoy-list-section__header{padding:20px 24px 12px;border-bottom:1px solid var(--border-color)}.convoy-list-section__header h2,.convoy-list-section__header .convoy-list-section__title{font-size:.9375rem;font-weight:600;color:var(--text-primary);margin:0}.convoy-list-section__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.convoy-list-filters{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;padding:14px 24px;background:#ffffff03;border-bottom:1px solid var(--border-color)}.convoy-list-filters__group{display:flex;flex-direction:column;gap:4px}.convoy-list-filters__group label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;font-family:inherit;transition:border-color var(--transition-fast);color-scheme:dark}.convoy-list-filters__input:focus,.convoy-list-filters__select:focus,.convoy-list-filters__date:focus{border-color:var(--border-accent)}.convoy-list-filters__input{width:180px}.convoy-list-filters__date{width:150px}.convoy-list-filters__select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.convoy-list-filters__reset{height:34px;padding:0 14px;font-size:.75rem;font-weight:500;font-family:inherit;color:var(--text-secondary);background:#ffffff0f;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast);align-self:flex-end;white-space:nowrap}.convoy-list-filters__reset:hover{background:#ffffff1a;color:var(--text-primary)}.convoy-list-filters__reset:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-list-table{width:100%;border-collapse:collapse;font-size:.8125rem}.convoy-list-table thead{position:sticky;top:0}.convoy-list-table th{padding:10px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color);white-space:nowrap}.convoy-list-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.convoy-list-table tr{cursor:pointer;transition:background var(--transition-fast)}.convoy-list-table tbody tr:hover td{background:#a78bfa0d;color:var(--text-primary)}.convoy-list-table tbody tr:hover td:first-child{color:var(--text-accent)}.convoy-list-table .td-convoy-name{font-weight:600;color:var(--text-primary);max-width:240px;overflow:hidden;text-overflow:ellipsis}.convoy-list-pagination{display:flex;align-items:center;justify-content:center;gap:12px;padding:16px 0;margin-top:4px}.convoy-list-pagination__info{font-size:.8125rem;color:var(--text-secondary);min-width:100px;text-align:center}.convoy-list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:48px 24px;text-align:center;color:var(--text-tertiary)}.convoy-list-empty__icon{font-size:2rem;opacity:.35}.convoy-list-empty__text{font-size:.875rem;color:var(--text-tertiary);max-width:300px;line-height:1.5}.convoy-detail-hero{display:flex;flex-direction:column;gap:12px;padding:24px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;position:relative}.convoy-detail-hero:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--gradient-accent);opacity:.6;pointer-events:none}.convoy-detail-hero__top{display:flex;align-items:center;gap:14px;flex-wrap:wrap;justify-content:space-between}.convoy-chain-toggle{cursor:pointer;user-select:none;font-size:.75rem;margin-right:6px;opacity:.6}.convoy-chain-row{background:#a78bfa0a}.convoy-chain-row td:first-child{font-weight:600}.convoy-chain-child td:first-child{padding-left:28px}.convoy-chain-child td:first-child:before{content:"└ ";opacity:.4}.convoy-detail-hero__title{font-size:1.5rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.25;margin:0}.convoy-detail-hero__status{flex-shrink:0}.convoy-detail-hero__status .status-badge{padding:.25rem .875rem;font-size:.75rem;border-radius:8px}.convoy-detail-hero__meta{display:flex;flex-wrap:wrap;gap:20px;padding-top:4px;border-top:1px solid var(--border-color)}.convoy-detail-hero__meta-item{display:flex;flex-direction:column;gap:2px}.convoy-detail-hero__meta-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-detail-hero__meta-value{font-size:.875rem;color:var(--text-secondary);font-variant-numeric:tabular-nums}.task-row--clickable{cursor:pointer;transition:background var(--transition-fast)}.task-row--clickable:hover td{background:#a78bfa0a}.task-row--clickable td:first-child{position:relative}.task-row--clickable td:first-child:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:transparent;transition:background var(--transition-fast)}.task-row--clickable:hover td:first-child:before{background:var(--border-accent)}.task-detail-expand{background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.task-detail-expand__inner{padding:16px 20px}.task-detail-expand__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 24px}.task-detail-expand__field{display:flex;flex-direction:column;gap:3px}.task-detail-expand__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary)}.task-detail-expand__value{font-size:.8125rem;color:var(--text-secondary);word-break:break-word;font-variant-numeric:tabular-nums}.task-detail-expand__value code{font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:.75rem;background:#ffffff0f;padding:1px 6px;border-radius:4px;color:var(--text-accent)}@media(max-width:768px){.convoy-list-filters{padding:12px 16px;gap:8px}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{width:100%;min-width:unset}.convoy-list-filters__group{flex:1 1 calc(50% - 4px)}.convoy-list-filters__reset{flex:1 1 100%;width:100%}.convoy-list-section__header{padding:16px 16px 12px}}@media(max-width:480px){.convoy-list-filters__group{flex:1 1 100%}.convoy-detail-hero__title{font-size:1.25rem}.convoy-detail-hero{padding:16px}.task-detail-expand__grid{grid-template-columns:1fr}.breadcrumbs__current{max-width:180px}}.waiting-banner{text-align:center;padding:3rem 2rem;margin-bottom:2rem;border-radius:var(--radius-lg, 12px);background:var(--bg-surface, #1e1e2e);border:1px solid var(--border-subtle, rgba(255,255,255,.06))}.waiting-banner__content{display:flex;flex-direction:column;align-items:center;gap:.75rem}.waiting-banner__spinner{width:32px;height:32px;border:3px solid var(--border-subtle, rgba(255,255,255,.1));border-top-color:var(--accent, #60a5fa);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.waiting-banner__title{font-size:1.25rem;font-weight:600;margin:0;color:var(--text-primary, #e2e8f0)}.waiting-banner__subtitle{font-size:.875rem;color:var(--text-muted, #94a3b8);margin:0}.pipeline-chain-nav{display:flex;align-items:center;gap:.5rem;padding:.5rem 0;margin-bottom:.5rem;flex-wrap:wrap}.pipeline-chain__label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted, #94a3b8);margin-right:.25rem}.pipeline-chain__item{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .625rem;font-size:.8125rem;border-radius:var(--radius-sm, 6px);border:1px solid var(--border-subtle, rgba(255,255,255,.06));background:var(--bg-surface, #1e1e2e);color:var(--text-secondary, #cbd5e1);cursor:pointer;transition:border-color .15s,background .15s}.pipeline-chain__item:hover{border-color:var(--border-hover, rgba(255,255,255,.15));background:var(--bg-hover, rgba(255,255,255,.04))}.pipeline-chain__item--active{border-color:var(--accent, #60a5fa);background:#60a5fa14;color:var(--text-primary, #e2e8f0)}.pipeline-chain__dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0}.activity-timeline{display:flex;flex-direction:column;gap:4px}