cardinal-ai 0.0.1 → 0.2.4
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.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +50 -29
- data/Rakefile +6 -0
- data/app/assets/stylesheets/application.css +10 -0
- data/app/assets/stylesheets/cardinal.css +530 -0
- data/app/controllers/application_controller.rb +7 -0
- data/app/controllers/boards_controller.rb +5 -0
- data/app/controllers/cards_controller.rb +129 -0
- data/app/controllers/columns_controller.rb +130 -0
- data/app/controllers/messages_controller.rb +25 -0
- data/app/controllers/runs_controller.rb +58 -0
- data/app/helpers/application_helper.rb +35 -0
- data/app/javascript/application.js +2 -0
- data/app/javascript/controllers/application.js +7 -0
- data/app/javascript/controllers/autosave_controller.js +43 -0
- data/app/javascript/controllers/board_column_controller.js +96 -0
- data/app/javascript/controllers/clipboard_controller.js +18 -0
- data/app/javascript/controllers/composer_controller.js +10 -0
- data/app/javascript/controllers/index.js +3 -0
- data/app/javascript/controllers/modal_controller.js +45 -0
- data/app/javascript/controllers/reveal_controller.js +15 -0
- data/app/javascript/controllers/scroll_controller.js +44 -0
- data/app/javascript/controllers/tags_controller.js +49 -0
- data/app/javascript/controllers/theme_controller.js +43 -0
- data/app/javascript/controllers/tooltip_controller.js +37 -0
- data/app/jobs/ai_task_job.rb +26 -0
- data/app/jobs/application_job.rb +7 -0
- data/app/jobs/assistant_reply_job.rb +132 -0
- data/app/jobs/mark_pr_ready_job.rb +18 -0
- data/app/jobs/merge_pr_job.rb +27 -0
- data/app/jobs/resume_run_job.rb +30 -0
- data/app/jobs/start_run_job.rb +13 -0
- data/app/mailers/application_mailer.rb +4 -0
- data/app/models/agent_session.rb +8 -0
- data/app/models/application_record.rb +3 -0
- data/app/models/artifact.rb +8 -0
- data/app/models/board.rb +92 -0
- data/app/models/card.rb +83 -0
- data/app/models/column.rb +134 -0
- data/app/models/event.rb +44 -0
- data/app/models/run.rb +28 -0
- data/app/services/agent/runner.rb +379 -0
- data/app/services/agent/workspace.rb +138 -0
- data/app/services/card_transition.rb +97 -0
- data/app/services/claude_cli.rb +89 -0
- data/app/services/rules/compiler.rb +55 -0
- data/app/services/rules.rb +92 -0
- data/app/services/run_sweeper.rb +53 -0
- data/app/views/boards/show.html.erb +79 -0
- data/app/views/cards/_card.html.erb +48 -0
- data/app/views/cards/_detail.html.erb +190 -0
- data/app/views/cards/_tag_picker.html.erb +12 -0
- data/app/views/cards/new.html.erb +35 -0
- data/app/views/cards/show.html.erb +3 -0
- data/app/views/columns/_column.html.erb +25 -0
- data/app/views/columns/edit.html.erb +146 -0
- data/app/views/events/_event.html.erb +29 -0
- data/app/views/layouts/application.html.erb +46 -0
- data/app/views/layouts/mailer.html.erb +13 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/pwa/manifest.json.erb +22 -0
- data/app/views/pwa/service-worker.js +26 -0
- data/bin/rails +4 -0
- data/bin/rake +4 -0
- data/cardinal.md +695 -0
- data/config/application.rb +60 -0
- data/config/boot.rb +13 -0
- data/config/bundler-audit.yml +5 -0
- data/config/cable.yml +13 -0
- data/config/ci.rb +20 -0
- data/config/credentials.yml.enc +1 -0
- data/config/database.yml +31 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +78 -0
- data/config/environments/production.rb +89 -0
- data/config/environments/test.rb +53 -0
- data/config/importmap.rb +6 -0
- data/config/initializers/assets.rb +7 -0
- data/config/initializers/cardinal_bootstrap.rb +12 -0
- data/config/initializers/cardinal_instance.rb +20 -0
- data/config/initializers/content_security_policy.rb +29 -0
- data/config/initializers/filter_parameter_logging.rb +8 -0
- data/config/initializers/inflections.rb +16 -0
- data/config/initializers/run_sweeper.rb +17 -0
- data/config/locales/en.yml +31 -0
- data/config/puma.rb +42 -0
- data/config/routes.rb +22 -0
- data/config/storage.yml +27 -0
- data/config.ru +6 -0
- data/db/migrate/20260703000001_create_cardinal_schema.rb +78 -0
- data/db/migrate/20260703000002_add_agent_runner_fields.rb +7 -0
- data/db/migrate/20260704000001_add_parent_to_cards.rb +5 -0
- data/db/migrate/20260704000002_add_assistant_session_to_cards.rb +5 -0
- data/db/seeds.rb +13 -0
- data/docker/agent/Dockerfile +16 -0
- data/exe/cardinal +111 -0
- data/lib/cardinal/version.rb +1 -1
- data/public/400.html +135 -0
- data/public/404.html +135 -0
- data/public/406-unsupported-browser.html +135 -0
- data/public/422.html +135 -0
- data/public/500.html +135 -0
- data/public/icon.png +0 -0
- data/public/icon.svg +3 -0
- data/public/robots.txt +1 -0
- data/vendor/javascript/sortablejs.js +3378 -0
- metadata +236 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9765ce8a3b88ca8a2d72dcdaa766d67d42b0b1f1304ce44551fb0b31a8b62f84
|
|
4
|
+
data.tar.gz: 6bbd3904403e6e91b83a684d134c15ad402a98ab27f4600d6424752033565b0b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b91c51d2d12d2df7d7d1f81b7d8547545ed68cac112f4d844dd4666626ccb34081397dc038fa4620a8b0e76e804b18c64608d96c92be657238958bf4bf3540ff
|
|
7
|
+
data.tar.gz: 1e71c84583f3c6f02b3315ce7fa4abce078117dcb47ceb13a15a1641c3a90651673db22015c63ab8c1ca2e0683c136b50ac278b695e7144d34d7f7d2bf8378fc
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jason Ellis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -1,43 +1,64 @@
|
|
|
1
|
-
# Cardinal 🐦🔥
|
|
1
|
+
# Cardinal AI 🐦🔥
|
|
2
2
|
|
|
3
3
|
**A Kanban board where dragging a card to "In Progress" hires an AI to actually do the task.**
|
|
4
4
|
|
|
5
|
-
Cardinal
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
code on its own branch, reports its progress right on the card, and asks you questions when
|
|
11
|
-
it's stuck. When it's done, you drag the card to Review, look at the pull request it made,
|
|
12
|
-
and either send it back with notes or drag it to Done — which merges the code.
|
|
5
|
+
Cardinal AI puts a board on any of your projects. You write down what needs doing, chat
|
|
6
|
+
with an assistant to sharpen the idea, and then drag the card forward — at which point an
|
|
7
|
+
AI agent picks it up, does the work on its own branch, asks you questions when it's stuck,
|
|
8
|
+
and hands you a pull request to review. Approve it, drag the card to Done, and the work is
|
|
9
|
+
merged. You never leave the board.
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
repo, and the board is how you manage them. Dragging a card left to right literally *is*
|
|
16
|
-
assigning the work, supervising it, and shipping it.
|
|
11
|
+
## What you need
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
- **Ruby 3.2 or newer** (`ruby -v` to check)
|
|
14
|
+
- **The Claude CLI**, signed in — this is the AI: `npm install -g @anthropic-ai/claude-code`, then `claude` once to log in
|
|
15
|
+
- **git**, and for pull requests the **GitHub CLI** (`gh auth login`)
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
execution columns (plan approval → work → questions back to you → draft PR), you review
|
|
22
|
-
and request changes (revision runs on the same branch), and dragging to Done squash-merges
|
|
23
|
-
the PR. Column rules, one-shot AI maintenance agents, a policy editor behind every
|
|
24
|
-
column's gear icon, run heartbeats + sweeping, and `cardinal up` for spinning a board up
|
|
25
|
-
inside any repo. PRs #2 and #3 of this very repo were written by Cardinal cards. The
|
|
26
|
-
design document — architecture, decisions, roadmap — lives in [cardinal.md](cardinal.md).
|
|
17
|
+
## Install
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
```sh
|
|
20
|
+
gem install cardinal-ai
|
|
21
|
+
```
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
No database server, no Redis, no sign-in.
|
|
23
|
+
## Use it
|
|
32
24
|
|
|
33
|
-
|
|
25
|
+
Go to any project that lives in git, and start Cardinal:
|
|
34
26
|
|
|
35
27
|
```sh
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
bin/rails server
|
|
28
|
+
cd your-project
|
|
29
|
+
cardinal
|
|
39
30
|
```
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
The first time, a browser window asks **which Claude account this board should work as** —
|
|
33
|
+
pick one, and it's remembered for this project only. Then open **http://localhost:4000**.
|
|
34
|
+
|
|
35
|
+
That's the whole setup. Now:
|
|
36
|
+
|
|
37
|
+
1. **Add a card** for something you want done, in plain English.
|
|
38
|
+
2. **Drag it to Planning** — an assistant reads your card *and your code*, then asks the
|
|
39
|
+
questions that make the task clear. Chat until it feels right.
|
|
40
|
+
3. **Drag it to In Progress** — an agent studies the repo and proposes a plan. One click
|
|
41
|
+
to approve. Then it works: you can watch its progress live on the card, and it will
|
|
42
|
+
stop and ask you if it hits a real decision.
|
|
43
|
+
4. **Review** — read the final report and the pull request. Say what's wrong in the
|
|
44
|
+
card's conversation to send it back, or approve.
|
|
45
|
+
5. **QA** — the pull request goes live for formal review on GitHub.
|
|
46
|
+
6. **Drag to Done** — the pull request merges. Shipped.
|
|
47
|
+
|
|
48
|
+
Every column has a ⚙ gear where you can change the rules — which AI model works there,
|
|
49
|
+
how many cards can run at once, spending limits, and what happens when a card arrives
|
|
50
|
+
(written in plain English; Cardinal figures out the rest).
|
|
51
|
+
|
|
52
|
+
## Good to know
|
|
53
|
+
|
|
54
|
+
- Everything Cardinal knows about a project lives in a `.cardinal/` folder inside it,
|
|
55
|
+
invisible to git. Delete the folder and Cardinal was never there.
|
|
56
|
+
- Each project's board can use a **different Claude account** (`cardinal login` to switch,
|
|
57
|
+
`cardinal logout` to unlink).
|
|
58
|
+
- Agents can only push to their own card branches — merging is always your drag.
|
|
59
|
+
- AI usage bills the Claude account you linked, the same as using Claude Code.
|
|
60
|
+
|
|
61
|
+
## For developers
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
The architecture and design history live in [cardinal.md](cardinal.md). The engine is a
|
|
64
|
+
Rails 8 app — clone, `bundle install`, `bin/rails test`. MIT licensed.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css.
|
|
3
|
+
*
|
|
4
|
+
* With Propshaft, assets are served efficiently without preprocessing steps. You can still include
|
|
5
|
+
* application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
|
|
6
|
+
* cascading order, meaning styles declared later in the document or manifest will override earlier ones,
|
|
7
|
+
* depending on specificity.
|
|
8
|
+
*
|
|
9
|
+
* Consider organizing styles into separate files for maintainability.
|
|
10
|
+
*/
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg: #16181d;
|
|
3
|
+
--surface: #1e2128;
|
|
4
|
+
--surface-2: #262a33;
|
|
5
|
+
--border: #333845;
|
|
6
|
+
--text: #d7dae0;
|
|
7
|
+
--text-dim: #8b91a0;
|
|
8
|
+
--accent: #c94f4f; /* cardinal red */
|
|
9
|
+
--amber: #d9a441;
|
|
10
|
+
--green: #5fae6f;
|
|
11
|
+
--red: #d66;
|
|
12
|
+
--blue: #6b93c9;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Light theme — light greys, dark grey text. Applied via data-theme="light"
|
|
16
|
+
on <html> (see the theme controller + head boot script). Only the palette
|
|
17
|
+
and a few hardcoded dark-specific colors below need to flip; every surface
|
|
18
|
+
drives its colors through these variables. */
|
|
19
|
+
[data-theme="light"] {
|
|
20
|
+
--bg: #eceef1;
|
|
21
|
+
--surface: #f6f7f9;
|
|
22
|
+
--surface-2: #ffffff;
|
|
23
|
+
--border: #d3d7de;
|
|
24
|
+
--text: #23262c;
|
|
25
|
+
--text-dim: #646b78;
|
|
26
|
+
--accent: #c1443f; /* cardinal red */
|
|
27
|
+
--amber: #b5791b;
|
|
28
|
+
--green: #3f8a50;
|
|
29
|
+
--red: #c23b30;
|
|
30
|
+
--blue: #4d76ad;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
* { box-sizing: border-box; }
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
margin: 0;
|
|
37
|
+
background: var(--bg);
|
|
38
|
+
color: var(--text);
|
|
39
|
+
font: 14px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
a { color: var(--blue); text-decoration: none; }
|
|
43
|
+
|
|
44
|
+
/* ── Top bar ─────────────────────────────────────────── */
|
|
45
|
+
.topbar {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
padding: 10px 18px;
|
|
50
|
+
border-bottom: 1px solid var(--border);
|
|
51
|
+
background: var(--surface);
|
|
52
|
+
}
|
|
53
|
+
.topbar h1 { font-size: 16px; margin: 0; font-weight: 600; }
|
|
54
|
+
.topbar h1 .sep { color: var(--accent); margin: 0 4px; }
|
|
55
|
+
.topbar-right { display: flex; align-items: center; gap: 14px; }
|
|
56
|
+
|
|
57
|
+
.theme-toggle {
|
|
58
|
+
background: transparent; border: 1px solid var(--border); border-radius: 6px;
|
|
59
|
+
color: var(--text-dim); font-weight: 600; padding: 5px 10px; line-height: 1;
|
|
60
|
+
}
|
|
61
|
+
.theme-toggle:hover { color: var(--text); border-color: var(--text-dim); }
|
|
62
|
+
|
|
63
|
+
.attention summary {
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
color: var(--amber);
|
|
66
|
+
font-weight: 600;
|
|
67
|
+
list-style: none;
|
|
68
|
+
}
|
|
69
|
+
.auth-chip {
|
|
70
|
+
font-size: 11px; color: var(--text-dim); border: 1px solid var(--border);
|
|
71
|
+
border-radius: 10px; padding: 2px 9px; cursor: default;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.attention { position: relative; }
|
|
75
|
+
.attention-list {
|
|
76
|
+
position: absolute; right: 0; top: 26px; z-index: 20;
|
|
77
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
|
|
78
|
+
padding: 8px 12px; margin: 0; min-width: 300px; max-height: 60vh; overflow-y: auto;
|
|
79
|
+
}
|
|
80
|
+
.attention ul { list-style: none; margin: 0 0 6px; padding: 0; }
|
|
81
|
+
.attention li { padding: 4px 0; }
|
|
82
|
+
.attn-part { margin-left: 10px; }
|
|
83
|
+
.attn-part:first-child { margin-left: 0; }
|
|
84
|
+
.attn-part.working-part { color: var(--blue); }
|
|
85
|
+
.attn-header {
|
|
86
|
+
font-size: 10px; text-transform: uppercase; letter-spacing: .07em;
|
|
87
|
+
color: var(--text-dim); margin: 8px 0 2px; font-weight: 700;
|
|
88
|
+
}
|
|
89
|
+
.attn-header:first-child { margin-top: 0; }
|
|
90
|
+
.attn-working { display: flex; align-items: center; gap: 6px; }
|
|
91
|
+
.pulse-dot {
|
|
92
|
+
display: inline-block; width: 7px; height: 7px; border-radius: 50%;
|
|
93
|
+
background: var(--blue); animation: pulse-dot 1.6s ease-in-out infinite;
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
}
|
|
96
|
+
@keyframes pulse-dot {
|
|
97
|
+
0%, 100% { opacity: .35; transform: scale(.85); }
|
|
98
|
+
50% { opacity: 1; transform: scale(1.15); }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.add-card {
|
|
102
|
+
cursor: pointer; color: var(--text-dim); font-weight: 700;
|
|
103
|
+
line-height: 1; padding: 0 4px; margin-bottom: 6px; text-decoration: none;
|
|
104
|
+
}
|
|
105
|
+
.add-card:hover { color: var(--text); }
|
|
106
|
+
|
|
107
|
+
button, input[type="submit"] {
|
|
108
|
+
background: var(--accent); color: #fff; border: 0; border-radius: 6px;
|
|
109
|
+
padding: 6px 12px; cursor: pointer; font-weight: 600;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.new-column { position: relative; }
|
|
113
|
+
.new-column summary { cursor: pointer; color: var(--text-dim); font-weight: 600; list-style: none; }
|
|
114
|
+
.new-column summary:hover { color: var(--text); }
|
|
115
|
+
.new-column-form {
|
|
116
|
+
position: absolute; right: 0; top: 28px; z-index: 20;
|
|
117
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
|
|
118
|
+
padding: 10px; display: flex; flex-direction: column; gap: 8px; min-width: 220px;
|
|
119
|
+
}
|
|
120
|
+
.new-column-form input[type="text"], .new-column-form select {
|
|
121
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
|
|
122
|
+
color: var(--text); padding: 6px 10px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* ── Board ───────────────────────────────────────────── */
|
|
126
|
+
.board {
|
|
127
|
+
display: flex;
|
|
128
|
+
gap: 12px;
|
|
129
|
+
padding: 14px;
|
|
130
|
+
align-items: stretch;
|
|
131
|
+
overflow-x: auto;
|
|
132
|
+
height: calc(100vh - 53px);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.column {
|
|
136
|
+
background: var(--surface);
|
|
137
|
+
border: 1px solid var(--border);
|
|
138
|
+
border-radius: 10px;
|
|
139
|
+
min-width: 250px;
|
|
140
|
+
width: 250px;
|
|
141
|
+
padding: 10px;
|
|
142
|
+
display: flex;
|
|
143
|
+
flex-direction: column;
|
|
144
|
+
}
|
|
145
|
+
.column-execution { background: #1c2a21; border-color: #375844; }
|
|
146
|
+
.column-review { background: #24211c; border-color: #4a4232; }
|
|
147
|
+
[data-theme="light"] .column-execution { background: #e9f3ec; border-color: #bcd8c4; }
|
|
148
|
+
[data-theme="light"] .column-review { background: #f6f1e6; border-color: #e3d7bf; }
|
|
149
|
+
.column-header { display: flex; justify-content: space-between; align-items: center; }
|
|
150
|
+
.column-title { display: flex; align-items: center; gap: 2px; }
|
|
151
|
+
.column-header h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .06em; margin: 2px 4px 8px; color: var(--text-dim); }
|
|
152
|
+
.gear { cursor: pointer; color: var(--text-dim); }
|
|
153
|
+
.drop-hint { display: none; font-size: 11px; color: var(--amber); margin: 0 4px 8px; }
|
|
154
|
+
body.dragging .drop-hint { display: block; }
|
|
155
|
+
.ticker { font-size: 11px; color: var(--text-dim); margin: 0 4px 8px; }
|
|
156
|
+
|
|
157
|
+
.cards { min-height: 40px; display: flex; flex-direction: column; gap: 8px; flex: 1; overflow-y: auto; }
|
|
158
|
+
.cards-clickable { cursor: pointer; }
|
|
159
|
+
.agent-chip { color: var(--blue); }
|
|
160
|
+
|
|
161
|
+
/* ── Cards ───────────────────────────────────────────── */
|
|
162
|
+
.card {
|
|
163
|
+
background: var(--surface-2);
|
|
164
|
+
border: 1px solid var(--border);
|
|
165
|
+
border-radius: 8px;
|
|
166
|
+
padding: 9px 10px;
|
|
167
|
+
cursor: grab;
|
|
168
|
+
}
|
|
169
|
+
.card-link { color: inherit; display: block; }
|
|
170
|
+
|
|
171
|
+
/* PR footer: the card's bottom edge is the link out to GitHub. The left
|
|
172
|
+
slot is reserved for ticket integrations (Asana/Trello). */
|
|
173
|
+
.card-footer {
|
|
174
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
175
|
+
margin: 8px -10px -9px; padding: 4px 10px 5px;
|
|
176
|
+
background: var(--bg);
|
|
177
|
+
border-top: 1px solid rgba(255, 255, 255, .09);
|
|
178
|
+
border-radius: 0 0 7px 7px;
|
|
179
|
+
font-size: 11px; color: var(--text-dim); font-weight: 600;
|
|
180
|
+
}
|
|
181
|
+
.card-footer:hover .footer-pr { color: var(--blue); }
|
|
182
|
+
.footer-left { min-width: 1px; }
|
|
183
|
+
.card-ghost { opacity: .4; }
|
|
184
|
+
.card-title { font-weight: 600; }
|
|
185
|
+
.card-number { color: var(--text-dim); font-weight: 400; }
|
|
186
|
+
.card-number-sub { color: var(--text-dim); font-weight: 400; font-size: 11px; margin-left: 6px; }
|
|
187
|
+
.status-glyph { float: right; }
|
|
188
|
+
.card-progress { margin: 5px 0 0; font-size: 12px; color: var(--text-dim); overflow: hidden; word-break: break-all; }
|
|
189
|
+
.card-meta { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 4px; }
|
|
190
|
+
.tag, .chip {
|
|
191
|
+
font-size: 11px; padding: 1px 7px; border-radius: 10px;
|
|
192
|
+
background: var(--surface); border: 1px solid var(--border); color: var(--text-dim);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* Status treatments (§6) */
|
|
196
|
+
.card.status-working { animation: breathe 2.2s ease-in-out infinite; }
|
|
197
|
+
.card.status-queued { opacity: .65; border-style: dashed; }
|
|
198
|
+
|
|
199
|
+
.working-line { color: var(--blue); }
|
|
200
|
+
.spinner {
|
|
201
|
+
display: inline-block; width: 9px; height: 9px;
|
|
202
|
+
border: 2px solid var(--blue); border-top-color: transparent; border-radius: 50%;
|
|
203
|
+
animation: spin 0.9s linear infinite; vertical-align: -1px;
|
|
204
|
+
}
|
|
205
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
206
|
+
.card.status-needs_input { border-color: var(--amber); box-shadow: 0 0 0 1px var(--amber); }
|
|
207
|
+
.card.status-needs_input .attention-text { color: var(--amber); font-weight: 600; }
|
|
208
|
+
.card.status-blocked, .card.status-failed { border-color: var(--red); }
|
|
209
|
+
.card.status-failed .attention-text { color: var(--red); font-weight: 600; }
|
|
210
|
+
.card.status-work_complete { border-color: var(--green); }
|
|
211
|
+
.card.status-work_complete .attention-text { color: var(--green); font-weight: 600; }
|
|
212
|
+
.card.status-in_review { border-color: var(--blue); }
|
|
213
|
+
.card.status-approved { border-color: var(--green); box-shadow: 0 0 0 1px var(--green); }
|
|
214
|
+
.card.status-approved .approved-text { color: var(--green); font-weight: 600; }
|
|
215
|
+
.card.status-changes_requested { border-color: var(--amber); border-style: dashed; }
|
|
216
|
+
.card.status-done, .card.status-archived { opacity: .55; }
|
|
217
|
+
|
|
218
|
+
@keyframes breathe {
|
|
219
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(107, 147, 201, 0); border-color: var(--border); }
|
|
220
|
+
50% { box-shadow: 0 0 0 3px rgba(107, 147, 201, .3); border-color: var(--blue); }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Bounce-back on a move the destination's accept policy forbids (card #15) */
|
|
224
|
+
.card.move-rejected { animation: reject-flash 0.6s ease; }
|
|
225
|
+
@keyframes reject-flash {
|
|
226
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(201, 107, 107, 0); border-color: var(--border); }
|
|
227
|
+
15%, 55% { box-shadow: 0 0 0 3px rgba(201, 107, 107, .45); border-color: var(--red); }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* ── Card modal ──────────────────────────────────────── */
|
|
231
|
+
.modal-backdrop {
|
|
232
|
+
position: fixed; inset: 0; z-index: 50;
|
|
233
|
+
background: rgba(0, 0, 0, .6);
|
|
234
|
+
display: flex; align-items: center; justify-content: center;
|
|
235
|
+
padding: 3vh 3vw;
|
|
236
|
+
}
|
|
237
|
+
.modal {
|
|
238
|
+
background: var(--bg);
|
|
239
|
+
border: 1px solid var(--border);
|
|
240
|
+
border-radius: 12px;
|
|
241
|
+
width: 100%; height: 100%;
|
|
242
|
+
display: flex; flex-direction: column;
|
|
243
|
+
overflow: hidden;
|
|
244
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
|
|
245
|
+
}
|
|
246
|
+
[data-theme="light"] .modal { box-shadow: 0 20px 60px rgba(0, 0, 0, .18); }
|
|
247
|
+
.modal-header {
|
|
248
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
249
|
+
padding: 14px 18px; border-bottom: 1px solid var(--border);
|
|
250
|
+
background: var(--surface); border-radius: 12px 12px 0 0;
|
|
251
|
+
flex-shrink: 0;
|
|
252
|
+
}
|
|
253
|
+
.modal-body { overflow-y: auto; }
|
|
254
|
+
.modal-header h1 { font-size: 17px; margin: 0; font-weight: 600; }
|
|
255
|
+
.modal-header-right { display: flex; align-items: center; gap: 14px; }
|
|
256
|
+
.modal-close {
|
|
257
|
+
background: var(--surface-2); color: var(--text-dim);
|
|
258
|
+
font-size: 15px; line-height: 1; padding: 7px 10px;
|
|
259
|
+
}
|
|
260
|
+
.modal-close:hover { color: var(--text); }
|
|
261
|
+
.modal-sm { max-width: 580px; height: auto; max-height: 88vh; }
|
|
262
|
+
.modal-body { padding: 16px 18px; }
|
|
263
|
+
.modal-body h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin: 16px 0 6px; }
|
|
264
|
+
.modal pre {
|
|
265
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
|
|
266
|
+
padding: 10px 12px; font-size: 12px; overflow-x: auto; color: var(--text);
|
|
267
|
+
}
|
|
268
|
+
.git-line { margin: 0; font-size: 12px; color: var(--text-dim); display: inline-flex; align-items: center; gap: 6px; }
|
|
269
|
+
.branch-base { font-family: ui-monospace, monospace; }
|
|
270
|
+
.git-arrow { color: var(--text-dim); }
|
|
271
|
+
.branch-pill {
|
|
272
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
273
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: 6px;
|
|
274
|
+
padding: 2px 4px 2px 8px;
|
|
275
|
+
}
|
|
276
|
+
.branch-pill code { font-size: 12px; font-family: ui-monospace, monospace; color: var(--text); }
|
|
277
|
+
.copy-btn {
|
|
278
|
+
background: none; border: 0; color: var(--text-dim); cursor: pointer;
|
|
279
|
+
font-size: 12px; padding: 0 4px; border-radius: 4px;
|
|
280
|
+
}
|
|
281
|
+
.copy-btn:hover { color: var(--text); background: var(--surface); }
|
|
282
|
+
.copy-btn.copied { color: var(--green); }
|
|
283
|
+
.pr-link { font-weight: 700; }
|
|
284
|
+
.pr-state { font-size: 11px; }
|
|
285
|
+
.status-chip { margin-left: 8px; }
|
|
286
|
+
|
|
287
|
+
.card-edit { display: flex; flex-direction: column; gap: 4px; margin-bottom: 18px; }
|
|
288
|
+
.card-edit label { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin-top: 6px; }
|
|
289
|
+
.card-edit .hint { text-transform: none; letter-spacing: 0; }
|
|
290
|
+
.card-edit input[type="text"], .card-edit textarea {
|
|
291
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: 6px;
|
|
292
|
+
color: var(--text); padding: 6px 10px; font: inherit;
|
|
293
|
+
}
|
|
294
|
+
.card-edit input[type="submit"] { margin-top: 10px; align-self: flex-end; }
|
|
295
|
+
.card-edit .locked-field { margin: 4px 0 0; font-size: 12px; word-break: break-all; }
|
|
296
|
+
.card-edit .locked-field code { font-family: ui-monospace, monospace; color: var(--text); }
|
|
297
|
+
.card-edit-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 10px; }
|
|
298
|
+
.card-edit-actions input[type="submit"] { margin-top: 0; }
|
|
299
|
+
.btn-cancel { background: transparent; color: var(--text-dim); border: 1px solid var(--border); }
|
|
300
|
+
.btn-cancel:hover { color: var(--text); border-color: var(--text-dim); }
|
|
301
|
+
|
|
302
|
+
.related-list { list-style: none; margin: 0 0 8px; padding: 0; font-size: 13px; }
|
|
303
|
+
.related-list li { padding: 3px 0; }
|
|
304
|
+
.child-card-link { display: inline-block; font-size: 12px; color: var(--text-dim); margin-bottom: 14px; }
|
|
305
|
+
.child-card-link:hover { color: var(--text); }
|
|
306
|
+
|
|
307
|
+
.tag-chips { display: flex; flex-wrap: wrap; gap: 5px; margin: 2px 0 6px; }
|
|
308
|
+
.tag-chip {
|
|
309
|
+
font-size: 11px; padding: 2px 9px; border-radius: 10px; cursor: pointer;
|
|
310
|
+
background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
|
|
311
|
+
font-weight: 400;
|
|
312
|
+
}
|
|
313
|
+
.tag-chip.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
|
|
314
|
+
.new-tag-input {
|
|
315
|
+
background: var(--surface-2); border: 1px dashed var(--border); border-radius: 6px;
|
|
316
|
+
color: var(--text); padding: 4px 10px; font-size: 12px; width: 100%;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.detail-panes { display: flex; gap: 16px; padding: 16px; flex: 1; min-height: 0; }
|
|
320
|
+
.timeline { flex: 2; display: flex; flex-direction: column; min-height: 0; position: relative; }
|
|
321
|
+
|
|
322
|
+
.new-messages-pill {
|
|
323
|
+
display: none;
|
|
324
|
+
position: absolute; left: 50%; bottom: 78px; transform: translateX(-50%);
|
|
325
|
+
z-index: 10; padding: 5px 14px; border-radius: 14px;
|
|
326
|
+
background: var(--blue); color: #fff; font-size: 12px; font-weight: 600;
|
|
327
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, .4); cursor: pointer; border: 0;
|
|
328
|
+
}
|
|
329
|
+
.new-messages-pill.visible { display: block; }
|
|
330
|
+
.timeline-scroll { flex: 1; overflow-y: auto; min-height: 0; padding-right: 6px; }
|
|
331
|
+
.work-panel {
|
|
332
|
+
flex: 1; background: var(--surface); border: 1px solid var(--border);
|
|
333
|
+
border-radius: 10px; padding: 12px 14px; overflow-y: auto;
|
|
334
|
+
}
|
|
335
|
+
.work-panel h3 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; color: var(--text-dim); }
|
|
336
|
+
|
|
337
|
+
.zoom-tabs { display: flex; gap: 4px; margin-bottom: 12px; }
|
|
338
|
+
.zoom-tabs a { padding: 4px 12px; border-radius: 6px; color: var(--text-dim); }
|
|
339
|
+
.zoom-tabs a.active { background: var(--surface-2); color: var(--text); }
|
|
340
|
+
|
|
341
|
+
.event { display: flex; gap: 10px; padding: 8px 4px; border-bottom: 1px solid var(--surface-2); }
|
|
342
|
+
|
|
343
|
+
/* Column moves are chapter markers in the card's story */
|
|
344
|
+
.stage-divider {
|
|
345
|
+
display: flex; align-items: center; gap: 10px;
|
|
346
|
+
margin: 18px 0 8px; color: var(--accent);
|
|
347
|
+
font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
|
|
348
|
+
}
|
|
349
|
+
.stage-divider::before, .stage-divider::after {
|
|
350
|
+
content: ""; flex: 1; height: 1px; background: var(--border);
|
|
351
|
+
}
|
|
352
|
+
.stage-divider time { color: var(--text-dim); font-weight: 400; letter-spacing: 0; text-transform: none; }
|
|
353
|
+
|
|
354
|
+
/* A move the accept policy blocked — logged but never happened (card #15) */
|
|
355
|
+
.move-rejected-row {
|
|
356
|
+
display: flex; align-items: center; gap: 10px;
|
|
357
|
+
margin: 10px 0; padding: 4px 8px;
|
|
358
|
+
border-left: 2px solid var(--red); border-radius: 3px;
|
|
359
|
+
background: rgba(201, 107, 107, .08); color: var(--red); font-size: 12px;
|
|
360
|
+
}
|
|
361
|
+
.move-rejected-row time { margin-left: auto; color: var(--text-dim); }
|
|
362
|
+
.event-actor { width: 22px; text-align: center; }
|
|
363
|
+
.event-body { flex: 1; }
|
|
364
|
+
.event-body p { margin: 0 0 4px; }
|
|
365
|
+
.event-body time { font-size: 11px; color: var(--text-dim); }
|
|
366
|
+
|
|
367
|
+
/* Markdown inside timeline events */
|
|
368
|
+
.event-body h1, .event-body h2, .event-body h3 {
|
|
369
|
+
font-size: 13px; margin: 12px 0 4px; color: var(--text);
|
|
370
|
+
text-transform: uppercase; letter-spacing: .04em;
|
|
371
|
+
}
|
|
372
|
+
.event-body ul, .event-body ol { margin: 4px 0 8px 20px; padding: 0; }
|
|
373
|
+
.event-body li { margin: 2px 0; }
|
|
374
|
+
.event-body code {
|
|
375
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 4px;
|
|
376
|
+
padding: 0 4px; font-size: 12px; font-family: ui-monospace, monospace;
|
|
377
|
+
}
|
|
378
|
+
.event-body pre {
|
|
379
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
|
|
380
|
+
padding: 8px 10px; overflow-x: auto; margin: 6px 0 8px;
|
|
381
|
+
}
|
|
382
|
+
.event-body pre code { background: none; border: 0; padding: 0; }
|
|
383
|
+
.event-body blockquote {
|
|
384
|
+
margin: 6px 0; padding: 2px 10px; border-left: 2px solid var(--border);
|
|
385
|
+
color: var(--text-dim);
|
|
386
|
+
}
|
|
387
|
+
.event-body table { border-collapse: collapse; margin: 6px 0; font-size: 12px; }
|
|
388
|
+
.event-body th, .event-body td { border: 1px solid var(--border); padding: 3px 8px; }
|
|
389
|
+
.event-kind { color: var(--text-dim); font-size: 12px; }
|
|
390
|
+
.event-description {
|
|
391
|
+
display: block; /* .event is flex for icon+body; raw markdown children must stack */
|
|
392
|
+
background: var(--surface); border-radius: 8px; border-bottom: 0; padding: 10px 12px;
|
|
393
|
+
}
|
|
394
|
+
.actor-agent .event-body p { color: #b9c3d8; }
|
|
395
|
+
[data-theme="light"] .actor-agent .event-body p { color: #3a4a63; }
|
|
396
|
+
|
|
397
|
+
.empty { color: var(--text-dim); font-style: italic; }
|
|
398
|
+
|
|
399
|
+
/* AI typing indicator */
|
|
400
|
+
.event.typing { border-bottom: 0; }
|
|
401
|
+
.typing-dots { display: inline-flex; gap: 4px; padding: 8px 2px; align-items: center; }
|
|
402
|
+
.typing-dots span {
|
|
403
|
+
width: 6px; height: 6px; border-radius: 50%;
|
|
404
|
+
background: var(--text-dim); animation: typing-blink 1.2s infinite;
|
|
405
|
+
}
|
|
406
|
+
.typing-dots span:nth-child(2) { animation-delay: .2s; }
|
|
407
|
+
.typing-dots span:nth-child(3) { animation-delay: .4s; }
|
|
408
|
+
.typing-dots.mini { padding: 0 1px; gap: 3px; }
|
|
409
|
+
.typing-dots.mini span { width: 4px; height: 4px; }
|
|
410
|
+
.thinking-chip { display: inline-flex; align-items: center; gap: 3px; }
|
|
411
|
+
@keyframes typing-blink {
|
|
412
|
+
0%, 80%, 100% { opacity: .25; }
|
|
413
|
+
40% { opacity: 1; }
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.message-form { display: flex; gap: 8px; margin-top: 12px; align-items: flex-end; flex-shrink: 0; }
|
|
417
|
+
.message-form textarea {
|
|
418
|
+
flex: 1; background: var(--surface-2); border: 1px solid var(--border);
|
|
419
|
+
border-radius: 8px; color: var(--text); padding: 8px 10px; font: inherit; resize: vertical;
|
|
420
|
+
}
|
|
421
|
+
.actor-assistant .event-body p { color: #d8cfc0; }
|
|
422
|
+
[data-theme="light"] .actor-assistant .event-body p { color: #5a4e3c; }
|
|
423
|
+
|
|
424
|
+
.run-list { list-style: none; padding: 0; margin: 0 0 10px; }
|
|
425
|
+
.run-list .run { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--surface-2); font-size: 13px; }
|
|
426
|
+
.run-running { color: var(--blue); }
|
|
427
|
+
.run-succeeded { color: var(--green); }
|
|
428
|
+
.run-failed, .run-cancelled { color: var(--red); }
|
|
429
|
+
.cancel-btn { font-size: 11px; padding: 3px 8px; background: var(--red); }
|
|
430
|
+
.event-final_report .event-body { background: rgba(95, 174, 111, .07); border-radius: 8px; padding: 8px 10px; }
|
|
431
|
+
.event-plan_proposed .event-body { background: rgba(107, 147, 201, .08); border-radius: 8px; padding: 8px 10px; }
|
|
432
|
+
.event-question .event-body { background: rgba(217, 164, 65, .1); border-radius: 8px; padding: 8px 10px; }
|
|
433
|
+
.event-error .event-body { background: rgba(214, 102, 102, .08); border-radius: 8px; padding: 8px 10px; }
|
|
434
|
+
.event-error .event-body > p:first-of-type { color: var(--red); }
|
|
435
|
+
.error-detail summary { font-size: 11px; color: var(--text-dim); cursor: pointer; }
|
|
436
|
+
.error-detail pre {
|
|
437
|
+
font-size: 11px; max-height: 180px; overflow: auto;
|
|
438
|
+
white-space: pre-wrap; overflow-wrap: anywhere;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.panel-callout { border-radius: 8px; padding: 10px 12px; margin-bottom: 12px; font-size: 13px; }
|
|
442
|
+
.panel-callout p { margin: 0 0 8px; }
|
|
443
|
+
.callout-plan { border: 1px solid var(--blue); background: rgba(107, 147, 201, .08); }
|
|
444
|
+
.callout-question { border: 1px solid var(--amber); background: rgba(217, 164, 65, .08); }
|
|
445
|
+
.callout-restart { border: 1px solid var(--accent); background: rgba(201, 79, 79, .08); }
|
|
446
|
+
.approve-btn { background: var(--green); }
|
|
447
|
+
.pr-view-btn {
|
|
448
|
+
display: block; width: 100%; box-sizing: border-box; text-align: center;
|
|
449
|
+
background: var(--green); color: #fff; border-radius: 6px;
|
|
450
|
+
padding: 8px 12px; font-weight: 600; margin-bottom: 12px;
|
|
451
|
+
}
|
|
452
|
+
.restart-btn { background: var(--accent); }
|
|
453
|
+
.align-right { display: flex; justify-content: flex-end; }
|
|
454
|
+
.autosave-status { font-size: 11px; color: var(--green); text-transform: none; letter-spacing: 0; margin-left: 6px; }
|
|
455
|
+
|
|
456
|
+
.field-row { display: flex; gap: 10px; }
|
|
457
|
+
.field-row > div { flex: 1; display: flex; flex-direction: column; gap: 4px; }
|
|
458
|
+
.field-row input, .field-row select {
|
|
459
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: 6px;
|
|
460
|
+
color: var(--text); padding: 6px 10px; width: 100%;
|
|
461
|
+
}
|
|
462
|
+
.check-row { display: flex; align-items: center; gap: 8px; margin: 10px 0; font-size: 13px; color: var(--text); text-transform: none; letter-spacing: 0; }
|
|
463
|
+
.mono { font-family: ui-monospace, monospace; font-size: 12px; }
|
|
464
|
+
.form-error { color: var(--red); font-size: 13px; }
|
|
465
|
+
.delete-column { margin-top: 6px; }
|
|
466
|
+
.color-cell { flex: 0 0 auto !important; }
|
|
467
|
+
.color-row { display: flex; align-items: center; gap: 6px; }
|
|
468
|
+
.color-row input[type="color"] {
|
|
469
|
+
width: 42px; height: 30px; padding: 2px; border: 1px solid var(--border);
|
|
470
|
+
border-radius: 6px; background: var(--surface-2); cursor: pointer;
|
|
471
|
+
}
|
|
472
|
+
.check-row.inline { margin: 0; font-size: 12px; color: var(--text-dim); display: flex; gap: 4px; }
|
|
473
|
+
.accepts-from { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 4px 0 6px; }
|
|
474
|
+
.panel-advanced { margin-top: 18px; border-top: 1px solid var(--surface-2); padding-top: 10px; }
|
|
475
|
+
.delete-card { margin: 4px 0 16px; opacity: .7; }
|
|
476
|
+
.delete-card:hover { opacity: 1; }
|
|
477
|
+
.delete-card[disabled] { opacity: .3; cursor: not-allowed; }
|
|
478
|
+
.default-rule {
|
|
479
|
+
font-size: 12px; color: var(--text-dim); margin: 2px 0 6px;
|
|
480
|
+
padding: 7px 10px; background: var(--surface); border-left: 2px solid var(--accent);
|
|
481
|
+
border-radius: 0 6px 6px 0; text-transform: none; letter-spacing: 0;
|
|
482
|
+
}
|
|
483
|
+
.advanced-rules { margin: 8px 0; }
|
|
484
|
+
.advanced-rules summary { cursor: pointer; font-size: 12px; color: var(--text-dim); }
|
|
485
|
+
.advanced-rules textarea { width: 100%; }
|
|
486
|
+
|
|
487
|
+
/* (i) tooltips */
|
|
488
|
+
.info {
|
|
489
|
+
cursor: help; position: relative; display: inline-flex;
|
|
490
|
+
align-items: center; justify-content: center;
|
|
491
|
+
width: 14px; height: 14px; margin-left: 5px;
|
|
492
|
+
border: 1px solid var(--border); border-radius: 50%;
|
|
493
|
+
color: var(--text-dim); font-size: 10px; font-style: italic; font-weight: 600;
|
|
494
|
+
text-transform: none; vertical-align: middle;
|
|
495
|
+
}
|
|
496
|
+
.info:hover, .info:focus { color: var(--text); border-color: var(--text-dim); outline: none; }
|
|
497
|
+
|
|
498
|
+
.tooltip-pop {
|
|
499
|
+
position: fixed; z-index: 100; max-width: 260px;
|
|
500
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
|
|
501
|
+
padding: 8px 10px; color: var(--text);
|
|
502
|
+
font-size: 12px; font-style: normal; font-weight: 400;
|
|
503
|
+
letter-spacing: 0; text-transform: none; line-height: 1.4; white-space: normal;
|
|
504
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, .4);
|
|
505
|
+
pointer-events: none;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* Light overrides for components added on main after the theme branch was cut */
|
|
509
|
+
[data-theme="light"] .card-footer { background: #e2e5ea; border-top-color: rgba(0, 0, 0, .1); }
|
|
510
|
+
|
|
511
|
+
/* Accept-policy visibility while dragging + rejected-drop flash */
|
|
512
|
+
.column.drop-blocked { opacity: .35; filter: grayscale(.5) brightness(.7); transition: opacity .15s, filter .15s; }
|
|
513
|
+
.column.drop-blocked .drop-hint { color: var(--red); }
|
|
514
|
+
.column.drop-blocked .drop-hint::before { content: "✗ won't accept from here — "; }
|
|
515
|
+
|
|
516
|
+
.hidden { display: none !important; }
|
|
517
|
+
|
|
518
|
+
/* The reveal wrappers must be invisible to the form's flex layout — their
|
|
519
|
+
children should behave as direct .card-edit flex items (full width). */
|
|
520
|
+
.card-edit [data-controller="reveal"],
|
|
521
|
+
.card-edit [data-reveal-target="panel"] { display: contents; }
|
|
522
|
+
.card-edit textarea, .card-edit input[type="text"] { width: 100%; }
|
|
523
|
+
|
|
524
|
+
.default-rule.active-rule { border-left-color: var(--green); }
|
|
525
|
+
|
|
526
|
+
.archetype-locked {
|
|
527
|
+
font-size: 13px; color: var(--text-dim); margin: 0;
|
|
528
|
+
padding: 6px 10px; background: var(--surface-2);
|
|
529
|
+
border: 1px solid var(--border); border-radius: 6px;
|
|
530
|
+
}
|