You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Repo: jasonhnd/jobs → mirai-shigoto.com. JA-only static Astro site. /rankings/* receives 38.1% of entering sessions at ~10s engagement — visitors land from queries like 「AIに奪われる仕事」, see no job names on the first screen, and leave.
Base branch is preview. Your PR targets preview. NEVER push, merge, or open a PR to main. Never trigger a production deploy. The owner reviews everything on preview and personally decides promotion.
Referee spec: docs/MOBILE_SHAPES.md — read §0, §3 (esp. 3.1 type floor / 3.2 tap targets / 3.3 job-row atom / 3.5 SEO invariants), §4.1 (this issue).
Visual reference: mockups/shots/pair-1.png (live vs target), mockups/shots/frame-02.png. Mockup pixel values are directional; §3.1 floors and existing site tokens win.
Problem
Current first screen at 390px: breadcrumb → H1 → sub → intro paragraph → .ai-fact citation block → stats cards → highlights → sector chart → the TOP list starts ~2 screens down. See mockups/shots/live-ranking.png: not a single occupation name is visible.
src/components/Footer.astro (one new branch in the existing delegated click-tracking script)
analytics/spec.yaml (+1 event)
Spec
New order (all viewports; §3.8 desktop non-regression applies):
Breadcrumb, <h1> — H1 text unchanged.
NEW one-line summary under the H1 (class rk-sum): 1位は{TOP1名}({score}/10) · TOP{N}平均 {mean}/10 · {YYYY年M月}更新. Data: result.items[0], safeMean (importable from @/views/ranking.js), CONTENT_DATE (src/lib/_content-date.ts) formatted as {Y}年{M}月. ~13.5px muted; names/numbers bold ink. Null score renders — (defensive; all 556 are scored today).
The ranked list immediately. Keep <h2>TOP {N}</h2> (a11y landmark, §3.5 no deletion) restyled visually small. Rows keep existing content (rank, name, sector, per-ranking ExtraCols, salary/workers) restyled to the §3.3 atom; one <a class="rl-row"> wraps the whole row (name becomes a <span>); rows 1–4 minimum fit in the first 844px incl. top bar.
AFTER the list: <details class="chap"><summary>このランキングの読み方・出典</summary> containing in order: the former .sub line text (first), the former .intro paragraph, the unchanged, complete.ai-fact block, the .stats cards, remaining highlights, the sector chart. Nothing deleted; inner content byte-identical.
Desktop expansion: this issue is the FIRST to introduce <details class="chap">, so it also ships the minimal helper — a static-bodied inline <script> (bodyEnd): if matchMedia('(min-width:900px)').matches, set open on all details.chap. No interpolation; run bun run check:csp-hashes and commit the updated hash. Style the new classes so [mobile][W4·gated] Roll List shape out to Q&A / sectors / theme hubs #328 can later reuse them — prefer a shared location (src/lib/canonical-css.ts or a small shared module) over page-local CSS.
Unchanged below: MeEntry, FAQ, cross-hub, related rankings, escape-routes.
GA4 list_row_click: add data-track-event="list_row_click" on the row anchor and extend the existing delegated listener in src/components/Footer.astro (the same mechanism as me_entry_click / jobtag_outbound_click) with a branch setting params { language: 'ja' }. Do NOT use inline onclick — a stale comment in analytics/spec.yaml describes an obsolete wiring; the CSP has no unsafe-inline. Register the event in analytics/spec.yaml; bun run check:analytics-config must pass.
Invariants
H1/title/meta/JSON-LD/canonical unchanged (§3.5). .ai-fact full text unchanged. Type floor §3.1 (row name ≥15.5px, captions ≥12px). No content deletion. Do not add new element ids — anchor ids are tracked in tests/baseline/internal-links.jsonl and unneeded ids force a baseline regen; use classes.
Acceptance
PR screenshots: 390×844 before/after of /rankings/ai-risk-high and one non-AI ranking (e.g. /rankings/salary — salary extras must still render); desktop ≥1280 after-shot with chapters expanded. Take screenshots in a consent-decided state or with [mobile][W0] Compact one-line cookie consent bar (site-wide) #320's compact bar in base.
Whole-row tap works anywhere on the row; hit area ≥44px.
bun run typecheck && bun run test && bun run verify:gates && bun run test:e2e green; Ranking.test.ts snapshots updated for the new markup and listed in the PR.
bun run capture:seo-baseline diff shows no title/meta/JSON-LD change.
list_row_click registered + firing (GA4 DebugView or document the payload {language:'ja'} in the PR).
Context (read this first)
jasonhnd/jobs→ mirai-shigoto.com. JA-only static Astro site./rankings/*receives 38.1% of entering sessions at ~10s engagement — visitors land from queries like 「AIに奪われる仕事」, see no job names on the first screen, and leave.preview. Your PR targetspreview. NEVER push, merge, or open a PR tomain. Never trigger a production deploy. The owner reviews everything onpreviewand personally decides promotion.preview(the compact cookie bar; your acceptance screenshots depend on it).docs/MOBILE_SHAPES.md— read §0, §3 (esp. 3.1 type floor / 3.2 tap targets / 3.3 job-row atom / 3.5 SEO invariants), §4.1 (this issue).mockups/shots/pair-1.png(live vs target),mockups/shots/frame-02.png. Mockup pixel values are directional; §3.1 floors and existing site tokens win.Problem
Current first screen at 390px: breadcrumb → H1 → sub → intro paragraph →
.ai-factcitation block → stats cards → highlights → sector chart → the TOP list starts ~2 screens down. Seemockups/shots/live-ranking.png: not a single occupation name is visible.Scope — one template, 39 pages
src/pages/rankings/[type].astro(block order + folded block + styles + desktop-open helper)src/pages/rankings/_rankings-bindings.ts(summary-line binding)src/templates/Ranking.ts(row markup: full-row link) +src/templates/Ranking.test.ts(snapshot updates)src/components/Footer.astro(one new branch in the existing delegated click-tracking script)analytics/spec.yaml(+1 event)Spec
New order (all viewports; §3.8 desktop non-regression applies):
<h1>— H1 text unchanged.rk-sum):1位は{TOP1名}({score}/10) · TOP{N}平均 {mean}/10 · {YYYY年M月}更新. Data:result.items[0],safeMean(importable from@/views/ranking.js),CONTENT_DATE(src/lib/_content-date.ts) formatted as{Y}年{M}月. ~13.5px muted; names/numbers bold ink. Null score renders—(defensive; all 556 are scored today).<h2>TOP {N}</h2>(a11y landmark, §3.5 no deletion) restyled visually small. Rows keep existing content (rank, name, sector, per-rankingExtraCols, salary/workers) restyled to the §3.3 atom; one<a class="rl-row">wraps the whole row (name becomes a<span>); rows 1–4 minimum fit in the first 844px incl. top bar.<details class="chap"><summary>このランキングの読み方・出典</summary>containing in order: the former.subline text (first), the former.introparagraph, the unchanged, complete.ai-factblock, the.statscards, remaininghighlights, the sector chart. Nothing deleted; inner content byte-identical.<details class="chap">, so it also ships the minimal helper — a static-bodied inline<script>(bodyEnd): ifmatchMedia('(min-width:900px)').matches, setopenon alldetails.chap. No interpolation; runbun run check:csp-hashesand commit the updated hash. Style the new classes so [mobile][W4·gated] Roll List shape out to Q&A / sectors / theme hubs #328 can later reuse them — prefer a shared location (src/lib/canonical-css.tsor a small shared module) over page-local CSS.MeEntry, FAQ, cross-hub, related rankings, escape-routes.list_row_click: adddata-track-event="list_row_click"on the row anchor and extend the existing delegated listener insrc/components/Footer.astro(the same mechanism asme_entry_click/jobtag_outbound_click) with a branch setting params{ language: 'ja' }. Do NOT use inlineonclick— a stale comment inanalytics/spec.yamldescribes an obsolete wiring; the CSP has nounsafe-inline. Register the event inanalytics/spec.yaml;bun run check:analytics-configmust pass.Invariants
H1/title/meta/JSON-LD/canonical unchanged (§3.5).
.ai-factfull text unchanged. Type floor §3.1 (row name ≥15.5px, captions ≥12px). No content deletion. Do not add new elementids — anchor ids are tracked intests/baseline/internal-links.jsonland unneeded ids force a baseline regen; use classes.Acceptance
/rankings/ai-risk-highand one non-AI ranking (e.g./rankings/salary— salary extras must still render); desktop ≥1280 after-shot with chapters expanded. Take screenshots in a consent-decided state or with [mobile][W0] Compact one-line cookie consent bar (site-wide) #320's compact bar in base.bun run typecheck && bun run test && bun run verify:gates && bun run test:e2egreen;Ranking.test.tssnapshots updated for the new markup and listed in the PR.bun run capture:seo-baselinediff shows no title/meta/JSON-LD change.list_row_clickregistered + firing (GA4 DebugView or document the payload{language:'ja'}in the PR).