devaanand commited on
Commit
3967e32
·
1 Parent(s): e360d80

feat(ui): drop the dark banner; the sidebar is the chrome now

Browse files

"Every modern website doesn't have an explicit header these days, ours looks
old school" (2026-09-15). The banner sat on every screen, carried the
product's full name, and cost vertical space on a phone to say something the
landing page already says.

The dashboard now has no top chrome at all, the way ChatGPT and Claude have
none: the sidebar holds the logo, the guides, the admin link and the account,
and the content area starts at the content. The landing page and /admin have
no sidebar, so they keep a bar, but a light and quiet one with no tagline. The
three static doc pages get the same treatment, and their inline logo strokes
with currentColor, which is what lets one mark serve both their light and dark
themes.

Two things this forced, both right anyway. The dashboard became a real app
shell (100vh, each pane scrolling inside it): stretched by a long page, the
sidebar's account row and New project button had drifted to the bottom of the
document instead of sitting at the bottom of the rail. And the project's
Archive/Delete pair stopped stacking into a ragged column on phones, which was
already true before but invisible under the banner.

The tagline stays where it explains something: the landing hero and the
footer. The operator identity Safe Browsing reads is in index.html's meta tags
and noscript block (da069b3), not the banner, so this does not touch it.

Verified at 1280 and 390 px: no horizontal overflow on the landing page, the
dashboard, /admin or the guides; the main pane scrolls while the rail stays
put; modals still sit above the bounded shell; and the guide reads correctly
in both light and dark.

CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ Format: [Keep a Changelog](https://keepachangelog.com/). User-visible changes on
5
  ## [Unreleased]
6
 
7
  ### Changed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  - The project sidebar closes, the way it does in ChatGPT and Claude (asked for
9
  2026-09-15). A panel button at the left of the header hides and shows it, and
10
  the choice is remembered between visits. On a phone the sidebar is now a
 
5
  ## [Unreleased]
6
 
7
  ### Changed
8
+ - The dark banner is gone. It sat on every screen carrying the product's full
9
+ name, and it made the app look older than it is (2026-09-15). The dashboard
10
+ now has no top chrome at all: the sidebar is the chrome, as in ChatGPT and
11
+ Claude, and it holds the logo, the guides, the admin link and the account.
12
+ The two views with no sidebar, the landing page and /admin, get a light,
13
+ quiet top line instead, and so do the guide and how-it-works pages, whose
14
+ logo now takes the colour of the page and so works in dark mode. The
15
+ dashboard also became a proper app shell: it fills the window and the two
16
+ panes scroll inside it, so the account row and "New project" stay put
17
+ instead of drifting to the bottom of a long page.
18
+ - "Psychological Text Analysis with Contextualized Construct Representation" no
19
+ longer appears in the chrome of every page. It is a description of the
20
+ product, so it belongs on the landing page and in the footer, which still
21
+ carry it along with the lab's name. Nothing changed in the served HTML that
22
+ identifies the operator to crawlers and link scanners.
23
  - The project sidebar closes, the way it does in ChatGPT and Claude (asked for
24
  2026-09-15). A panel button at the left of the header hides and shows it, and
25
  the choice is remembered between visits. On a phone the sidebar is now a
DECISIONS.md CHANGED
@@ -258,3 +258,16 @@ currently "Anand, D., & Atari, M." with the lab as publisher - developer first,
258
  That is a credit decision, not a code one; Mohammad should confirm it before the button is
259
  announced. Revisit: a tagged release or a Zenodo DOI would give the citation a version and
260
  a DOI of its own, which is the usual way to make research software citable.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  That is a credit decision, not a code one; Mohammad should confirm it before the button is
259
  announced. Revisit: a tagged release or a Zenodo DOI would give the citation a version and
260
  a DOI of its own, which is the usual way to make research software citable.
261
+
262
+ ## 2026-09-15 - No top chrome on the dashboard; the sidebar is the chrome (Deva)
263
+ The dark banner came off every screen. The dashboard is now an app shell (100vh, panes
264
+ scrolling inside) with the identity, navigation and account in the sidebar; the landing
265
+ page, /admin and the three static doc pages get a light sticky top line. The product's
266
+ full name leaves the chrome entirely and stays where it explains something: the landing
267
+ hero and the footer. Rejected: keeping a slim branded bar everywhere (it is the thing
268
+ that reads as dated, and it costs vertical space on a phone on every screen). Safe: the
269
+ operator identity that Safe Browsing cares about lives in index.html's meta tags and
270
+ <noscript> block (da069b3), not in the banner, so removing the banner does not touch it.
271
+ The static pages' inline logo now strokes with currentColor, which is what lets one mark
272
+ serve both their light and dark themes. Revisit: when the React app gets dark mode, the
273
+ same trick replaces ccr-logo-white.svg with a single currentColor mark.
backend/app/guide.html CHANGED
@@ -27,30 +27,29 @@
27
  /* Topbar mirrors the app header EXACTLY (gradient, height, logo size,
28
  tagline, link styles) so navigating app <-> docs doesn't jump. Update
29
  styles.css .header alongside any change here. */
 
 
 
30
  .topbar {
31
- background: linear-gradient(180deg, #1b1b1c, var(--brand)); color: #fff;
32
- padding: 14px 28px;
33
- display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
34
  position: sticky; top: 0; z-index: 30;
35
- border-bottom: 1px solid rgba(255,255,255,.07);
36
  }
37
  .topbar .brand { display: inline-flex; align-items: center; text-decoration: none; }
38
  .brand-logo { height: 28px; width: auto; display: block; }
39
  .topbar .brand:hover { opacity: .88; }
40
- .topbar .lab {
41
- flex: 1 1 280px; min-width: 0; font-size: 12.5px; line-height: 1.5;
42
- color: #fff; opacity: .85;
43
- }
44
- .topbar nav { margin-left: auto; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
45
- .topbar nav a { color: rgba(255,255,255,.82); text-decoration: none; font-size: 13px; }
46
- .topbar nav a:hover { color: #fff; text-decoration: underline; }
47
- .topbar nav a.current { color: #fff; font-weight: 600; }
48
  .topbar .topbar-btn {
49
- background: rgba(255,255,255,.12); color: #fff;
50
- border: 1px solid rgba(255,255,255,.45);
51
- padding: 5px 14px; border-radius: 9px; font-size: 13px; text-decoration: none;
52
  }
53
- .topbar .topbar-btn:hover { background: rgba(255,255,255,.22); text-decoration: none; }
54
  main { max-width: 860px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
55
  h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
56
  h2 { font-size: 1.25rem; margin: 2.2rem 0 .6rem; padding-top: .6rem; border-top: 1px solid var(--border); }
@@ -111,7 +110,7 @@
111
  <body>
112
  <header class="topbar">
113
  <a class="brand" href="/"><svg class="brand-logo" viewBox="188 455 880 338" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
114
- <g fill="none" stroke="#fff" stroke-width="32">
115
  <path d="M 458.884 538.509 A 133 133 0 1 0 458.884 709.491"/>
116
  <path d="M 563.116 538.509 A 133 133 0 0 1 766.884 538.509"/>
117
  <path d="M 563.116 709.491 A 133 133 0 0 0 766.884 709.491"/>
@@ -121,7 +120,6 @@
121
  <circle cx="481" cy="624" r="15" fill="#339B98"/>
122
  <circle cx="538" cy="624" r="15" fill="#339B98"/>
123
  </svg></a>
124
- <span class="lab">Psychological Text Analysis with Contextualized Construct Representation</span>
125
  <nav>
126
  <a href="/welcome">About</a>
127
  <a href="/guide">Guide</a>
 
27
  /* Topbar mirrors the app header EXACTLY (gradient, height, logo size,
28
  tagline, link styles) so navigating app <-> docs doesn't jump. Update
29
  styles.css .header alongside any change here. */
30
+ /* Light, quiet bar - the dark banner (and the product's full name inside it)
31
+ came off every screen on 2026-09-15. Tokens, not fixed colours, so this
32
+ follows the page into dark mode. */
33
  .topbar {
34
+ background: var(--bg); color: var(--fg);
35
+ padding: 12px 24px;
36
+ display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
37
  position: sticky; top: 0; z-index: 30;
38
+ border-bottom: 1px solid var(--border);
39
  }
40
  .topbar .brand { display: inline-flex; align-items: center; text-decoration: none; }
41
  .brand-logo { height: 28px; width: auto; display: block; }
42
  .topbar .brand:hover { opacity: .88; }
43
+ .topbar nav { margin-left: auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
44
+ .topbar nav a { color: var(--muted); text-decoration: none; font-size: 13.5px; }
45
+ .topbar nav a:hover { color: var(--fg); }
46
+ .topbar nav a.current { color: var(--fg); font-weight: 600; }
 
 
 
 
47
  .topbar .topbar-btn {
48
+ background: var(--accent); color: var(--bg); border: 0;
49
+ padding: 8px 15px; border-radius: 9px; font-size: 13px; font-weight: 600;
50
+ text-decoration: none; line-height: 1;
51
  }
52
+ .topbar .topbar-btn:hover { filter: brightness(1.08); text-decoration: none; }
53
  main { max-width: 860px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
54
  h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
55
  h2 { font-size: 1.25rem; margin: 2.2rem 0 .6rem; padding-top: .6rem; border-top: 1px solid var(--border); }
 
110
  <body>
111
  <header class="topbar">
112
  <a class="brand" href="/"><svg class="brand-logo" viewBox="188 455 880 338" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
113
+ <g fill="none" stroke="currentColor" stroke-width="32">
114
  <path d="M 458.884 538.509 A 133 133 0 1 0 458.884 709.491"/>
115
  <path d="M 563.116 538.509 A 133 133 0 0 1 766.884 538.509"/>
116
  <path d="M 563.116 709.491 A 133 133 0 0 0 766.884 709.491"/>
 
120
  <circle cx="481" cy="624" r="15" fill="#339B98"/>
121
  <circle cx="538" cy="624" r="15" fill="#339B98"/>
122
  </svg></a>
 
123
  <nav>
124
  <a href="/welcome">About</a>
125
  <a href="/guide">Guide</a>
backend/app/product.html CHANGED
@@ -26,30 +26,29 @@
26
  /* Topbar mirrors the app header EXACTLY (gradient, height, logo size,
27
  tagline, link styles) so navigating app <-> docs doesn't jump. Update
28
  styles.css .header alongside any change here. */
 
 
 
29
  .topbar {
30
- background: linear-gradient(180deg, #1b1b1c, var(--brand)); color: #fff;
31
- padding: 14px 28px;
32
- display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
33
  position: sticky; top: 0; z-index: 30;
34
- border-bottom: 1px solid rgba(255,255,255,.07);
35
  }
36
  .topbar .brand { display: inline-flex; align-items: center; text-decoration: none; }
37
  .brand-logo { height: 28px; width: auto; display: block; }
38
  .topbar .brand:hover { opacity: .88; }
39
- .topbar .lab {
40
- flex: 1 1 280px; min-width: 0; font-size: 12.5px; line-height: 1.5;
41
- color: #fff; opacity: .85;
42
- }
43
- .topbar nav { margin-left: auto; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
44
- .topbar nav a { color: rgba(255,255,255,.82); text-decoration: none; font-size: 13px; }
45
- .topbar nav a:hover { color: #fff; text-decoration: underline; }
46
- .topbar nav a.current { color: #fff; font-weight: 600; }
47
  .topbar .topbar-btn {
48
- background: rgba(255,255,255,.12); color: #fff;
49
- border: 1px solid rgba(255,255,255,.45);
50
- padding: 5px 14px; border-radius: 9px; font-size: 13px; text-decoration: none;
51
  }
52
- .topbar .topbar-btn:hover { background: rgba(255,255,255,.22); text-decoration: none; }
53
  main { max-width: 860px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
54
  h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
55
  h2 { font-size: 1.25rem; margin: 2.2rem 0 .6rem; padding-top: .6rem; border-top: 1px solid var(--border); }
@@ -109,7 +108,7 @@
109
  <body>
110
  <header class="topbar">
111
  <a class="brand" href="/"><svg class="brand-logo" viewBox="188 455 880 338" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
112
- <g fill="none" stroke="#fff" stroke-width="32">
113
  <path d="M 458.884 538.509 A 133 133 0 1 0 458.884 709.491"/>
114
  <path d="M 563.116 538.509 A 133 133 0 0 1 766.884 538.509"/>
115
  <path d="M 563.116 709.491 A 133 133 0 0 0 766.884 709.491"/>
@@ -119,7 +118,6 @@
119
  <circle cx="481" cy="624" r="15" fill="#339B98"/>
120
  <circle cx="538" cy="624" r="15" fill="#339B98"/>
121
  </svg></a>
122
- <span class="lab">Psychological Text Analysis with Contextualized Construct Representation</span>
123
  <nav>
124
  <a href="/welcome">About</a>
125
  <a href="/guide">Guide</a>
 
26
  /* Topbar mirrors the app header EXACTLY (gradient, height, logo size,
27
  tagline, link styles) so navigating app <-> docs doesn't jump. Update
28
  styles.css .header alongside any change here. */
29
+ /* Light, quiet bar - the dark banner (and the product's full name inside it)
30
+ came off every screen on 2026-09-15. Tokens, not fixed colours, so this
31
+ follows the page into dark mode. */
32
  .topbar {
33
+ background: var(--bg); color: var(--fg);
34
+ padding: 12px 24px;
35
+ display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
36
  position: sticky; top: 0; z-index: 30;
37
+ border-bottom: 1px solid var(--border);
38
  }
39
  .topbar .brand { display: inline-flex; align-items: center; text-decoration: none; }
40
  .brand-logo { height: 28px; width: auto; display: block; }
41
  .topbar .brand:hover { opacity: .88; }
42
+ .topbar nav { margin-left: auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
43
+ .topbar nav a { color: var(--muted); text-decoration: none; font-size: 13.5px; }
44
+ .topbar nav a:hover { color: var(--fg); }
45
+ .topbar nav a.current { color: var(--fg); font-weight: 600; }
 
 
 
 
46
  .topbar .topbar-btn {
47
+ background: var(--accent); color: var(--bg); border: 0;
48
+ padding: 8px 15px; border-radius: 9px; font-size: 13px; font-weight: 600;
49
+ text-decoration: none; line-height: 1;
50
  }
51
+ .topbar .topbar-btn:hover { filter: brightness(1.08); text-decoration: none; }
52
  main { max-width: 860px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
53
  h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
54
  h2 { font-size: 1.25rem; margin: 2.2rem 0 .6rem; padding-top: .6rem; border-top: 1px solid var(--border); }
 
108
  <body>
109
  <header class="topbar">
110
  <a class="brand" href="/"><svg class="brand-logo" viewBox="188 455 880 338" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
111
+ <g fill="none" stroke="currentColor" stroke-width="32">
112
  <path d="M 458.884 538.509 A 133 133 0 1 0 458.884 709.491"/>
113
  <path d="M 563.116 538.509 A 133 133 0 0 1 766.884 538.509"/>
114
  <path d="M 563.116 709.491 A 133 133 0 0 0 766.884 709.491"/>
 
118
  <circle cx="481" cy="624" r="15" fill="#339B98"/>
119
  <circle cx="538" cy="624" r="15" fill="#339B98"/>
120
  </svg></a>
 
121
  <nav>
122
  <a href="/welcome">About</a>
123
  <a href="/guide">Guide</a>
backend/app/public_guide.html CHANGED
@@ -26,30 +26,29 @@
26
  /* Topbar mirrors the app header EXACTLY (gradient, height, logo size,
27
  tagline, link styles) so navigating app <-> docs doesn't jump. Kept
28
  identical to guide.html and styles.css .header. */
 
 
 
29
  .topbar {
30
- background: linear-gradient(180deg, #1b1b1c, var(--brand)); color: #fff;
31
- padding: 14px 28px;
32
- display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
33
  position: sticky; top: 0; z-index: 30;
34
- border-bottom: 1px solid rgba(255,255,255,.07);
35
  }
36
  .topbar .brand { display: inline-flex; align-items: center; text-decoration: none; }
37
  .brand-logo { height: 28px; width: auto; display: block; }
38
  .topbar .brand:hover { opacity: .88; }
39
- .topbar .lab {
40
- flex: 1 1 280px; min-width: 0; font-size: 12.5px; line-height: 1.5;
41
- color: #fff; opacity: .85;
42
- }
43
- .topbar nav { margin-left: auto; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
44
- .topbar nav a { color: rgba(255,255,255,.82); text-decoration: none; font-size: 13px; }
45
- .topbar nav a:hover { color: #fff; text-decoration: underline; }
46
- .topbar nav a.current { color: #fff; font-weight: 600; }
47
  .topbar .topbar-btn {
48
- background: rgba(255,255,255,.12); color: #fff;
49
- border: 1px solid rgba(255,255,255,.45);
50
- padding: 5px 14px; border-radius: 9px; font-size: 13px; text-decoration: none;
51
  }
52
- .topbar .topbar-btn:hover { background: rgba(255,255,255,.22); text-decoration: none; }
53
  main { max-width: 860px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
54
  h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
55
  h2 { font-size: 1.25rem; margin: 2.2rem 0 .6rem; padding-top: .6rem; border-top: 1px solid var(--border); }
@@ -125,7 +124,7 @@
125
  <body>
126
  <header class="topbar">
127
  <a class="brand" href="/"><svg class="brand-logo" viewBox="188 455 880 338" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
128
- <g fill="none" stroke="#fff" stroke-width="32">
129
  <path d="M 458.884 538.509 A 133 133 0 1 0 458.884 709.491"/>
130
  <path d="M 563.116 538.509 A 133 133 0 0 1 766.884 538.509"/>
131
  <path d="M 563.116 709.491 A 133 133 0 0 0 766.884 709.491"/>
@@ -135,7 +134,6 @@
135
  <circle cx="481" cy="624" r="15" fill="#339B98"/>
136
  <circle cx="538" cy="624" r="15" fill="#339B98"/>
137
  </svg></a>
138
- <span class="lab">Psychological Text Analysis with Contextualized Construct Representation</span>
139
  <nav>
140
  <a href="/welcome">About</a>
141
  <a href="/guide" class="current">Guide</a>
 
26
  /* Topbar mirrors the app header EXACTLY (gradient, height, logo size,
27
  tagline, link styles) so navigating app <-> docs doesn't jump. Kept
28
  identical to guide.html and styles.css .header. */
29
+ /* Light, quiet bar - the dark banner (and the product's full name inside it)
30
+ came off every screen on 2026-09-15. Tokens, not fixed colours, so this
31
+ follows the page into dark mode. */
32
  .topbar {
33
+ background: var(--bg); color: var(--fg);
34
+ padding: 12px 24px;
35
+ display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
36
  position: sticky; top: 0; z-index: 30;
37
+ border-bottom: 1px solid var(--border);
38
  }
39
  .topbar .brand { display: inline-flex; align-items: center; text-decoration: none; }
40
  .brand-logo { height: 28px; width: auto; display: block; }
41
  .topbar .brand:hover { opacity: .88; }
42
+ .topbar nav { margin-left: auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
43
+ .topbar nav a { color: var(--muted); text-decoration: none; font-size: 13.5px; }
44
+ .topbar nav a:hover { color: var(--fg); }
45
+ .topbar nav a.current { color: var(--fg); font-weight: 600; }
 
 
 
 
46
  .topbar .topbar-btn {
47
+ background: var(--accent); color: var(--bg); border: 0;
48
+ padding: 8px 15px; border-radius: 9px; font-size: 13px; font-weight: 600;
49
+ text-decoration: none; line-height: 1;
50
  }
51
+ .topbar .topbar-btn:hover { filter: brightness(1.08); text-decoration: none; }
52
  main { max-width: 860px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
53
  h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
54
  h2 { font-size: 1.25rem; margin: 2.2rem 0 .6rem; padding-top: .6rem; border-top: 1px solid var(--border); }
 
124
  <body>
125
  <header class="topbar">
126
  <a class="brand" href="/"><svg class="brand-logo" viewBox="188 455 880 338" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
127
+ <g fill="none" stroke="currentColor" stroke-width="32">
128
  <path d="M 458.884 538.509 A 133 133 0 1 0 458.884 709.491"/>
129
  <path d="M 563.116 538.509 A 133 133 0 0 1 766.884 538.509"/>
130
  <path d="M 563.116 709.491 A 133 133 0 0 0 766.884 709.491"/>
 
134
  <circle cx="481" cy="624" r="15" fill="#339B98"/>
135
  <circle cx="538" cy="624" r="15" fill="#339B98"/>
136
  </svg></a>
 
137
  <nav>
138
  <a href="/welcome">About</a>
139
  <a href="/guide" class="current">Guide</a>
backend/static/assets/index-Bmj3fjiw.js DELETED
The diff for this file is too large to render. See raw diff
 
backend/static/assets/index-C34IhTSf.css DELETED
@@ -1 +0,0 @@
1
- :root{--brand-ink: #151515;--brand: #26736f;--brand-dark: #1d5a57;--accent: #339b98;--ink: #1d2129;--muted: #667085;--line: #e5e7eb;--bg: #f7f7f8;--card: #ffffff;--ok: #157f3d;--err: #b42318;--accent-soft: #e7f3f2;--control-height: 40px;--radius: 12px;--radius-sm: 9px;--shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);--shadow-md: 0 2px 6px rgba(16, 24, 40, .05), 0 12px 24px -16px rgba(16, 24, 40, .14);--shadow-lg: 0 24px 60px -12px rgba(16, 24, 40, .26);--ring: 0 0 0 3px rgba(51, 155, 152, .18)}*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,sans-serif;color:var(--ink);background:var(--bg);font-size:14.5px;line-height:1.5}@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 2dppx){body{-webkit-font-smoothing:antialiased}}*{scrollbar-width:thin;scrollbar-color:#c3c9d1 transparent}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-thumb{background:#c3c9d1;border-radius:999px}*::-webkit-scrollbar-track{background:transparent}.app{display:flex;flex-direction:column;min-height:100vh}a{color:var(--brand)}.header{background:linear-gradient(180deg,#1b1b1c,var(--brand-ink));color:#fff;padding:14px 28px;display:flex;align-items:center;flex-wrap:wrap;gap:14px;position:sticky;top:0;z-index:30;border-bottom:1px solid rgba(255,255,255,.07)}.header .brand{flex:0 0 auto;display:inline-flex;align-items:center;gap:10px;font-size:17px;font-weight:650;letter-spacing:.2px;white-space:nowrap;color:#fff;text-decoration:none}.brand-logo{height:28px;width:auto;display:block}.header .brand:hover{opacity:.88}.header .sub{flex:1 1 280px;min-width:0;font-size:12.5px;opacity:.85}.layout{display:flex;flex:1;min-width:0;min-height:0}.sidebar{transition:margin-left .18s ease}.layout.sidebar-closed .sidebar{margin-left:-250px}.sidebar-toggle{flex:0 0 auto;order:-1;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:#ffffff1a;color:#fff;border:1px solid rgba(255,255,255,.28);border-radius:8px;cursor:pointer;transition:background-color .15s ease}.sidebar-toggle:hover{background:#ffffff38}.sidebar-close,.sidebar-backdrop{display:none}.sidebar{width:250px;background:var(--card);border-right:1px solid var(--line);padding:18px 14px;flex-shrink:0;display:flex;flex-direction:column;min-height:0}.sidebar h2{font-size:11.5px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);margin:0 0 10px 4px;display:flex;align-items:center;gap:8px}.sidebar h2 .count{background:var(--bg);border:1px solid var(--line);border-radius:999px;padding:0 8px;font-size:10.5px;letter-spacing:0;color:var(--muted)}.sidebar-filter{width:100%;padding:7px 10px;margin-bottom:10px;border:1px solid var(--line);border-radius:var(--radius-sm);font:inherit;font-size:13px;background:#fff;color:var(--ink)}.sidebar-filter:focus{outline:none;border-color:var(--brand)}.project-list{flex:1;min-height:0;overflow-y:auto;margin:0 -4px;padding:0 4px 4px}.group-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);margin:10px 4px 5px}div:first-child>.group-label{margin-top:2px}.project-item{display:block;width:100%;text-align:left;padding:9px 12px;margin-bottom:5px;border:1px solid transparent;border-radius:var(--radius-sm);background:none;cursor:pointer;font:inherit;color:var(--ink)}.project-item:hover{background:var(--bg)}.project-item.active{background:var(--accent-soft);border-color:var(--brand);font-weight:600}.project-item .project-name{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.project-item .date{display:block;font-size:11.5px;color:var(--muted);font-weight:400}.project-create{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}.project-create>button{width:100%}.main{flex:1;padding:22px 28px;overflow-y:auto;min-width:0}.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;margin-bottom:16px;box-shadow:var(--shadow-sm)}.card h3{margin:0 0 4px;font-size:15px}.card .hint{color:var(--muted);font-size:12.5px;margin:0 0 12px}.step-badge{display:inline-flex;align-items:center;justify-content:center;width:21px;height:21px;border-radius:50%;background:var(--brand);color:#fff;font-size:12px;font-weight:700;margin-right:8px;vertical-align:-3px}button{white-space:nowrap}button.primary{background:var(--brand);color:#fff;border:none;min-height:var(--control-height);display:inline-flex;align-items:center;justify-content:center;padding:0 18px;border-radius:var(--radius-sm);font:inherit;font-weight:600;cursor:pointer;line-height:1.2;transition:background-color .15s ease}button.primary:hover{background:var(--brand-dark)}button.primary:active{transform:translateY(1px)}button.primary:disabled{background:#c9ccd1;cursor:not-allowed;transform:none}a.google-btn{background:var(--brand);color:#fff;border:none;min-height:var(--control-height);display:flex;align-items:center;justify-content:center;padding:0 18px;border-radius:var(--radius-sm);font:inherit;font-weight:600;cursor:pointer;line-height:1.2;text-decoration:none;width:100%;box-sizing:border-box}a.google-btn:hover{background:var(--brand-dark)}button.ghost,a.ghost{background:none;border:1px solid var(--line);color:var(--ink);min-height:var(--control-height);display:inline-flex;align-items:center;justify-content:center;padding:0 14px;border-radius:var(--radius-sm);font:inherit;cursor:pointer;line-height:1.2;text-decoration:none;transition:border-color .15s ease,color .15s ease}button.ghost:hover,a.ghost:hover{border-color:var(--brand);color:var(--brand);background:var(--accent-soft)}button.ghost:active,a.ghost:active{transform:translateY(1px)}button.linkish{background:none;border:none;color:var(--brand);font:inherit;cursor:pointer;padding:0;text-decoration:underline}input[type=text],input[type=email],input[type=password],textarea,select{width:100%;padding:8px 10px;border:1px solid var(--line);border-radius:var(--radius-sm);font:inherit;background:#fff;color:var(--ink)}input[type=text],input[type=email],input[type=password],select{height:var(--control-height)}input[type=text]:focus,input[type=email]:focus,input[type=password]:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring)}button:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{outline:2px solid rgba(51,155,152,.5);outline-offset:2px}input[type=file]{display:block;max-width:100%;margin-top:6px;font-size:13px;color:var(--muted)}input[type=file]::file-selector-button{background:#fff;border:1px solid var(--line);color:var(--ink);padding:7px 14px;border-radius:var(--radius-sm);font:inherit;font-size:13px;cursor:pointer;margin-right:10px}input[type=file]::file-selector-button:hover{border-color:var(--brand);color:var(--brand)}.row>button{align-self:flex-end;margin-bottom:1px}textarea{resize:vertical}label.field{display:block;margin-bottom:10px;font-size:13px;font-weight:600}label.field>*{margin-top:4px;font-weight:400}.field-hint{margin-top:0;font-weight:400;color:var(--muted);font-size:12px}.row{display:flex;gap:14px;flex-wrap:wrap}.row>*{min-width:0}.row>.grow{flex:1;min-width:min(220px,100%)}.language-control{min-width:170px}.model-control{min-width:260px}.run-settings{display:grid;grid-template-columns:minmax(160px,230px) minmax(320px,720px) max-content;justify-content:start;gap:14px;align-items:end}.run-settings .field{margin-bottom:0}.run-button{min-width:180px;height:var(--control-height)}.construct-row{display:grid;grid-template-columns:minmax(320px,1120px) max-content;justify-content:start;align-items:end;gap:14px}.results-toolbar{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:14px;flex-wrap:wrap}.result-actions{justify-content:flex-end}.result-actions a{display:inline-flex;text-decoration:none}.pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:999px;font-size:11.5px;font-weight:600}.pill:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.75}.pill.running:before{animation:pill-pulse 1.2s ease-in-out infinite}@keyframes pill-pulse{50%{opacity:.2}}.pill.completed{background:#e6f4ea;color:var(--ok)}.pill.running{background:#fff3e0;color:#b45309}.pill.queued{background:#eef2f7;color:var(--muted)}.pill.failed{background:#fdecea;color:var(--err)}.progress-track{background:var(--line);border-radius:999px;height:7px;overflow:hidden}.progress-fill{background:linear-gradient(90deg,var(--brand),var(--accent));height:100%;transition:width .4s ease;border-radius:999px}.warnings{background:#fff8e6;border:1px solid #f2dfa8;color:#7a5b00;border-radius:var(--radius-sm);padding:10px 14px}.error-banner{background:#fdecea;color:var(--err);border:1px solid #f5c6c0;padding:10px 14px;border-radius:var(--radius-sm);margin-bottom:14px;font-size:13px}.table-wrap{width:100%;overflow-x:auto}table.docs{width:100%;border-collapse:collapse;font-size:13px}table.docs th{text-align:left;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.5px;padding:6px 8px;border-bottom:1px solid var(--line)}table.docs td{padding:8px;border-bottom:1px solid #f0f1f3;vertical-align:top;overflow-wrap:anywhere}table.docs tbody tr:last-child td{border-bottom:none}table.docs td.score{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}table.docs tbody tr:hover td{background:var(--bg)}.stat-grid{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:4px}.stat{flex:1;min-width:110px;background:var(--bg);border:1px solid var(--line);border-radius:10px;padding:10px 14px}.stat .v{font-size:21px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.02em}.stat .k{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}.item-bar-row{display:flex;align-items:center;gap:10px;margin-bottom:7px}.item-bar-label{flex:1;font-size:12.5px;min-width:0;overflow-wrap:anywhere}.item-bar-track{flex:1.2;background:var(--bg);border-radius:999px;height:10px}.item-bar-fill{background:var(--accent);opacity:.85;height:100%;border-radius:999px}.item-bar-val{width:52px;text-align:right;font-variant-numeric:tabular-nums;font-size:12.5px;font-weight:600}.construct-items{margin:8px 0 0;padding-left:20px;color:var(--muted);font-size:12.5px}.construct-items li{margin-bottom:2px}.anchor-toggle{margin-top:14px;display:flex;flex-direction:column;gap:3px}.anchor-panel{margin-top:10px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--bg)}.anchor-metric{margin:12px 0 0;padding:8px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);display:flex;gap:18px;flex-wrap:wrap;align-items:center}.anchor-metric legend{padding:0 4px}.check{display:inline-flex;align-items:center;gap:7px;cursor:pointer;font-size:13.5px}.check input{width:auto;height:auto;margin:0}.meta-footer{font-size:12px;color:var(--muted);background:var(--bg);border-radius:var(--radius-sm);padding:10px 14px;margin-top:14px;font-variant-numeric:tabular-nums}.meta-footer code{font-size:11.5px}.muted{color:var(--muted)}.small{font-size:12.5px}.mt{margin-top:12px}.header-nav{margin-left:auto;display:flex;align-items:center;gap:14px;color:#fff;flex-wrap:wrap}.header-link{background:none;border:none;padding:0;color:#ffffffd1;font:inherit;font-size:13px;cursor:pointer;text-decoration:none;transition:color .15s ease}.header-link:hover{color:#fff;text-decoration:underline}.header-link.current{color:#fff;font-weight:600}.header-btn{background:#ffffff1f;color:#fff;border:1px solid rgba(255,255,255,.45);padding:5px 14px;border-radius:7px;font:inherit;font-size:13px;cursor:pointer;text-decoration:none;transition:background-color .15s ease}.header-btn:hover{background:#ffffff38}.project-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;flex-wrap:wrap}.project-title{font-size:17px;font-weight:650;margin-right:10px}button.danger{color:var(--err);border-color:#f0c4be}button.danger:hover{color:var(--err);border-color:var(--err)}button.danger-solid{background:var(--err)}button.danger-solid:hover{background:#93261b}button.danger-solid:disabled{background:#c9ccd1}.picker{position:relative}.picker-display{width:100%;display:flex;align-items:center;gap:10px;padding:8px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);background:#fff;font:inherit;color:var(--ink);cursor:pointer;text-align:left}.picker-display:hover{border-color:var(--brand)}.picker-display .picker-caret{margin-left:auto;color:var(--muted);font-size:11px}.picker-search{width:100%;padding:8px 12px;border:1px solid var(--brand);border-radius:var(--radius-sm);font:inherit;background:#fff}.picker-search:focus{outline:none;box-shadow:0 0 0 3px #339b9826}.picker-panel{position:absolute;top:calc(100% + 6px);left:0;z-index:50;width:100%;max-width:640px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-lg);max-height:340px;overflow-y:auto;padding:4px 0 6px;animation:float-in .14s ease-out}@keyframes float-in{0%{opacity:0;transform:translateY(-4px)}}.picker-group{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);padding:8px 12px 3px;position:sticky;top:0;background:var(--card)}.picker-option{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:6px 12px;cursor:pointer;font-size:13.5px}.picker-option:hover,.picker-option.active{background:var(--accent-soft)}.picker-option.selected .picker-name{font-weight:650;color:var(--brand)}.picker-name{min-width:0}.picker-meta{flex-shrink:0;font-size:11.5px;color:var(--muted);white-space:nowrap}.picker-empty{padding:12px;margin:0}.picker-delete{flex-shrink:0;border:0;background:none;cursor:pointer;color:var(--muted);font-size:15px;line-height:1;padding:0 2px;opacity:0;transition:opacity .12s,color .12s}.picker-option:hover .picker-delete,.picker-delete:focus-visible{opacity:1}.picker-delete:hover,.picker-delete:focus-visible{color:var(--err)}.modal-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:18px}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#14161a66;backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;z-index:40;padding:16px}.modal{background:var(--card);border-radius:14px;padding:26px 28px 24px;width:100%;max-width:460px;box-shadow:var(--shadow-lg);animation:modal-in .16s ease-out}@keyframes modal-in{0%{opacity:0;transform:translateY(6px) scale(.985)}}.modal h3{margin:0 0 8px;font-size:18px}.modal .hint{color:var(--muted);font-size:13px;line-height:1.5;margin:0 0 4px}.modal form.mt{margin-top:18px}.modal label.field{margin-bottom:16px}.modal label.field:last-of-type{margin-bottom:20px}.modal .row{gap:10px}.modal .row>.primary{flex:1}.modal p.small.muted.mt{margin-top:18px;padding-top:16px;border-top:1px solid var(--line);font-size:12.5px;line-height:1.6}@media (max-width: 820px){body{font-size:14px}.header{padding:12px 16px;align-items:flex-start;gap:2px 12px}.header .brand{font-size:16px}.header-nav{gap:10px 14px}.header .sub{flex:1 1 210px;font-size:12px;line-height:1.35}.layout{display:block}.sidebar{position:fixed;top:0;left:0;bottom:0;z-index:45;width:min(290px,84vw);margin-left:0;padding:14px;border-right:1px solid var(--line);box-shadow:var(--shadow-lg);transform:translate(-100%);transition:transform .2s ease}.layout:not(.sidebar-closed) .sidebar{transform:translate(0)}.layout.sidebar-closed .sidebar{margin-left:0}.project-list{margin-right:0}.project-create{border-top:0}.sidebar-close{display:inline-flex;align-items:center;justify-content:center;margin-left:auto;padding:0 2px;border:0;background:none;cursor:pointer;color:var(--muted);font-size:14px;line-height:1}.sidebar-close:hover{color:var(--ink)}.sidebar-backdrop{display:block;position:fixed;top:0;right:0;bottom:0;left:0;z-index:44;background:#14161a66;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.main{width:100%;padding:16px 14px 28px;overflow:visible}.card{padding:16px;margin-bottom:14px}.row,.run-settings,.construct-row,.results-toolbar,.result-actions{gap:10px}.row,.results-toolbar,.result-actions{flex-direction:column;align-items:stretch}.run-settings,.construct-row{grid-template-columns:1fr}.row>.grow,.construct-row>.grow,.language-control,.model-control{width:100%;min-width:0}.main .row>button,.main .row>a,.main .row>a>button,.results-toolbar>button{align-self:stretch;margin-bottom:0;width:100%}.run-button{width:100%;min-width:0}.stat-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.stat{min-width:0}.item-bar-row{display:grid;grid-template-columns:minmax(0,1fr) 56px;gap:6px 10px}.item-bar-track{grid-column:1 / -1;width:100%}.item-bar-val{width:auto}table.docs{min-width:520px}}@media (max-width: 460px){.header .sub{flex-basis:100%}.stat-grid{grid-template-columns:1fr}}.empty-state{text-align:center;max-width:560px;margin:48px auto 0;padding:36px 28px 28px}.empty-state h3{font-size:17px}.empty-state .hint{font-size:13px}.empty-actions{display:flex;gap:16px;align-items:center;justify-content:center;flex-wrap:wrap;margin:18px 0 16px}.ghost-link{color:var(--brand);font-weight:600;text-decoration:none}.ghost-link:hover{text-decoration:underline}.welcome{padding-top:1.2rem}.welcome-hero{padding:26px 28px;background:linear-gradient(135deg,#ffffff 55%,var(--accent-soft))}.welcome-hero h2{margin:0 0 .6rem;font-size:1.5rem}.welcome-hero p{max-width:62ch}.welcome-cta{display:flex;gap:1rem;align-items:center;flex-wrap:wrap;margin:1.1rem 0 .6rem}.welcome-cta .ghost-link{font-size:.95rem}.welcome-steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.welcome-step h3{margin:.2rem 0 .3rem}.step-n{width:1.9rem;height:1.9rem;border-radius:50%;background:var(--brand);color:#fff;font-weight:700;display:flex;align-items:center;justify-content:center}@media (max-width: 700px){.welcome-steps{grid-template-columns:1fr}table.docs.runs-table{min-width:0;width:100%;max-width:100%}table.docs.runs-table thead{display:none}table.docs.runs-table,table.docs.runs-table tbody,table.docs.runs-table tr,table.docs.runs-table td{display:block}table.docs.runs-table tr{border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 12px;margin-bottom:10px;max-width:100%}table.docs.runs-table tbody tr:hover td{background:none}table.docs.runs-table td{padding:3px 0;border-bottom:0;text-align:left;max-width:100%;overflow-wrap:anywhere}table.docs.runs-table td:before{content:attr(data-label);display:inline-block;min-width:88px;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.4px}table.docs.runs-table td[data-label=""]{padding-top:8px}table.docs.runs-table td[data-label=""]:before{content:none}table.docs.texts-table,table.docs.corr-table{min-width:0}table.docs.texts-table th:first-child,table.docs.texts-table td.score{width:52px}table.docs.corr-table th,table.docs.corr-table td{padding:6px 5px}.construct-selected summary,.construct-results summary{flex-wrap:wrap}.construct-selected summary .picker-meta,.construct-results summary .picker-meta{white-space:normal;margin-left:0;flex:1 1 100%}.construct-selected summary .construct-remove{margin-left:auto}}.construct-selected{margin-top:8px;border:1px solid var(--line);border-radius:var(--radius-sm);padding:8px 12px;background:#fff}.construct-selected summary,.construct-results summary{cursor:pointer;display:flex;align-items:baseline;gap:8px;list-style:none}.construct-selected summary::-webkit-details-marker,.construct-results summary::-webkit-details-marker{display:none}.construct-selected summary:before,.construct-results summary:before{content:"▸";color:var(--muted);font-size:11px;transition:transform .15s ease;align-self:center}details[open]>summary:before{transform:rotate(90deg)}.construct-selected-name{font-weight:600;font-size:13.5px}.construct-remove{margin-left:auto;flex-shrink:0}.construct-results summary .picker-meta{margin-left:6px}.construct-results h4{margin:14px 0 4px;font-size:13.5px}.new-construct{border:1px solid var(--line);border-radius:var(--radius-sm);padding:14px 16px 16px;margin-top:12px;background:var(--bg)}.new-construct-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.source-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin:0 0 14px}.source-card{text-align:left;padding:10px 12px;border:1.5px solid var(--line);border-radius:var(--radius-sm);background:var(--card);cursor:pointer;font:inherit;color:var(--ink);transition:border-color .12s,background .12s}.source-card:hover{border-color:var(--accent)}.source-card.active{border-color:var(--brand);background:var(--accent-soft)}.source-card b{display:block;font-size:13.5px;margin-bottom:2px}.source-card span{display:block;font-size:12px;color:var(--muted);line-height:1.35}.field-row{display:flex;gap:14px;align-items:end;flex-wrap:wrap}.field-row .field{margin-bottom:0}.field-row>.small{align-self:center;margin:0 0 8px}.ai-modeline{display:flex;align-items:center;gap:8px;margin:2px 0 10px}.infotip{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:none;cursor:help;font:inherit;line-height:1}.infotip-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;background:var(--accent-soft);color:var(--brand);border:1px solid var(--brand);font-size:11px;font-weight:700;font-style:normal}.infotip:hover .infotip-icon,.infotip:focus-visible .infotip-icon{background:var(--brand);color:#fff}.infotip:focus-visible{outline:none}.infotip:focus-visible .infotip-icon{box-shadow:var(--ring)}.infotip-pop{position:absolute;left:0;top:calc(100% + 8px);z-index:40;width:300px;max-width:78vw;padding:10px 12px;background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);font-size:12px;line-height:1.45;text-align:left;white-space:normal;overflow-wrap:anywhere;opacity:0;visibility:hidden;transform:translateY(-3px);transition:opacity .12s,transform .12s,visibility .12s;pointer-events:none}.infotip:hover .infotip-pop,.infotip:focus-within .infotip-pop{opacity:1;visibility:visible;transform:translateY(0)}.infotip-pop b{display:block;margin-bottom:4px;color:var(--brand-ink)}.infotip-pop ul{margin:0;padding-left:16px}.infotip-pop li{margin:2px 0;color:var(--ink)}.infotip-pop a{display:inline-block;margin-top:6px;color:var(--brand);font-weight:600}.site-footer{max-width:920px;margin:40px auto 0;padding:18px 1rem 28px;border-top:1px solid var(--line);color:var(--muted);font-size:12.5px;line-height:1.6}.site-footer p{margin:0 0 6px}.site-footer p:last-child{margin-bottom:0}.site-footer strong{color:var(--ink)}.site-footer a{color:var(--brand);text-decoration:none}.site-footer a:hover{text-decoration:underline}@media (prefers-reduced-motion: reduce){.sidebar,.infotip-pop{transition:none}.picker-panel,.modal{animation:none}.pill.running:before{animation:none}.construct-selected summary:before,.construct-results summary:before{transition:none}button.primary:active,button.ghost:active,a.ghost:active{transform:none}}.keep-notice{margin-top:12px;padding:10px 12px;border-radius:8px;background:var(--accent-soft);border:1px solid var(--border)}.linklike{border:0;background:none;padding:0;cursor:pointer;color:var(--brand);text-decoration:underline;font:inherit}.or-rule{display:flex;align-items:center;gap:14px;margin:18px 0 16px;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.8px}.or-rule:before,.or-rule:after{content:"";flex:1;height:1px;background:var(--line)}.samples{max-width:640px}.samples-field{margin-bottom:0}.samples-row{display:flex;align-items:center;gap:8px;margin-top:4px}.samples-row select{flex:1;min-width:0}.samples-row button{flex-shrink:0}button.info-button{width:var(--control-height);padding:0;border-radius:var(--radius-sm);font-family:Georgia,Times New Roman,serif;font-style:italic;font-size:15px;color:var(--muted)}.samples-detail{margin:8px 0 0}.modal-wide{max-width:560px}.modal-head{display:flex;align-items:center;gap:12px;margin-bottom:8px}.modal-head h3{margin:0}.corpus-logo{height:34px;width:auto;flex-shrink:0}.cite-modal{max-width:620px;max-height:min(86vh,900px);overflow-y:auto}.cite-modal .modal-head{justify-content:space-between;align-items:baseline}.cite-close{font-size:15px;color:var(--muted);line-height:1;text-decoration:none}.cite-close:hover{color:var(--ink)}.cite-modal:focus{outline:none}.cite-list{border-top:1px solid var(--line);margin-top:6px}.cite-row{display:grid;grid-template-columns:74px minmax(0,1fr) 52px;gap:12px;align-items:start;width:100%;padding:11px 6px;border:0;border-bottom:1px solid var(--line);background:none;font:inherit;text-align:left;cursor:pointer;white-space:normal}.cite-row:hover{background:var(--bg)}.cite-style{color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.5px;text-align:right;padding-top:2px}.cite-text{font-size:13px;line-height:1.55;overflow-wrap:anywhere}.cite-copied{color:var(--ok);font-size:11.5px;font-weight:600;text-align:right;padding-top:2px}.cite-also{margin-top:14px;padding:10px 14px;background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);font-size:12.5px;line-height:1.55;color:var(--muted)}.cite-also b{color:var(--ink)}.cite-also ul{margin:8px 0 0;padding-left:18px}.cite-also li{margin-bottom:6px;overflow-wrap:anywhere}.cite-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}.cite-export{margin-top:12px}.cite-export pre{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 12px;margin:0 0 10px;font-size:11.5px;line-height:1.5;max-height:260px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere}@media (max-width: 700px){.cite-row{grid-template-columns:minmax(0,1fr) 56px;gap:2px 10px}.cite-style{text-align:left;grid-column:1;grid-row:1}.cite-copied{grid-column:2;grid-row:1}.cite-text{grid-column:1 / -1}.cite-actions>button{flex:1 1 100%}}
 
 
backend/static/assets/index-CrxbvzWk.css ADDED
@@ -0,0 +1 @@
 
 
1
+ :root{--brand-ink: #151515;--brand: #26736f;--brand-dark: #1d5a57;--accent: #339b98;--ink: #1d2129;--muted: #667085;--line: #e5e7eb;--bg: #f7f7f8;--rail: #f1f1f3;--card: #ffffff;--ok: #157f3d;--err: #b42318;--accent-soft: #e7f3f2;--control-height: 40px;--radius: 12px;--radius-sm: 9px;--shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);--shadow-md: 0 2px 6px rgba(16, 24, 40, .05), 0 12px 24px -16px rgba(16, 24, 40, .14);--shadow-lg: 0 24px 60px -12px rgba(16, 24, 40, .26);--ring: 0 0 0 3px rgba(51, 155, 152, .18)}*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,sans-serif;color:var(--ink);background:var(--bg);font-size:14.5px;line-height:1.5}@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 2dppx){body{-webkit-font-smoothing:antialiased}}*{scrollbar-width:thin;scrollbar-color:#c3c9d1 transparent}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-thumb{background:#c3c9d1;border-radius:999px}*::-webkit-scrollbar-track{background:transparent}.app{display:flex;flex-direction:column;min-height:100vh}@media (min-width: 821px){.app-dashboard{height:100vh;overflow:hidden}}a{color:var(--brand)}.topline{position:sticky;top:0;z-index:30;display:flex;align-items:center;gap:16px;padding:12px 24px;background:#f7f7f8d1;backdrop-filter:saturate(180%) blur(10px);-webkit-backdrop-filter:saturate(180%) blur(10px);border-bottom:1px solid var(--line)}.topline .brand{display:inline-flex;align-items:center;text-decoration:none}.brand-logo{height:26px;width:auto;display:block}.topline-nav{margin-left:auto;display:flex;align-items:center;gap:16px;flex-wrap:wrap}.top-link{background:none;border:0;padding:0;font:inherit;font-size:13.5px;color:var(--muted);cursor:pointer;text-decoration:none;transition:color .15s ease}.top-link:hover{color:var(--ink)}.top-name{font-size:13px;color:var(--muted)}.top-btn{background:var(--brand);color:#fff;border:0;padding:8px 15px;border-radius:9px;font:inherit;font-size:13px;font-weight:600;line-height:1;cursor:pointer;text-decoration:none;transition:background-color .15s ease}.top-btn:hover{background:var(--brand-dark)}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;flex-shrink:0;border:0;border-radius:8px;background:none;color:var(--muted);cursor:pointer;transition:background-color .15s ease,color .15s ease}.icon-btn:hover{background:#10182812;color:var(--ink)}.layout{display:flex;flex:1;min-width:0;min-height:0}.sidebar{transition:margin-left .18s ease}.layout.sidebar-closed .sidebar{margin-left:-250px}.sidebar-toggle{flex:0 0 auto;order:-1;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:#ffffff1a;color:#fff;border:1px solid rgba(255,255,255,.28);border-radius:8px;cursor:pointer;transition:background-color .15s ease}.sidebar-toggle:hover{background:#ffffff38}.sidebar-backdrop{display:none}.sidebar{width:250px;background:var(--rail);border-right:1px solid var(--line);padding:10px 12px 12px;flex-shrink:0;display:flex;flex-direction:column;min-height:0}.sidebar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 2px 8px}.brand-mini{display:inline-flex;align-items:center;border:0;background:none;padding:2px;cursor:pointer;border-radius:8px}.brand-mini img,.brand-mini-img{height:22px;width:auto;display:block}.brand-mini:hover{background:#1018280f}.sidebar-foot{margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}.sidebar-nav{display:flex;flex-wrap:wrap;gap:4px 14px;margin-bottom:10px}.side-link{background:none;border:0;padding:0;font:inherit;font-size:12.5px;color:var(--muted);cursor:pointer;text-decoration:none}.side-link:hover{color:var(--ink);text-decoration:underline}.sidebar-account{display:flex;align-items:center;gap:10px}.account-name{font-size:13px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-account .linkish{margin-left:auto;font-size:12.5px;flex-shrink:0}.sidebar-signin{width:100%;background:var(--card)}.sidebar h2{font-size:11.5px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);margin:0 0 10px 4px;display:flex;align-items:center;gap:8px}.sidebar h2 .count{background:var(--bg);border:1px solid var(--line);border-radius:999px;padding:0 8px;font-size:10.5px;letter-spacing:0;color:var(--muted)}.sidebar-filter{width:100%;padding:7px 10px;margin-bottom:10px;border:1px solid var(--line);border-radius:var(--radius-sm);font:inherit;font-size:13px;background:#fff;color:var(--ink)}.sidebar-filter:focus{outline:none;border-color:var(--brand)}.project-list{flex:1 1 auto;min-height:0;overflow-y:auto;margin:0 -4px;padding:0 4px 4px}.group-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);margin:10px 4px 5px}div:first-child>.group-label{margin-top:2px}.project-item{display:block;width:100%;text-align:left;padding:9px 12px;margin-bottom:5px;border:1px solid transparent;border-radius:var(--radius-sm);background:none;cursor:pointer;font:inherit;color:var(--ink)}.project-item:hover{background:#1018280d}.project-item.active{background:var(--card);border-color:var(--brand);font-weight:600}.project-item .project-name{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.project-item .date{display:block;font-size:11.5px;color:var(--muted);font-weight:400}.project-create{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}.project-create>button{width:100%}.main{flex:1;padding:12px 28px 28px;overflow-y:auto;min-width:0}.main-toolbar{display:flex;align-items:center;gap:10px;height:32px;margin-bottom:6px}.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;margin-bottom:16px;box-shadow:var(--shadow-sm)}.card h3{margin:0 0 4px;font-size:15px}.card .hint{color:var(--muted);font-size:12.5px;margin:0 0 12px}.step-badge{display:inline-flex;align-items:center;justify-content:center;width:21px;height:21px;border-radius:50%;background:var(--brand);color:#fff;font-size:12px;font-weight:700;margin-right:8px;vertical-align:-3px}button{white-space:nowrap}button.primary{background:var(--brand);color:#fff;border:none;min-height:var(--control-height);display:inline-flex;align-items:center;justify-content:center;padding:0 18px;border-radius:var(--radius-sm);font:inherit;font-weight:600;cursor:pointer;line-height:1.2;transition:background-color .15s ease}button.primary:hover{background:var(--brand-dark)}button.primary:active{transform:translateY(1px)}button.primary:disabled{background:#c9ccd1;cursor:not-allowed;transform:none}a.google-btn{background:var(--brand);color:#fff;border:none;min-height:var(--control-height);display:flex;align-items:center;justify-content:center;padding:0 18px;border-radius:var(--radius-sm);font:inherit;font-weight:600;cursor:pointer;line-height:1.2;text-decoration:none;width:100%;box-sizing:border-box}a.google-btn:hover{background:var(--brand-dark)}button.ghost,a.ghost{background:none;border:1px solid var(--line);color:var(--ink);min-height:var(--control-height);display:inline-flex;align-items:center;justify-content:center;padding:0 14px;border-radius:var(--radius-sm);font:inherit;cursor:pointer;line-height:1.2;text-decoration:none;transition:border-color .15s ease,color .15s ease}button.ghost:hover,a.ghost:hover{border-color:var(--brand);color:var(--brand);background:var(--accent-soft)}button.ghost:active,a.ghost:active{transform:translateY(1px)}button.linkish{background:none;border:none;color:var(--brand);font:inherit;cursor:pointer;padding:0;text-decoration:underline}input[type=text],input[type=email],input[type=password],textarea,select{width:100%;padding:8px 10px;border:1px solid var(--line);border-radius:var(--radius-sm);font:inherit;background:#fff;color:var(--ink)}input[type=text],input[type=email],input[type=password],select{height:var(--control-height)}input[type=text]:focus,input[type=email]:focus,input[type=password]:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring)}button:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{outline:2px solid rgba(51,155,152,.5);outline-offset:2px}input[type=file]{display:block;max-width:100%;margin-top:6px;font-size:13px;color:var(--muted)}input[type=file]::file-selector-button{background:#fff;border:1px solid var(--line);color:var(--ink);padding:7px 14px;border-radius:var(--radius-sm);font:inherit;font-size:13px;cursor:pointer;margin-right:10px}input[type=file]::file-selector-button:hover{border-color:var(--brand);color:var(--brand)}.row>button{align-self:flex-end;margin-bottom:1px}textarea{resize:vertical}label.field{display:block;margin-bottom:10px;font-size:13px;font-weight:600}label.field>*{margin-top:4px;font-weight:400}.field-hint{margin-top:0;font-weight:400;color:var(--muted);font-size:12px}.row{display:flex;gap:14px;flex-wrap:wrap}.row>*{min-width:0}.row>.grow{flex:1;min-width:min(220px,100%)}.language-control{min-width:170px}.model-control{min-width:260px}.run-settings{display:grid;grid-template-columns:minmax(160px,230px) minmax(320px,720px) max-content;justify-content:start;gap:14px;align-items:end}.run-settings .field{margin-bottom:0}.run-button{min-width:180px;height:var(--control-height)}.construct-row{display:grid;grid-template-columns:minmax(320px,1120px) max-content;justify-content:start;align-items:end;gap:14px}.results-toolbar{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:14px;flex-wrap:wrap}.result-actions{justify-content:flex-end}.result-actions a{display:inline-flex;text-decoration:none}.pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:999px;font-size:11.5px;font-weight:600}.pill:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.75}.pill.running:before{animation:pill-pulse 1.2s ease-in-out infinite}@keyframes pill-pulse{50%{opacity:.2}}.pill.completed{background:#e6f4ea;color:var(--ok)}.pill.running{background:#fff3e0;color:#b45309}.pill.queued{background:#eef2f7;color:var(--muted)}.pill.failed{background:#fdecea;color:var(--err)}.progress-track{background:var(--line);border-radius:999px;height:7px;overflow:hidden}.progress-fill{background:linear-gradient(90deg,var(--brand),var(--accent));height:100%;transition:width .4s ease;border-radius:999px}.warnings{background:#fff8e6;border:1px solid #f2dfa8;color:#7a5b00;border-radius:var(--radius-sm);padding:10px 14px}.error-banner{background:#fdecea;color:var(--err);border:1px solid #f5c6c0;padding:10px 14px;border-radius:var(--radius-sm);margin-bottom:14px;font-size:13px}.table-wrap{width:100%;overflow-x:auto}table.docs{width:100%;border-collapse:collapse;font-size:13px}table.docs th{text-align:left;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.5px;padding:6px 8px;border-bottom:1px solid var(--line)}table.docs td{padding:8px;border-bottom:1px solid #f0f1f3;vertical-align:top;overflow-wrap:anywhere}table.docs tbody tr:last-child td{border-bottom:none}table.docs td.score{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}table.docs tbody tr:hover td{background:var(--bg)}.stat-grid{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:4px}.stat{flex:1;min-width:110px;background:var(--bg);border:1px solid var(--line);border-radius:10px;padding:10px 14px}.stat .v{font-size:21px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.02em}.stat .k{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}.item-bar-row{display:flex;align-items:center;gap:10px;margin-bottom:7px}.item-bar-label{flex:1;font-size:12.5px;min-width:0;overflow-wrap:anywhere}.item-bar-track{flex:1.2;background:var(--bg);border-radius:999px;height:10px}.item-bar-fill{background:var(--accent);opacity:.85;height:100%;border-radius:999px}.item-bar-val{width:52px;text-align:right;font-variant-numeric:tabular-nums;font-size:12.5px;font-weight:600}.construct-items{margin:8px 0 0;padding-left:20px;color:var(--muted);font-size:12.5px}.construct-items li{margin-bottom:2px}.anchor-toggle{margin-top:14px;display:flex;flex-direction:column;gap:3px}.anchor-panel{margin-top:10px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--bg)}.anchor-metric{margin:12px 0 0;padding:8px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);display:flex;gap:18px;flex-wrap:wrap;align-items:center}.anchor-metric legend{padding:0 4px}.check{display:inline-flex;align-items:center;gap:7px;cursor:pointer;font-size:13.5px}.check input{width:auto;height:auto;margin:0}.meta-footer{font-size:12px;color:var(--muted);background:var(--bg);border-radius:var(--radius-sm);padding:10px 14px;margin-top:14px;font-variant-numeric:tabular-nums}.meta-footer code{font-size:11.5px}.muted{color:var(--muted)}.small{font-size:12.5px}.mt{margin-top:12px}.project-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;flex-wrap:wrap}.project-title{font-size:17px;font-weight:650;margin-right:10px}button.danger{color:var(--err);border-color:#f0c4be}button.danger:hover{color:var(--err);border-color:var(--err)}button.danger-solid{background:var(--err)}button.danger-solid:hover{background:#93261b}button.danger-solid:disabled{background:#c9ccd1}.picker{position:relative}.picker-display{width:100%;display:flex;align-items:center;gap:10px;padding:8px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);background:#fff;font:inherit;color:var(--ink);cursor:pointer;text-align:left}.picker-display:hover{border-color:var(--brand)}.picker-display .picker-caret{margin-left:auto;color:var(--muted);font-size:11px}.picker-search{width:100%;padding:8px 12px;border:1px solid var(--brand);border-radius:var(--radius-sm);font:inherit;background:#fff}.picker-search:focus{outline:none;box-shadow:0 0 0 3px #339b9826}.picker-panel{position:absolute;top:calc(100% + 6px);left:0;z-index:50;width:100%;max-width:640px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-lg);max-height:340px;overflow-y:auto;padding:4px 0 6px;animation:float-in .14s ease-out}@keyframes float-in{0%{opacity:0;transform:translateY(-4px)}}.picker-group{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);padding:8px 12px 3px;position:sticky;top:0;background:var(--card)}.picker-option{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:6px 12px;cursor:pointer;font-size:13.5px}.picker-option:hover,.picker-option.active{background:var(--accent-soft)}.picker-option.selected .picker-name{font-weight:650;color:var(--brand)}.picker-name{min-width:0}.picker-meta{flex-shrink:0;font-size:11.5px;color:var(--muted);white-space:nowrap}.picker-empty{padding:12px;margin:0}.picker-delete{flex-shrink:0;border:0;background:none;cursor:pointer;color:var(--muted);font-size:15px;line-height:1;padding:0 2px;opacity:0;transition:opacity .12s,color .12s}.picker-option:hover .picker-delete,.picker-delete:focus-visible{opacity:1}.picker-delete:hover,.picker-delete:focus-visible{color:var(--err)}.modal-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:18px}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#14161a66;backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;z-index:40;padding:16px}.modal{background:var(--card);border-radius:14px;padding:26px 28px 24px;width:100%;max-width:460px;box-shadow:var(--shadow-lg);animation:modal-in .16s ease-out}@keyframes modal-in{0%{opacity:0;transform:translateY(6px) scale(.985)}}.modal h3{margin:0 0 8px;font-size:18px}.modal .hint{color:var(--muted);font-size:13px;line-height:1.5;margin:0 0 4px}.modal form.mt{margin-top:18px}.modal label.field{margin-bottom:16px}.modal label.field:last-of-type{margin-bottom:20px}.modal .row{gap:10px}.modal .row>.primary{flex:1}.modal p.small.muted.mt{margin-top:18px;padding-top:16px;border-top:1px solid var(--line);font-size:12.5px;line-height:1.6}@media (max-width: 820px){body{font-size:14px}.topline{padding:10px 14px;gap:10px}.topline-nav{gap:12px}.top-link{font-size:13px}.top-name{display:none}.layout{display:block}.sidebar{position:fixed;top:0;left:0;bottom:0;z-index:45;width:min(290px,84vw);margin-left:0;padding:10px 12px 14px;background:var(--card);border-right:1px solid var(--line);box-shadow:var(--shadow-lg);transform:translate(-100%);transition:transform .2s ease}.layout:not(.sidebar-closed) .sidebar{transform:translate(0)}.layout.sidebar-closed .sidebar{margin-left:0}.project-list{margin-right:0}.project-create{border-top:0}.sidebar-backdrop{display:block;position:fixed;top:0;right:0;bottom:0;left:0;z-index:44;background:#14161a66;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.main{width:100%;padding:16px 14px 28px;overflow:visible}.card{padding:16px;margin-bottom:14px}.row,.run-settings,.construct-row,.results-toolbar,.result-actions{gap:10px}.row,.results-toolbar,.result-actions{flex-direction:column;align-items:stretch}.run-settings,.construct-row{grid-template-columns:1fr}.row>.grow,.construct-row>.grow,.language-control,.model-control{width:100%;min-width:0}.main .row>button,.main .row>a,.main .row>a>button,.results-toolbar>button{align-self:stretch;margin-bottom:0;width:100%}.project-header .row{flex-direction:row;justify-content:flex-end}.project-header .row>button{width:auto;align-self:auto}.run-button{width:100%;min-width:0}.stat-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.stat{min-width:0}.item-bar-row{display:grid;grid-template-columns:minmax(0,1fr) 56px;gap:6px 10px}.item-bar-track{grid-column:1 / -1;width:100%}.item-bar-val{width:auto}table.docs{min-width:520px}}@media (max-width: 460px){.stat-grid{grid-template-columns:1fr}}.empty-state{text-align:center;max-width:560px;margin:48px auto 0;padding:36px 28px 28px}.empty-state h3{font-size:17px}.empty-state .hint{font-size:13px}.empty-actions{display:flex;gap:16px;align-items:center;justify-content:center;flex-wrap:wrap;margin:18px 0 16px}.ghost-link{color:var(--brand);font-weight:600;text-decoration:none}.ghost-link:hover{text-decoration:underline}.welcome{padding-top:1.2rem}.welcome-hero{padding:26px 28px;background:linear-gradient(135deg,#ffffff 55%,var(--accent-soft))}.welcome-hero h2{margin:0 0 .6rem;font-size:1.5rem}.welcome-hero p{max-width:62ch}.welcome-cta{display:flex;gap:1rem;align-items:center;flex-wrap:wrap;margin:1.1rem 0 .6rem}.welcome-cta .ghost-link{font-size:.95rem}.welcome-steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.welcome-step h3{margin:.2rem 0 .3rem}.step-n{width:1.9rem;height:1.9rem;border-radius:50%;background:var(--brand);color:#fff;font-weight:700;display:flex;align-items:center;justify-content:center}@media (max-width: 700px){.welcome-steps{grid-template-columns:1fr}table.docs.runs-table{min-width:0;width:100%;max-width:100%}table.docs.runs-table thead{display:none}table.docs.runs-table,table.docs.runs-table tbody,table.docs.runs-table tr,table.docs.runs-table td{display:block}table.docs.runs-table tr{border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 12px;margin-bottom:10px;max-width:100%}table.docs.runs-table tbody tr:hover td{background:none}table.docs.runs-table td{padding:3px 0;border-bottom:0;text-align:left;max-width:100%;overflow-wrap:anywhere}table.docs.runs-table td:before{content:attr(data-label);display:inline-block;min-width:88px;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.4px}table.docs.runs-table td[data-label=""]{padding-top:8px}table.docs.runs-table td[data-label=""]:before{content:none}table.docs.texts-table,table.docs.corr-table{min-width:0}table.docs.texts-table th:first-child,table.docs.texts-table td.score{width:52px}table.docs.corr-table th,table.docs.corr-table td{padding:6px 5px}.construct-selected summary,.construct-results summary{flex-wrap:wrap}.construct-selected summary .picker-meta,.construct-results summary .picker-meta{white-space:normal;margin-left:0;flex:1 1 100%}.construct-selected summary .construct-remove{margin-left:auto}}.construct-selected{margin-top:8px;border:1px solid var(--line);border-radius:var(--radius-sm);padding:8px 12px;background:#fff}.construct-selected summary,.construct-results summary{cursor:pointer;display:flex;align-items:baseline;gap:8px;list-style:none}.construct-selected summary::-webkit-details-marker,.construct-results summary::-webkit-details-marker{display:none}.construct-selected summary:before,.construct-results summary:before{content:"▸";color:var(--muted);font-size:11px;transition:transform .15s ease;align-self:center}details[open]>summary:before{transform:rotate(90deg)}.construct-selected-name{font-weight:600;font-size:13.5px}.construct-remove{margin-left:auto;flex-shrink:0}.construct-results summary .picker-meta{margin-left:6px}.construct-results h4{margin:14px 0 4px;font-size:13.5px}.new-construct{border:1px solid var(--line);border-radius:var(--radius-sm);padding:14px 16px 16px;margin-top:12px;background:var(--bg)}.new-construct-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.source-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin:0 0 14px}.source-card{text-align:left;padding:10px 12px;border:1.5px solid var(--line);border-radius:var(--radius-sm);background:var(--card);cursor:pointer;font:inherit;color:var(--ink);transition:border-color .12s,background .12s}.source-card:hover{border-color:var(--accent)}.source-card.active{border-color:var(--brand);background:var(--accent-soft)}.source-card b{display:block;font-size:13.5px;margin-bottom:2px}.source-card span{display:block;font-size:12px;color:var(--muted);line-height:1.35}.field-row{display:flex;gap:14px;align-items:end;flex-wrap:wrap}.field-row .field{margin-bottom:0}.field-row>.small{align-self:center;margin:0 0 8px}.ai-modeline{display:flex;align-items:center;gap:8px;margin:2px 0 10px}.infotip{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:none;cursor:help;font:inherit;line-height:1}.infotip-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;background:var(--accent-soft);color:var(--brand);border:1px solid var(--brand);font-size:11px;font-weight:700;font-style:normal}.infotip:hover .infotip-icon,.infotip:focus-visible .infotip-icon{background:var(--brand);color:#fff}.infotip:focus-visible{outline:none}.infotip:focus-visible .infotip-icon{box-shadow:var(--ring)}.infotip-pop{position:absolute;left:0;top:calc(100% + 8px);z-index:40;width:300px;max-width:78vw;padding:10px 12px;background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);font-size:12px;line-height:1.45;text-align:left;white-space:normal;overflow-wrap:anywhere;opacity:0;visibility:hidden;transform:translateY(-3px);transition:opacity .12s,transform .12s,visibility .12s;pointer-events:none}.infotip:hover .infotip-pop,.infotip:focus-within .infotip-pop{opacity:1;visibility:visible;transform:translateY(0)}.infotip-pop b{display:block;margin-bottom:4px;color:var(--brand-ink)}.infotip-pop ul{margin:0;padding-left:16px}.infotip-pop li{margin:2px 0;color:var(--ink)}.infotip-pop a{display:inline-block;margin-top:6px;color:var(--brand);font-weight:600}.site-footer{max-width:920px;margin:40px auto 0;padding:18px 1rem 28px;border-top:1px solid var(--line);color:var(--muted);font-size:12.5px;line-height:1.6}.site-footer p{margin:0 0 6px}.site-footer p:last-child{margin-bottom:0}.site-footer strong{color:var(--ink)}.site-footer a{color:var(--brand);text-decoration:none}.site-footer a:hover{text-decoration:underline}@media (prefers-reduced-motion: reduce){.sidebar,.infotip-pop{transition:none}.picker-panel,.modal{animation:none}.pill.running:before{animation:none}.construct-selected summary:before,.construct-results summary:before{transition:none}button.primary:active,button.ghost:active,a.ghost:active{transform:none}}.keep-notice{margin-top:12px;padding:10px 12px;border-radius:8px;background:var(--accent-soft);border:1px solid var(--border)}.linklike{border:0;background:none;padding:0;cursor:pointer;color:var(--brand);text-decoration:underline;font:inherit}.or-rule{display:flex;align-items:center;gap:14px;margin:18px 0 16px;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.8px}.or-rule:before,.or-rule:after{content:"";flex:1;height:1px;background:var(--line)}.samples{max-width:640px}.samples-field{margin-bottom:0}.samples-row{display:flex;align-items:center;gap:8px;margin-top:4px}.samples-row select{flex:1;min-width:0}.samples-row button{flex-shrink:0}button.info-button{width:var(--control-height);padding:0;border-radius:var(--radius-sm);font-family:Georgia,Times New Roman,serif;font-style:italic;font-size:15px;color:var(--muted)}.samples-detail{margin:8px 0 0}.modal-wide{max-width:560px}.modal-head{display:flex;align-items:center;gap:12px;margin-bottom:8px}.modal-head h3{margin:0}.corpus-logo{height:34px;width:auto;flex-shrink:0}.cite-modal{max-width:620px;max-height:min(86vh,900px);overflow-y:auto}.cite-modal .modal-head{justify-content:space-between;align-items:baseline}.cite-close{font-size:15px;color:var(--muted);line-height:1;text-decoration:none}.cite-close:hover{color:var(--ink)}.cite-modal:focus{outline:none}.cite-list{border-top:1px solid var(--line);margin-top:6px}.cite-row{display:grid;grid-template-columns:74px minmax(0,1fr) 52px;gap:12px;align-items:start;width:100%;padding:11px 6px;border:0;border-bottom:1px solid var(--line);background:none;font:inherit;text-align:left;cursor:pointer;white-space:normal}.cite-row:hover{background:var(--bg)}.cite-style{color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.5px;text-align:right;padding-top:2px}.cite-text{font-size:13px;line-height:1.55;overflow-wrap:anywhere}.cite-copied{color:var(--ok);font-size:11.5px;font-weight:600;text-align:right;padding-top:2px}.cite-also{margin-top:14px;padding:10px 14px;background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);font-size:12.5px;line-height:1.55;color:var(--muted)}.cite-also b{color:var(--ink)}.cite-also ul{margin:8px 0 0;padding-left:18px}.cite-also li{margin-bottom:6px;overflow-wrap:anywhere}.cite-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}.cite-export{margin-top:12px}.cite-export pre{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 12px;margin:0 0 10px;font-size:11.5px;line-height:1.5;max-height:260px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere}@media (max-width: 700px){.cite-row{grid-template-columns:minmax(0,1fr) 56px;gap:2px 10px}.cite-style{text-align:left;grid-column:1;grid-row:1}.cite-copied{grid-column:2;grid-row:1}.cite-text{grid-column:1 / -1}.cite-actions>button{flex:1 1 100%}}
backend/static/assets/index-dPONKjSo.js ADDED
The diff for this file is too large to render. See raw diff
 
backend/static/index.html CHANGED
@@ -19,8 +19,8 @@
19
  property="og:description"
20
  content="Score a text corpus against validated psychological questionnaires. Operated by the Culture and Morality Lab, University of Massachusetts Amherst."
21
  />
22
- <script type="module" crossorigin src="/assets/index-Bmj3fjiw.js"></script>
23
- <link rel="stylesheet" crossorigin href="/assets/index-C34IhTSf.css">
24
  </head>
25
  <body>
26
  <noscript>
 
19
  property="og:description"
20
  content="Score a text corpus against validated psychological questionnaires. Operated by the Culture and Morality Lab, University of Massachusetts Amherst."
21
  />
22
+ <script type="module" crossorigin src="/assets/index-dPONKjSo.js"></script>
23
+ <link rel="stylesheet" crossorigin href="/assets/index-CrxbvzWk.css">
24
  </head>
25
  <body>
26
  <noscript>
frontend/src/App.jsx CHANGED
@@ -31,6 +31,22 @@ function initialSidebarOpen() {
31
  }
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  function relativeTime(iso) {
35
  if (!iso) return "";
36
  const then = new Date(iso.endsWith("Z") || iso.includes("+") ? iso : iso + "Z");
@@ -228,6 +244,11 @@ export default function App() {
228
  if (isNarrow()) setSidebarOpen(false); // the drawer covers what you picked
229
  }
230
 
 
 
 
 
 
231
  const selected = projects.find((p) => p.id === selectedId) || null;
232
  const normalizedFilter = filter.trim().toLowerCase();
233
  const visibleProjects = projects.filter((p) =>
@@ -235,86 +256,57 @@ export default function App() {
235
  );
236
 
237
  return (
238
- <div className="app">
239
- <header className="header">
240
- {!IS_ADMIN_PATH && !showWelcome && (
241
- <button
242
- className="sidebar-toggle"
243
- onClick={() => setSidebarOpen((open) => !open)}
244
- aria-expanded={sidebarOpen}
245
- aria-controls="project-sidebar"
246
- aria-label={sidebarOpen ? "Hide projects" : "Show projects"}
247
- title={sidebarOpen ? "Hide projects" : "Show projects"}
 
 
 
 
248
  >
249
- {/* "Panel left", the same mark ChatGPT and Claude use, so the
250
- gesture is recognisable without a label. */}
251
- <svg
252
- width="17" height="17" viewBox="0 0 24 24" fill="none"
253
- stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"
254
- strokeLinejoin="round" aria-hidden="true"
255
- >
256
- <rect x="3" y="4" width="18" height="16" rx="2" />
257
- <line x1="9" y1="4" x2="9" y2="20" />
258
- </svg>
259
- </button>
260
- )}
261
- <a
262
- className="brand"
263
- href="/"
264
- onClick={(e) => {
265
- // Inside the SPA the brand is an instant way back to the
266
- // dashboard; from /admin it's a normal navigation.
267
- if (!IS_ADMIN_PATH) {
268
- e.preventDefault();
269
- enterDashboard();
270
- }
271
- }}
272
- >
273
- {/* The logo already reads "CCR" - no wordmark next to it, and the
274
- tagline says what the tool does instead of re-expanding the acronym. */}
275
- <img className="brand-logo" src="/ccr-logo-white.svg" alt="CCR Platform" />
276
- </a>
277
- <span className="sub">
278
- Psychological Text Analysis with Contextualized Construct Representation
279
- </span>
280
- <nav className="header-nav">
281
- {IS_ADMIN_PATH ? (
282
- <a className="header-link" href="/welcome">About</a>
283
- ) : (
284
- <button
285
- className={"header-link" + (showWelcome ? " current" : "")}
286
- onClick={() => setShowWelcome(true)}
287
- >
288
- About
289
- </button>
290
- )}
291
- <a className="header-link" href="/guide">Guide</a>
292
- {/* /testing (the click-through testing guide) and /product are both
293
- lab-internal; the server enforces the gate, the header just
294
- doesn't advertise them to everyone else. */}
295
- {["lab", "maintainer", "pi"].includes(auth?.role) && (
296
- <>
297
- <a className="header-link" href="/testing">Testing</a>
298
- <a className="header-link" href="/product">How it works</a>
299
- </>
300
- )}
301
- {auth?.signed_in ? (
302
- <>
303
- <span className="small">Hi, {auth.name}</span>
304
- {auth.is_admin && !IS_ADMIN_PATH && (
305
- <a className="header-btn" href="/admin">Admin</a>
306
- )}
307
- <button className="header-btn" onClick={handleLogout}>
308
- Sign out
309
  </button>
310
- </>
311
- ) : (
312
- <button className="header-btn" onClick={() => setShowLogin(true)}>
313
- Sign in
314
- </button>
315
- )}
316
- </nav>
317
- </header>
318
 
319
  {showLogin && (
320
  <div className="modal-backdrop" onClick={() => setShowLogin(false)}>
@@ -431,18 +423,27 @@ export default function App() {
431
  ) : (
432
  <div className={"layout" + (sidebarOpen ? "" : " sidebar-closed")}>
433
  <aside className="sidebar" id="project-sidebar">
434
- <h2>
435
- Projects
436
- {projects.length > 0 && <span className="count">{projects.length}</span>}
437
- {/* Only shown while the sidebar is a drawer: there it covers the
438
- header's toggle, so it has to carry its own way out. */}
 
 
439
  <button
440
- className="sidebar-close"
441
  onClick={() => setSidebarOpen(false)}
 
 
442
  aria-label="Hide projects"
 
443
  >
444
- ✕
445
  </button>
 
 
 
 
446
  </h2>
447
  <input
448
  type="text"
@@ -501,6 +502,30 @@ export default function App() {
501
  </button>
502
  )}
503
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  </aside>
505
 
506
  {/* Tapping beside an open drawer closes it. Hidden above 820px, where
@@ -514,6 +539,26 @@ export default function App() {
514
  )}
515
 
516
  <main className="main">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  {error && (
518
  <div className="error-banner" onClick={() => setError("")}>
519
  {error}
 
31
  }
32
  }
33
 
34
+ // "Panel left", the mark ChatGPT and Claude both use for this, so the gesture
35
+ // is recognisable without a label. Three buttons share it: collapse, expand,
36
+ // and closing the drawer on a phone.
37
+ function PanelIcon() {
38
+ return (
39
+ <svg
40
+ width="17" height="17" viewBox="0 0 24 24" fill="none"
41
+ stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"
42
+ strokeLinejoin="round" aria-hidden="true"
43
+ >
44
+ <rect x="3" y="4" width="18" height="16" rx="2" />
45
+ <line x1="9" y1="4" x2="9" y2="20" />
46
+ </svg>
47
+ );
48
+ }
49
+
50
  function relativeTime(iso) {
51
  if (!iso) return "";
52
  const then = new Date(iso.endsWith("Z") || iso.includes("+") ? iso : iso + "Z");
 
244
  if (isNarrow()) setSidebarOpen(false); // the drawer covers what you picked
245
  }
246
 
247
+ // The dashboard carries no top bar at all: its sidebar IS the chrome. Only
248
+ // the two views without a sidebar (landing page, /admin) get one.
249
+ const isDashboard = !IS_ADMIN_PATH && !showWelcome;
250
+ const isLabMember = ["lab", "maintainer", "pi"].includes(auth?.role);
251
+
252
  const selected = projects.find((p) => p.id === selectedId) || null;
253
  const normalizedFilter = filter.trim().toLowerCase();
254
  const visibleProjects = projects.filter((p) =>
 
256
  );
257
 
258
  return (
259
+ <div className={"app" + (isDashboard ? " app-dashboard" : "")}>
260
+ {!isDashboard && (
261
+ <header className="topline">
262
+ <a
263
+ className="brand"
264
+ href="/"
265
+ onClick={(e) => {
266
+ // Inside the SPA the brand is an instant way back to the
267
+ // dashboard; from /admin it's a normal navigation.
268
+ if (!IS_ADMIN_PATH) {
269
+ e.preventDefault();
270
+ enterDashboard();
271
+ }
272
+ }}
273
  >
274
+ <img className="brand-logo" src="/ccr-logo.svg" alt="CCR Platform" />
275
+ </a>
276
+ {/* The tagline used to sit here on every screen. It says what the
277
+ product is, which is a landing-page job, so it now lives in the
278
+ hero and the footer and nowhere else. */}
279
+ <nav className="topline-nav">
280
+ {IS_ADMIN_PATH ? (
281
+ <a className="top-link" href="/">Dashboard</a>
282
+ ) : (
283
+ <button className="top-link" onClick={enterDashboard}>Dashboard</button>
284
+ )}
285
+ <a className="top-link" href="/guide">Guide</a>
286
+ {/* /testing and /product are lab-internal; the server enforces the
287
+ gate, the nav just doesn't advertise them to everyone else. */}
288
+ {isLabMember && (
289
+ <>
290
+ <a className="top-link" href="/testing">Testing</a>
291
+ <a className="top-link" href="/product">How it works</a>
292
+ </>
293
+ )}
294
+ {auth?.signed_in ? (
295
+ <>
296
+ <span className="top-name">{auth.name}</span>
297
+ {auth.is_admin && !IS_ADMIN_PATH && (
298
+ <a className="top-link" href="/admin">Admin</a>
299
+ )}
300
+ <button className="top-btn" onClick={handleLogout}>Sign out</button>
301
+ </>
302
+ ) : (
303
+ <button className="top-btn" onClick={() => setShowLogin(true)}>
304
+ Sign in
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  </button>
306
+ )}
307
+ </nav>
308
+ </header>
309
+ )}
 
 
 
 
310
 
311
  {showLogin && (
312
  <div className="modal-backdrop" onClick={() => setShowLogin(false)}>
 
423
  ) : (
424
  <div className={"layout" + (sidebarOpen ? "" : " sidebar-closed")}>
425
  <aside className="sidebar" id="project-sidebar">
426
+ {/* The sidebar carries the identity now that no banner does. The
427
+ same button collapses it on a wide screen and closes the drawer
428
+ on a phone, where it is also the only way out from inside. */}
429
+ <div className="sidebar-head">
430
+ <button className="brand-mini" onClick={enterDashboard} title="CCR Platform">
431
+ <img src="/ccr-logo.svg" alt="CCR Platform" />
432
+ </button>
433
  <button
434
+ className="icon-btn"
435
  onClick={() => setSidebarOpen(false)}
436
+ aria-expanded={sidebarOpen}
437
+ aria-controls="project-sidebar"
438
  aria-label="Hide projects"
439
+ title="Hide projects"
440
  >
441
+ <PanelIcon />
442
  </button>
443
+ </div>
444
+ <h2>
445
+ Projects
446
+ {projects.length > 0 && <span className="count">{projects.length}</span>}
447
  </h2>
448
  <input
449
  type="text"
 
502
  </button>
503
  )}
504
  </div>
505
+
506
+ <div className="sidebar-foot">
507
+ <nav className="sidebar-nav">
508
+ <button className="side-link" onClick={() => setShowWelcome(true)}>About</button>
509
+ <a className="side-link" href="/guide">Guide</a>
510
+ {isLabMember && (
511
+ <>
512
+ <a className="side-link" href="/testing">Testing</a>
513
+ <a className="side-link" href="/product">How it works</a>
514
+ </>
515
+ )}
516
+ {auth?.is_admin && <a className="side-link" href="/admin">Admin</a>}
517
+ </nav>
518
+ {auth?.signed_in ? (
519
+ <div className="sidebar-account">
520
+ <span className="account-name" title={auth.email || ""}>{auth.name}</span>
521
+ <button className="linkish" onClick={handleLogout}>Sign out</button>
522
+ </div>
523
+ ) : (
524
+ <button className="ghost sidebar-signin" onClick={() => setShowLogin(true)}>
525
+ Sign in
526
+ </button>
527
+ )}
528
+ </div>
529
  </aside>
530
 
531
  {/* Tapping beside an open drawer closes it. Hidden above 820px, where
 
539
  )}
540
 
541
  <main className="main">
542
+ {/* Always in the flow, so opening the sidebar does not shift the
543
+ page. It holds the way back in when the sidebar is away, which on
544
+ a phone is every visit. */}
545
+ <div className="main-toolbar">
546
+ {!sidebarOpen && (
547
+ <>
548
+ <button
549
+ className="icon-btn"
550
+ onClick={() => setSidebarOpen(true)}
551
+ aria-expanded={sidebarOpen}
552
+ aria-controls="project-sidebar"
553
+ aria-label="Show projects"
554
+ title="Show projects"
555
+ >
556
+ <PanelIcon />
557
+ </button>
558
+ <img className="brand-mini-img" src="/ccr-logo.svg" alt="CCR Platform" />
559
+ </>
560
+ )}
561
+ </div>
562
  {error && (
563
  <div className="error-banner" onClick={() => setError("")}>
564
  {error}
frontend/src/styles.css CHANGED
@@ -11,6 +11,9 @@
11
  --muted: #667085;
12
  --line: #e5e7eb;
13
  --bg: #f7f7f8;
 
 
 
14
  --card: #ffffff;
15
  --ok: #157f3d;
16
  --err: #b42318;
@@ -50,37 +53,64 @@ body {
50
 
51
  .app { display: flex; flex-direction: column; min-height: 100vh; }
52
 
 
 
 
 
 
 
 
 
 
53
  a { color: var(--brand); }
54
 
55
- /* ---------- header ---------- */
56
- .header {
57
- background: linear-gradient(180deg, #1b1b1c, var(--brand-ink)); /* logo ink */
58
- color: #fff;
59
- padding: 14px 28px;
60
- display: flex;
61
- align-items: center;
62
- flex-wrap: wrap;
63
- gap: 14px;
64
- position: sticky;
65
- top: 0;
66
- z-index: 30;
67
- border-bottom: 1px solid rgba(255, 255, 255, 0.07);
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
- .header .brand {
70
- flex: 0 0 auto;
71
- display: inline-flex;
72
- align-items: center;
73
- gap: 10px;
74
- font-size: 17px;
75
- font-weight: 650;
76
- letter-spacing: 0.2px;
77
- white-space: nowrap;
78
- color: #fff;
79
- text-decoration: none;
80
  }
81
- .brand-logo { height: 28px; width: auto; display: block; } /* sole brand mark - no wordmark */
82
- .header .brand:hover { opacity: 0.88; }
83
- .header .sub { flex: 1 1 280px; min-width: 0; font-size: 12.5px; opacity: 0.85; }
 
 
 
 
 
 
 
 
 
84
 
85
  .layout { display: flex; flex: 1; min-width: 0; min-height: 0; }
86
 
@@ -101,21 +131,52 @@ a { color: var(--brand); }
101
  }
102
  .sidebar-toggle:hover { background: rgba(255, 255, 255, 0.22); }
103
 
104
- /* The in-drawer close button and the backdrop exist only under 820px. */
105
- .sidebar-close { display: none; }
106
  .sidebar-backdrop { display: none; }
107
 
108
  /* ---------- sidebar ---------- */
109
  .sidebar {
110
  width: 250px;
111
- background: var(--card);
112
  border-right: 1px solid var(--line);
113
- padding: 18px 14px;
114
  flex-shrink: 0;
115
  display: flex;
116
  flex-direction: column;
117
  min-height: 0;
118
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  .sidebar h2 {
120
  font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.7px;
121
  color: var(--muted); margin: 0 0 10px 4px;
@@ -127,12 +188,13 @@ a { color: var(--brand); }
127
  }
128
  .sidebar-filter {
129
  width: 100%; padding: 7px 10px; margin-bottom: 10px;
 
130
  border: 1px solid var(--line); border-radius: var(--radius-sm); font: inherit; font-size: 13px;
131
  background: #fff; color: var(--ink);
132
  }
133
  .sidebar-filter:focus { outline: none; border-color: var(--brand); }
134
  .project-list {
135
- flex: 1;
136
  min-height: 0;
137
  overflow-y: auto;
138
  margin: 0 -4px;
@@ -149,8 +211,8 @@ div:first-child > .group-label { margin-top: 2px; }
149
  border: 1px solid transparent; border-radius: var(--radius-sm);
150
  background: none; cursor: pointer; font: inherit; color: var(--ink);
151
  }
152
- .project-item:hover { background: var(--bg); }
153
- .project-item.active { background: var(--accent-soft); border-color: var(--brand); font-weight: 600; }
154
  .project-item .project-name {
155
  display: block;
156
  overflow: hidden;
@@ -166,7 +228,15 @@ div:first-child > .group-label { margin-top: 2px; }
166
  .project-create > button { width: 100%; }
167
 
168
  /* ---------- main ---------- */
169
- .main { flex: 1; padding: 22px 28px; overflow-y: auto; min-width: 0; }
 
 
 
 
 
 
 
 
170
 
171
  .card {
172
  background: var(--card); border: 1px solid var(--line);
@@ -396,26 +466,6 @@ table.docs tbody tr:hover td { background: var(--bg); }
396
  .small { font-size: 12.5px; }
397
  .mt { margin-top: 12px; }
398
 
399
- /* ---------- header nav + auth ---------- */
400
- .header-nav {
401
- margin-left: auto; display: flex; align-items: center; gap: 14px; color: #fff;
402
- flex-wrap: wrap;
403
- }
404
- .header-link {
405
- background: none; border: none; padding: 0;
406
- color: rgba(255, 255, 255, 0.82); font: inherit; font-size: 13px;
407
- cursor: pointer; text-decoration: none; transition: color 0.15s ease;
408
- }
409
- .header-link:hover { color: #fff; text-decoration: underline; }
410
- .header-link.current { color: #fff; font-weight: 600; }
411
- .header-btn {
412
- background: rgba(255, 255, 255, 0.12); color: #fff;
413
- border: 1px solid rgba(255, 255, 255, 0.45);
414
- padding: 5px 14px; border-radius: 7px; font: inherit; font-size: 13px; cursor: pointer;
415
- text-decoration: none; transition: background-color 0.15s ease;
416
- }
417
- .header-btn:hover { background: rgba(255, 255, 255, 0.22); }
418
-
419
  /* ---------- project header + actions ---------- */
420
  .project-header {
421
  display: flex; align-items: center; justify-content: space-between;
@@ -509,18 +559,13 @@ button.danger-solid:disabled { background: #c9ccd1; }
509
  @media (max-width: 820px) {
510
  body { font-size: 14px; }
511
 
512
- .header {
513
- padding: 12px 16px;
514
- align-items: flex-start;
515
- gap: 2px 12px;
516
- }
517
- .header .brand { font-size: 16px; }
518
- .header-nav { gap: 10px 14px; }
519
- .header .sub {
520
- flex: 1 1 210px;
521
- font-size: 12px;
522
- line-height: 1.35;
523
  }
 
 
 
524
 
525
  .layout { display: block; }
526
  /* The sidebar becomes a drawer over the workspace. It used to be a
@@ -530,7 +575,8 @@ button.danger-solid:disabled { background: #c9ccd1; }
530
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 45;
531
  width: min(290px, 84vw);
532
  margin-left: 0;
533
- padding: 14px;
 
534
  border-right: 1px solid var(--line);
535
  box-shadow: var(--shadow-lg);
536
  transform: translateX(-100%);
@@ -542,13 +588,6 @@ button.danger-solid:disabled { background: #c9ccd1; }
542
  .project-list { margin-right: 0; }
543
  .project-create { border-top: 0; }
544
 
545
- .sidebar-close {
546
- display: inline-flex; align-items: center; justify-content: center;
547
- margin-left: auto; padding: 0 2px;
548
- border: 0; background: none; cursor: pointer;
549
- color: var(--muted); font-size: 14px; line-height: 1;
550
- }
551
- .sidebar-close:hover { color: var(--ink); }
552
  .sidebar-backdrop {
553
  display: block; position: fixed; inset: 0; z-index: 44;
554
  background: rgba(20, 22, 26, 0.4);
@@ -596,6 +635,10 @@ button.danger-solid:disabled { background: #c9ccd1; }
596
  margin-bottom: 0;
597
  width: 100%;
598
  }
 
 
 
 
599
  .run-button {
600
  width: 100%;
601
  min-width: 0;
@@ -614,7 +657,6 @@ button.danger-solid:disabled { background: #c9ccd1; }
614
  }
615
 
616
  @media (max-width: 460px) {
617
- .header .sub { flex-basis: 100%; }
618
  .stat-grid { grid-template-columns: 1fr; }
619
  }
620
 
 
11
  --muted: #667085;
12
  --line: #e5e7eb;
13
  --bg: #f7f7f8;
14
+ /* the sidebar rail: a shade under the canvas, the way Claude and ChatGPT
15
+ separate navigation from content without a border doing the work */
16
+ --rail: #f1f1f3;
17
  --card: #ffffff;
18
  --ok: #157f3d;
19
  --err: #b42318;
 
53
 
54
  .app { display: flex; flex-direction: column; min-height: 100vh; }
55
 
56
+ /* The dashboard is an app shell, not a document: it fills the viewport exactly
57
+ and the two panes scroll inside it, so the sidebar's account row and the
58
+ "New project" button stay put instead of drifting to the bottom of a long
59
+ page. Below 820px the sidebar is a drawer and the page scrolls normally, so
60
+ this must not apply there. */
61
+ @media (min-width: 821px) {
62
+ .app-dashboard { height: 100vh; overflow: hidden; }
63
+ }
64
+
65
  a { color: var(--brand); }
66
 
67
+ /* ---------- top line (landing page and /admin only) ----------
68
+ Every screen used to wear a dark banner with the product's full name in it.
69
+ The dashboard now has no top chrome at all - its sidebar is the chrome, as
70
+ in Claude and ChatGPT - and the two views with no sidebar get this instead:
71
+ light, quiet, and no tagline. */
72
+ .topline {
73
+ position: sticky; top: 0; z-index: 30;
74
+ display: flex; align-items: center; gap: 16px;
75
+ padding: 12px 24px;
76
+ background: rgba(247, 247, 248, 0.82);
77
+ backdrop-filter: saturate(180%) blur(10px);
78
+ -webkit-backdrop-filter: saturate(180%) blur(10px);
79
+ border-bottom: 1px solid var(--line);
80
+ }
81
+ .topline .brand { display: inline-flex; align-items: center; text-decoration: none; }
82
+ .brand-logo { height: 26px; width: auto; display: block; }
83
+
84
+ .topline-nav {
85
+ margin-left: auto;
86
+ display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
87
+ }
88
+ .top-link {
89
+ background: none; border: 0; padding: 0;
90
+ font: inherit; font-size: 13.5px; color: var(--muted);
91
+ cursor: pointer; text-decoration: none; transition: color 0.15s ease;
92
  }
93
+ .top-link:hover { color: var(--ink); }
94
+ .top-name { font-size: 13px; color: var(--muted); }
95
+ .top-btn {
96
+ background: var(--brand); color: #fff; border: 0;
97
+ padding: 8px 15px; border-radius: 9px;
98
+ font: inherit; font-size: 13px; font-weight: 600; line-height: 1;
99
+ cursor: pointer; text-decoration: none;
100
+ transition: background-color 0.15s ease;
 
 
 
101
  }
102
+ .top-btn:hover { background: var(--brand-dark); }
103
+
104
+ /* A quiet square button for icons: the sidebar's collapse control and the one
105
+ that brings it back. */
106
+ .icon-btn {
107
+ display: inline-flex; align-items: center; justify-content: center;
108
+ width: 30px; height: 30px; padding: 0; flex-shrink: 0;
109
+ border: 0; border-radius: 8px; background: none;
110
+ color: var(--muted); cursor: pointer;
111
+ transition: background-color 0.15s ease, color 0.15s ease;
112
+ }
113
+ .icon-btn:hover { background: rgba(16, 24, 40, 0.07); color: var(--ink); }
114
 
115
  .layout { display: flex; flex: 1; min-width: 0; min-height: 0; }
116
 
 
131
  }
132
  .sidebar-toggle:hover { background: rgba(255, 255, 255, 0.22); }
133
 
134
+ /* The backdrop exists only under 820px, where the sidebar is a drawer. */
 
135
  .sidebar-backdrop { display: none; }
136
 
137
  /* ---------- sidebar ---------- */
138
  .sidebar {
139
  width: 250px;
140
+ background: var(--rail);
141
  border-right: 1px solid var(--line);
142
+ padding: 10px 12px 12px;
143
  flex-shrink: 0;
144
  display: flex;
145
  flex-direction: column;
146
  min-height: 0;
147
  }
148
+ .sidebar-head {
149
+ display: flex; align-items: center; justify-content: space-between;
150
+ gap: 8px; padding: 2px 2px 8px;
151
+ }
152
+ .brand-mini {
153
+ display: inline-flex; align-items: center;
154
+ border: 0; background: none; padding: 2px; cursor: pointer; border-radius: 8px;
155
+ }
156
+ .brand-mini img, .brand-mini-img { height: 22px; width: auto; display: block; }
157
+ .brand-mini:hover { background: rgba(16, 24, 40, 0.06); }
158
+
159
+ /* What the banner used to carry: the guides, the account, and the way out. */
160
+ .sidebar-foot {
161
+ margin-top: 10px; padding-top: 10px;
162
+ border-top: 1px solid var(--line);
163
+ }
164
+ .sidebar-nav {
165
+ display: flex; flex-wrap: wrap; gap: 4px 14px; margin-bottom: 10px;
166
+ }
167
+ .side-link {
168
+ background: none; border: 0; padding: 0;
169
+ font: inherit; font-size: 12.5px; color: var(--muted);
170
+ cursor: pointer; text-decoration: none;
171
+ }
172
+ .side-link:hover { color: var(--ink); text-decoration: underline; }
173
+ .sidebar-account { display: flex; align-items: center; gap: 10px; }
174
+ .account-name {
175
+ font-size: 13px; font-weight: 600; min-width: 0;
176
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
177
+ }
178
+ .sidebar-account .linkish { margin-left: auto; font-size: 12.5px; flex-shrink: 0; }
179
+ .sidebar-signin { width: 100%; background: var(--card); }
180
  .sidebar h2 {
181
  font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.7px;
182
  color: var(--muted); margin: 0 0 10px 4px;
 
188
  }
189
  .sidebar-filter {
190
  width: 100%; padding: 7px 10px; margin-bottom: 10px;
191
+ /* white on the tinted rail, so the field reads as a field */
192
  border: 1px solid var(--line); border-radius: var(--radius-sm); font: inherit; font-size: 13px;
193
  background: #fff; color: var(--ink);
194
  }
195
  .sidebar-filter:focus { outline: none; border-color: var(--brand); }
196
  .project-list {
197
+ flex: 1 1 auto;
198
  min-height: 0;
199
  overflow-y: auto;
200
  margin: 0 -4px;
 
211
  border: 1px solid transparent; border-radius: var(--radius-sm);
212
  background: none; cursor: pointer; font: inherit; color: var(--ink);
213
  }
214
+ .project-item:hover { background: rgba(16, 24, 40, 0.05); }
215
+ .project-item.active { background: var(--card); border-color: var(--brand); font-weight: 600; }
216
  .project-item .project-name {
217
  display: block;
218
  overflow: hidden;
 
228
  .project-create > button { width: 100%; }
229
 
230
  /* ---------- main ---------- */
231
+ .main { flex: 1; padding: 12px 28px 28px; overflow-y: auto; min-width: 0; }
232
+
233
+ /* Always present, so opening or closing the sidebar never shifts the page.
234
+ Empty while the sidebar is open: that top margin is deliberate breathing
235
+ room now that no banner supplies it. */
236
+ .main-toolbar {
237
+ display: flex; align-items: center; gap: 10px;
238
+ height: 32px; margin-bottom: 6px;
239
+ }
240
 
241
  .card {
242
  background: var(--card); border: 1px solid var(--line);
 
466
  .small { font-size: 12.5px; }
467
  .mt { margin-top: 12px; }
468
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
  /* ---------- project header + actions ---------- */
470
  .project-header {
471
  display: flex; align-items: center; justify-content: space-between;
 
559
  @media (max-width: 820px) {
560
  body { font-size: 14px; }
561
 
562
+ .topline {
563
+ padding: 10px 14px;
564
+ gap: 10px;
 
 
 
 
 
 
 
 
565
  }
566
+ .topline-nav { gap: 12px; }
567
+ .top-link { font-size: 13px; }
568
+ .top-name { display: none; } /* the sidebar names the account; this is chrome */
569
 
570
  .layout { display: block; }
571
  /* The sidebar becomes a drawer over the workspace. It used to be a
 
575
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 45;
576
  width: min(290px, 84vw);
577
  margin-left: 0;
578
+ padding: 10px 12px 14px;
579
+ background: var(--card);
580
  border-right: 1px solid var(--line);
581
  box-shadow: var(--shadow-lg);
582
  transform: translateX(-100%);
 
588
  .project-list { margin-right: 0; }
589
  .project-create { border-top: 0; }
590
 
 
 
 
 
 
 
 
591
  .sidebar-backdrop {
592
  display: block; position: fixed; inset: 0; z-index: 44;
593
  background: rgba(20, 22, 26, 0.4);
 
635
  margin-bottom: 0;
636
  width: 100%;
637
  }
638
+ /* ...except the project's own Archive/Delete pair, which read as a tall
639
+ ragged column at the top of the page. They stay side by side. */
640
+ .project-header .row { flex-direction: row; justify-content: flex-end; }
641
+ .project-header .row > button { width: auto; align-self: auto; }
642
  .run-button {
643
  width: 100%;
644
  min-width: 0;
 
657
  }
658
 
659
  @media (max-width: 460px) {
 
660
  .stat-grid { grid-template-columns: 1fr; }
661
  }
662