diff --git a/static/css/marketing.css b/static/css/marketing.css index f9d6bee..7e6ba40 100644 --- a/static/css/marketing.css +++ b/static/css/marketing.css @@ -3701,6 +3701,22 @@ outline-style: none; } } + .focus-visible\:outline-2 { + &:focus-visible { + outline-style: var(--tw-outline-style); + outline-width: 2px; + } + } + .focus-visible\:outline-offset-2 { + &:focus-visible { + outline-offset: 2px; + } + } + .focus-visible\:outline-brand-b1 { + &:focus-visible { + outline-color: #0062ff; + } + } .active\:scale-95 { &:active { --tw-scale-x: 95%; diff --git a/templates/marketing/landing.html b/templates/marketing/landing.html index 0891706..d83ff7e 100644 --- a/templates/marketing/landing.html +++ b/templates/marketing/landing.html @@ -51,7 +51,7 @@ {# Social proof microcopy — defensible: refers to pre-launch waitlist + factual ordres pros count #} -

+

+ x-transition.opacity.duration.200ms>

{{ item.a | safe }}

diff --git a/tests/test_marketing_landing_template.py b/tests/test_marketing_landing_template.py index 3738cd4..af55b5e 100644 --- a/tests/test_marketing_landing_template.py +++ b/tests/test_marketing_landing_template.py @@ -696,6 +696,23 @@ def test_faq_jsonld_schema_present(): assert ' ' not in body[body.find('"FAQPage"'):body.find('', body.find('"FAQPage"'))], \ "JSON-LD must not contain raw ' ' entities — strip them server-side" + # M-1 hardening: actually parse the JSON-LD to catch malformed JSON regressions + import json + import re + match = re.search(r'', + body, re.DOTALL) + assert match, "JSON-LD block not found" + parsed = json.loads(match.group(1)) + assert parsed['@context'] == 'https://schema.org' + assert parsed['@type'] == 'FAQPage' + assert isinstance(parsed['mainEntity'], list) + assert len(parsed['mainEntity']) == 7, "FAQPage must contain exactly 7 questions" + for q in parsed['mainEntity']: + assert q['@type'] == 'Question' + assert q['acceptedAnswer']['@type'] == 'Answer' + assert q['name'].strip(), "Question name must not be empty" + assert q['acceptedAnswer']['text'].strip(), "Answer text must not be empty" + def test_cta_final_section(): """CTA final section with mailto pré-inscription + ghost button to #tarifs."""