Spaces:
Configuration error
Configuration error
File size: 22,243 Bytes
79cf005 85dca58 79cf005 85dca58 79cf005 85dca58 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | # Handoff: Riprap Findings Region
**Current target version: v0.4.5** (polish on v0.4.4 β now applied in `Riprap Stone-Grouped UI v0.4.5.html`). See `V0.4.5_SPEC.md` for the nine deltas. This README is the v0.4.4 specification and remains the reference for everything *not* changing in v0.4.5.
**Read order for the implementer:**
1. `CLAUDE_CODE_PROMPT.md` β paste into Claude Code
2. `V0.4.5_SPEC.md` β the nine fixes (now realized in `v0.4.5.html`)
3. `README.md` (this file) β v0.4.4 reference
4. `design_files/` β prototypes (both v0.4.4 and v0.4.5 HTMLs are present)
## Overview
**Riprap** is a citation-grounded Flood Exposure Briefing tool for New York City. A user enters an address, neighborhood, or proposed development; Riprap returns a written briefing where every numeric claim links to its primary public-record source (FEMA, USGS, NYC DOITT, FloodNet, NYC OpenData, etc.).
This handoff covers the **Findings region** β the structured-data sibling of the briefing prose. It groups model outputs into five named "Stones" (cognitive roles), each rendered as a card stack with explicit epistemic tiering, smart provenance traces, and cross-linking to the map.
The target codebase is **SvelteKit** (Svelte 5 with runes). The files in `design_files/` are React-based prototypes β design references, not production code. Recreate them as Svelte components.
## About the Design Files
The files in `design_files/` are **design references created in HTML + React** β high-fidelity prototypes showing the intended look and behavior. They are **not production code to copy directly**.
Your task is to **recreate these designs in the existing Svelte codebase**, using its established patterns (Svelte 5 runes, scoped styles, the project's existing route structure and data layer). Lift visual values, copy, and interaction logic from the references; do not transpile JSX to Svelte.
**File pairing** (each prototype area has one or two source files):
- `Riprap Stone-Grouped UI v0.4.4.html` β main prototype, the v0.4.4 Findings region in context
- `findings.jsx` β Findings region: stones, cards, run-health, grammar reference (the centerpiece of this handoff)
- `briefing.jsx` β long-form briefing prose with inline citations
- `map.jsx` β mini-map with FEMA AE / HWM / FloodNet / 311 / address layers and link highlighting
- `trace.jsx`, `stones-trace.jsx`, `stone-evidence.jsx` β provenance trace variants
- `shell.jsx` β app header, footer, cold-start state
- `glyphs.jsx` β four tier glyphs as inline SVG
- `tokens.css` β design tokens (colors, type, spacing). Port verbatim.
- `styles.css` β component CSS. Reference only; rewrite as scoped Svelte styles.
- `tweaks-panel.jsx`, `design-canvas.jsx`, `landing-variants.*` β prototype-time tooling. Ignore.
## Fidelity
**High-fidelity (hifi).** Pixel-perfect mockups with final colors, typography, spacing, glyphs, and interactions. Recreate the UI pixel-perfectly using the codebase's existing libraries and patterns. The tier color values, the IBM Plex font stack, the 4/8/12/16/24/32/48/64/96 spacing scale, and the four-tier glyph system are all final.
The Findings region in particular has been through several iterations (v0.4.0 β v0.4.4) and is settled. Don't redesign card layouts; port them as-is.
## Screens / Views
The product is a single-page app with two states: **cold-start** (no query) and **briefing** (query active).
### 1. Cold-start
Empty state with the wordmark, a deck explaining what Riprap is, a query input, three sample-query buttons, and a "How Riprap is built" trust band. See `shell.jsx` β `<ColdStart>`.
- **Layout**: centered single column, max-width ~720px, paper background (`--paper`)
- **Wordmark**: `riprap` lowercase, IBM Plex Mono 14px / 600, with a 0.85em accent bar `β` prefix
- **Deck**: serif paragraph, 18px, line-height 1.55, ink-secondary
- **Query input**: full width, 1px ink border, mono placeholder, 16px
- **Submit**: ink fill, paper text, mono caps, 13px
- **Sample queries**: three buttons in a column, each shows mode (caps mono) / query (sans 16px) / sub (mono 12px tertiary)
- **Trust band**: section-label heading, italic-serif "Cornerstone remembers. Keystone tallies. Touchstone watches. Lodestone projects. Capstone writes it all down with citations." then a bullet list
### 2. Briefing (active query)
Three-region layout, vertical stack:
1. **App header** (sticky top): wordmark Β· context Β· query pill Β· methodology / export PDF / live status
2. **Briefing prose region**: long-form text with inline `[N]` citations, three side-by-side panes (excerpt Β· evidence cards Β· mini map)
3. **Findings region**: the v0.4.4 Stone-grouped card stack (this handoff's focus)
4. **Footer**: tier legend + build line
The Findings region is the substantial new surface. Everything below documents it.
## Findings Region (v0.4.4) β detailed spec
### Composition
```
<FindingsRegion>
<RunHealthStrip /> β 1 row, top, summarizes all 25 model calls
<StoneRegion stone="cornerstone" />
<StoneRegion stone="keystone" />
<StoneRegion stone="touchstone" />
<StoneRegion stone="lodestone" />
<StoneRegion stone="capstone" />
<CardGrammarReference /> β optional, on by default; one stub per variant
</FindingsRegion>
```
### Stones
Five fixed roles, in order:
| key | name | role | tag |
|---|---|---|---|
| `cornerstone` | Cornerstone | the hazard reader | what NYC's ground remembers |
| `keystone` | Keystone | the asset register | what's exposed |
| `touchstone` | Touchstone | the present-tense witness | what's happening now |
| `lodestone` | Lodestone | the future-pointer | what's coming |
| `capstone` | Capstone | the writer | what we say, with citations |
Each `<StoneRegion>` has:
- **Header**: Stone name (IBM Plex Serif 26px italic for the name, sans for the role) Β· role tagline Β· `<StoneTally>` chip showing `N/M cards fired` Β· provenance toggle button
- **Provenance trace**: smart-default expansion (see below). Renders specialist tree with status pips.
- **Card grid**: 12-column grid, each card spans 4 cols by default (3 per row); register/timeseries/raster cards may span 6.
### Card data schema
```ts
type Card = {
stone: "cornerstone" | "keystone" | "touchstone" | "lodestone" | "capstone";
tier: "empirical" | "modeled" | "proxy" | "synthetic";
variant: CardVariant; // see below
source: string; // short label, e.g. "FEMA"
agency: string; // long form, e.g. "FEMA preliminary FIRM, panel 36047C..."
vintage: string; // e.g. "2024-Q3" or "2007βpresent"
title: string; // card title
// variant-specific fields:
headline?: string; subhead?: string;
columns?: string[]; rows?: (string | number)[][];
scalars?: { label: string; value: string; unit?: string }[];
spark?: number[]; histogram?: number[];
timeseries?: { hours: number[]; values: number[]; threshold?: number };
forecast?: { years: number[]; p10: number[]; p50: number[]; p90: number[] };
raster?: "stormwater" | "fema-ae" | "hwm" | "floodnet-density" | ...;
register?: { tag: string; label: string; sourceId: string; detail: string }[];
comparison?: { left: ScalarSet; right: ScalarSet; delta: string };
meta?: Record<string, string>;
// citation fan-out:
cites?: { id: string; label: string; href?: string }[];
// map link:
mapLayer?: "fema-ae" | "hwm" | "floodnet" | "nycha" | "address" | ...;
};
```
See `findings.jsx` lines 12β230 for the canonical `CARDS` table populated for the Red Hook query.
### Card grammar (12 variants)
Every card uses the same chrome β title row (sans 14/600), source Β· agency Β· vintage row (mono 11/tertiary), a body block, and a footer with the **tier badge** (3-letter caps mono) and a "cite" button. The body block is one of:
| variant | shape | use |
|---|---|---|
| `headline` | one big number/label, scenario-tagged subhead | single-fact cards: "Zone AE" |
| `tabular` | small NΓ3 table, mono | observation lists: HWM marks |
| `scalars` | 2β3 labeled scalars in a row | "1.2 m Β· 0.18 mi Β· 2012" |
| `spark` | 60Γ24 inline sparkline, no axes | trend at a glance |
| `histogram` | 8β12 bar histogram, mono labels | distributions |
| `timeseries` | 240Γ84 line chart with threshold rule | hourly water level, 311 calls |
| `forecast` | 240Γ88 fan chart (p10/p50/p90) | 2050/2080 SLR, surge |
| `raster` | 240Γ120 stylized raster thumbnail | FEMA AE polygon, stormwater extent, HWM contour |
| `raster-pred` | same shape with dashed top-rule (synthetic tier) | TerraMind 2050 prediction |
| `register` | 3-col dense list (tag Β· label Β· sourceId), detail in `title=` tooltip | NYCHA buildings, schools |
| `comparison` | side-by-side scalar columns with delta | FEMA-AE vs Prithvi-2050 |
| `meta` | definition list of run metadata | model id, prompt hash, latency |
**Synthetic tier** cards (TerraMind predictions, prior-only Lodestone outputs) get a **dashed top-rule** (1px dashed `--tier-synthetic-line`) to telegraph "no observed data here." Comparison cards always render synthetic.
The `<CardGrammarReference>` region renders one stub per variant in `findings.jsx` lines 529β581 β a visual catalog the design team uses to spot-check fidelity. Keep it, gate it on `showGrammar` prop (default true in dev, false in prod).
### Tier system
Four epistemic tiers, encoded redundantly:
| tier | color | glyph | badge | meaning |
|---|---|---|---|---|
| `empirical` | `#0B5394` (8.59:1) | filled square | EMP | observed, ground-truth |
| `modeled` | `#2A6FA8` (5.41:1) | open square | MOD | computed from observations |
| `proxy` | `#6B6B6B` (5.74:1) | dotted ring | PRX | indirect signal, e.g. 311 calls |
| `synthetic` | `#2A6FA8` + dashed | hatched square | SYN | model prior, no observation |
Glyphs are inline SVG, 12Γ12, black-stroke. See `glyphs.jsx` for the four shapes.
**Accessibility**: tier is *always* encoded by color + glyph + label, never color alone. Modeled and synthetic share a hue; the dashed top-rule and glyph carry the difference.
### Provenance trace
Every Stone has a tree of specialists ("CORN-001: pull FEMA NFHL β CORN-002: parse panel index β ..."). Each specialist has a status: `ok` / `warn` / `error` / `silent`.
**Smart-default rule** (`provenanceMode = "smart"`):
- All-`ok` Stone β **collapsed** by default, single-line summary "12/12 specialists fired clean"
- Any `warn` or `error` β **expanded**, full tree visible
- All `silent` β collapsed, single-line "no firings (section omitted from briefing)"
`provenanceMode = "expanded"` forces all expanded; `"collapsed"` forces all collapsed (warn/error still get a count chip).
The trace UI: indented tree, mono ids, status pip (β/β²/β /β) in tier-color or warn/error colors. Specialist names italic-serif. Hovering a specialist row dims the rest. See `trace.jsx` for the leaf and `stones-trace.jsx` for the per-Stone composition.
### Run-health strip
Single row above the Stones, full-width. Shows:
- Total specialists fired / total specialists registered (e.g. `83/100`)
- Per-tier breakdown as four chips: `EMP 41 Β· MOD 28 Β· PRX 12 Β· SYN 2`
- Total runtime (e.g. `3.4s`)
- Cache-hit ratio (e.g. `92%`)
Mono throughout. Background `--paper-deep`, 1px ink-soft top + bottom rule.
### Hover linking
Every card with a `mapLayer` is hoverable. On hover (or focus), the card's `key` becomes the page-level `linkedKey`. The briefing's map frame reads `linkedKey` and:
- Adds `is-link-{layer}` class to its root, which lights up that layer (see `map.jsx` for the CSS rules)
- Renders a small label badge bottom-right: "linked: {layer}"
The same applies in reverse: hovering a layer in the map sets `linkedKey` to the corresponding card key, which gets a 2px accent outline.
In Svelte: lift `linkedKey` to `+page.svelte` as `let linkedKey = $state(null)`, pass it down both branches, and have the cards / layers update it on `pointerenter` / `focus` / `pointerleave` / `blur`.
### Density
`density: "compact" | "comfortable"` (default `comfortable`).
- **Comfortable**: 16px card padding, 14px line-height multiplier 1.4
- **Compact**: 10px card padding, 12px line-height multiplier 1.25, register-card row height 18px (vs 24px)
Pass through to all card bodies; only register/tabular/meta visibly change.
## Interactions & Behavior
- **Card hover**: 200ms `background-color` transition to `--paper-deep`, 2px accent outline if linked
- **Cite button**: opens a small popover with the full citation list (`cites[]`), each row a link to the source PDF/page
- **Provenance toggle**: button with `aria-expanded`, animates the tree open/closed via `details`/`summary` or scoped `max-height` transition (β€200ms)
- **Map layer hover**: sets `linkedKey`, 100ms layer fill opacity transition
- **Reduced motion**: all transitions become 0.01ms via the global rule in `tokens.css`. Don't add motion on top.
- **Keyboard**: every card is `tabindex=0` with `aria-label="{tier} card Β· {title} Β· {source}"`. Cite button is real `<button>`. Provenance toggle is real `<button>`.
- **Loading**: cards show a 1px ink-soft skeleton (no spinner); replace with content when the specialist returns
- **Error / silent**: cards with status `error` render a 1-line "specialist failed: {reason}" in tier-error color and stay; cards with status `silent` are omitted entirely (silence over confabulation β design tenet)
## State Management
Svelte 5 runes; lift to `+page.svelte`:
```svelte
<script>
let query = $state(null);
let density = $state("comfortable");
let provenanceMode = $state("smart");
let showComparison = $state(false);
let showGrammar = $state(false); // dev-only toggle
let linkedKey = $state(null);
// Data: load once per query, hydrate from server
let cardsByStone = $derived(loadCards(query));
let runHealth = $derived(summarize(cardsByStone));
</script>
```
Children take props via `$props()`. No Svelte stores unless cross-route.
Data fetching: assume the existing codebase has a `+page.server.ts` load function that runs the 25 specialists and returns the `Card[]` payload. This handoff doesn't change the data layer; it changes the rendering.
## Design Tokens
Port `tokens.css` verbatim. Key values:
**Tier colors** (all WCAG AA on white):
- `--tier-empirical: #0B5394` (8.59:1)
- `--tier-modeled: #2A6FA8` (5.41:1)
- `--tier-proxy: #6B6B6B` (5.74:1)
- `--tier-synthetic: #2A6FA8` (pattern-differentiated)
**Neutrals**:
- `--paper: #FAFAF7` (warm near-white, USGS-report register)
- `--paper-deep: #F2F2EE`
- `--ink: #1A1A1A` Β· `--ink-secondary: #4A4A4A` Β· `--ink-tertiary: #6B6B6B`
- `--rule: #1A1A1A` Β· `--rule-soft: #C9C9C5`
**Accent**:
- `--accent: #B8620A` (for text, AA)
- `--accent-graphical: #D17C00` (for shapes/lines, β₯3:1)
**Type**:
- `--font-sans: "IBM Plex Sans"` (UI, body)
- `--font-serif: "IBM Plex Serif"` (Stone names, hero italic emphasis, oversized stone numerals)
- `--font-mono: "IBM Plex Mono"` (labels, source ids, badges, table cells)
All three are SIL OFL / Apache; self-host or load from Google Fonts. **No system fallbacks for branding** β always specify the Plex stack, fall through only on load failure.
**Spacing** (`--s-1` through `--s-9`): 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96 px. Use these tokens; don't hand-roll values.
**Type scale** (suggested, not enforced):
- 11px mono labels (`section-label`)
- 12β13px mono row text
- 14px sans card titles (600)
- 16px sans body
- 18px sans deck text
- 26px serif italic Stone names
- 36β52px serif headlines (italic for emphasis)
**Radius**: 0 throughout (this is a civic-tech-clean, USGS-report register; no rounded corners except `1px` on focus rings).
**Shadows**: none. Differentiation by 1px rules and `--paper-deep` fills only.
## Assets
- **Fonts**: IBM Plex Sans / Serif / Mono. Self-host woff2 or Google Fonts.
- **Wordmark**: text + accent bar `β` prefix, no logo file
- **Tier glyphs**: inline SVG, see `glyphs.jsx`
- **Map raster thumbnails**: hand-drawn SVG approximations using each layer's conventional palette. See `findings.jsx` β `RasterThumb`. Replace with real raster previews if/when MapLibre tile snapshots are wired up.
- **Real map**: the production map should use **MapLibre GL** with a custom `style.json` that respects the tier palette. Style fragments are sketched in `shell.jsx` comments.
- **No icon library.** No Lucide, no Heroicons. SVG glyphs for tiers, mono characters (β, β, β) for chrome.
- **No emoji.**
## Files in this bundle
```
design_handoff_riprap_findings/
βββ CLAUDE_CODE_PROMPT.md β paste this into Claude Code first
βββ README.md β you are here
βββ design_files/
βββ Riprap Stone-Grouped UI v0.4.4.html β main prototype, open in browser
βββ Riprap Landing.html
βββ Riprap Landing Variants.html
βββ tokens.css β port verbatim
βββ styles.css β reference only
βββ findings.jsx β Findings region (this handoff's centerpiece)
βββ briefing.jsx β long-form prose
βββ evidence.jsx β evidence card stack used in briefing
βββ map.jsx β mini-map with link highlighting
βββ trace.jsx
βββ stones-trace.jsx
βββ stone-evidence.jsx
βββ shell.jsx β header, footer, cold-start
βββ glyphs.jsx β four tier glyphs
βββ tweaks-panel.jsx β prototype tooling, ignore
βββ design-canvas.jsx β prototype tooling, ignore
βββ landing-variants.css β marketing-page exploration, ignore unless asked
βββ landing-variants.jsx β marketing-page exploration, ignore unless asked
```
## Scope
**In scope** for this handoff:
- The Findings region (5 Stones, 12 card variants, run-health strip, smart provenance, hover linking, card grammar reference)
- Briefing prose and map, to the extent they connect to Findings via `linkedKey`
- The marketing **landing page** (see Β§"Landing page" below)
- v0.4.5 deltas in `V0.4.5_SPEC.md`
**Out of scope**: the methodology PDF, the export-PDF flow.
## Landing page
The landing page is the public-facing entry point at `/` (separate from the app's cold-start state at `/app`). Two design files in `design_files/`:
- `Riprap Landing.html` β final shipping landing page
- `Riprap Landing Variants.html` β three exploratory variants on a design canvas (kept for reference; do not port)
### Landing structure (port `Riprap Landing.html`)
Four-section vertical scroll, max-width 1200px, paper background:
1. **Hero**
- Wordmark top-left (with `β` accent prefix)
- Headline (52px serif, italic emphasis on *any place*, line-broken into two lines)
- Deck (18px sans, max 70ch, ink-secondary)
- Big query box: "Try:" label + cycling example queries on a fixed dotted-underline rail (rail width pinned, ellipsis fallback for overflow)
- Submit button (ink fill, paper text, mono caps)
2. **"What you'll get back" preview** β 3-pane grid (1.4fr / 1fr / 1fr), bottoms equalized:
- **Excerpt pane**: serif briefing snippet with inline `[N]` citation pins; compact source list at bottom (tier-coded)
- **Evidence cards pane**: 2x2 grid of compact evidence cards, each with tier-coded left rule (2px), claim, source
- **Map pane**: mini SVG map (240x200, 8px paper-grain grid texture) with FEMA-AE polygon fill, HWM contour, FloodNet sensor pin, 311 cluster, address pin, and a compact tier-legend overlay bottom-edge
3. **Five Stones strip** β explanation grid: 5 columns (`repeat(5, 1fr)`), one cell per Stone:
- Oversized italic-serif numerals `01..05` top-right of each cell (in `--rule-soft`, decorative)
- Stone name (serif 22px / 500)
- Role tagline (sans 13px / ink-secondary)
- Italic-serif tag ("what NYC's ground remembers" etc.)
- Dashed rule + mono source list at bottom
4. **Footer** β earns its keep:
- Tier legend (4 swatches: empirical / modeled / proxy / synthetic)
- Build line (mono, ink-tertiary)
### Landing β what's settled (don't redesign)
- The hero dropped the redundant "Riprap" eyebrow; the wordmark already says it. Headline carries the lede.
- Cycling examples ride a single fixed dotted underline (no jump on length change). Pin the rail width; ellipsis-truncate overflow.
- Pane heights are equalized via a flex-1 spacer in the cards pane and `flex: 1` on the map pane.
- Map texture is a subtle 8px paper-grain grid behind the colored layers β gives it a map register, not a diagram register.
- Stones strip uses oversized italic numerals as a typographic register (decorative, in soft-rule color).
- Italic serif is intentional: hero emphasis + Stone tags + Stone numerals. Reads as a deliberate third voice.
### Landing β em-dashes
All user-facing em-dashes have been purged from `Riprap Landing.html`, `landing-variants.css`, and `landing-variants.jsx`. Replacement convention: `, ` (comma-space) for em-dashes used as parenthetical breaks. **Maintain this convention** when porting copy. Em-dashes in source-code comments (non-rendered) are fine.
### Landing β out of scope variants
`Riprap Landing Variants.html` contains three earlier explorations on a design canvas: v1 (minimal pushed harder), v2 (example gallery), v3 (methodology-forward). Kept for reference only; **do not port**. The shipping landing page is `Riprap Landing.html` (a refinement of v1).
## Open questions for the design team
These are deliberately *not* resolved in the prototype; raise them with the designer before locking implementation:
1. Should `register` cards paginate when N > 20, or stay scrollable in a fixed-height card?
2. The `comparison` card is currently always synthetic (FEMA-AE vs Prithvi-2050). Will there be empirical-vs-empirical comparisons (e.g. FEMA-AE vs HWM observed)?
3. Run-health cache-hit ratio β is this surfaced to end users, or is it dev-mode only?
4. Provenance trace expansion: should expanded state survive across query changes, or reset?
|