Spaces:
Running on CPU Upgrade
fix(ui): one compact corpus row instead of two large cards
Browse filesThree problems with the first cut, all fair.
CAMEL appeared twice, as two "corpora". It is one dataset in two sizes,
so the sizes are now options in a single dropdown and it reads as one
dataset.
It was badged DEFAULT, which overstates it. The PI asked for CAMEL to be
"available and ready-to-use"; that is a starting point, not a claim that
this is THE corpus. The field is renamed default -> preselected, it
decides ordering and what loads first, and nothing is badged.
The two expanded cards took most of Step 1 and pushed the upload control
below the fold, which is the wrong hierarchy: most researchers bring
their own data. Step 1 is now one labelled row - dropdown, info button,
action - and the provenance (description, text column, preprocessing,
citation, dataset link) moved into a modal behind the info button, where
it is one click away without occupying the step.
Also: the listing now knows this instance's row ceiling. The full corpus
is 57,174 rows against a deployed CCR_MAX_ROWS of 50,000, so picking it
failed at ingest AFTER the click. It is now shown as unavailable with
the reason, and becomes usable the moment the deployment raises the
limit - no code change, and the test pins both directions.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- CHANGELOG.md +5 -3
- backend/app/example_corpora.py +37 -7
- backend/app/guide.html +4 -4
- backend/app/main.py +1 -1
- backend/static/assets/index-5w0TZmkt.js +0 -0
- backend/static/assets/index-CrSc0N6z.js +0 -0
- backend/static/assets/{index-DIYdnO4u.css → index-DBdfew4A.css} +1 -1
- backend/static/index.html +2 -2
- backend/tests/test_example_corpora.py +18 -4
- docs/specs/0010-example-corpora.md +16 -0
- frontend/src/Workspace.jsx +83 -43
- frontend/src/styles.css +14 -22
|
@@ -33,9 +33,11 @@ Format: [Keep a Changelog](https://keepachangelog.com/). User-visible changes on
|
|
| 33 |
travels with your results. The full 57,174-text corpus, annotated for 25
|
| 34 |
cultural and moral constructs, is linked on Hugging Face; the platform ships a
|
| 35 |
sample because it runs in seconds. The complete 57,174-text corpus, with the
|
| 36 |
-
annotations for all 25 constructs, is offered
|
| 37 |
-
|
| 38 |
-
|
|
|
|
|
|
|
| 39 |
- Anonymous work is now private to the browser that made it, and is adopted into
|
| 40 |
your account when you sign in. Anonymous visitors previously shared one bucket,
|
| 41 |
so they saw each other's projects and custom constructs; each visitor now has
|
|
|
|
| 33 |
travels with your results. The full 57,174-text corpus, annotated for 25
|
| 34 |
cultural and moral constructs, is linked on Hugging Face; the platform ships a
|
| 35 |
sample because it runs in seconds. The complete 57,174-text corpus, with the
|
| 36 |
+
annotations for all 25 constructs, is offered in the same dropdown for real
|
| 37 |
+
analyses, and an info button shows the text column, preprocessing and citation
|
| 38 |
+
for whichever is selected. A corpus larger than the instance's row limit is
|
| 39 |
+
shown as unavailable with the reason, instead of failing after you pick it.
|
| 40 |
+
Corpus by Zewail et al. (2026). (spec 0010)
|
| 41 |
- Anonymous work is now private to the browser that made it, and is adopted into
|
| 42 |
your account when you sign in. Anonymous visitors previously shared one bucket,
|
| 43 |
so they saw each other's projects and custom constructs; each visitor now has
|
|
@@ -38,7 +38,9 @@ class ExampleCorpus:
|
|
| 38 |
citation: str
|
| 39 |
source_url: str
|
| 40 |
preprocessing: str
|
| 41 |
-
|
|
|
|
|
|
|
| 42 |
storage_key: str = ""
|
| 43 |
# Shown on the card so a researcher can judge fit before running.
|
| 44 |
detail: str = ""
|
|
@@ -57,10 +59,29 @@ class ExampleCorpus:
|
|
| 57 |
and a missing object surfaces as a clear 404 on selection instead."""
|
| 58 |
return self.path.exists() if self.bundled else True
|
| 59 |
|
| 60 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
data = asdict(self)
|
| 62 |
-
data["available"] = self.available()
|
| 63 |
data["bundled"] = self.bundled
|
|
|
|
|
|
|
|
|
|
| 64 |
data.pop("storage_key", None) # internal location, not the user's business
|
| 65 |
return data
|
| 66 |
|
|
@@ -97,7 +118,7 @@ EXAMPLES: list[ExampleCorpus] = [
|
|
| 97 |
"999 texts - median 25 words, mean 69. Runs in seconds on any model. "
|
| 98 |
"Best for a first look at how CCR works."
|
| 99 |
),
|
| 100 |
-
|
| 101 |
),
|
| 102 |
ExampleCorpus(
|
| 103 |
id="camel_full",
|
|
@@ -139,6 +160,15 @@ def get(example_id: str) -> ExampleCorpus | None:
|
|
| 139 |
return BY_ID.get(example_id)
|
| 140 |
|
| 141 |
|
| 142 |
-
def listed() -> list[dict]:
|
| 143 |
-
"""
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
citation: str
|
| 39 |
source_url: str
|
| 40 |
preprocessing: str
|
| 41 |
+
# First in the list and selected on load. NOT a claim that it is 'the'
|
| 42 |
+
# corpus: the PI's ask was for CAMEL to be available and ready to use.
|
| 43 |
+
preselected: bool = False
|
| 44 |
storage_key: str = ""
|
| 45 |
# Shown on the card so a researcher can judge fit before running.
|
| 46 |
detail: str = ""
|
|
|
|
| 59 |
and a missing object surfaces as a clear 404 on selection instead."""
|
| 60 |
return self.path.exists() if self.bundled else True
|
| 61 |
|
| 62 |
+
def blocked_reason(self, row_ceiling: int) -> str:
|
| 63 |
+
"""Why this instance cannot run this corpus, or "" if it can.
|
| 64 |
+
|
| 65 |
+
A corpus larger than CCR_MAX_ROWS is refused at ingest, so offering it
|
| 66 |
+
as a working option produces a dead end. Saying so up front, and why,
|
| 67 |
+
beats an error after the click - and it corrects itself the moment the
|
| 68 |
+
deployment raises the limit.
|
| 69 |
+
"""
|
| 70 |
+
if not self.available():
|
| 71 |
+
return "Not loaded on this instance."
|
| 72 |
+
if row_ceiling and self.n_rows > row_ceiling:
|
| 73 |
+
return (
|
| 74 |
+
f"Too large for this instance: {self.n_rows:,} texts against a "
|
| 75 |
+
f"{row_ceiling:,}-row limit."
|
| 76 |
+
)
|
| 77 |
+
return ""
|
| 78 |
+
|
| 79 |
+
def public(self, row_ceiling: int = 0) -> dict:
|
| 80 |
data = asdict(self)
|
|
|
|
| 81 |
data["bundled"] = self.bundled
|
| 82 |
+
blocked = self.blocked_reason(row_ceiling)
|
| 83 |
+
data["usable"] = not blocked
|
| 84 |
+
data["blocked_reason"] = blocked
|
| 85 |
data.pop("storage_key", None) # internal location, not the user's business
|
| 86 |
return data
|
| 87 |
|
|
|
|
| 118 |
"999 texts - median 25 words, mean 69. Runs in seconds on any model. "
|
| 119 |
"Best for a first look at how CCR works."
|
| 120 |
),
|
| 121 |
+
preselected=True,
|
| 122 |
),
|
| 123 |
ExampleCorpus(
|
| 124 |
id="camel_full",
|
|
|
|
| 160 |
return BY_ID.get(example_id)
|
| 161 |
|
| 162 |
|
| 163 |
+
def listed(row_ceiling: int = 0) -> list[dict]:
|
| 164 |
+
"""Examples this instance has, preselected one first.
|
| 165 |
+
|
| 166 |
+
Entries too large for the row ceiling are still listed but marked unusable
|
| 167 |
+
with a reason, rather than hidden: a corpus quietly vanishing is harder to
|
| 168 |
+
explain than one that says why it is unavailable.
|
| 169 |
+
"""
|
| 170 |
+
return [
|
| 171 |
+
e.public(row_ceiling)
|
| 172 |
+
for e in sorted(EXAMPLES, key=lambda e: not e.preselected)
|
| 173 |
+
if e.available()
|
| 174 |
+
]
|
|
@@ -208,13 +208,13 @@ after that they stay warm.</p>
|
|
| 208 |
<h2 id="samples">0. Sample datasets</h2>
|
| 209 |
<p><b>Nothing to upload?</b> Step 1 of the workspace offers the <b>CAMEL corpus sample</b>
|
| 210 |
as a built-in dataset: click <i>Use this corpus</i> and go straight to picking a construct.
|
| 211 |
-
Two
|
| 212 |
of the full corpus and finishes in seconds, which is the fastest way to see how CCR works.
|
| 213 |
The <b>full corpus</b> is all 57,174 texts with the lab's annotations for 25 cultural and
|
| 214 |
moral constructs included, so CCR scores can be compared against human ratings; expect a few
|
| 215 |
-
minutes on MiniLM and considerably longer on the large models.
|
| 216 |
-
|
| 217 |
-
|
| 218 |
<p class="cite">Zewail, A., Setia, A., Mohammadsadegh, R., Seker, F., Hajian, A., Sosa, H.,
|
| 219 |
Morhayim, L., Reddy, S., & Atari, M. (2026). The Cultural and Moral Expressions in
|
| 220 |
Language (CAMEL) corpus [Preprint].</p>
|
|
|
|
| 208 |
<h2 id="samples">0. Sample datasets</h2>
|
| 209 |
<p><b>Nothing to upload?</b> Step 1 of the workspace offers the <b>CAMEL corpus sample</b>
|
| 210 |
as a built-in dataset: click <i>Use this corpus</i> and go straight to picking a construct.
|
| 211 |
+
Two sizes are offered from one dropdown. The <b>sample</b> (999 texts) keeps the platform mix
|
| 212 |
of the full corpus and finishes in seconds, which is the fastest way to see how CCR works.
|
| 213 |
The <b>full corpus</b> is all 57,174 texts with the lab's annotations for 25 cultural and
|
| 214 |
moral constructs included, so CCR scores can be compared against human ratings; expect a few
|
| 215 |
+
minutes on MiniLM and considerably longer on the large models. The <i>i</i> button beside the dropdown
|
| 216 |
+
shows the text column, preprocessing and citation for whichever is selected. If you publish
|
| 217 |
+
results from either, cite:</p>
|
| 218 |
<p class="cite">Zewail, A., Setia, A., Mohammadsadegh, R., Seker, F., Hajian, A., Sosa, H.,
|
| 219 |
Morhayim, L., Reddy, S., & Atari, M. (2026). The Cultural and Moral Expressions in
|
| 220 |
Language (CAMEL) corpus [Preprint].</p>
|
|
@@ -700,7 +700,7 @@ def list_corpora(project_id: str, db: Session = Depends(get_db)):
|
|
| 700 |
@app.get("/api/example-corpora")
|
| 701 |
def list_example_corpora():
|
| 702 |
"""Bundled corpora a visitor can analyse without uploading anything."""
|
| 703 |
-
return example_corpora.listed()
|
| 704 |
|
| 705 |
|
| 706 |
@app.post(
|
|
|
|
| 700 |
@app.get("/api/example-corpora")
|
| 701 |
def list_example_corpora():
|
| 702 |
"""Bundled corpora a visitor can analyse without uploading anything."""
|
| 703 |
+
return example_corpora.listed(corpus_max_rows())
|
| 704 |
|
| 705 |
|
| 706 |
@app.post(
|
|
The diff for this file is too large to render.
See raw diff
|
|
|
|
The diff for this file is too large to render.
See raw diff
|
|
|
|
@@ -1 +1 @@
|
|
| 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{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{width:100%;border-right:0;border-bottom:1px solid var(--line);padding:14px}.project-list{max-height:220px;margin-right:0;flex:none}.project-create{border-top:0}.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}}.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){.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}.examples{margin:0 0 16px}.examples-label{margin-bottom:8px}.example-card{display:flex;align-items:flex-start;gap:14px;padding:12px 14px;border:1px solid var(--border);border-radius:10px;background:var(--accent-soft)}.example-card+.example-card{margin-top:8px}.example-card button{flex-shrink:0}.example-name{font-weight:600;font-size:14px}.example-desc{margin:4px 0 0;line-height:1.5}.example-cite{margin:6px 0 0;line-height:1.45;opacity:.85}.badge-default{display:inline-block;margin-left:8px;padding:1px 7px;border-radius:999px;background:var(--brand);color:#fff;font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;vertical-align:1px}.example-more{margin-top:6px}.example-more summary{cursor:pointer;color:var(--brand)}.example-more p{margin:6px 0;line-height:1.5}
|
|
|
|
| 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{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{width:100%;border-right:0;border-bottom:1px solid var(--line);padding:14px}.project-list{max-height:220px;margin-right:0;flex:none}.project-create{border-top:0}.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}}.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){.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}.examples{margin:0 0 14px;max-width:620px}.examples-row{align-items:center;gap:8px;margin-top:4px}.examples-row select{flex:1;min-width:0}.examples-row button{flex-shrink:0}.examples-blocked{margin:6px 0 0}.icon-button{width:26px;height:26px;padding:0;border-radius:50%;font-style:italic;font-family:Georgia,Times New Roman,serif;font-size:14px;line-height:1}.example-more p{margin:6px 0;line-height:1.5}
|
|
@@ -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-
|
| 23 |
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
| 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-5w0TZmkt.js"></script>
|
| 23 |
+
<link rel="stylesheet" crossorigin href="/assets/index-DBdfew4A.css">
|
| 24 |
</head>
|
| 25 |
<body>
|
| 26 |
<noscript>
|
|
@@ -51,10 +51,24 @@ def test_storage_location_is_not_exposed_to_clients():
|
|
| 51 |
assert "storage_key" not in row
|
| 52 |
|
| 53 |
|
| 54 |
-
def
|
| 55 |
-
|
| 56 |
-
assert len(
|
| 57 |
-
assert example_corpora.listed()[0]["id"] == "camel_sample"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
|
| 60 |
def test_endpoint_lists_examples(client):
|
|
|
|
| 51 |
assert "storage_key" not in row
|
| 52 |
|
| 53 |
|
| 54 |
+
def test_exactly_one_preselected_example_and_it_is_listed_first():
|
| 55 |
+
picked = [e for e in example_corpora.EXAMPLES if e.preselected]
|
| 56 |
+
assert len(picked) == 1 and picked[0].id == "camel_sample"
|
| 57 |
+
assert example_corpora.listed()[0]["id"] == "camel_sample"
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def test_a_corpus_larger_than_the_row_ceiling_is_listed_but_not_usable():
|
| 61 |
+
"""Offering a corpus this instance would refuse at ingest is a dead end.
|
| 62 |
+
It stays visible with the reason, and becomes usable when the deployment
|
| 63 |
+
raises CCR_MAX_ROWS - no code change needed."""
|
| 64 |
+
rows = {r["id"]: r for r in example_corpora.listed(50_000)}
|
| 65 |
+
assert rows["camel_sample"]["usable"] is True
|
| 66 |
+
assert rows["camel_full"]["usable"] is False
|
| 67 |
+
assert "50,000" in rows["camel_full"]["blocked_reason"]
|
| 68 |
+
|
| 69 |
+
raised = {r["id"]: r for r in example_corpora.listed(100_000)}
|
| 70 |
+
assert raised["camel_full"]["usable"] is True
|
| 71 |
+
assert raised["camel_full"]["blocked_reason"] == ""
|
| 72 |
|
| 73 |
|
| 74 |
def test_endpoint_lists_examples(client):
|
|
@@ -69,6 +69,22 @@ stranger can push into the server; this is a file we ship at a size we chose,
|
|
| 69 |
and letting a visitor try the platform without their own data is the point of
|
| 70 |
the feature. The per-day run cap still applies.
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
## Non-goals
|
| 73 |
|
| 74 |
- Serving the full 57k corpus from the platform. It stays on Hugging Face,
|
|
|
|
| 69 |
and letting a visitor try the platform without their own data is the point of
|
| 70 |
the feature. The per-day run cap still applies.
|
| 71 |
|
| 72 |
+
## Presentation (revised 2026-09-07)
|
| 73 |
+
|
| 74 |
+
The first cut rendered every example as an expanded card, which took most of
|
| 75 |
+
Step 1 and pushed the upload control below the fold - the wrong hierarchy, since
|
| 76 |
+
most researchers bring their own data. It also presented CAMEL twice, as two
|
| 77 |
+
"corpora", when it is one dataset in two sizes.
|
| 78 |
+
|
| 79 |
+
Now: one labelled row holding a dropdown, an info button and the action. Sizes
|
| 80 |
+
are options in that dropdown, so CAMEL reads as one dataset. Provenance
|
| 81 |
+
(description, text column, preprocessing, citation, dataset link) moved into a
|
| 82 |
+
modal behind the info button, where it is available without occupying the step.
|
| 83 |
+
|
| 84 |
+
The entry that loads first is `preselected`, not `default`: the PI asked for
|
| 85 |
+
CAMEL to be "available and ready-to-use", which is a starting point rather than
|
| 86 |
+
a claim that this is THE corpus, and nothing is badged as a default.
|
| 87 |
+
|
| 88 |
## Non-goals
|
| 89 |
|
| 90 |
- Serving the full 57k corpus from the platform. It stays on Hugging Face,
|
|
@@ -7,7 +7,10 @@ export default function Workspace({ project, auth, onAuthRefresh, onProjectChang
|
|
| 7 |
const [corpora, setCorpora] = useState([]);
|
| 8 |
const [constructs, setConstructs] = useState([]);
|
| 9 |
const [examples, setExamples] = useState([]);
|
|
|
|
|
|
|
| 10 |
const [loadingExample, setLoadingExample] = useState("");
|
|
|
|
| 11 |
// Set after an ANONYMOUS visitor saves a construct: their work is scoped to
|
| 12 |
// this browser session and expires with it, so say so at the moment it is
|
| 13 |
// saved rather than letting them discover it later.
|
|
@@ -97,7 +100,16 @@ export default function Workspace({ project, auth, onAuthRefresh, onProjectChang
|
|
| 97 |
useEffect(() => {
|
| 98 |
api.listCorpora(project.id).then(setCorpora).catch((e) => setError(e.message));
|
| 99 |
api.listConstructs().then(setConstructs).catch((e) => setError(e.message));
|
| 100 |
-
api
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
api
|
| 102 |
.models()
|
| 103 |
.then((m) => {
|
|
@@ -296,53 +308,81 @@ export default function Workspace({ project, auth, onAuthRefresh, onProjectChang
|
|
| 296 |
</p>
|
| 297 |
{examples.length > 0 && (
|
| 298 |
<div className="examples">
|
| 299 |
-
<
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
<
|
| 309 |
-
{
|
| 310 |
-
|
| 311 |
-
</
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
<details className="example-more">
|
| 315 |
-
<summary className="small">About this dataset</summary>
|
| 316 |
-
<p className="small">{ex.description}</p>
|
| 317 |
-
<p className="small">
|
| 318 |
-
<b>Text column:</b> {ex.text_column} · <b>Language:</b>{" "}
|
| 319 |
-
{languageName(ex.language)} · <b>Texts:</b>{" "}
|
| 320 |
-
{ex.n_rows.toLocaleString()}
|
| 321 |
-
</p>
|
| 322 |
-
<p className="small">
|
| 323 |
-
<b>Preprocessing:</b> {ex.preprocessing}
|
| 324 |
-
</p>
|
| 325 |
-
<p className="small example-cite">
|
| 326 |
-
<b>Cite as:</b> {ex.citation}
|
| 327 |
-
</p>
|
| 328 |
-
<p className="small">
|
| 329 |
-
Recorded in the run metadata of anything you analyse with it.{" "}
|
| 330 |
-
<a href={ex.source_url} target="_blank" rel="noreferrer">
|
| 331 |
-
Dataset page
|
| 332 |
-
</a>
|
| 333 |
-
</p>
|
| 334 |
-
</details>
|
| 335 |
-
</div>
|
| 336 |
<button
|
| 337 |
type="button"
|
| 338 |
-
className=
|
| 339 |
-
|
| 340 |
-
|
|
|
|
| 341 |
>
|
| 342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
</button>
|
| 344 |
</div>
|
| 345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
</div>
|
| 347 |
)}
|
| 348 |
<div className="row">
|
|
|
|
| 7 |
const [corpora, setCorpora] = useState([]);
|
| 8 |
const [constructs, setConstructs] = useState([]);
|
| 9 |
const [examples, setExamples] = useState([]);
|
| 10 |
+
const [exampleId, setExampleId] = useState("");
|
| 11 |
+
const [showExampleInfo, setShowExampleInfo] = useState(false);
|
| 12 |
const [loadingExample, setLoadingExample] = useState("");
|
| 13 |
+
const selectedExample = examples.find((e) => e.id === exampleId) || null;
|
| 14 |
// Set after an ANONYMOUS visitor saves a construct: their work is scoped to
|
| 15 |
// this browser session and expires with it, so say so at the moment it is
|
| 16 |
// saved rather than letting them discover it later.
|
|
|
|
| 100 |
useEffect(() => {
|
| 101 |
api.listCorpora(project.id).then(setCorpora).catch((e) => setError(e.message));
|
| 102 |
api.listConstructs().then(setConstructs).catch((e) => setError(e.message));
|
| 103 |
+
api
|
| 104 |
+
.exampleCorpora()
|
| 105 |
+
.then((rows) => {
|
| 106 |
+
setExamples(rows);
|
| 107 |
+
// The preselected entry is a starting point, not a claim that this is
|
| 108 |
+
// THE corpus; the list is ordered so it lands first.
|
| 109 |
+
const first = rows.find((r) => r.preselected) || rows[0];
|
| 110 |
+
if (first) setExampleId(first.id);
|
| 111 |
+
})
|
| 112 |
+
.catch(() => {});
|
| 113 |
api
|
| 114 |
.models()
|
| 115 |
.then((m) => {
|
|
|
|
| 308 |
</p>
|
| 309 |
{examples.length > 0 && (
|
| 310 |
<div className="examples">
|
| 311 |
+
<label className="field examples-pick">
|
| 312 |
+
Or use a ready-to-use corpus
|
| 313 |
+
<div className="row examples-row">
|
| 314 |
+
<select
|
| 315 |
+
value={exampleId}
|
| 316 |
+
onChange={(e) => setExampleId(e.target.value)}
|
| 317 |
+
disabled={!!loadingExample}
|
| 318 |
+
>
|
| 319 |
+
{examples.map((ex) => (
|
| 320 |
+
<option key={ex.id} value={ex.id} disabled={!ex.usable}>
|
| 321 |
+
{ex.name} · {ex.n_rows.toLocaleString()} texts
|
| 322 |
+
{ex.usable ? "" : " · unavailable here"}
|
| 323 |
+
</option>
|
| 324 |
+
))}
|
| 325 |
+
</select>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
<button
|
| 327 |
type="button"
|
| 328 |
+
className="icon-button"
|
| 329 |
+
aria-label="About this corpus"
|
| 330 |
+
title="About this corpus"
|
| 331 |
+
onClick={() => setShowExampleInfo(true)}
|
| 332 |
>
|
| 333 |
+
i
|
| 334 |
+
</button>
|
| 335 |
+
<button
|
| 336 |
+
type="button"
|
| 337 |
+
onClick={() => selectedExample && useExample(selectedExample)}
|
| 338 |
+
disabled={!!loadingExample || !selectedExample?.usable}
|
| 339 |
+
>
|
| 340 |
+
{loadingExample ? "Loading…" : "Use this corpus"}
|
| 341 |
</button>
|
| 342 |
</div>
|
| 343 |
+
</label>
|
| 344 |
+
{selectedExample && !selectedExample.usable && (
|
| 345 |
+
<p className="small muted examples-blocked">
|
| 346 |
+
{selectedExample.blocked_reason}
|
| 347 |
+
</p>
|
| 348 |
+
)}
|
| 349 |
+
</div>
|
| 350 |
+
)}
|
| 351 |
+
{showExampleInfo && selectedExample && (
|
| 352 |
+
<div className="modal-backdrop" onMouseDown={() => setShowExampleInfo(false)}>
|
| 353 |
+
<div
|
| 354 |
+
className="modal"
|
| 355 |
+
role="dialog"
|
| 356 |
+
aria-modal="true"
|
| 357 |
+
aria-label={`About ${selectedExample.name}`}
|
| 358 |
+
onMouseDown={(e) => e.stopPropagation()}
|
| 359 |
+
>
|
| 360 |
+
<h3>{selectedExample.name}</h3>
|
| 361 |
+
<p>{selectedExample.description}</p>
|
| 362 |
+
<p className="small">
|
| 363 |
+
<b>Texts:</b> {selectedExample.n_rows.toLocaleString()} ·{" "}
|
| 364 |
+
<b>Text column:</b> {selectedExample.text_column} ·{" "}
|
| 365 |
+
<b>Language:</b> {languageName(selectedExample.language)}
|
| 366 |
+
</p>
|
| 367 |
+
<p className="small">
|
| 368 |
+
<b>Preprocessing:</b> {selectedExample.preprocessing}
|
| 369 |
+
</p>
|
| 370 |
+
<p className="small">
|
| 371 |
+
<b>Cite as:</b> {selectedExample.citation}
|
| 372 |
+
</p>
|
| 373 |
+
<p className="small muted">
|
| 374 |
+
This citation is written into the run metadata of anything you analyse
|
| 375 |
+
with it, so the attribution travels with your results.{" "}
|
| 376 |
+
<a href={selectedExample.source_url} target="_blank" rel="noreferrer">
|
| 377 |
+
Dataset page
|
| 378 |
+
</a>
|
| 379 |
+
</p>
|
| 380 |
+
<div className="modal-actions">
|
| 381 |
+
<button type="button" onClick={() => setShowExampleInfo(false)}>
|
| 382 |
+
Close
|
| 383 |
+
</button>
|
| 384 |
+
</div>
|
| 385 |
+
</div>
|
| 386 |
</div>
|
| 387 |
)}
|
| 388 |
<div className="row">
|
|
@@ -774,26 +774,18 @@ details[open] > summary::before { transform: rotate(90deg); }
|
|
| 774 |
color: var(--brand); text-decoration: underline; font: inherit;
|
| 775 |
}
|
| 776 |
|
| 777 |
-
/* ---------- example corpora (Step 1) ----------
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
.
|
| 781 |
-
|
| 782 |
-
|
| 783 |
-
|
| 784 |
-
}
|
| 785 |
-
.
|
| 786 |
-
.
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
.example-cite { margin: 6px 0 0; line-height: 1.45; opacity: 0.85; }
|
| 792 |
-
.badge-default {
|
| 793 |
-
display: inline-block; margin-left: 8px; padding: 1px 7px; border-radius: 999px;
|
| 794 |
-
background: var(--brand); color: #fff; font-size: 10.5px; font-weight: 600;
|
| 795 |
-
text-transform: uppercase; letter-spacing: 0.5px; vertical-align: 1px;
|
| 796 |
-
}
|
| 797 |
-
.example-more { margin-top: 6px; }
|
| 798 |
-
.example-more summary { cursor: pointer; color: var(--brand); }
|
| 799 |
.example-more p { margin: 6px 0; line-height: 1.5; }
|
|
|
|
| 774 |
color: var(--brand); text-decoration: underline; font: inherit;
|
| 775 |
}
|
| 776 |
|
| 777 |
+
/* ---------- example corpora (Step 1) ----------
|
| 778 |
+
One compact row, not a pile of cards: most researchers upload their own data,
|
| 779 |
+
so the example must not push the upload control below the fold. Detail lives
|
| 780 |
+
behind the info button. */
|
| 781 |
+
.examples { margin: 0 0 14px; max-width: 620px; }
|
| 782 |
+
.examples-row { align-items: center; gap: 8px; margin-top: 4px; }
|
| 783 |
+
.examples-row select { flex: 1; min-width: 0; }
|
| 784 |
+
.examples-row button { flex-shrink: 0; }
|
| 785 |
+
.examples-blocked { margin: 6px 0 0; }
|
| 786 |
+
.icon-button {
|
| 787 |
+
width: 26px; height: 26px; padding: 0; border-radius: 50%;
|
| 788 |
+
font-style: italic; font-family: Georgia, "Times New Roman", serif;
|
| 789 |
+
font-size: 14px; line-height: 1;
|
| 790 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 791 |
.example-more p { margin: 6px 0; line-height: 1.5; }
|