The 'no code changes / no SDK / no rewrite' line is already said
clearly in the Hero subhead and the WhyUs cards. Repeating it on
step 1 of HowItWorks adds nothing. Step 3's tail 'Nothing to
instrument. Nothing to maintain.' is two sentences saying the
same thing — both removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the rotating headline and its <script> block
- Replace with single category-defining H1: 'Ship Camel integrations.
Sleep through the night.'
- Add price microline under the CTAs (14-day trial · from €20/mo)
- Replace 'Sign in' secondary CTA with 'See it in action ↓' anchor
to #walkthrough
- Add three numbered annotation pins overlaid on the screenshot,
with a 3-up legend below the image (correlation ID, failure
context, error pinned)
The eyebrow pill is retained — the only surviving camel pun on
the homepage per the pun-budget decision in the spec.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces DualValueProps + ProductShowcase with a single before/after
split: a styled <pre> block (the 'without' state) next to the
existing /product/error-detail.png screenshot (the 'with' state).
Three short callouts below.
Section anchor #walkthrough is the target for the Hero's
'See it in action ↓' secondary CTA (added in Task 4).
The 'without' panel is implemented as a styled <pre> per the spec —
no asset production required. A future phase may swap to a recorded
terminal screencap; that swap is a one-component change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Founder pedigree quote plus design-partner mailto CTA.
Uses auth.salesEmail (not auth.salesMailto) so we can pass a subject.
Two PENDING gates documented in the component:
- [Founder Name] placeholder
- 'ex-nJAMS' wording subject to trademark clearance
Component is created but not yet wired into index.astro.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds html { scroll-behavior: smooth } with a prefers-reduced-motion
override. Required for the relaunch hero's 'See it in action' anchor
CTA to feel natural.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Twelve atomic tasks, each ending with its own commit:
1. Add scroll-behavior:smooth to global.css
2. Create SocialProofStrip.astro
3. Create ThreeAmWalkthrough.astro
4. Rebuild Hero.astro
5. Slim HowItWorks.astro
6. Refresh WhyUs.astro
7. Rebuild FinalCTA.astro
8. Refresh PricingTeaser.astro
9. Refresh /pricing.astro tier names
10. Wire new sections into index.astro
11. Delete DualValueProps + ProductShowcase
12. Run full quality gates
Order is build-safe: each task leaves the build green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Structural relaunch of the homepage to address the conversion gaps
identified in the post-launch design review:
- Single H1 (kill the rotating one)
- New social proof strip (founder quote + design-partner CTA)
- 3 AM walkthrough section with before/after split (replaces
DualValueProps + ProductShowcase)
- Pricing tier rename: Trial / Starter / Scale / Enterprise
- Pricing teaser slimmed to 2 cards on the homepage
- Pun budget cut from 5+ to 1 (eyebrow pill survives)
Static stack, hosting, and security posture unchanged from the
2026-04-24 spec.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lightbox.astro — reusable native HTMLDialogElement wrapper:
- Trigger: <button> wrapping the <img>, cursor: zoom-in, amber zoom-pill
badge fades in on hover/focus.
- Dialog: showModal() opens a full-viewport modal (≤1800x1200 cap) with
blurred amber-tinted backdrop.
- Close paths: native form[method=dialog] submit (Escape + close button),
click on backdrop, click on the image itself.
- Accessibility: aria-labelledby + visually-hidden heading avoids both
aria-label-misuse and no-redundant-role validator conflicts. Focus
returns to trigger on close (native HTMLDialogElement behavior).
- Motion: 220ms fade+scale open, disabled under prefers-reduced-motion.
- CSP: <script> is Astro-bundled to an external file — script-src 'self'
respected.
Hero and ProductShowcase now use <Lightbox> instead of a raw <img> for
the product screenshots. The existing frame styling (border, glow, ring
overlay) is untouched — the lightbox trigger is a block-level button
that fills the frame.
TopographicBg now actually reads:
- Per-line stroke width varies (triangle wave — contour-interval feel)
- Per-line opacity varies by vertical depth (darker mid-section, lighter
edges)
- One line in four rendered in cyan (echo of cross-route correlation)
- Radial-mask soft edge fade so lines dissolve into the section boundary
- Default opacity bumped from 0.12 to 0.35; section callers still scale it
down via the opacity prop, but the new internal variation makes the
atmosphere visible where before it was invisible
WhyUs second tile: 3-AM storytelling moment now lands typographically:
- Decorative 03:00 glyph (amber/4% alpha) in the top-right corner
- Eyebrow log-entry treatment: pulsing amber dot + mono 03:00:47.218
timestamp + OPS DESK label — reads like a product UI log row
- The rest of the tile unchanged
ProductShowcase figure: figcaption moved to last child (HTML spec
requires figcaption to be first or last in a figure; a div after it was
a validation error).
- DualValueProps: 110ms staggered rise-in on load (cubic-bezier ease),
reduced-motion users see cards pre-populated, no animation.
- All card sections (DualValueProps, HowItWorks, WhyUs, Pricing) gain a
subtle hover lift: -translate-y-0.5, amber/40 border, soft amber drop
shadow. 200ms ease-out — tactile but not noisy.
- Pricing MID tier now looks like the highlighted option: ring-2 accent,
amber-tinted drop shadow, lg:-translate-y-2 (sits above the others),
and a 'MOST POPULAR' ribbon pill. The 1px border swap was invisible.
Editorial section between DualValueProps and HowItWorks. Breaks the
identical-rectangle cascade with an asymmetric 8/4 grid: large
error-detail screenshot with subtle cyan/amber backlight on the left,
three numbered callout captions on the right.
The screenshot (cross-route correlation chain + circuit breaker +
fallback + Java stack trace) makes the 'deep tracing, replay, live
control' claims concrete in a way the abstract RouteDiagram never did.
Cyan kicker on this section (vs. amber elsewhere) signals 'this one is
different' and echoes the cross-route correlation color in the product.
Accidentally committed .claude/scheduled_tasks.lock in the previous
commit. Untrack it and add .claude/ to .gitignore so local Claude Code
session state does not leak into the repo.
- Hero restructured from stacked to 2-col grid on lg+ (copy left, product
screenshot right). Replaces the abstract RouteDiagram with the actual
exchange-detail view — the product doing the thing the copy promises.
- Kicker broken out of the shared uppercase-mono pattern: italic pill with
a soft amber fill/border, scaled up to 14px. The humor now wears a
different costume from the other section kickers.
- Hero brand mark scaled to 64px and given a slow 7s sway (reduced-motion
guarded) — living atmosphere, not ambient animation.
- H1 min-height raised to 2.5em to absorb the 2-line wrap of line 1 at
mobile sizes without layout shift on rotation.
- Amber radial glow behind the product shot + subtle bevel + frame ring.
- Footer placeholder 3-wavy-lines SVG replaced with real camel logo
(spec gap from earlier refresh — header got swapped, footer didn't).
- Screenshot assets imported under public/product/.
1200x630, solid #060a13 ground, amber topographic lines, circle-C mark,
headline 'Run Apache Camel without running Apache Camel.' plus short
subhead. The full camel-compass product logo is not embedded — raster
inside SVG at OG size would bloat the asset. Circle-C wordmark reads
cleanly at the 600x315 thumbnail render.
Tile 2 headline now 'Built by people who know what 3 AM looks like.'
Bodies soften 'bidirectional protocol / signed config' into plain-value
language. nJAMS-legacy trademark review note preserved.
Three tiles: ship-then-sleep, debug-in-daylight, keep-what-you-chose.
Drops -javaagent, nanosecond, and 45+ EIP node types from the landing
copy — those belong in docs.
All three lines render in the DOM; CSS drives the fade via data-active.
Reduced-motion users see the first line only (no interval, no fade).
Rotation pauses on hover and keyboard focus. aria-live=off on the
rotator so AT does not announce every swap; aria-hidden flips per-swap
to avoid duplicate heading announcements.
Also set vite.build.assetsInlineLimit=0 in astro.config.mjs so Astro
emits the rotator script as a same-origin external file (dist/assets/)
rather than inlining it — required for CSP script-src 'self' compliance.
Camel + cameleer figure on compass rose, amber on transparent. Imported
from design-system/assets. Replaces the placeholder topographic-wave icon
across favicon chain, header, and OG assets (subsequent tasks).
13 tasks, each self-contained with exact file paths, final copy,
verification steps, and a commit at the end. Covers: logo + favicon
import (tasks 1-3), SEO meta (task 4), Hero static + rotating H1
(tasks 5-6), all five section copy rewrites (tasks 7-11), OG image
redesign (task 12), end-to-end verification (task 13). CSP-safe
rotation via Astro <script> bundling (script-src 'self' respected).
Hetzner Webhosting L runs Apache with AllowOverride None on the
user docroot, so file-based .htaccess is silently ignored — directives
in public/.htaccess never applied. Confirmed via direct-origin tests:
neither Header, Rewrite, nor FilesMatch fired regardless of the file
being present and readable.
The only origin-side override path on this tier is konsoleH's per-
directory Serverkonfiguration UI, which writes to a separate Apache
config file outside the user's filesystem (and thus outside any
deploy pipeline).
Make the architecture honest:
- Delete public/.htaccess (dead code Apache never reads).
- Remove the "Copy .htaccess into dist" CI step (now a no-op).
- Update deploy.yml header comment to point at Cloudflare for headers.
- Update OPERATOR-CHECKLIST.md §1 with the three Webhosting-L gotchas:
port 222 for SSH, SFTP_PATH must match the actual vhost docroot
(default is bare public_html/), and AllowOverride None.
- Update §5 to reflect manual workflow_dispatch (no auto-deploy on
push) and 5-header expectation.
- Update README.md deploy section likewise.
Headers (HSTS, CSP, XFO, X-Content-Type-Options, Referrer-Policy,
Permissions-Policy) are now owned by Cloudflare Transform Rules,
documented in OPERATOR-CHECKLIST.md §2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes:
1. Merge build and deploy jobs into a single 'deploy' job. This
eliminates the actions/upload-artifact@v3 round-trip, which was
silently stripping dotfiles (.htaccess) from the artifact and
leaving the deployed origin without security headers. The built
dist/ (including .htaccess) now flows directly into rsync in the
same workspace.
2. Remove the 'push: branches: [main]' trigger so deploy runs only
on workflow_dispatch (manual click in Gitea Actions UI).
Merges to main no longer auto-deploy — production promotion is
an explicit user action.
The concurrency group at workflow level still prevents overlapping
deploys. All secrets remain unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy public/.htaccess into dist after Astro build (Astro/Vite drops
dotfiles from public/ otherwise, leaving the origin without HSTS).
# Conflicts:
# .gitea/workflows/deploy.yml
Astro/Vite drops dotfiles from public/ during build, so .htaccess
never makes it into dist/. The deployed Apache origin then has no
header rules to apply, leaving the site without HSTS, X-Frame-Options,
Referrer-Policy, etc. — caught today by the post-deploy smoke test
("HSTS missing").
Copy the file explicitly after build. test -f makes the step fail
loudly if public/.htaccess goes missing, rather than silently
shipping a header-less site.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hetzner Webhosting exposes SSH on TWO ports:
port 22 — SFTP only, refuses remote command exec
port 222 — full SSH with shell, supports rsync
Previous deploys hit "exec request failed on channel 0" because we
were using port 22. Switch back from lftp to plain rsync, but route
it through port 222 with --rsync-path=/usr/bin/rsync (Hetzner's
locked-down PATH doesn't include rsync by default) and BatchMode=yes
to disable interactive prompts.
Mirrors the working local command:
rsync -avz --rsync-path=/usr/bin/rsync \
-e "ssh -p 222 -i ~/.ssh/id_ed25519_gitea -o BatchMode=yes" \
./ apibny@www691.your-server.de:/usr/www/users/apibny/www.cameleer.io
Keeps host-key pinning (StrictHostKeyChecking + UserKnownHostsFile)
which the local command omits because the user's personal known_hosts
already trusts the host.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues from the previous lftp run:
- "GetPass() failed -- assume anonymous login" / "Password required":
without `-u USER,` (trailing comma = empty password), lftp tries
to prompt for a password instead of relying on the ssh key passed
via sftp:connect-program.
- Heredoc body was indented with leading whitespace; lftp can mis-
parse leading-whitespace lines as command continuations.
Also bump verbosity (`debug 3`) so the ssh command lftp launches
is logged — makes the next failure easier to read — and bound
retries to 1 so we fail fast in CI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hetzner Webhosting accepts SSH for file transfer but refuses remote
command exec, failing rsync with:
exec request failed on channel 0
rsync error: error in rsync protocol data stream (code 12)
rsync over SSH requires spawning a remote rsync binary, which isn't
possible on SFTP-only tiers. Switch the mirror to lftp, which speaks
SFTP end-to-end. Same semantics (upload + delete removed files), same
key + known_hosts pinning via sftp:connect-program.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings in the CI infrastructure fixes:
- ci.yml: probe Chromium binary; fall back to Playwright (95977c8)
- tailwind: lift text-faint to meet WCAG AA contrast (2fde385)
- deploy.yml: pin artifact actions to v3 for Gitea (bbd68ec)
actions/upload-artifact@v4 and download-artifact@v4 use the
@actions/artifact v2+ client, which targets a github.com-only
backend and fails on Gitea / Forgejo / GHES with:
GHESNotSupportedError: @actions/artifact v2.0.0+, upload-artifact@v4+
and download-artifact@v4+ are not currently supported on GHES.
Pin both to v3, which uses the older artifact protocol that Gitea
Actions implements.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
text-faint #6b7280 on bg #060a13 measures ~4.06:1 contrast — under the
4.5:1 normal-text threshold — which fails Lighthouse's color-contrast
audit and drops the accessibility score to 0.90 on /pricing and
/privacy (the only pages currently using this token).
#828b9b yields ~5.66:1, clears AA with margin, and stays visually
distinct from text-muted (#9aa3b2, ~7.8:1) so the design hierarchy
between text / text-muted / text-faint is preserved.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Ubuntu runner image ships /usr/bin/chromium-browser as a snap
forwarder stub that exits with "install via snap" when invoked but
is found on PATH. The previous detection used `command -v` only, so
it accepted the stub, set CHROME_PATH to it, and Lighthouse later
failed to launch Chrome (ECONNREFUSED on the debug port).
Probe each candidate with `--version` to confirm it actually runs.
When no working system binary exists, install Playwright's bundled
Chromium (supports linux/arm64) with --with-deps for system libs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Switch ci.yml + deploy.yml env bindings from ${{ vars.* }} to
${{ secrets.* }}. Gitea lets you put non-sensitive Actions values in
either tab, and the secrets tab was used in practice — workflow was
reading the wrong context and getting empty strings.
- Broaden the "no TODO markers ship" guard to accept both TODO: and
legacy TBD: prefixes, matching the imprint/privacy page markers that
were recently renamed.
- Document the secret-vs-variable choice in OPERATOR-CHECKLIST so the
next operator doesn't get tripped up by the same thing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>