Owner-authored CV rework: technical skills promoted above experience,
'Centres d'intérêt' dropped, markup trimmed 656 -> 424 lines. Header
carries the Loire-Atlantique · Vendée · Morbihan zone and the presence
hierarchy (full remote, hybrid or on-site in the zone, Paris capped at
1-2 days/month).
Adds CV_Bastien_CHANOT_General.{html,pdf} as the general variant kept
alongside the served CV. Not linked from the landing and not in the
Dockerfile COPY whitelist, so it ships in the repo only, not to prod.
Both HTML/PDF pairs verified in sync via weasyprint re-render (text
identical, 2 pages each). New files normalized to mode 644.
Landing was still advertising Yerres (91) + a planned Nantes relocation,
and a presence rule that omitted on-site work in the target zone.
- about paragraph + callout: zone replaces 'Localisation actuelle';
presence stated in order of preference — full remote, then hybrid or
on-site in the zone, Paris only as a fallback at 1-2 days/month max
- ZenQuality timeline entry: drop the 'Yerres' location, keep 'Full remote'
- CLAUDE.md content rules: geography note rewritten to match, with an
explicit 'never mention Yerres' guard
Verified: no 'Yerres' left outside the negative rule, CSP script hash
unchanged, headless render checked at 375px and 1440px.
Dotfile location moved above caching regex locations (first match wins).
application/pdf out of gzip_types (already flate-compressed). Compose
healthcheck block removed — image HEALTHCHECK is the single source,
inherited. Oracles: nginx -t, dotfiles 404, PDF no Content-Encoding,
HTML still gzipped, headers 5/5, inherited health = healthy.
CLAUDE.md requires the profile/job-search state to stay consistent across
index.html and the CV. The CV stated a concrete Nantes relocation + a
hybride-Nantes option the landing lacked. Per owner decision, the CV is
canonical: propagate those facts into the landing (about paragraph +
callout) and update CLAUDE.md's geography note to match. No invented claims
— mirrors what the CV already states. CV unchanged (no PDF regen).
The 'Me contacter' and 'Voir le CV' arrow SVGs were missing the
aria-hidden the sibling download arrow already carries; they are purely
decorative, so screen readers should skip them. Visual output unchanged.
index.html: drop unused .reveal.d6 rule (markup uses d1-d5 only).
CV_Bastien_Chanot.html:
- remove dead `position: running(siteFooter)` — no `element()` consumer,
and .footer-bar is `display:none` in @media print (the @page
auto-numbered footer replaces it); on screen running() is an invalid
position value, ignored.
- remove no-op `box-shadow: none` on .page (weasyprint ignores box-shadow;
.page sets a shadow nowhere).
- remove dead `.skills-grid { font-size: 8.4pt }` (every direct child is a
.skill-label/.skill-values div that sets its own size; no bare text).
- normalize stray blank lines.
Behavior-preserving: PDF regenerated from the edited HTML is byte-identical
to the pre-edit baseline (text sha256 + per-page PNG render hash match),
so CV_Bastien_Chanot.pdf is unchanged and the PDF=HTML invariant holds.
CLAUDE.md palette now two enforceable lists (6 brand + 8 documented
neutrals — anything else is a violation); workflow gains the recompute-
CSP-hash-after-JS-edit invariant with the exact command. README points to
the neutrals list. TOUR.md follow-up: CLN-3/CLN-4/SEC-7 closed, INF-2
corrected (false positive — .gitignore exists).
Shared chrome/hover/head/title/tag blocks for stack/project/theme cards +
methode items; per-class blocks keep only specifics. Zero HTML change,
cascade-order verified (no interfering rules between shared and specific
blocks). Net -60 lines; the audit's ~421 estimate was overstated.
- 5x background:#fff -> var(--page) (stack/project/theme/methode cards +
CV body) per CLAUDE.md 'no pure white background' (user-approved strict
conformity; visual change: cards now blend with parchment, border-kept)
- prefers-reduced-motion now also kills transitions (universal rule)
- dead .screen-label rule removed (no matching element)
- PDF regenerated via weasyprint (must match HTML invariant)
- base image -> nginxinc/nginx-unprivileged:1.28-alpine, digest-pinned
(BREAKING for the docker path: container port 80 -> 8080; compose
mapping/healthcheck updated in the same change, cap_add dropped)
- nginx add_header inheritance fix: shared snippets file re-included in
every location that sets Cache-Control -- previously ALL security
headers were dropped on real responses (verified live before/after)
- server_tokens off; set_real_ip_from restricted to 127.0.0.1
- expires directives removed (duplicated Cache-Control); gzip_types
text/html redundancy removed (nginx -t warn)
Root cause + fix logged. New repo assets must be added to Dockerfile
COPY whitelist explicitly; future option = glob pattern if asset count
grows. Journal updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dockerfile selectively COPYs files into /usr/share/nginx/html. Favicon
assets (favicon.svg, favicon-32.png, favicon.ico, apple-touch-icon.png)
were added to the repo in ef31fb3 but never wired into the Dockerfile,
so a rebuilt container served 404 for /favicon.svg and friends — broken
favicon in prod even after `docker compose up -d --build`.
nginx.conf gets a matching long-cache rule for icon/image assets
(30 days, immutable, access_log off) — they rarely change and the file
name is the cache key anyway.
Deploy: on the VPS, `docker compose up -d --build`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brand pulse-dot translated to favicon: dark rounded square (#0d1b12) +
inner green dot (#6ab98a) + faint outer ring (#2d7a4f @60%). Identical
visual language to .brand::before in the nav.
Assets:
- favicon.svg — vector primary (modern browsers, scales)
- favicon-32.png — PNG hint
- favicon.ico — legacy multi-size (16/24/32/48)
- apple-touch-icon.png — iOS home-screen 180x180
PIL-generated PNG/ICO at 8x supersample + Lanczos downscale for clean
antialiasing. No external dependency added (PIL already on system).
index.html: 4 <link> tags wired in <head> (SVG, PNG 32, ICO alternate,
apple-touch). CV HTML left untouched; browser auto-fetches /favicon.ico
from root as fallback — TODO logged to mirror the link block when the
user finalizes CV edits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>