Restores and rewrites content on Home, Mobile SDK, DNS Protect, Halo CPE,
For Operators, Financial Services, Why BlackDice, Investors and Contact to
match the approved source copy, removing stray dashes site-wide in favour
of plain punctuation. Removes an unreachable duplicate Contact page block
that left a stray unclosed <div> in the markup. Shrinks and repads the
Guardian Mobile SDK explorer widget so it fits without excess scrolling.
Also includes in-progress nav, blog seed and demo scenario tweaks.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removes the Retina Dashboard and Stats sections from the home page,
repositions the newsroom section after the CTA cards, and fills in
the blank "£bn" APP-fraud stat with "£3.3bn". Caps .bd-hero-in and
.bd-si at 1120px max-width so content stops stretching edge to edge
on wide viewports.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drops speechSynthesis narration, the per-module mute toggle, and the
spoken tab-click announcement. Each module's timing reverts to its
original snappy pace (e.g. Location zones: 32s -> 11s), since the
longer durations were only there to give the voice room to finish.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ports the 9-tab Guardian Mobile SDK phone-demo mockup (mobile-sdk.html)
into a React component and swaps it into #mobile-sdk-demo-mount in
place of ThreatDemosSlider, keeping the site's real header/nav/footer
around it.
- Adds voiceover per module, spoken via speechSynthesis and paced to
the actual speech (each step waits for its utterance to finish
before advancing, instead of a fixed guess at timing), plus a
per-module mute toggle and a spoken announcement on tab click.
- Never autoplays — playback only starts on an explicit tap, matching
the rest of the embedded demos on the site.
- Enhances the Location safety zones module with a full create-a-
boundary -> leave-the-zone -> notified-of-the-alert flow (banner,
breach-colored geofence, updated activity feed).
- Layout polish: floating/glow phone, centred max-width content,
fading tab-strip edges; fixes a CSS grid min-width bug that blew the
hero out to ~1450px on narrow viewports.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
favicon.ico/-32/-192 had an opaque white square behind the cube mark.
Removed the white matte and recoloured the navy line-art to white
(teal accent dots kept) so it reads cleanly on dark browser tabs.
apple-touch-icon.png is left as-is since iOS fills transparent PNGs
with black.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Retina and Angel dashboard images ran full-bleed edge to edge.
Cap them at 75% width and centre, scoped to the Halo CPE page only
(home page keeps its full-width dash-frame). Reverts to 100% under
900px so mobile isn't cramped.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cinematic 30s player showing safe-zone creation and leave-zone alerts,
matching the existing threat-demo pattern. Added as a 6th rotating
slide in ThreatDemosSlider (live on /mobile-sdk and /threat-demos),
plus a standalone /location-demo route for recording.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Route CSS (src/site/styles.css, admin.css) is code-split and only loads once
its lazy route's chunk arrives, so the default browser body margin showed as
a white ring around the dark Suspense fallback until then. Reset html/body
margin directly in index.html so it applies before any JS runs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The registered-office block and the "Company" details line on the contact
page still read "BlackDice Cyber Ltd" — updated both, plus their cached CMS
field previews.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The svg combined a raster BlackDice lockup (icon + wordmark) with a separate
vector "Angel" glyph group appended to the right. Dropped that group and
cropped the viewBox from 417x71 to 280x71 to match. All 12 usages across the
site set height with width:auto, so the narrower logo scales correctly with
no markup/CSS changes needed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
F-03: the legacy markup's 77 onclick="" attributes were the reason script-src
still needed 'unsafe-inline', which let injected inline script/handlers run
right past the policy. Migrated them to data-page/data-action markers handled
by a single delegated click listener in siteController.js, dropped
'unsafe-inline' from script-src, and switched both server/index.mjs and
vercel.json from Content-Security-Policy-Report-Only to enforcing. style-src
keeps 'unsafe-inline' — that governs inline style="" attributes used
throughout, a separate CSS-injection concern out of scope here.
Verified against the built site with a real headless-Chromium run: nav,
company dropdown, mobile menu, the demo modal (open/close/overlay-click/
inner-click), the modal's contact-page link, and the scroll-hint all still
work, with zero console errors.
F-10: confirmed via npm audit fix --dry-run that no non-breaking update
remains (vite and react-router-dom both need a major bump, left deferred).
Added npm audit to CI — full report for visibility, gated on critical only
so it doesn't block on the already-tracked moderate/high advisories.
F-11: uploaded PDFs now serve with Content-Disposition: attachment instead
of rendering inline from the site's own origin.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Post bodies were already re-sanitised on the way back in from a version
snapshot or an imported content file, but content.content{} (the inline
text-field map) wasn't. applyContent() writes that map straight into the
DOM via innerHTML as soon as it loads into the editor, before the admin
ever publishes, so a crafted content file or tampered snapshot could carry
a stored-XSS payload there and execute it in the admin's session on import
alone.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixes the two High-severity findings from Isaac Hague's 19/08/2026 review
(F-01, F-02) plus F-03 through F-09:
- F-01: content writes are now sanitised server-side (sanitize-html) as the
real security boundary — the browser-side sanitiser is UX, not enforcement,
and a direct API write bypassed it entirely. Also closes the javascript:
href gap in sanitiseInline().
- F-02: refusing the factory admin password no longer depends on NODE_ENV;
it's the unconditional default now, with an explicit ALLOW_DEV_PASSWORD=1
opt-in for local dev.
- F-03: adds CSP (report-only — the legacy inline onclick="" handlers would
break under enforcement) and HSTS, in both server/index.mjs and vercel.json.
- F-04/F-05: rate-limits /api/leads and rotates leads.jsonl past 5MB; CSV
export neutralises leading =+-@ so exports can't carry live formulas.
- F-06: sessions drop from 12h to 4h and are tied to a per-boot random epoch,
so a restart now actually revokes outstanding tokens.
- F-07/F-08/F-09: generic messages on 5xx, fixed-length password comparison
(no more length disclosure via the short-circuit), periodic throttle-map
cleanup.
F-10 (dependency advisories): applied the two non-breaking patches (nanoid,
postcss); the vite/react-router-dom major bumps are left for a separate pass,
per the report's own recommendation. F-11 (PDF Content-Disposition) and a
CAPTCHA/honeypot on the enquiry form are deliberately left open — both are
product/UX calls, not pure security fixes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Publishing the GSMA release re-ran scripts/seed-content.mjs, which
fully rebuilds seedContent.json from the studio draft. The hero,
heroAlt, and photo-credit fields added for 12 placeholder images in
f02461b lived only in the generated file, not its source, so the
regeneration silently dropped them again even though the image files
were still on disk.
Restores the 12 posts' hero data and, this time, persists it in
content-seed/additional-posts.json, which seed-content.mjs treats as
an authoritative override that survives re-import.
Replaces the wide wordmark SVG, which was unreadable at tab size, with
the cube mark: a multi-resolution favicon.ico (16-256px) plus PNGs for
modern browsers and mobile home screens.
Also fixes the share image while touching the same tags — og:image and
twitter:image pointed at logo.svg, and no major platform renders SVG
share images, so link previews were coming up blank. Adds a 1200x630
og-default.png and points the JSON-LD organisation logo at a raster URL
too. Articles still override the default with their own hero.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the placeholder draft with the approved final copy from
"2026_0308_BlackDice GSMA PR_V1 GSMA final.docx": real quotes from Paul
Hague and Henry Calvert, the 10 August release date, and the press
contacts. Status flipped to published, so it appears in the newsroom,
the home page strip and sitemap.xml.
Hero is the GSMA Open Gateway logo composed onto a 16:9 white canvas so
it reads correctly both full-width on the article and cropped in card
thumbnails.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ThreatDemosSlider always passed autoPlay to ThreatCinematic, so the
Mobile SDK page's embedded demo — including its speech-synthesis
narration — started 450ms after the page loaded rather than waiting
for a visitor to tap the phone. Autoplay is now standalone-only
(/threat-demos); the embedded instance stays idle until tapped.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Server: refuse to start in production with the default admin password,
drop SVG from the upload allow-list (stored-XSS risk), add baseline
security headers, make the login rate limiter proxy-aware via TRUST_PROXY,
and auto-load .env.local/.env in dev.
Admin: sanitise post bodies on content import/snapshot restore (previously
bypassed sanitiseBody), confirm before discarding a draft, drop back to the
login screen on a mid-session 401 instead of a stuck error, add hero-image
alt text and a title/excerpt search to the articles panel.
Site: replace the soft-404-to-homepage fallback with a real noindex 404
page, add a focus trap/Escape handling/aria-modal to the enquiry modal,
aria-expanded on the mobile nav toggle, ItemList/breadcrumb structured data
for the newsroom and articles, and wire sitemap generation into the build
so it can't go stale. Extract the duplicated NewsGrid/ArticlePage card
markup into a shared PostCard component.
Content: 13 of 18 seed articles shipped with no hero image (one pointed at
a dead WordPress URL); the live blackdice.ai site turned out to still be
the old blackdice-studio.html export, so recovering the originals wasn't
feasible. Filled the gap with freely-licensed Unsplash placeholders,
credited in the author field, until real photography is ready.
Also adds a Gitea Actions CI workflow (typecheck + build).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ArticlePage and NewsGrid called useContent() directly, bypassing the
draft content SiteApp resolves for admin previews. Since /admin is
rendered outside ContentProvider, this always returned an empty post
list, so every article in the studio looked unpublished.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rebuilds content management around a single admin route (/admin —
"BlackDice Studio"), replacing blackdice-studio.html. Publishing writes
one JSON content document instead of regenerating HTML files, so it can
no longer overwrite hand-made site changes the way the old tool did.
- /admin: click-to-edit copy/images, article CRUD with a Word-safe rich
text editor, demo clip management, per-page SEO, enquiry log, publish
history with rollback
- Real per-page URLs for all pages and articles, each with its own
meta/canonical/OG/JSON-LD
- Newsroom + article pages driven by the CMS post library, seeded from
the old studio's export (17 articles) plus a drafted GSMA Open Gateway
press release awaiting approval
- Demo sections on Mobile SDK and Halo CPE, interactive by default and
upgradable to an uploaded clip per slot
- Dependency-free Node API server (auth, publish, uploads, snapshots,
leads, live sitemap)
- Deployment configs for Node/nginx/IIS, Vercel and Netlify
See docs/ARCHITECTURE.md, docs/PROJECT-STRUCTURE.md, docs/CMS-GUIDE.md
and docs/DEPLOYMENT.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>