feat(legal): B-2.9 6 pages légales (CGU, Loi 25, cookies, remboursement, accessibilité, mentions)

- src/legal/__init__.py: define canonical LEGAL_VERSION='2026-04-27' constant
  (single source of truth — auth.py now imports it as SIGNUP_LEGAL_VERSION).
- src/legal/routes.py: add /legal/<page> + /legal/ index routes; markdown rendered
  from src/legal/content/*.md with toc, tables, fenced_code, attr_list extensions.
- src/legal/content/: 6 French (Québec) markdown documents — DictIA Inc. /
  InnovA AI S.E.N.C. branding, Loi 25-compliant 12-section privacy policy,
  WCAG 2.2 AA accessibility statement, AGPL-3.0 attribution. All marked
  DRAFT v1.0 pending legal review by Allison Rioux.
- templates/legal/_layout.html + index.html: extends marketing/base.html;
  inline .legal-content typographic styles (no CSS rebuild required).
- .gitignore: allow-rule for src/legal/content/*.md so markdown is tracked
  despite the global *.md ignore.
- tests/test_legal_pages.py: 9 tests covering 200 responses, DictIA branding,
  rprp@dictia.ca presence, 12 mandatory Loi 25 sections, public indexability
  (no X-Robots-Tag noindex), shared layout, marketing/base.html extension,
  DRAFT callout, and LEGAL_VERSION/SIGNUP_LEGAL_VERSION equivalence.
- tests/_run_legal_pages_windows.py: manual driver (Windows fcntl stub).
- static/css/marketing.css: regenerated by `npm run build:css` to include
  new utility classes referenced from templates/legal/*.html.

Tests: 9/9 pass. No off-limits files modified beyond the 2-line auth.py
constant move spec'd in B-2.9. No schema changes; markdown==3.5.1 already
pinned in requirements.txt (B-1.1). Pages publicly indexable by design
(Loi 25 transparency).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Allison
2026-04-28 08:57:36 -04:00
parent 64738bfd1f
commit 55569366f4
15 changed files with 1034 additions and 6 deletions

View File

@@ -751,6 +751,9 @@
.h-16 {
height: calc(var(--spacing) * 16);
}
.h-20 {
height: calc(var(--spacing) * 20);
}
.h-24 {
height: calc(var(--spacing) * 24);
}
@@ -832,6 +835,9 @@
.min-h-\[8rem\] {
min-height: 8rem;
}
.min-h-\[60vh\] {
min-height: 60vh;
}
.min-h-\[calc\(100vh-62px\)\] {
min-height: calc(100vh - 62px);
}
@@ -1588,6 +1594,12 @@
border-color: color-mix(in oklab, var(--color-white) 8%, transparent);
}
}
.border-white\/\[0\.12\] {
border-color: color-mix(in srgb, #fff 12%, transparent);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-white) 12%, transparent);
}
}
.border-white\/\[0\.045\] {
border-color: color-mix(in srgb, #fff 4.5%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1912,6 +1924,12 @@
background-color: color-mix(in oklab, var(--color-white) 5%, transparent);
}
}
.bg-white\/\[0\.06\] {
background-color: color-mix(in srgb, #fff 6%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-white) 6%, transparent);
}
}
.bg-yellow-50 {
background-color: var(--color-yellow-50);
}
@@ -2298,6 +2316,12 @@
.text-\[80px\] {
font-size: 80px;
}
.text-\[clamp\(1\.5rem\,2vw\,2rem\)\] {
font-size: clamp(1.5rem, 2vw, 2rem);
}
.text-\[clamp\(1\.75rem\,2\.5vw\,2\.25rem\)\] {
font-size: clamp(1.75rem, 2.5vw, 2.25rem);
}
.text-\[clamp\(2\.5rem\,4vw\,4rem\)\] {
font-size: clamp(2.5rem, 4vw, 4rem);
}
@@ -3084,6 +3108,13 @@
}
}
}
.hover\:border-brand-b1 {
&:hover {
@media (hover: hover) {
border-color: #0062ff;
}
}
}
.hover\:border-brand-b1\/30 {
&:hover {
@media (hover: hover) {
@@ -3688,6 +3719,14 @@
}
}
}
.hover\:shadow-cta {
&:hover {
@media (hover: hover) {
--tw-shadow: 0 4px 20px var(--tw-shadow-color, rgba(0, 98, 255, 0.28));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
}
}
.hover\:shadow-cta-hover {
&:hover {
@media (hover: hover) {
@@ -3784,6 +3823,12 @@
outline-style: none;
}
}
.focus-visible\:outline {
&:focus-visible {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
}
.focus-visible\:outline-2 {
&:focus-visible {
outline-style: var(--tw-outline-style);
@@ -4264,6 +4309,11 @@
padding: calc(var(--spacing) * 8);
}
}
.md\:p-10 {
@media (width >= 48rem) {
padding: calc(var(--spacing) * 10);
}
}
.md\:px-6 {
@media (width >= 48rem) {
padding-inline: calc(var(--spacing) * 6);
@@ -4295,6 +4345,12 @@
line-height: var(--tw-leading, var(--text-2xl--line-height));
}
}
.md\:text-4xl {
@media (width >= 48rem) {
font-size: var(--text-4xl);
line-height: var(--tw-leading, var(--text-4xl--line-height));
}
}
.md\:text-base {
@media (width >= 48rem) {
font-size: var(--text-base);