Critical talent feasibility for Nordic enterprises.
A one-page site for the Capasight design-partner program.
Capasight is a pre-commitment talent feasibility gate. Before a technical transformation, site or capability plan is approved, it tests whether the critical roles can be supplied and attracted in the chosen market, compares hire/build/partner/relocate/redesign, records the evidence, and sets the baseline for measuring whether the chosen intervention worked.
The wedge: 10–25 business-critical AI, data, software, embedded or engineering roles, across 1–3 Nordic locations, with an executive decision due inside 90 days.
The site exists to turn that buyer into a paid design-partner conversation — without implying a product, dataset, customer or partnership that does not yet exist.
Live: https://tonyq7.github.io/capasight/
The booking CTA is currently a placeholder. Production builds normally reject placeholder URLs; the ban is temporarily suspended via
ALLOW_PLACEHOLDER_BOOKING_URL. See Before public launch.
Astro, strict TypeScript, native JavaScript and bespoke CSS. No backend, forms, cookies, analytics, CMS, React or Tailwind. Fonts are self-hosted; the site makes no third-party requests until a visitor deliberately follows the booking or source link.
Requires Node 24.
npm ci
cp .env.example .env # then set a real PUBLIC_BOOKING_URL
npm run dev # http://localhost:4321/capasight/| Script | What it does |
|---|---|
npm run dev |
Dev server at the production base path. |
npm run build |
Verifies the evidence ledger, then builds to dist/. |
npm run preview |
Serves the built output. |
npm run check |
astro check — typecheck, including .astro files. |
npm run lint |
ESLint plus the evidence gate. |
npm test |
Playwright: smoke, keyboard, links, axe, responsive. |
Every "Discuss one workforce decision" button points here. It must be a valid, absolute HTTPS scheduling URL that the founder controls, and it must not be a placeholder.
Production builds fail without it, and fail on a placeholder. That is
deliberate — a launch site whose only conversion path is a dead link should not
deploy. Set it locally in .env, and in CI as a repository variable (not a
secret; it ships in the HTML and is public by construction):
Settings → Secrets and variables → Actions → Variables →
PUBLIC_BOOKING_URL
The fit call should ask for company and role, the decision at stake, the critical roles and locations, the decision deadline, and current workforce-planning tooling — and should explicitly ask for no employee or candidate personal data.
Set to 1 while a real scheduling page is being arranged. It suspends the
placeholder ban only.
The escape hatch is deliberately loud rather than convenient: while it is set,
the no production CTA is a placeholder test reports as skipped with its
reason in every CI run instead of quietly passing.
To enforce, set a real PUBLIC_BOOKING_URL and delete
ALLOW_PLACEHOLDER_BOOKING_URL from the repository variables, both workflows,
and playwright.config.ts.
src/config/copy.ts— every string the site renders, as typed records: hero, model, triggers, method, positioning, pilot, FAQ, footer.src/config/claims.ts—Claimrecords (the source ledger).src/config/scenarios.ts—Scenariorecords behind the feasibility gate.src/config/site.ts— identity and the booking URL. The only config module that touchesimport.meta.env.
That split is load-bearing: the other three are free of Astro imports, so
scripts/verify-claims.mjs imports them directly under Node's type stripping and
checks the real records instead of regexing source text.
scripts/verify-claims.mjs runs before every build and fails it on any of:
- Incomplete claims — a missing field, a non-HTTPS source, a malformed or future date, a definition too short to name the population.
- Unsourced market claims — a percentage, money figure or multiplier in the
copy with no
Claimrecord behind it. - Invented scenario counts — any digit, or a spelled-out count of roles, in
an illustrative scenario. An "illustrative" label does not stop "18 roles"
reading as measurement. Durations ("three quarters") are allowed; counts are
not. A record may opt out only by declaring
dataClass: 'user-provided-sample', meaning the figures are the customer's own. - Claims that exceed reality — customers, partnerships, data rights, proof or ROI that do not exist. Checked against the copy records, so a rename cannot smuggle one past.
The rules exist because Capasight's argument is that a number without its population is not evidence. A site that shipped a bare percentage — or a fictional role count — would be arguing against itself.
src/lib/contours.ts models a talent market as a scalar field — overlapping
employers and clusters sum into terrain — and traces iso-lines through it with
marching squares. SurveyPlate.astro draws the result as a contour map with the
plan's route across it, plus a cross-section comparing that route against the
level the plan requires.
It all runs at build time and emits static SVG: the plates are complete with JavaScript disabled, and ship no runtime cost.
The terrain shapes are illustrative. They encode nothing measured. They exist to make the shape of a constraint legible, the way a sketch map makes a route legible without being a survey.
Nothing load-bearing needs JavaScript. Without it the scenario tabs do not
collapse, so all three plates render stacked and readable; reveal animations are
skipped and content is simply present; the FAQ uses native <details>. Reduced
motion is a hard stop, not a softening.
public/og.png is committed. Its source is the unlisted /og-card route,
screenshotted by a real browser because the design depends on self-hosted
variable fonts and an optical-size axis, which SVG rasterisers render
approximately or not at all.
npm run dev # in one terminal
node scripts/make-og.mjs # in anotherPush to main. .github/workflows/deploy.yml builds and publishes to GitHub
Pages via the official Pages workflow, with separate build and deploy jobs, the
github-pages environment, and only contents: read, pages: write and
id-token: write.
Pages must be set to GitHub Actions as its source (Settings → Pages).
.github/workflows/ci.yml runs lint, typecheck, build and the full Playwright
suite on every pull request.
Recorded here because it is a positioning constraint, not a preference. Most are enforced by the evidence gate; all of them are the rule regardless:
- No customer, logo, testimonial or case study — there are none.
- No claimed accuracy, savings, ROI, performance result or market size.
- No proprietary dataset or integration that does not exist.
- No attribution to Talent Venture Group, Talent Venture Studios or Universum Global, and no implication of their endorsement or of privileged data access, without written approval. Until data rights are signed, the site may say only that Capasight can use employer and talent research the customer licenses or commissions.
- No pilot price before three real proposals have tested willingness to pay. No free pilot either.
- Scenarios are labelled illustrative decision logic wherever they appear, and carry no counts.
Human decisions that no script can make:
- Clear Capasight through PRV, Bolagsverket, EUIPO/TMview, domains, search and relevant app/company databases. If a material HR/SaaS conflict appears, stop rather than improvising another brand. (EUIPO guidance)
- Configure the 30-minute design-partner fit call, set the real
PUBLIC_BOOKING_URL, and deleteALLOW_PLACEHOLDER_BOOKING_URLfrom the repository variables, both workflows andplaywright.config.ts. - Approve any future TVG / TVS / Universum attribution in writing, and resolve Universum data rights separately from marketing attribution.
- Add the incorporated entity name to
site.legalEntityonce it exists; it surfaces on the privacy page automatically. - Re-verify the Arbetsförmedlingen claim and bump
lastVerifiedAt. - After name clearance, connect a company-controlled custom domain. Not required for the Pages launch.
This repository was TonyQ7/ML-Project. Its previous contents are preserved at
the tag archive/ml-project-before-capasight.
MIT. Manrope and Newsreader are used under the SIL Open Font License;
their licences are in public/fonts/.