# MICRO_INTERACTIONS.md
Component-level interaction specs. Every interactive element defines: rest / hover / active / focus-visible / disabled, keyboard behaviour, and touch behaviour.

---

## Buttons
- **Primary (accent fill):** hover → brightness +6% and 1px rise (transform); active → rise removed (press); focus-visible → 2px accent ring, 2px offset; disabled → surface-2 + ink-faint, no events.
- **Secondary (outline):** hover → border-strong + surface-1 fill.
- **Ghost (nav, footer):** hover → ink (from ink-muted) + accent underline draw.
- Touch: no hover states persist; active state on touchstart (≤80ms feedback).

## Split CV button (header)
- Primary zone downloads locale CV; label: `Download CV` / `Last ned CV`, mono-meta suffix shows size `· pdf 180 kB`.
- Chevron zone (separate 44px hit area) opens a 2-item menu: `English (pdf)` / `Norsk (pdf)` with a subtle flag-free language tag (`EN`/`NO` mono chips — no flag icons anywhere; flags conflate language and nationality).
- Keyboard: button reachable in tab order; chevron = separate stop; menu arrows + Esc. Download triggers a one-time toast-less confirmation: button icon swaps to check for 1.5s.

## Language switch (header, segmented control)
- Two segments `EN | NO`, active segment has surface-1 thumb + ink text; inactive = ink-muted. Hover inactive → ink. Thumb slides 160ms on change (A7).
- Keyboard: single tab stop, arrow keys toggle, Enter/Space activates. `aria` as a proper toggle group; screen reader announces "Norsk — bytt språk / English — switch language" (label in *target* language, the convention that works when you can't read the current one).
- Mobile: inside menu overlay header, full-width segmented control, same behaviour.
- Never a dropdown (two options), never flags, never auto-switching.

## Theme toggle
- Icon-only button, morphing sun⇄moon; tooltip on hover-delay 600ms (`Switch to light mode` / `Bytt til lyst modus` — target-state phrasing).
- First visit follows system; once touched, choice persists and system changes no longer override (standard expectation).

## Nav links
- Rest: ink-muted → hover: ink + 2px accent underline drawing left→right (160ms). Current-page: ink + static accent underline + `aria-current`.
- Scroll-spy on homepage: section currently in view marks its nav item (underline at 60% opacity) — subtle, no jumping.

## Chips
- Fact chips: non-interactive, no hover (cursor default — honesty about affordance).
- Stack chips on project cards: hover shows a 600ms-delay tooltip with one context line ("React 18 — SPA frontend"); tap on mobile: no-op (tooltip content lives in case-study text instead).

## Project cards
- Whole card = one link (single tab stop); internal "Read case study →" is decorative affordance, not a second link. Hover per A3. Focus-visible: ring around entire card.
- Screenshot inside frames: `alt` text written per language, meaningful ("JobTrack applications table with status filters", not "screenshot").

## Timeline items
- Featured item expanded by default. Compact one-liners: entire row hover → surface-1 tint; they are *not* expandable (content lives in CV/experience page — avoid hidden-content traps for scanners).

## Form (contact)
- Fields: 2px border; focus → accent border + ring; label always visible above (no placeholder-as-label). Error on blur-validate: danger border + icon + message under field (`Please enter a valid e-mail` / `Skriv inn en gyldig e-postadresse`); error summary focus-moved on failed submit.
- Submit per A9. Honey-pot antispam invisible to AT (no CAPTCHA — friction kills recruiter conversion).
- Beside the form, equal visual weight: direct e-mail (click-to-copy with `copied ✓ / kopiert ✓` mono feedback) and LinkedIn — many recruiters won't touch forms.

## Screenshot lightbox
- Click/Enter opens; Esc, backdrop-click, or × closes; arrows navigate gallery; focus trapped; caption + `n/N` mono counter. Mobile: pinch-zoom enabled, swipe between captures.

## "On this page" mini-TOC (case studies, ≥1200px)
- Items = ghost links with scroll-spy accent tick; click = smooth scroll (instant under reduced motion) with header-offset anchor.

## Copy affordances
- E-mail and `git.cesnimda.uk` in footer/contact: click-to-copy with mono `copied ✓` swap (1.5s). Phone number: plain `tel:` link, no copy gimmick.
