Files
intotheeast-com/docs/working/specs/2026-06-20-ui-ux-alignment-design.md
T

5.3 KiB

UI/UX Alignment — Design Spec

2026-06-20


Goal

Unify three disconnected micro-interaction patterns across the site:

  1. Back navigation — inconsistent style and position across story and entry pages
  2. Card hover — inconsistent lift behaviour and structural divergence across the three card types
  3. Map flash — no visual feedback after the feed scrolls to a marker-targeted card

1. Back pill system

Canonical pill component

The site is dark-themed (--color-paper: #1A1814, --color-ink: #EDE8DF cream). Two visual variants of a single pill component, chosen by what is behind it:

Surface pill (sits on the dark paper/canvas background):

background: var(--color-canvas);
border: 1px solid var(--color-border);
color: var(--color-ink);
border-radius: 9999px;
padding: 0.4rem 0.9rem;
font-size: var(--text-sm);
font-weight: 500;
text-decoration: none;
transition: border-color 0.15s, color 0.15s;

Hover: border-color: var(--color-accent); color: var(--color-accent)

Overlay pill (sits on top of a hero photo):

background: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
color: var(--color-ink);
border-radius: 9999px;
padding: var(--space-2) var(--space-4);
font-size: var(--text-sm);
font-weight: 500;
text-decoration: none;

Hover: color: var(--color-accent)

The .story-totop button already matches the surface pill tokens (--color-canvas bg, --color-border border, --color-ink text) — it becomes part of this system without visual changes.

Pill inventory

Element Page Variant Position Notes
.story-escape story overlay fixed, top-left Overlays hero; keep as-is
← Back in story body story surface static, below-hero body section Apply surface pill class
Entry top back entry surface fixed, top: calc(var(--site-header-height) + var(--space-3)), left New element
Entry footer back entry surface static, in .entry-footer Replaces current teal text link
.story-totop story surface fixed, bottom-right Existing; bring into token system

Shared behaviour

All back pills use the same onclick pattern already present on .story-escape:

onclick="if(history.length > 1){ history.back(); return false; }"

Fallback href is always page.parent().url.


2. Card hover unification

Structural fix — entry card markup

Entry cards currently use a two-level structure (<article> wrapping <a class="entry-card-inner">), which causes the hover target to differ from trip and story cards. This diverges for no functional reason — id and data-* attributes are valid on <a> elements.

Before:

<article class="entry-card" id="entry-{{ entry.slug }}"
         data-type="journal" data-lat="..." data-lng="...">
    <a class="entry-card-inner" href="{{ entry.url }}">
        ...
    </a>
</article>

After:

<a class="entry-card" id="entry-{{ entry.slug }}"
   data-type="journal" data-lat="..." data-lng="..."
   href="{{ entry.url }}">
    ...
</a>

The class .entry-card-inner is eliminated. All CSS rules previously on .entry-card-inner move to .entry-card. The map's document.getElementById('entry-' + slug) continues to work unchanged.

The story variant card in the trip feed (entry-card--story) follows the same structural change.

Hover pattern

All three card root elements get a uniform background lift:

.trip-card:hover,
.entry-card:hover,
.story-card:hover {
    background: var(--color-surface-raised);
}

Existing per-card effects are additive on top of the lift:

  • Entry card: photo zoom (transform: scale(1.04)) + title tint (color: var(--color-accent)) — keep
  • Story card: shadow (box-shadow: var(--shadow-md)) — keep
  • Trip card: border accent (border-color: var(--color-accent)) — keep

Transition values align across all three cards: transition: background 0.15s, border-color 0.15s.


3. Map flash

Problem

After clicking a marker on the trip page mini-map, scrollIntoView({ behavior: 'smooth', block: 'center' }) scrolls the feed but provides no visual confirmation of which card arrived.

Solution

A 700ms keyframe animation adds a faint teal wash to the targeted card, delayed 350ms after the click to let the scroll complete first.

CSS:

@keyframes card-highlight {
    0%   { background-color: color-mix(in srgb, var(--color-accent) 12%, transparent); }
    100% { background-color: transparent; }
}

.entry-card.is-highlighted {
    animation: card-highlight 0.7s ease-out forwards;
}

JS (in trip.html.twig, marker click handler):

el.addEventListener('click', function () {
    var card = document.getElementById('entry-' + entry.slug);
    if (!card) return;
    card.scrollIntoView({ behavior: 'smooth', block: 'center' });
    setTimeout(function () {
        card.classList.add('is-highlighted');
        setTimeout(function () { card.classList.remove('is-highlighted'); }, 700);
    }, 350);
});

The is-highlighted class is removed after the animation so it can re-trigger on repeated clicks of the same marker.


Out of scope

  • Semantics/accessibility audit of feed list containers and landmark roles (logged as backlog)
  • <article> element on full entry/story pages (logged as backlog)
  • .story-totop behaviour changes — visual tokens only