The .app-header__logo SVG was decorative on every tool. Web's strongest convention is "click logo → go home" — so users tapping it expecting that fallback got nothing. Now the logo is wrapped in an anchor whose href reflects the URL the page was loaded from: file:// → no wrap (no server home to point at) / → wrap, href=/ (deployment root) /index.html / /<tool>.html → wrap, href=/ (root, no project) /<project>/... → wrap, href=/<project> (project landing) The wrap happens client-side at DOMContentLoaded via shared/logo.js, loaded by every tool's build.sh after toast/nav. Idempotent — a template-supplied anchor or a second mount call is a no-op. The companion shared/logo.css adds a subtle hover/focus affordance (opacity 0.82, focus ring) so the logo reads as clickable without otherwise altering its visual weight. Tools opt out by setting window.zddc.logo.disabled = true before DOMContentLoaded (e.g. for deployments that pin the logo to an external destination). Five Playwright tests (tests/logo.spec.js) lock the contract: no-wrap on file://, href=/ at root, href=/<project> in project subtree, aria-label matches target, idempotent re-mount. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
21 lines
635 B
CSS
21 lines
635 B
CSS
/* shared/logo.css — paired with shared/logo.js. The wrapping anchor
|
|
inherits the logo's box and adds a subtle hover/focus affordance
|
|
so it reads as clickable without altering the logo's visual weight. */
|
|
|
|
.app-header__logo-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
text-decoration: none;
|
|
border-radius: var(--radius);
|
|
transition: opacity 0.15s, box-shadow 0.15s;
|
|
}
|
|
|
|
.app-header__logo-link:hover .app-header__logo,
|
|
.app-header__logo-link:focus-visible .app-header__logo {
|
|
opacity: 0.82;
|
|
}
|
|
|
|
.app-header__logo-link:focus-visible {
|
|
outline: 2px solid var(--primary);
|
|
outline-offset: 2px;
|
|
}
|