Align with the Pacific Data Hub visual identity - #1
Open
gvdr wants to merge 26 commits into
Open
Conversation
A package-lock.json above this directory makes Turbopack's root inference select /home/gvdr/reps, which breaks module resolution locally: the dev server logs "Can't resolve 'tailwindcss'" and then serves every page unstyled while still returning 200. Easy to misread as the page being broken rather than the toolchain picking the wrong root. Vercel is unaffected, since the repository is the root there, which is why this only ever appears in local development. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The visual identity guidelines (52pp, V1.0) plus logo, pattern, icon and font artefacts, ~300 MB from SharePoint. The source package is gitignored: SharePoint is its home, and only four curated SVGs belong here. The headline is that we are most of the way there already. The PDH website uses Inter (p26, p27) and so do we. Trade Gothic, which the guidelines otherwise specify, is for the logotype and print, and is a licensed Linotype face we could not have served as a webfont. What looked like the largest obstacle before reading the document does not exist. What remains is colour, chrome and iconography: dark blue #223b83, turquoise #00a6c8, deep orange #e37b0a as an accent only, a turquoise to dark blue gradient, a solid dark blue header with the active nav item in orange, a near-black footer, and the horizontal logo lockup, which is the one case where the guidelines prefer it over the centred version. Two things recorded rather than resolved. The supplied artwork renders #1c478e and #e47f25 against the #223b83 and #e37b0a printed on p11, likely a CMYK to RGB export difference; the guidelines are taken as authoritative and the artwork left untouched, since altering brand files is PDH's call. And the fifteen domain pictograms map onto the categories we already carry per dataflow, which is an alignment opportunity that costs little because the categorisation exists. The logos are converted to SVG from the vector PDFs rather than shipped as PNG, so the header scales without raster assets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The Web Elements folder arrived on a second attempt and supersedes the vector-PDF conversions: web-ready SVGs for the logos, the fifteen domain pictograms, the pattern at three densities, and a favicon set. It also resolves what the last commit left open. The print artwork renders #1c478e and #e47f25, which looked like a conflict with the #223b83 and #e37b0a printed on p11. The official web SVGs use the p11 values exactly, so the guidelines are authoritative for web and the print files simply carry a CMYK to RGB export difference. Nothing to raise with PDH. Recorded because someone will otherwise fix them: the pictograms use #f47216 and the pattern #1ab4cf, both brighter than their brand equivalents. They sit on dark blue fields where the brand values would go muddy, so they read as intended rather than as drift. The favicon set is not adopted. It is the PDH mark, and taking it would have Surfer's browser tab claim to be Pacific Data Hub rather than a tool within it. That is the same identity question as the per-tool header on p28, and it is a decision rather than a file copy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
Sets the name in Trade Gothic Bold Extended, the face the guidelines specify for the logotype, with two bespoke glyphs in the PDH manner. The lambda is the A with its crossbar removed, which is what PDH already does. Its geometry is lifted from the real A outline rather than eyeballed: the outer edges are the A's own, the inner edges are those offset by the stem width, and they meet at (.447,.5846). The florin is the new one. The F keeps its uppercase skeleton so the cap line stays unbroken, and the stem carries past the baseline into a wave breaking left, drawn as a constant-width stroke. A literal florin is a lowercase italic and would fight the geometry around it. Two variants, because the choice is a judgement rather than a fact. With one accent it matches the sibling tools, which use one each: .STAT EXPL⊙RER, PACIFIC MΛP, NEXUS GE⊙NODE. With three it echoes the parent lockup, but the lambdas only restate what PΛCIFIC DΛTΛ HUB already says, so it reads as family resemblance where the florin reads as identity. Glyphs are outlined into SVG rather than shipped as a webfont, which is also the licence-clean way round: Trade Gothic is a licensed Linotype face and outlining for a logo is ordinary desktop use, serving the TTF would not be. The preview route puts the pieces together: the p28 header with the pattern as a faint watermark, both wordmarks, the palette including the two accents that differ from brand, and the fifteen pictograms. Not linked from anywhere; deleting the route removes the experiment. Also excludes brand/ from the proxy matcher. Public assets were being auth-gated, so the logo on the sign-in page, which is itself public, would have been blocked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
One accent, per the decision: DATA SURƒER. The florin is Surfer's own mark and carries the meaning, where a lambda in DATA would only restate what PΛCIFIC DΛTΛ HUB already says. It also matches the sibling tools, which use one accent each. The three-accent variant is retired. The wordmark was generated on a 1240x320 page of which 74% was empty margin, so sizing the image by its box made the product name look far smaller than the parent lockup beside it. Now cropped to its ink, 941x119. Note that cap height is only 68% of that box, the rest being the florin's tail, so box heights are not interchangeable when aligning it and it needs a nudge up rather than true centring. BrandField carries the pattern across header, hero and footer rather than leaving it a header watermark. Drawn with a CSS mask, so one 186 KB asset takes whatever colour a surface needs instead of shipping a recoloured copy per context; where masks are unsupported the field is flat colour, which degrades cleanly rather than breaking. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
Tokens first. The three anchors become PDH's: primary #223b83, secondary #00a6c8, tertiary #e37b0a. Derived tints are recomputed by carrying the lightness and saturation offset each had from its anchor, so the ramp keeps its shape rather than being re-picked by eye; two of them overshot, because the old anchors were far more saturated, and were set by role instead. brand-theme.ts mirrors the same values for the dashboard theme and export, which cannot read CSS variables. Display type moves from Montserrat to Inter, because that is what the PDH website uses. One less font request, and one less thing to be inconsistent about. Chrome: AppHeader is the p28 tool bar, the same one .STAT EXPL⊙RER and PACIFIC MΛP wear, with our lockup and wordmark. AppFooter becomes the p27 near-black field, keeping its old single line behind a compact flag. Neither is mounted globally: pages compose their own top areas today, so adopting these is per-page rather than a change that lands everywhere at once. Pictograms are mapped to the categories the index already carries, which is why this is cheap: both halves existed. Five of ten map. The rest return null on purpose. XDO (Multi-domain) and IND (Industry and Services) have no pictogram that means them, and SDG, BP50 and NMDI are indicator frameworks rather than subjects, so an icon would assert a domain the dataflow does not have. A wrong domain label is worse than none, and the tests pin that rather than leaving it to be improved later. The pattern gets a rule instead of case-by-case judgement: density runs inversely to information density. Strong where there is no data, absent behind data. The empty state is the interesting case, since it inverts the instinct: the user with nothing to read is the one with the most to be persuaded by. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The wordmark sat high in the banner, and my earlier nudge made it worse: I moved it up when the descender means it needed to go down. The florin's tail occupies the bottom third of the image, so centring the bounding box leaves the caps visibly above centre. Fixed in the asset rather than in CSS. The viewBox is now padded so its centre IS the cap centre, which makes items-center correct everywhere and removes the per-call-site nudge entirely. Caps are 49% of the image height, so the header uses a larger h to compensate. This is the kind of alignment that gets re-broken every time someone reuses the asset, so it belongs in the file, not in a class name. The home page now wears the PDH header. AppHeader gained an actions slot, so the settings, admin and sign-out controls move onto the bar restyled for a dark field instead of being replaced. The old glass panel and the local SurferLogo branding block are gone. The hero was filling its space with blurred circles. That is generic decoration, and the Pacific pattern is the identity's own answer to a large empty field, so BrandField's hero variant replaces it: full strength, because nothing on that panel competes with it. This is the rule from the last commit applied rather than described. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The home page headline and body copy were sitting on full-bleed pattern and the contrast was too low to read comfortably. The rule I wrote was the cause. "Pattern density runs inversely to information density" permitted a strong pattern wherever there was no data, and the hero has no data, so it got the pattern behind its text. No data is not no text. Replaced with: the pattern goes around content, never under it. That is also what the guidelines do, on every section divider the pattern sits top-right and bottom-right with the title in clear space, and it is the one instruction they give outright: always give priority to legibility. BrandField now takes a patternArea, so this is enforced rather than remembered. The hero uses a frame: clear in the middle, present in the outer band. Not a right-hand band, which was the obvious choice and is wrong here, because both hero columns carry text and below lg the text column goes full width, so a vertical band would end up under copy at some breakpoint. A frame sits in the padding at every size without the component knowing the layout. The header keeps the full width as the deliberate exception: a thin ribbon with large type, which PDH's own headers do the same way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The flat grey behind the cards was the largest empty area left, and it takes the pattern without breaking the rule: every card, panel and chart is opaque and sits on top, so the pattern only shows in the gutters and nothing is read through it. In the brand dark blue at 5.5%, baked into a separate asset rather than applied with a mask. Masking the body background needs a stacking context on <body>, which is a lot of risk to take for a texture, whereas a plain background-image cannot interact with anything. The cost is one more 187 KB file, cached and requested once. Fixed attachment, so the field stays put while content scrolls, which reads calmer than a moving one; switched to scroll under prefers-reduced-motion, where a fixed field can shimmer against moving content. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
At 5.5% the page background was effectively invisible, which is not what was asked for: the pattern should be seen in the areas around the cards, like the band behind Quick Start. Raised to 12% and the tile tightened from 46rem to 34rem so it reads as pattern rather than as a faint wash. Checked rather than eyeballed, since text does sit on this surface. On the darkest point of a pattern line the background blends to #e0e4ee, where the section headings hold 8.0:1 and body text 12.9:1. Both clear AAA, and they would still clear it at 16%. That headroom exists because every card is opaque, so the only text over the pattern is large headings on a near-white field; it is not a licence to put the pattern behind anything else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The florin is now the font's glyph, U+0192, not a drawn approximation. It was worth checking for: the previous version was an F with a tail that I had to weight and curve by eye against a face somebody else designed, and the real one is simply better. Finding it took a detour. pymupdf drops the character silently because insert_text encodes Latin-1, and its TextWriter cannot embed this font at all, so it looked absent. Reading the cmap directly showed U+0192 mapped to glyph 100 all along. The wordmark is now set from the font outlines via fontTools, with kerning, which also fixes spacing the previous approach got wrong: the florin advances 0.722em against the F's 0.778em, so patching one glyph into a layout built for the F left a gap. Files dropped from 8 KB to 4 KB as a side effect. The headline reads Surƒ the Data, using Inter's own U+0192 rather than the SVG. That answers the question behind it: the two are deliberately different faces. Trade Gothic is the logotype and print face and cannot be served as a webfont, Inter is the website face (p26, p27). A logo in one and running text in the other is the guidelines' own split, not an inconsistency to fix. Checking contrast for the accent turned up a live problem in the hero that predates this. The gradient ran turquoise into dark blue, and the headline and paragraph sit in the top-left, on the turquoise end, where white is 2.9:1. That is under AA for body text. The gradient now starts dark where the copy is and runs turquoise out to the right behind the stat cards, which carry their own surfaces: white goes to 10.4:1. The guidelines put their titles on the dark end too. The accent needed its own value for the same reason. #e37b0a is 3.5:1 on the dark blue and 2.9:1 over the gradient's mid tone, under AA even for large text, so --color-accent-on-dark holds 4.6:1 and 3.7:1. Chrome and light surfaces keep the brand value. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
Checked rather than assumed. PDH's guidelines say it twice, p26 and p27: the website uses the Inter font family. The live site agrees, serving Inter, Roboto Flex and an icon font, with no occurrence of Trade Gothic in the page or any stylesheet. So the split is PDH's own position, not a constraint we invented. Recorded alongside it: desktop and webfont licences are sold separately, so having paid for Trade Gothic can be true and still not cover @font-face. If a webfont licence covering the domain is confirmed later, serving it is about half an hour and the wordmark could become live text rather than SVG; the doc says what that would take and why it is still worth thinking twice, since Trade Gothic Bold Extended is a display face and most of our screens are dense UI and data labels. Also fixes a weight that was never loaded. The hero stat figures use font-black, which is 900, while the font request stops at 800, so the browser has been synthesising it. The old Montserrat request stopped at 800 too, so this predates the switch. Moved to font-extrabold, which is a weight we actually load, rather than adding a sixth file to the critical path for two numbers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The headline and the wordmark carried different florins: Inter's in the running text, Trade Gothic's in the mark. Same character, two drawings, in the same view. My reasoning for that was wrong. I justified it as the guidelines' own split, Trade Gothic for the logotype and Inter for the website, which is right for running text and does not apply here. In the headline the florin is not a letter, it is the mark being quoted inside a sentence. Rendering it in a different face is the one thing that stops it reading as the same identity. So the headline now uses the wordmark's glyph, as an inline SVG. Inline rather than an <img> so it inherits currentColor and costs no request. It is placed from the font's own metrics rather than nudged: the glyph spans 929 units of a 1000 unit em and descends 184 below the baseline, so it is 0.929em tall and shifted down 0.184em, which puts its baseline on the text baseline instead of its bottom edge where a replaced element would otherwise sit. Rendered both together to confirm they match. It keeps role=img with an "f" label, so the line still reads as "Surf the Data" to a screen reader.
These are the other eleven sites of the change committed with the page background: every page root carried min-h-screen bg-surface, and bg-surface is an opaque background-color covering the full viewport, so it painted straight over the body's pattern. Only app/page.tsx made it into that commit; the rest were staged by path and missed. The colour is redundant in all of them, since <body> already carries it. The pattern was being requested and rendered the whole time and then hidden by an opaque rectangle, which is why it read as flat grey on every page rather than only some. Also ignores the two dev logs this worktree writes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The token swap changed the main app and left this module behind, because its colours were written as Tailwind arbitrary values rather than tokens. So Country Snapshots was still Oceanic teal while everything around it had gone PDH blue. That is the module built for MFAT, and the one most likely to be shown to a partner. 49 arbitrary values across 16 files now use tokens. The mapping was chosen against measured usage rather than by matching hues, and one choice matters: #006970 is TEXT in seven of its eight sites, so it maps to the dark cyan rather than the brand cyan. Mapping it by appearance to --color-secondary would have put 2.9:1 text on every one of them; the dark cyan holds 7.3:1. Both the navy and teal buttons carry white text, so their replacements had to stay dark for the same reason. --color-primary-dark is new, for the darkening hover on those buttons. The existing container token is lighter than primary, so it cannot serve that role. The structure diagram is the one place that cannot use tokens, since Mermaid reads a JS object and not CSS. It now takes its values from BRAND_THEME rather than repeating literals, so it follows the palette instead of drifting: the previous theme mixed Oceanic blues with Material green and orange and matched neither of them. BRAND_THEME gained the accent values it needed for that. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The pictogram mapping existed and nothing called it. Now the catalogue cards and the dataflow page both show the Pacific Data Hub icon for their domain, larger on the detail page since it carries one dataflow rather than a grid. It is absent more often than present, by design: five of the ten categories have a pictogram that honestly means them, and the rest return null rather than borrow a near-miss. The category badges keep their colours. They are a rainbow of Tailwind hues and off-brand, but they are also doing categorical work that three brand colours cannot do, which is the chart problem in miniature. Worth deciding while looking at it rather than now: the pictogram may make the colour redundant, in which case the badges could go neutral. Sign-in becomes a split field, brand on the left and the form on a plain surface at the right. It is the strongest brand moment in the app and was a small card on grey, and it is the first thing every new user sees. The pattern runs full strength there because nothing is read over it, and the form never sits on pattern at any width, which keeps the rule intact rather than making an exception for the page that most invites one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
An audit that resolves Tailwind classes against the real token values and
checks every text/background pair that co-occurs on an element. It kept
as scripts/audit-contrast.py, because this is the kind of thing that
regresses quietly.
Four failures, all of which had shipped:
1.1:1 a Measure badge that was light orange on light orange
2.4:1 search placeholders at 50% opacity
2.9:1 the brand cyan as text on white, 18 occurrences
4.2:1 a muted grey that passes on white and fails on the surface it
is actually used on
The cyan is the same trap that came up in Country Snapshots: #00a6c8
reads as an obvious choice for accent text and is not one. The grey is
the more interesting failure, because checking it against white would
have said it was fine.
Focus had no floor at all. Nothing in the app defined a focus-visible
style and six components apply outline-none, so some controls had no
visible keyboard indicator. There is now a ring on anything focusable,
keyboard-only so it never fires on click. Components can still style
focus; they cannot remove it.
Reduced motion had one rule covering the page background against 26
animate-* utilities. Someone who asks for reduced motion now gets the end
state rather than the movement.
Two findings in the first pass were the audit's own bugs rather than the
app's, and are recorded in the script instead of being "fixed": an <img>
matched inside a doc comment, and every input looked unlabelled because
an arrow function in a JSX attribute ends a naive tag match at its >.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The left panel runs the pattern at full strength and the text sat directly on it. Measured against the worst case, where a line of the pattern passes behind the copy, the tagline was 2.37:1. That is the "pattern goes around content, never under it" rule broken by me, on the page that most invites the exception, three commits after writing the rule down. A translucent card at black/35 brings it to 5.7:1 while staying light enough that the pattern still reads through it. Dark rather than white, so the white wordmark sitting above keeps its own contrast. The audit script did not catch this: the field is a gradient with a masked overlay, neither of which is a Tailwind colour class, so it never appeared as a text/background pair. Worth remembering that a clean run means the pairs it can see are fine, not that the page is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
Two renames with different rules, applied together because leaving either half would have produced exactly the inconsistency the pass was meant to remove. The product is Data Surfer now, so 30 user-facing "SDMX Surfer" strings follow: the page title, the builder header, the chat panel's empty state, the gallery copy, invite and access emails, the usage-budget message, and the footers stamped into exported dashboards and PDFs. The standard has been styled SDMx since the SIS-CC restyling, so 42 prose occurrences follow that too. Identifiers keep their old spelling, and the pattern gets that for free rather than by an exception list: it matches SDMX only when the next character cannot continue an identifier. So SDMXDashboard, SDMXParser and SDMXVisualConfig are untouched, and sdmx-dashboard-components and SDMX_ENDPOINT differ in case or separator anyway. Verified afterwards: 11 files still reference SDMXDashboard, tsc is clean, 249 tests pass. One consequence worth stating rather than discovering: this edits both system prompts, so the Anthropic prompt cache misses once per prompt on first use after deploy. A single cold turn each, not a behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
The working screen stays quiet, which is right: the transcript is long-form reading and the preview is data, so neither takes pattern. But quiet had become anonymous, and it was the one screen that did not look like part of the product. Two changes, both cheap in the currency that screen is short of. The header carries the real marks instead of a coloured square and two lines of text: the PDH lockup, a divider, the Data Surfer wordmark, in their coloured versions since that bar is a light glass panel rather than the dark PDH header. Recognisable, and no taller than what it replaced. The chat empty state gets the pattern. That is not an exception to the rule, it is the rule's clearest case: nothing is being read, the user is waiting rather than working, and it disappears the moment a conversation starts. BrandField gains a panel variant for it, on a light surface with the pattern in brand blue at 10% and framed so the copy stays clear, so other empty states can reuse it rather than each inventing something. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
There was no not-found.tsx, so Next served its own default: black Helvetica on white, no navigation, nothing naming the service. A 404 is reached by someone who followed a stale link or mistyped, which makes it one of the few pages guaranteed to find a person already slightly lost, and the worst place to hand them a dead end. It now carries the wordmark, says what probably happened, and offers three ways onward. Verified on the path that matters: a signed-out visitor following a dead link to a published dashboard, /p/<gone>, gets the branded page. Unknown routes elsewhere still redirect to sign-in, which is correct for a private app and not something the 404 should override. The eight surfaces are the same bug as before, missed because the first sweep matched "min-h-screen bg-surface" as adjacent words and these read "flex min-h-screen items-center justify-center bg-surface". Mostly loading and error states, plus the Country Snapshots layout and the builder. Matching on the class list rather than the literal string found them; there are now none left outside <body>, which keeps the colour because it is the surface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
It is a sibling of Data Surfer under the Pacific Data Hub: separate audience, separate access, its own name. So it gets its own wordmark and the same PDH bar, the way .STAT EXPL⊙RER and PACIFIC MΛP do, rather than wearing Data Surfer's marks. C⊙UNTRY SNAPSHOTS, with the circled O. That accent rather than a lambda in SNΛPSHOTS: both were built and rendered, and the lambda mid-way through a long word reads like a typo at a glance, where the circled O at the second letter reads as deliberate. Trade Gothic has no U+2299, so the glyph is the font's own O with a dot at its optical centre, sized at 12.5% of the O width to leave the counter breathing; the first attempt at 15.5% looked stopped-up. The two wordmark generators are now one script covering three kinds of accent: a real glyph substituted from the font, which is what the florin is and what to reach for first; the A with its crossbar removed; and the circled O. Adding a third tool is a table entry. AppHeader takes the product rather than being forked, so the bar cannot drift between the two. Country Snapshots is set smaller in it: the same cap height on a much longer word would leave the bar as nothing but wordmark. Its logo links to its own home, not to Data Surfer's, which is the part that makes it read as a sibling rather than a section. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
Giving Country Snapshots the shared footer left it saying "Data Surfer · Built at the Pacific Community" on every one of its pages, which undoes in the footer what the header just established. AppFooter takes the same product prop the header does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The UI was renamed on this branch; the docs still said SDMX Surfer, and the README and technical reference still carried the older descriptive name, "SPC Conversational Dashboard Builder". Three names for one product across one repo. Also applies the SDMx restyle to doc prose, by the same rule the UI uses: the standard becomes SDMx, and identifiers keep the old spelling, since they are names rather than prose. SDMXDashboard and its config types belong to sdmx-dashboard-components, SDMX_ENDPOINT and SDMX_STATSNZ_KEY are environment variables, and SDMX-JSON is a format name published under the old styling. Dated records are left alone: stitch_assets, docs/superpowers plans and specs, and dashboard-architecture.md, which labels itself Version 0.2, March 2026. Those say what was written at the time, and a rename would quietly rewrite it. Say the word if uniformity is worth more than that. The slide deck is renamed on disk and its four affected text runs edited inside the package, rather than regenerated. The committed .pptx is a hand edit from 2026-07-27 that build_pptx.py cannot reproduce: it carries two embedded screenshots and later copy on slides 3 and 4, and rebuilding it drops the file from 977 KB to 37 KB. The script now says so at the top, because nothing else in the repo did. The licence files never named the product, so nothing changed there. They name SPC as copyright holder, which is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
It opened with "No code has been implemented yet" and described a repo of scoping documents and UI mockups. That has been wrong for months: this is the deployed app. It also still described the Oceanic Data-Scapes theme, which this branch replaced, so a session reading it would have been sent at the palette we just migrated away from. The rewrite points at docs/current-architecture.md rather than restating it, since duplicating 383 lines of route and access semantics into a file nobody rebuilds is how this went stale in the first place. What stays here is what is not derivable from the code: the MCP tool contract, the design tokens, and which documents are current against which are dated records. Records the Country Snapshots gap rather than papering over it: current-architecture.md does not cover it at all. The MCP tools section is unchanged apart from its punctuation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JCDoYnDMGZmu3jREoEKhMo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Aligns the app with the Pacific Data Hub visual identity (Guidelines V1.0), and
brands Country Snapshots as a sibling product rather than a section of Data
Surfer.
Charts are deliberately untouched. Dashboards still render in the existing
chart palette. Three brand colours cannot separate eight series, so data colour
needs its own accessible categorical scale designed to sit beside the brand
rather than be drawn from it. That is a design decision rather than an
implementation, and it is the one place where "align to the standard" and "keep
the data readable" genuinely conflict. Everything here is coherent without it.
What changed
Palette and type. Tokens move to PDH:
#223b83,#00a6c8,#e37b0a.Derived tints were recomputed by carrying each one's offset from its anchor
rather than being re-picked by eye. Display type moves from Montserrat to Inter,
because that is what the PDH website uses — verified against both the guidelines
(p26, p27) and the live site, which serves no Trade Gothic at all. Trade Gothic
appears only as outlined SVG in the wordmarks, which is also the licence-clean
split: desktop licences cover outlining a logo, not
@font-face.Wordmarks.
DATA SURƒERandC⊙UNTRY SNAPSHOTS, following the conventionof
.STAT EXPL⊙RERandPACIFIC MΛP. The florin is Trade Gothic's own U+0192,not an approximation.
scripts/build-wordmarks.pyregenerates both; adding athird tool is a table entry.
Pattern. Carried through header, hero, footer, page surface and empty states
via
BrandField. One rule governs it: the pattern goes around content, neverunder it. An earlier version said "density runs inversely to information
density", which sounds similar and permitted a strong pattern behind the home
page headline, dropping it to an unreadable contrast.
Pictograms. The fifteen PDH domain icons are wired to the categories the
dataflow index already carries. Five of ten categories map; the rest return
nullrather than borrow a near-miss, sinceXDOandINDhave no icon thatmeans them and
SDG/BP50/NMDIare frameworks rather than subjects.Country Snapshots. 49 hardcoded Oceanic colours moved to tokens, and it now
wears the PDH bar with its own wordmark and its own home link.
Renames.
SDMX Surfer→Data Surfer(30 user-facing strings) and proseSDMX→SDMx(42). Identifiers keep their spelling. Note this edits bothsystem prompts, so the Anthropic prompt cache misses once per prompt after
deploy.
A 404 page, which did not exist — Next served its bare default.
Accessibility
An audit (
scripts/audit-contrast.py, kept) found four contrast failures thathad already shipped:
Also fixed: the hero gradient put white text at 2.9:1 (it now runs dark where the
copy sits), nothing defined a
focus-visiblestyle while six components appliedoutline-none, and 26animate-*utilities had no reduced-motion handling.What reviewers should look at
The whole branch was built and verified headless — typecheck, lint, 249 tests,
production build — and only reviewed visually at the end. Visual review is the
thing being asked for, not correctness review.
Three questions are open by choice:
One bar too many, or correct?
the domain, the colour may be redundant and they could go neutral.
One known factual item, unrelated to styling: the hero stat card says
"121 Dataflows", hardcoded, against 127 in the index.