diff --git a/config/brand-assets.manifest.json b/config/brand-assets.manifest.json index cfa56b1..6c61efc 100644 --- a/config/brand-assets.manifest.json +++ b/config/brand-assets.manifest.json @@ -1,7 +1,7 @@ { - "version": "1.0.0", + "version": "1.2.0", "organization": "Miracles in Motion Foundation", - "updated": "2026-05-27", + "updated": "2026-06-15", "colors": [ { "name": "Forest green", "hex": "#1a3c34", "role": "primary background" }, { "name": "Forest green (deep)", "hex": "#0f2922", "role": "dark text" }, @@ -22,6 +22,18 @@ } ], "groups": [ + { + "id": "nav", + "title": "Website nav lockups (transparent)", + "description": "Approved header/footer assets — gold artwork on transparent background for light and dark UI shells.", + "assets": [ + { "title": "Nav horizontal (SVG)", "path": "/brand/logo-horizontal-nav.svg", "format": "SVG" }, + { "title": "Nav horizontal (PNG)", "path": "/brand/logo-horizontal-nav.png", "format": "PNG" }, + { "title": "Nav horizontal (WebP)", "path": "/brand/logo-horizontal-nav.webp", "format": "WebP" }, + { "title": "Nav symbol (SVG)", "path": "/brand/logo-symbol-nav.svg", "format": "SVG" }, + { "title": "Nav symbol (PNG)", "path": "/brand/logo-symbol-nav.png", "format": "PNG" } + ] + }, { "id": "symbol", "title": "Symbol mark (icon only)", diff --git a/package.json b/package.json index d74dcf2..736042b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "brand:export": "bash scripts/brand/export-brand-assets.sh", "prebuild": "npm run brand:export", "build": "tsc && vite build", + "test": "vitest run", + "test:watch": "vitest", + "a11y:header-audit": "node scripts/a11y/audit-header-wcag.mjs", + "a11y:header-audit:live": "node scripts/a11y/audit-header-wcag.mjs --lighthouse", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "prepreview": "npm run build", "preview": "vite preview", diff --git a/public/brand/BRAND_GUIDELINES.md b/public/brand/BRAND_GUIDELINES.md index b6a30fe..35dbdde 100644 --- a/public/brand/BRAND_GUIDELINES.md +++ b/public/brand/BRAND_GUIDELINES.md @@ -21,7 +21,7 @@ Logo type in lockups is part of the artwork; do not substitute fonts in the logo 1. Use approved files from this kit only. 2. Do not stretch, rotate, or change logo colors. 3. Maintain clear space around the lockup (minimum: height of the “M” in MIRACLES). -4. **Nav / web header:** horizontal lockup (tablet/desktop) or symbol mark (mobile). +4. **Nav / web header:** use `logo-horizontal-nav.svg` (preferred), `.webp`, or `.png` (tablet/desktop) and `logo-symbol-nav.svg` or `.png` (mobile). Opaque `logo-horizontal.png` is for print, social, and partner kits only. 5. **Social / square placements:** square lockup with full name. 6. **Favicon / app icon:** symbol on forest green (`#1a3c34`). 7. Co-branding and sponsor logo placement require written approval — see [mim4u.org/#/legal](https://mim4u.org/#/legal). diff --git a/public/brand/MIM4U-Brand-Kit.zip b/public/brand/MIM4U-Brand-Kit.zip index fe9d2e5..c56bce9 100644 Binary files a/public/brand/MIM4U-Brand-Kit.zip and b/public/brand/MIM4U-Brand-Kit.zip differ diff --git a/public/brand/logo-horizontal-nav.png b/public/brand/logo-horizontal-nav.png new file mode 100644 index 0000000..1e6a6e0 Binary files /dev/null and b/public/brand/logo-horizontal-nav.png differ diff --git a/public/brand/logo-horizontal-nav.svg b/public/brand/logo-horizontal-nav.svg new file mode 100644 index 0000000..779197f --- /dev/null +++ b/public/brand/logo-horizontal-nav.svg @@ -0,0 +1,48 @@ + diff --git a/public/brand/logo-horizontal-nav.webp b/public/brand/logo-horizontal-nav.webp new file mode 100644 index 0000000..8180dba Binary files /dev/null and b/public/brand/logo-horizontal-nav.webp differ diff --git a/public/brand/logo-symbol-nav.png b/public/brand/logo-symbol-nav.png new file mode 100644 index 0000000..183fe39 Binary files /dev/null and b/public/brand/logo-symbol-nav.png differ diff --git a/public/brand/logo-symbol-nav.svg b/public/brand/logo-symbol-nav.svg new file mode 100644 index 0000000..c896381 --- /dev/null +++ b/public/brand/logo-symbol-nav.svg @@ -0,0 +1,37 @@ + diff --git a/reports/status/lighthouse-a11y-mim4u-latest.json b/reports/status/lighthouse-a11y-mim4u-latest.json new file mode 100644 index 0000000..32e37ef --- /dev/null +++ b/reports/status/lighthouse-a11y-mim4u-latest.json @@ -0,0 +1,2940 @@ +{ + "lighthouseVersion": "13.4.0", + "requestedUrl": "https://mim4u.org/", + "mainDocumentUrl": "https://mim4u.org/", + "finalDisplayedUrl": "https://mim4u.org/", + "finalUrl": "https://mim4u.org/", + "fetchTime": "2026-06-16T02:05:28.018Z", + "gatherMode": "navigation", + "runWarnings": [], + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/147.0.0.0 Safari/537.36", + "environment": { + "networkUserAgent": "Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36", + "hostUserAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/147.0.0.0 Safari/537.36", + "benchmarkIndex": 2191, + "credits": { + "axe-core": "4.12.1" + } + }, + "audits": { + "accesskeys": { + "id": "accesskeys", + "title": "`[accesskey]` values are unique", + "description": "Access keys let users quickly focus a part of the page. For proper navigation, each access key must be unique. [Learn more about access keys](https://dequeuniversity.com/rules/axe/4.12/accesskeys).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-allowed-attr": { + "id": "aria-allowed-attr", + "title": "`[aria-*]` attributes match their roles", + "description": "Each ARIA `role` supports a specific subset of `aria-*` attributes. Mismatching these invalidates the `aria-*` attributes. [Learn how to match ARIA attributes to their roles](https://dequeuniversity.com/rules/axe/4.12/aria-allowed-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-allowed-role": { + "id": "aria-allowed-role", + "title": "Uses ARIA roles only on compatible elements", + "description": "Many HTML elements can only be assigned certain ARIA roles. Using ARIA roles where they are not allowed can interfere with the accessibility of the web page. [Learn more about ARIA roles](https://dequeuniversity.com/rules/axe/4.12/aria-allowed-role).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-command-name": { + "id": "aria-command-name", + "title": "`button`, `link`, and `menuitem` elements have accessible names", + "description": "When an element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to make command elements more accessible](https://dequeuniversity.com/rules/axe/4.12/aria-command-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-conditional-attr": { + "id": "aria-conditional-attr", + "title": "ARIA attributes are used as specified for the element's role", + "description": "Some ARIA attributes are only allowed on an element under certain conditions. [Learn more about conditional ARIA attributes](https://dequeuniversity.com/rules/axe/4.12/aria-conditional-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-deprecated-role": { + "id": "aria-deprecated-role", + "title": "Deprecated ARIA roles were not used", + "description": "Deprecated ARIA roles may not be processed correctly by assistive technology. [Learn more about deprecated ARIA roles](https://dequeuniversity.com/rules/axe/4.12/aria-deprecated-role).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-dialog-name": { + "id": "aria-dialog-name", + "title": "Elements with `role=\"dialog\"` or `role=\"alertdialog\"` have accessible names.", + "description": "ARIA dialog elements without accessible names may prevent screen readers users from discerning the purpose of these elements. [Learn how to make ARIA dialog elements more accessible](https://dequeuniversity.com/rules/axe/4.12/aria-dialog-name).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-hidden-body": { + "id": "aria-hidden-body", + "title": "`[aria-hidden=\"true\"]` is not present on the document ``", + "description": "Assistive technologies, like screen readers, work inconsistently when `aria-hidden=\"true\"` is set on the document ``. [Learn how `aria-hidden` affects the document body](https://dequeuniversity.com/rules/axe/4.12/aria-hidden-body).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-hidden-focus": { + "id": "aria-hidden-focus", + "title": "`[aria-hidden=\"true\"]` elements do not contain focusable descendents", + "description": "Focusable descendents within an `[aria-hidden=\"true\"]` element prevent those interactive elements from being available to users of assistive technologies like screen readers. [Learn how `aria-hidden` affects focusable elements](https://dequeuniversity.com/rules/axe/4.12/aria-hidden-focus).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-input-field-name": { + "id": "aria-input-field-name", + "title": "ARIA input fields have accessible names", + "description": "When an input field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about input field labels](https://dequeuniversity.com/rules/axe/4.12/aria-input-field-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-meter-name": { + "id": "aria-meter-name", + "title": "ARIA `meter` elements have accessible names", + "description": "When a meter element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `meter` elements](https://dequeuniversity.com/rules/axe/4.12/aria-meter-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-progressbar-name": { + "id": "aria-progressbar-name", + "title": "ARIA `progressbar` elements have accessible names", + "description": "When a `progressbar` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to label `progressbar` elements](https://dequeuniversity.com/rules/axe/4.12/aria-progressbar-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-prohibited-attr": { + "id": "aria-prohibited-attr", + "title": "Elements use only permitted ARIA attributes", + "description": "Using ARIA attributes in roles where they are prohibited can mean that important information is not communicated to users of assistive technologies. [Learn more about prohibited ARIA roles](https://dequeuniversity.com/rules/axe/4.12/aria-prohibited-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-required-attr": { + "id": "aria-required-attr", + "title": "`[role]`s have all required `[aria-*]` attributes", + "description": "Some ARIA roles have required attributes that describe the state of the element to screen readers. [Learn more about roles and required attributes](https://dequeuniversity.com/rules/axe/4.12/aria-required-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-required-children": { + "id": "aria-required-children", + "title": "Elements with an ARIA `[role]` that require children to contain a specific `[role]` have all required children.", + "description": "Some ARIA parent roles must contain specific child roles to perform their intended accessibility functions. [Learn more about roles and required children elements](https://dequeuniversity.com/rules/axe/4.12/aria-required-children).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-required-parent": { + "id": "aria-required-parent", + "title": "`[role]`s are contained by their required parent element", + "description": "Some ARIA child roles must be contained by specific parent roles to properly perform their intended accessibility functions. [Learn more about ARIA roles and required parent element](https://dequeuniversity.com/rules/axe/4.12/aria-required-parent).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-roles": { + "id": "aria-roles", + "title": "`[role]` values are valid", + "description": "ARIA roles must have valid values in order to perform their intended accessibility functions. [Learn more about valid ARIA roles](https://dequeuniversity.com/rules/axe/4.12/aria-roles).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-text": { + "id": "aria-text", + "title": "Elements with the `role=text` attribute do not have focusable descendents.", + "description": "Adding `role=text` around a text node split by markup enables VoiceOver to treat it as one phrase, but the element's focusable descendents will not be announced. [Learn more about the `role=text` attribute](https://dequeuniversity.com/rules/axe/4.12/aria-text).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-toggle-field-name": { + "id": "aria-toggle-field-name", + "title": "ARIA toggle fields have accessible names", + "description": "When a toggle field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about toggle fields](https://dequeuniversity.com/rules/axe/4.12/aria-toggle-field-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-tooltip-name": { + "id": "aria-tooltip-name", + "title": "ARIA `tooltip` elements have accessible names", + "description": "When a tooltip element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `tooltip` elements](https://dequeuniversity.com/rules/axe/4.12/aria-tooltip-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-treeitem-name": { + "id": "aria-treeitem-name", + "title": "ARIA `treeitem` elements have accessible names", + "description": "When a `treeitem` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about labeling `treeitem` elements](https://dequeuniversity.com/rules/axe/4.12/aria-treeitem-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-valid-attr-value": { + "id": "aria-valid-attr-value", + "title": "`[aria-*]` attributes have valid values", + "description": "Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid values. [Learn more about valid values for ARIA attributes](https://dequeuniversity.com/rules/axe/4.12/aria-valid-attr-value).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "aria-valid-attr": { + "id": "aria-valid-attr", + "title": "`[aria-*]` attributes are valid and not misspelled", + "description": "Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid names. [Learn more about valid ARIA attributes](https://dequeuniversity.com/rules/axe/4.12/aria-valid-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "button-name": { + "id": "button-name", + "title": "Buttons have an accessible name", + "description": "When a button doesn't have an accessible name, screen readers announce it as \"button\", making it unusable for users who rely on screen readers. [Learn how to make buttons more accessible](https://dequeuniversity.com/rules/axe/4.12/button-name).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "bypass": { + "id": "bypass", + "title": "The page contains a heading, skip link, or landmark region", + "description": "Adding ways to bypass repetitive content lets keyboard users navigate the page more efficiently. [Learn more about bypass blocks](https://dequeuniversity.com/rules/axe/4.12/bypass).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "color-contrast": { + "id": "color-contrast", + "title": "Background and foreground colors have a sufficient contrast ratio", + "description": "Low-contrast text is difficult or impossible for many users to read. [Learn how to provide sufficient color contrast](https://dequeuniversity.com/rules/axe/4.12/color-contrast).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [] + } + }, + "definition-list": { + "id": "definition-list", + "title": "`
`'s contain only properly-ordered `
` and `
` groups, `