diff --git a/js/render-elements.js b/js/render-elements.js index f82d18c..a206b5e 100644 --- a/js/render-elements.js +++ b/js/render-elements.js @@ -23,6 +23,7 @@ function pickTextColor(hex) { function buildChip(name, color, { rank = null } = {}) { const span = document.createElement('span'); span.className = 'chip' + (rank ? ' chip-tiobe' : ' chip-other'); + span.setAttribute('role', 'listitem'); span.textContent = name; if (color) { span.style.background = color; @@ -53,6 +54,8 @@ export function renderGrid(buckets, mountEl) { : `${langs.length} ngôn ngữ`; const chips = document.createElement('div'); chips.className = 'chips'; + chips.setAttribute('role', 'list'); + chips.setAttribute('aria-label', `Ngôn ngữ thuộc ${label}`); for (const { name, color, rank } of langs) chips.appendChild(buildChip(name, color, { rank })); card.append(h3, count, chips); fragment.appendChild(card); diff --git a/plans/260428-1003-implement-all-remaining/plan.md b/plans/260428-1003-implement-all-remaining/plan.md index 49c75f5..448c0db 100644 --- a/plans/260428-1003-implement-all-remaining/plan.md +++ b/plans/260428-1003-implement-all-remaining/plan.md @@ -15,7 +15,7 @@ Single pass through every remaining item in `plans/todo.md` and the post-cleanup | # | Title | Status | Items | |---|-------|--------|-------| -| 01 | Style & markup polish | pending | items 5–10, 13, 14, 15 (CSS one-liners + chip role + decision docs) | +| 01 | Style & markup polish | **done** | items 5–10, 13, 14, 15 (CSS one-liners + chip role + decision docs) | | 02 | Functional toggles & tooltip | pending | items 2, 3, 4 (URL persistence, GitLab tooltip, hide empty KIM in TIOBE view) | | 03 | Additive features | pending | items 11, 12 (Top-5 non-TIOBE peek, lunar SVG body texture) | | 04 | OG social card image | pending | item 1 (generate `assets/og-card.png`, may block on tooling) | diff --git a/style.css b/style.css index 33444ea..b171727 100644 --- a/style.css +++ b/style.css @@ -78,7 +78,7 @@ body { font-size: clamp(1.55rem, 4.4vw, 2.5rem); line-height: 1.2; color: var(--accent); letter-spacing: 0.2px; font-weight: 700; } -.hero .subtitle { margin: 0.5rem auto 0; max-width: 38ch; color: var(--muted); font-style: italic; } +.hero .subtitle { margin: 0.5rem auto 0; max-width: 38ch; color: var(--muted); letter-spacing: 0.15px; } .hero-ribbon { display: flex; justify-content: center; gap: 8px; margin: 1rem auto 0; width: max-content; max-width: 100%; @@ -121,10 +121,13 @@ body { text-align: center; margin-top: 0.6rem; color: var(--muted); font-size: 0.9rem; } .original-image figcaption a { - color: var(--accent-ink); text-decoration: none; - border-bottom: 1px dotted var(--accent); + color: var(--accent-ink); + text-decoration: underline; + text-decoration-style: dotted; + text-decoration-color: var(--accent); + text-underline-offset: 2px; } -.original-image figcaption a:hover { color: var(--gold); border-bottom-color: var(--gold); } +.original-image figcaption a:hover { color: var(--gold); text-decoration-color: var(--gold); } /* ---------- Section headings ---------- */ .elements h2, .credit h2 { @@ -137,6 +140,8 @@ body { } /* ---------- Card grid ---------- */ +/* Grid stays auto-fit (not forced 5-col) — the Ngũ-Hành wheel reads at any + viewport above 720px without crushing chip names. See plan 260428-1003. */ .grid { display: grid; gap: 1rem; @@ -158,7 +163,14 @@ body { .card:hover { transform: none; } } -.card h3 { margin: 0 0 0.45rem; font-size: 1.05rem; letter-spacing: 1.2px; font-weight: 700; } +.card h3 { + margin: 0 0 0.5rem; + font-size: 1.2rem; + letter-spacing: 0.4px; + font-weight: 700; + padding-bottom: 0.4rem; + border-bottom: 1px solid color-mix(in oklch, var(--gold) 60%, transparent); +} .card p { margin: 0; color: var(--fg); } .card.kim { border-top-color: var(--kim); background: color-mix(in oklch, var(--kim) 6%, var(--card-bg)); } @@ -181,13 +193,16 @@ body { padding: 1.25rem 1.4rem 1.4rem; box-shadow: var(--shadow-sm); } .credit p { margin: 0.4rem 0; } -.credit ul { margin: 0.5rem 0 0.75rem 1.25rem; padding: 0; } +.credit ul { margin: 0.5rem 0 0.75rem; padding-left: 1.25rem; } .credit a { - color: var(--accent-ink); text-decoration: none; - border-bottom: 1px dotted var(--accent); - transition: color 0.15s ease, border-color 0.15s ease; + color: var(--accent-ink); + text-decoration: underline; + text-decoration-style: dotted; + text-decoration-color: var(--accent); + text-underline-offset: 2px; + transition: color 0.15s ease, text-decoration-color 0.15s ease; } -.credit a:hover { color: var(--gold); border-bottom-color: var(--gold); } +.credit a:hover { color: var(--gold); text-decoration-color: var(--gold); } .credit a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 3px; } .credit .note { font-size: 0.85rem; color: var(--muted); font-style: italic; } @@ -225,11 +240,14 @@ body { background: var(--border-strong); border-radius: 3px; } +/* Chip text contrast policy: best-effort via WCAG luminance picker + (render-elements.js pickTextColor). Worst post-fix case ~3.5:1 + (Swift, MATLAB) is acceptable for decorative chips. */ .chip { display: inline-flex; align-items: center; padding: 0.22rem 0.6rem; border-radius: 999px; font-size: 0.78rem; line-height: 1.4; - border: 1px solid rgba(0, 0, 0, 0.18); + border: 1px solid rgba(0, 0, 0, 0.22); background: var(--bg); color: var(--fg); max-width: 100%; white-space: normal;