/* ==========================================================================
   Zero-Delay — by Cutera
   Landing page stylesheet
   Palette: pure white → soft canvas slate, transit-signal navy accents
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */
:root {
  /* Surfaces */
  --white: #ffffff;
  --canvas: #f8fafc;
  --canvas-deep: #f1f5f9;
  --slate-100: #f1f5f9;
  --slate-200: #e2e8f0;
  --slate-300: #cbd5e1;
  --slate-400: #94a3b8;
  --slate-500: #64748b;
  --slate-600: #475569;
  --slate-700: #334155;

  /* Brand navy / transit signal blue */
  --navy-950: #0b1220;
  --navy-900: #0f172a;
  --navy-800: #1e293b;
  --blue-900: #172554;
  --blue-700: #1e40af;
  --blue-600: #1d4ed8;
  --blue-500: #3b82f6;
  --blue-400: #60a5fa;
  --blue-50: #eff6ff;

  /* Incident / status colours */
  --sev-normal: #10b981;
  --sev-minor: #f59e0b;
  --sev-severe: #f97316;
  --sev-suspended: #ef4444;
  --sev-maintenance: #8b5cf6;

  /* Radii */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 26px;
  --r-pill: 999px;

  /* Shadows */
  --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.05);
  --shadow-soft: 0 1px 2px rgba(15, 23, 42, 0.04), 0 10px 26px -12px rgba(15, 23, 42, 0.16);
  --shadow-card: 0 1px 3px rgba(15, 23, 42, 0.05), 0 22px 46px -22px rgba(15, 23, 42, 0.24);
  --shadow-float: 0 24px 60px -20px rgba(15, 23, 42, 0.42);

  /* Layout */
  --container: 1200px;
  --header-h: 72px;

  --font-sans: "Inter", "Noto Sans JP", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* --------------------------------------------------------------------------
   Japanese typography — the PRIMARY language of this site
   --------------------------------------------------------------------------
   Japanese is the default, so the rules below carry the real typographic work
   instead of being a thin override on top of the Latin defaults:
     · line-height is much looser — CJK glyphs fill their whole em box, so the
       Latin 1.6 body value reads visibly cramped.
     · letter-spacing is POSITIVE. The negative tracking used for Latin display
       type makes kana and kanji collide; a small positive value opens them up.
     · line-break: strict applies proper kinsoku shori (禁則処理) so a line can
       never begin with 。、）」』】 etc., or end with （「『【.
     · word-break: auto-phrase wraps at natural phrase boundaries rather than
       mid-compound (progressive enhancement; ignored by browsers without it).
     · NO justification. Japanese print justifies to both edges, but the
       browser cannot do it acceptably here: `text-justify: inter-ideograph`
       is unsupported (measured CSS.supports() === false), so `text-align:
       justify` falls back to `auto` and dumps all the slack into EVERY
       inter-glyph gap. Measured on .vision-quote at 390px, justification
       pushed the advance per character from 14.75px (natural) to 18.01px —
       roughly a 3.3px hole between every pair of glyphs. That is the
       "stretched spacing" defect, and it hit 20 blocks on mobile / 16 on
       desktop. Prose now keeps its natural alignment (measured base: start
       for body copy, center for .phone-caption p); because Japanese glyphs
       are already monospaced on the em grid, the result is still even.
     · text-wrap: balance is KEPT — and that is a measured decision, not an
       oversight. An earlier note in this block claimed balance was switched
       off for JA, but the value it used to do that (`text-wrap: normal`) is not
       valid CSS, so the declaration was silently dropped and balance applied
       all along. Comparing the alternatives directly across 320-1100px:
       `wrap` stranded a two-character last line (「開発」) on .section-title at
       414-460px, while `balance` and `pretty` produced no orphan at any width.
       `balance` is now set EXPLICITLY below, so the behaviour is stated rather
       than accidental. The hero headline's mid-word break was never a
       text-wrap problem — that was the display font size, and it is fixed by
       the clamp in the max-width:620px block.
   -------------------------------------------------------------------------- */
html[lang="ja"] body {
  font-family: "Noto Sans JP", "Inter", system-ui, -apple-system, sans-serif;
  line-height: 1.9;
  letter-spacing: 0.02em;
  line-break: strict;
  word-break: normal;
  overflow-wrap: break-word;
}

/* Prose keeps its NATURAL alignment and is never justified.
   These selectors previously carried `text-align: justify`. Removed, because
   with `text-justify: inter-ideograph` unsupported the browser justified by
   widening every inter-glyph gap — the stretched-spacing defect measured above
   (18.01px vs 14.75px advance per character at 390px). It also flattened the
   centred .phone-caption p to two flush edges, which was never intended.
   `text-wrap: pretty` stays: it only prevents a lone final character from
   being stranded on its own line, and adds no horizontal stretching. */
html[lang="ja"] .vision-story p,
html[lang="ja"] .vision-quote,
html[lang="ja"] .pillar p,
html[lang="ja"] .benefit-card p,
html[lang="ja"] .benefit-detail,
html[lang="ja"] .milestone p,
html[lang="ja"] .phone-caption p,
html[lang="ja"] .notify-step p,
html[lang="ja"] .footer-brand p,
html[lang="ja"] .modal-panel p {
  text-wrap: pretty;
}

html[lang="ja"] .hero-sub,
html[lang="ja"] .section-sub,
html[lang="ja"] .notify-meta,
html[lang="ja"] .form-message {
  text-wrap: pretty;
}

/* Small print is centred and narrow — justification would open visible gaps. */
html[lang="ja"] .map-disclaimer,
html[lang="ja"] .notify-meta,
html[lang="ja"] .form-message,
html[lang="ja"] .app-note {
  text-align: inherit;
  text-justify: auto;
}

html[lang="ja"] h1,
html[lang="ja"] h2,
html[lang="ja"] h3,
html[lang="ja"] h4 {
  line-height: 1.45;
  letter-spacing: 0.015em;
  /* Explicit, NOT the invalid `normal` this used to say. `normal` is not a
     text-wrap value, so the declaration was dropped and the base h1..h4
     `balance` applied anyway — the "opted out" comment above was never true.
     Measured across 320-1100px, `balance` gives no orphan and no mid-word
     break on any JA heading, where `wrap` stranded 「開発」 at 414-460px. */
  text-wrap: balance;
  word-break: auto-phrase;
  line-break: strict;
  /* palt = proportional alternate widths. It removes the built-in half-em side
     bearing around Japanese punctuation, which is what makes headings look
     loose and mis-aligned when left at the default (monospaced) metrics. */
  font-feature-settings: "palt" 1;
}

/* Long-form Japanese copy: comfortable measure and no mid-phrase breaks. */
html[lang="ja"] .hero-sub,
html[lang="ja"] .section-sub,
html[lang="ja"] .hero-title,
html[lang="ja"] .section-title,
html[lang="ja"] .vision-story h3,
html[lang="ja"] .vision-story p,
html[lang="ja"] .vision-quote,
html[lang="ja"] .notify-inner > p {
  word-break: auto-phrase;
}

/* The display headline needs more room than the Latin value allows: the JA
   line runs longer and wraps to two or three lines. */
html[lang="ja"] .hero-title {
  line-height: 1.42;
  letter-spacing: 0.01em;
  /* No text-wrap here on purpose: the h1 rule above sets `balance`, which
     measured 0 orphans at every width. */
}

html[lang="ja"] .hero-sub {
  line-height: 1.95;
  letter-spacing: 0.02em;
}

html[lang="ja"] .section-title {
  line-height: 1.48;
}

html[lang="ja"] .section-sub {
  line-height: 1.95;
}

/* --- wrapping coverage ---------------------------------------------------
   `word-break: normal` splits Japanese at ANY character, so at 390px real
   mid-word breaks appeared: 「2027年 前|半リリース予定」 and
   「リアルタイム遅延マップ — 全国鉄道ネッ|トワーク」. These blocks were not yet
   covered by an auto-phrase rule (measured: the property is supported, but it
   was simply absent here, so the default `normal` applied).
   auto-phrase keeps compounds whole and breaks at phrase boundaries only.
   keep-all is the belt-and-braces value for the short pill labels, which must
   never split at all. */
html[lang="ja"] .badge,
html[lang="ja"] .brand-badge,
html[lang="ja"] .hero-note,
html[lang="ja"] .map-panel-title,
html[lang="ja"] .map-updated,
html[lang="ja"] .legend-chip,
html[lang="ja"] .map-disclaimer,
html[lang="ja"] .stat-label,
html[lang="ja"] .notify-inner > p,
html[lang="ja"] .section-sub,
html[lang="ja"] .section-title,
html[lang="ja"] .milestone h3,
html[lang="ja"] .milestone p,
html[lang="ja"] .footer-brand p,
html[lang="ja"] .footer-links a,
html[lang="ja"] .footer-links button {
  word-break: auto-phrase;
  line-break: strict;
  overflow-wrap: break-word;
}

/* Short pill labels: a character or two must never be stranded alone, and a
   break inside a compound reads as damage rather than as wrapping. */
html[lang="ja"] .badge,
html[lang="ja"] .brand-badge,
html[lang="ja"] .legend-chip {
  word-break: keep-all;
}

/* --- explicit phrase breaks (the actual fix for the reported defect) ------
   `word-break: auto-phrase` above is CHROMIUM-ONLY: Safari / iOS drops the
   declaration and falls back to `normal`, which breaks Japanese after any
   character — that is the mobile report (「から」 split into 「か / ら」,
   「前半リリース」 split). No CSS value can solve it either, because a phrase
   wider than the column has no legal break point to use.
   js/ja-linebreak.js therefore segments each Japanese run and inserts a real
   ZERO-WIDTH SPACE (U+200B) at every boundary Japanese typesetting permits.
   Those are honoured by every engine, so `keep-all` below makes them the ONLY
   legal break points, and Safari gets the same result as Chromium.
   `overflow-wrap: break-word` stays as the safety valve for the rare single
   segment that is on its own wider than the measure (a long katakana or Latin
   token), so nothing can ever overflow the column.
   The attribute is repeated in the selector on purpose: the earlier
   `html[lang="ja"] .vision-story p` and `.notify-inner > p` auto-phrase rules
   are (0,2,2), which OUTRANKS a single `html[lang="ja"] [data-phrased]`
   (0,2,1). Left at one attribute, auto-phrase survived on those paragraphs and
   added its own break points beside the inserted U+200B, which is how breaks
   such as 「における / 「予期せぬ」 and 「負荷 / （認知コスト）」 appeared.
   Doubling the attribute makes this rule (0,3,1) so it wins, leaving U+200B as
   the only break opportunity. English text never carries [data-phrased]. */
html[lang="ja"] [data-phrased][data-phrased] {
  word-break: keep-all;
  overflow-wrap: break-word;
  line-break: strict;
}

/* --- inline / control typography ---------------------------------------- */

/* Latin buttons use slightly tight tracking; Japanese needs the opposite, and
   the label must not break mid-word inside a pill. */
html[lang="ja"] .btn,
html[lang="ja"] .primary-nav a,
html[lang="ja"] .mobile-menu nav a,
html[lang="ja"] .footer-links a,
html[lang="ja"] .footer-links button,
html[lang="ja"] .footer-bottom nav a,
html[lang="ja"] .footer-bottom nav button,
html[lang="ja"] .lang-btn {
  letter-spacing: 0.025em;
  line-height: 1.7;
  word-break: keep-all;
  overflow-wrap: normal;
}

/* The badge is uppercased and widely tracked for Latin; uppercase is a no-op
   for kana, so the tracking only widens the word. Was 0.06em, then 0.04em;
   pulled to the 0.02em the rest of the JA layer uses, so the pill reads as one
   word instead of a spread-out string of characters. */
html[lang="ja"] .badge,
html[lang="ja"] .brand-badge {
  letter-spacing: 0.02em;
  line-height: 1.6;
}

/* These carry kana (「進行中」「2026年 · 現在」), where the Latin 0.12em tracking
   is far too wide — it was the loosest tracking left on the page (0.72px per
   glyph measured at 12px). Brought down to the 0.02em the rest of the JA layer
   uses. The Latin counterpart keeps its own wide tracking under html[lang="en"]. */
html[lang="ja"] .eyebrow,
html[lang="ja"] .app-section-label,
html[lang="ja"] .milestone__when,
html[lang="ja"] .milestone__status,
html[lang="ja"] .feed-head h3 {
  letter-spacing: 0.02em;
  line-height: 1.6;
}

/* Numerals should line up in columns next to Japanese labels. */
html[lang="ja"] .stat-value,
html[lang="ja"] .map-updated,
html[lang="ja"] .feed-item__rec,
html[lang="ja"] .app-row__badge {
  font-variant-numeric: tabular-nums;
}

/* --- card & list prose -------------------------------------------------- */
html[lang="ja"] .pillar h3,
html[lang="ja"] .pillar p,
html[lang="ja"] .benefit-card h3,
html[lang="ja"] .benefit-card p,
html[lang="ja"] .benefit-detail,
html[lang="ja"] .milestone h3,
html[lang="ja"] .milestone p,
html[lang="ja"] .phone-caption h3,
html[lang="ja"] .phone-caption p,
html[lang="ja"] .callout,
html[lang="ja"] .notify-step p,
html[lang="ja"] .footer-brand p,
html[lang="ja"] .modal-panel p,
html[lang="ja"] .modal-panel h2 {
  line-height: 1.85;
  letter-spacing: 0.02em;
  word-break: auto-phrase;
}

html[lang="ja"] .benefit-card h3,
html[lang="ja"] .pillar h3,
html[lang="ja"] .milestone h3,
html[lang="ja"] .phone-caption h3,
html[lang="ja"] .modal-panel h2 {
  line-height: 1.6;
}

/* The callout row is the one icon row built as a GRID, and the JA layer used
   to force `align-items: center` on it — which sank the tick 13px below line 1
   once the label wrapped (measured, 390px JA). The base grid uses `start` plus
   a tuned 4px icon offset, and Japanese only needs the same baseline treatment
   as the flex pills above. The .badge / .hero-note / .map-disclaimer fixes now
   live on their base rules, so they apply in both languages. */
html[lang="ja"] .callout {
  align-items: baseline;
}

html[lang="ja"] .callout i {
  margin-top: 0;
}

/* --- map tooltip & incident feed ---------------------------------------- */
html[lang="ja"] .map-line__name,
html[lang="ja"] .map-line__status,
html[lang="ja"] .map-line__meta,
html[lang="ja"] .feed-item__line,
html[lang="ja"] .feed-item__meta,
html[lang="ja"] .map-card__cluster,
html[lang="ja"] .map-disclaimer,
html[lang="ja"] .legend-chip {
  line-height: 1.75;
  letter-spacing: 0.02em;
  word-break: auto-phrase;
}

/* The incident feed is narrow; keep-all stops a rail line name from splitting
   across lines, but allow a break when a single name truly cannot fit. */
html[lang="ja"] .feed-item__line,
html[lang="ja"] .map-line__name {
  word-break: normal;
  overflow-wrap: anywhere;
}

/* --- in-device UI copy --------------------------------------------------
   These run at very small sizes where Japanese needs the most help: loose
   leading and a touch of tracking keep the glyphs from merging. */
html[lang="ja"] .app-h1,
html[lang="ja"] .app-h1__sub,
html[lang="ja"] .app-alert__title,
html[lang="ja"] .app-alert__sub,
html[lang="ja"] .app-row__name,
html[lang="ja"] .app-row__meta,
html[lang="ja"] .route-stop__title,
html[lang="ja"] .route-stop__meta,
html[lang="ja"] .route-bypass__label,
html[lang="ja"] .route-bypass__text,
html[lang="ja"] .app-cta,
html[lang="ja"] .app-note,
html[lang="ja"] .app-topbar__brand {
  letter-spacing: 0.025em;
  word-break: auto-phrase;
}

html[lang="ja"] .app-h1 {
  line-height: 1.5;
}

html[lang="ja"] .app-alert__title,
html[lang="ja"] .app-row__name,
html[lang="ja"] .route-stop__title,
html[lang="ja"] .route-bypass__text {
  line-height: 1.55;
}

html[lang="ja"] .app-alert__sub,
html[lang="ja"] .app-row__meta,
html[lang="ja"] .route-stop__meta {
  line-height: 1.6;
}

html[lang="ja"] .app-cta {
  line-height: 1.5;
}

/* --- header / navigation fit --------------------------------------------
   Japanese nav labels are full-width and therefore much wider than the English
   ones. Tighten them slightly so all five still fit on one row in the band
   just above the mobile breakpoint (1080–1240px). */
@media (min-width: 1081px) and (max-width: 1360px) {
  html[lang="ja"] .primary-nav a {
    font-size: 0.82rem;
    padding: 9px 9px;
    letter-spacing: 0.01em;
  }

  html[lang="ja"] .header-actions {
    gap: 8px;
  }
}

/* Vertical rhythm: Japanese block elements sit taller, so re-balance the
   spacing that was tuned around Latin line boxes. */
@media (min-width: 901px) {
  html[lang="ja"] .hero-ctas .btn {
    padding-top: 15px;
    padding-bottom: 15px;
  }
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  color: var(--navy-900);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  line-height: 1.16;
  letter-spacing: -0.022em;
  font-weight: 800;
  color: var(--navy-900);
  text-wrap: balance;
}

p {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

img,
svg {
  display: block;
  max-width: 100%;
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: none;
  background: none;
}

input {
  font: inherit;
}

:focus-visible {
  outline: 3px solid var(--blue-500);
  outline-offset: 3px;
  border-radius: 6px;
}

::selection {
  background: var(--blue-700);
  color: #fff;
}

.skip-link {
  position: absolute;
  left: 16px;
  top: -60px;
  z-index: 200;
  padding: 10px 16px;
  background: var(--navy-900);
  color: #fff;
  border-radius: var(--r-sm);
  font-size: 0.85rem;
  font-weight: 600;
  transition: top 0.18s ease;
}

.skip-link:focus {
  top: 12px;
}

/* --------------------------------------------------------------------------
   3. Layout helpers
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

.section {
  padding: 104px 0;
  position: relative;
}

.section--tint {
  background: linear-gradient(180deg, var(--white) 0%, var(--canvas) 42%, var(--canvas) 100%);
}

.section--slate {
  background: var(--canvas);
}

.section-head {
  max-width: 760px;
  margin: 0 auto 56px;
  text-align: center;
}

.section-head--left {
  margin-left: 0;
  text-align: left;
}

.badge {
  display: inline-flex;
  /* baseline, NOT center: this pill's label wraps at narrow widths, and
     `center` then floats the icon to the middle of the two-line block so the
     text reads as having dropped below its glyph. Measured at 390px with
     `center`: EN 9.9px / JA 10.4px below line 1; with `baseline`: 0.9px / 1.4px.
     baseline pins the icon to the FIRST line however far the label wraps. */
  align-items: baseline;
  gap: 8px;
  padding: 7px 15px;
  border-radius: var(--r-pill);
  background: var(--blue-50);
  border: 1px solid #dbeafe;
  color: var(--blue-700);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 20px;
}

.badge--launch {
  background: linear-gradient(135deg, #fff7ed, #ffedd5);
  border-color: #fed7aa;
  color: #b45309;
}

.badge--navy {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.2);
  color: #bfdbfe;
}

.badge i {
  font-size: 0.8rem;
}

.section-title {
  font-size: clamp(1.85rem, 3.4vw, 2.65rem);
}

.section-sub {
  margin-top: 18px;
  font-size: 1.05rem;
  color: var(--slate-600);
  max-width: 640px;
}

.section-head:not(.section-head--left) .section-sub {
  margin-left: auto;
  margin-right: auto;
}

.eyebrow {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blue-700);
}

/* --------------------------------------------------------------------------
   4. Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 24px;
  border-radius: var(--r-pill);
  font-size: 0.94rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease,
    color 0.18s ease, border-color 0.18s ease;
  border: 1px solid transparent;
}

.btn i {
  font-size: 0.9rem;
}

.btn-primary {
  background: var(--blue-700);
  color: #fff;
  box-shadow: 0 10px 24px -12px rgba(30, 64, 175, 0.85);
}

.btn-primary:hover {
  background: var(--blue-600);
  transform: translateY(-2px);
  box-shadow: 0 16px 32px -14px rgba(30, 64, 175, 0.9);
}

.btn-ghost {
  background: var(--white);
  color: var(--navy-900);
  border-color: var(--slate-200);
  box-shadow: var(--shadow-xs);
}

.btn-ghost:hover {
  border-color: var(--slate-300);
  transform: translateY(-2px);
  box-shadow: var(--shadow-soft);
}

.btn-onDark {
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.24);
}

/* --------------------------------------------------------------------------
   Print / "Save as PDF" affordances (screen side)
   --------------------------------------------------------------------------
   The print affordance is a real button because a static site cannot generate
   a PDF on a server: it opens the browser's print dialog, and css/print.css
   (linked with media="print") lays the document out for paper. The actual
   paper rules live in css/print.css.
   -------------------------------------------------------------------------- */
.btn-print {
  background: var(--white);
  color: var(--navy-800);
  border-color: var(--slate-200);
  box-shadow: var(--shadow-xs);
}

.btn-print:hover {
  border-color: var(--blue-400);
  color: var(--blue-700);
  transform: translateY(-2px);
  box-shadow: var(--shadow-soft);
}

.btn-print i {
  color: var(--blue-700);
}

/* Paper-only content: present in the DOM for the PDF, invisible on screen. */
.print-only {
  display: none;
}

/* The header is a tight single row, so the print utility collapses to an
   icon-only button there (label hidden, aria-label + title still describe it).
   The mobile drawer and the footer keep the full "PDFで保存" label. This keeps
   the 4-control header fitting on one line down to the 1081px breakpoint. */
.btn-print--icon span {
  display: none;
}

.btn-print--icon {
  padding: 10px 12px;
}

.btn-onDark:hover {
  background: rgba(255, 255, 255, 0.18);
  transform: translateY(-2px);
}

.btn-lg {
  padding: 16px 30px;
  font-size: 1rem;
}

.btn-sm {
  padding: 10px 18px;
  font-size: 0.85rem;
}

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 90;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}

.site-header.is-scrolled {
  border-bottom-color: var(--slate-200);
  box-shadow: 0 8px 24px -20px rgba(15, 23, 42, 0.4);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 20px;
  height: var(--header-h);
}

/* Brand */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Cutera logo lockup
   --------------------------------------------------------------------------
   Displays the user's ORIGINAL brand artwork via <img> — nothing is redrawn,
   traced or substituted. The same artwork is used in two files:
     images/cutera-logo.png        the untouched master (white background) —
                                   still the favicon / apple-touch-icon
     images/cutera-logo-clean.png  the same artwork with the background removed
                                   — used for the visible header and footer
   Pixel-identity of the two was verified, so the mark itself is unchanged.

   Measured with a canvas ink-pass (three thresholds agree), the master file is
   a 1024x1024 canvas that is 96.5% empty white, and the artwork occupies:
       x 124..969   y 370..675   →  846 x 306  →  aspect 2.765:1
   A second, far fainter mark sits at y 864..927; it is a separate element and
   is not part of this lockup.

   Why the previous version read as a white box floating on the page:
     The box was `aspect-ratio: 2.7` with `object-fit: cover`. The image is
     2.765:1, i.e. WIDER than the box, so `cover` scaled by height — which
     means the box showed the image's FULL height, including its white padding.
     Of the 1024 rows only 306 hold ink, so ~70% of a 32px box was blank white,
     and the wordmark itself rendered a mere ~9.6px tall. Against the tinted
     footer (#f8fafc) that padding is visible, so the logo looked like a small
     white rectangle sitting on the page instead of just the mark.

   The white background is now REMOVED FROM THE IMAGE ITSELF. The lockup uses
   images/cutera-logo-clean.png, a transparent-background extraction of the
   original master (verified: 96.49% of its pixels have alpha 0, all four
   corners are alpha 0, and the artwork's ink survives 100% — teal 100.1%,
   dark grey 100.0%). Because the background is genuinely gone, no blend mode
   is involved and the mark composites correctly on ANY surface colour,
   opaque or translucent, anywhere on the page.

   Why the previous `mix-blend-mode: multiply` never worked in the header, and
   could not: the header carries `backdrop-filter: blur()`, which forces it into
   its own stacking context — an isolated blending group. `isolation: auto`
   cannot undo that, so multiply composited the logo against the header's own
   82%-white surface only. white x white = white, so the white box stayed. That
   is exactly why the earlier attempt appeared to do nothing.

   The image is enlarged by the inverse of the artwork's share of the canvas and
   then offset to the artwork's origin, so the lockup contains the artwork and
   nothing else. The extraction preserved the original 1024x1024 canvas and left
   the artwork in place, so these are a re-measure of the same geometry:

     width  = 1024 / 847 * 100 = 120.897%    left = -124 / 847 * 100 = -14.640%
     height = 1024 / 307 * 100 = 333.550%    top  = -369 / 307 * 100 = -120.195%

   The box's aspect-ratio is the artwork's own, so the crop cannot cut the
   mark — there is no `object-fit` involved at all. Change --logo-h to resize.
   -------------------------------------------------------------------------- */
.logo-lockup {
  --logo-h: 28px;
  --logo-crop-w: 120.897%;
  --logo-crop-h: 333.550%;
  --logo-crop-left: -14.640%;
  --logo-crop-top: -120.195%;
  position: relative;
  display: block;
  height: var(--logo-h);
  aspect-ratio: 847 / 307;   /* the artwork's real proportions */
  flex-shrink: 0;
  overflow: hidden;
}

.logo-lockup img {
  position: absolute;
  top: var(--logo-crop-top);
  left: var(--logo-crop-left);
  width: var(--logo-crop-w);
  height: var(--logo-crop-h);
  max-width: none;
  display: block;
  /* Nothing else is required here: the file's own background is transparent, so
     the header and footer surfaces show through the mark. Deliberately NO
     mix-blend-mode — see the lockup note above for why it cannot work under a
     blurred, translucent header. */
}


.brand-badge {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: var(--r-pill);
  background: var(--blue-50);
  color: var(--blue-700);
  border: 1px solid #dbeafe;
  white-space: nowrap;
}

/* Primary nav */
.primary-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0 auto;
}

.primary-nav a {
  padding: 9px 14px;
  border-radius: var(--r-pill);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--slate-600);
  transition: color 0.16s ease, background 0.16s ease;
  white-space: nowrap;
}

.primary-nav a:hover {
  color: var(--navy-900);
  background: var(--slate-100);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

/* Language switcher */
.lang-switch {
  display: inline-flex;
  align-items: center;
  padding: 3px;
  border-radius: var(--r-pill);
  background: var(--slate-100);
  border: 1px solid var(--slate-200);
  position: relative;
}

.lang-btn {
  padding: 7px 14px;
  border-radius: var(--r-pill);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--slate-500);
  transition: color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

.lang-btn:hover {
  color: var(--navy-900);
}

.lang-btn.is-active {
  background: var(--navy-900);
  color: #fff;
  box-shadow: 0 6px 14px -8px rgba(15, 23, 42, 0.9);
}

/* Mobile nav toggle */
.nav-toggle {
  display: none;
  width: 42px;
  height: 42px;
  border-radius: var(--r-md);
  border: 1px solid var(--slate-200);
  background: var(--white);
  place-items: center;
  color: var(--navy-900);
  font-size: 1rem;
}

/* Mobile menu panel */
.mobile-menu {
  display: none;
  border-top: 1px solid var(--slate-200);
  background: var(--white);
  padding: 12px 0 20px;
}

.mobile-menu.is-open {
  display: block;
}

.mobile-menu nav {
  display: flex;
  flex-direction: column;
}

.mobile-menu nav a {
  padding: 13px 24px;
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--slate-700);
  border-bottom: 1px solid var(--slate-100);
}

.mobile-menu nav a:hover {
  background: var(--canvas);
  color: var(--navy-900);
}

.mobile-menu .btn {
  margin: 18px 24px 0;
  width: calc(100% - 48px);
}

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  padding: 84px 0 96px;
  background:
    radial-gradient(1100px 520px at 50% -8%, #eef4ff 0%, rgba(248, 250, 252, 0) 62%),
    linear-gradient(180deg, var(--white) 0%, var(--canvas) 100%);
  overflow: hidden;
}

/* faint transit-grid backdrop */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(30, 64, 175, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(30, 64, 175, 0.05) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(760px 420px at 50% 0%, #000 0%, transparent 78%);
  -webkit-mask-image: radial-gradient(760px 420px at 50% 0%, #000 0%, transparent 78%);
  pointer-events: none;
}

.hero-inner {
  position: relative;
  z-index: 1;
}

.hero-copy {
  max-width: 890px;
  margin: 0 auto;
  text-align: center;
}

.hero-title {
  font-size: clamp(2.1rem, 5.1vw, 4rem);
  letter-spacing: -0.032em;
  line-height: 1.06;
}

html[lang="ja"] .hero-title {
  line-height: 1.28;
  letter-spacing: -0.015em;
}

.hero-title .accent {
  background: linear-gradient(100deg, var(--blue-700) 8%, var(--blue-500) 92%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero-sub {
  margin: 24px auto 0;
  max-width: 700px;
  font-size: 1.09rem;
  color: var(--slate-600);
}

.hero-ctas {
  margin-top: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
}

.hero-note {
  margin-top: 18px;
  font-size: 0.84rem;
  color: var(--slate-500);
  display: inline-flex;
  /* Wraps to two lines on phones; `center` dropped the shield icon 11.5px
     below line 1 (EN) / 13.5px (JA). `baseline` keeps it on line 1. */
  align-items: baseline;
  gap: 8px;
}

.hero-note i {
  color: var(--blue-700);
}

/* Stat strip */
.stat-strip {
  margin: 54px auto 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  max-width: 760px;
  background: var(--slate-200);
  border: 1px solid var(--slate-200);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}

.stat {
  background: var(--white);
  padding: 22px 18px;
  text-align: center;
}

.stat-value {
  font-size: 1.6rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--navy-900);
  line-height: 1.1;
}

.stat-label {
  margin-top: 6px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--slate-500);
  letter-spacing: 0.01em;
}

/* --------------------------------------------------------------------------
   7. Live delay map panel
   -------------------------------------------------------------------------- */
.map-panel {
  margin-top: 76px;
  background: var(--white);
  border: 1px solid var(--slate-200);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  scroll-margin-top: 96px;
}

.map-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  padding: 20px 24px;
  border-bottom: 1px solid var(--slate-200);
  background: linear-gradient(180deg, var(--white), var(--canvas));
}

.map-panel-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.98rem;
  font-weight: 800;
  letter-spacing: -0.015em;
}

.live-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--sev-normal);
  box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.6);
  animation: livePulse 2.4s infinite;
  flex-shrink: 0;
}

@keyframes livePulse {
  0% {
    box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.55);
  }
  70% {
    box-shadow: 0 0 0 9px rgba(16, 185, 129, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
  }
}

.map-updated {
  font-size: 0.76rem;
  font-weight: 600;
  color: var(--slate-500);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.legend {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.legend-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--slate-200);
  background: var(--white);
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--slate-600);
  white-space: nowrap;
}

.legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Miniature copy of a map marker, so the legend explains the icon language
   actually used on the map rather than colour alone. */
.legend-glyph {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  display: block;
}

.map-body {
  display: grid;
  grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
}

.map-stage {
  position: relative;
  padding: 18px 18px 24px;
  /* The stage IS the sea: it continues the water drawn inside the SVG outward to
     the panel edge, so the square canvas never shows as a paler tile on a white
     surround. Without this the whole map section reads as "white background". */
  background: radial-gradient(620px 380px at 62% 36%, #eef3f5 0%, #e7eef1 52%, #dce5ea 100%);
  min-height: 440px;
  display: flex;
  align-items: center;
}

/* Positioning context for the floating detail card and the incident badges.
   Kept square so the SVG's percentage coordinates map 1:1 onto the canvas. */
.map-canvas {
  position: relative;
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  aspect-ratio: 1 / 1;
}

/* HTML overlay for the incident badges. Badges live in the DOM (not in the
   SVG) so their text boxes are measurable, which is what lets layoutBadges()
   score candidate positions against each other. */
.map-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 4;
}

.japan-map {
  width: 100%;
  height: 100%;
  display: block;
  touch-action: manipulation;
}

/* --------------------------------------------------------------------------
   Map layers
   --------------------------------------------------------------------------
   Transit-diagram approach: the LAND is light context and the RAIL LINES are
   the subject, each drawn in its own colour. All strokes carry
   `vector-effect: non-scaling-stroke`, so a stroke-width is interpreted as real
   CSS pixels instead of SVG user units — previously a 2.6 "unit" halo became
   ~13.5px of white paint around 11px text, which swallowed the glyphs and made
   every label look broken.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Land — pastel regional tints
   --------------------------------------------------------------------------
   The palette is the supplied reference map's own, taken from its oklch()
   definitions (converted to sRGB by the browser, then cross-checked against a
   render of that reference: every value matched within 1/255).

   The land was a flat cool grey (#e2e8f0) and then a warm off-white (#f8f7f3),
   which is exactly why the map kept reading as "white". It is now tinted per
   region, the way the reference is.
   -------------------------------------------------------------------------- */
.map-land__shape {
  /* No stroke: the coastline is provided by the .map-coast rim drawn beneath,
     so a stroke here would just ring the outside in a second colour. */
  fill: #f8f7f3;              /* fallback only, if a region class is ever absent */
  stroke: none;
  stroke-linejoin: round;
}

/* --------------------------------------------------------------------------
   Regional palette — the reference map's OWN measured pixel colours.
   Each region is its own real prefecture geometry, so there are no special
   single-island cases any more: Honshu carries five colours because Japan
   really is divided that way.
   -------------------------------------------------------------------------- */
.map-land__shape--hokkaido { fill: #b7d9f3; }   /* 北海道 */
.map-land__shape--tohoku   { fill: #bce3c2; }   /* 東北 */
.map-land__shape--kanto    { fill: #d6cbee; }   /* 関東 */
.map-land__shape--chubu    { fill: #ede2b5; }   /* 中部 */
.map-land__shape--kansai   { fill: #f2c7d2; }   /* 近畿 */
.map-land__shape--chugoku  { fill: #afdfdf; }   /* 中国 */
.map-land__shape--shikoku  { fill: #d3e7b4; }   /* 四国 */
.map-land__shape--kyushu   { fill: #e1c3de; }   /* 九州 */
.map-land__shape--okinawa  { fill: #b3e1ec; }   /* 沖縄 */

.map-land,
.map-coast,
.map-borders,
.map-land-shadow,
.map-inset__frame,
.map-inset__panel {
  pointer-events: none;
}

/* Internal prefecture divisions — the reference's crisp WHITE lines. These are
   the arcs shared by two neighbouring prefectures, so every boundary follows
   the real survey line rather than a drawn approximation. */
.map-border {
  fill: none;
  stroke: #ffffff;
  stroke-width: 0.9;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* Coast rim: the TRUE sea coastline only, drawn UNDER the fills so only its
   seaward half survives and each island keeps a defined edge against water. */
.map-coast__shape {
  fill: none;
  stroke: #b3bec4;
  stroke-width: 1.1;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}

/* Drop shadow: the real archipelago silhouette, blurred, nudged down-right. */
.map-land-shadow__shape {
  fill: #466072;
  stroke: none;
  opacity: 0.28;
}

/* Okinawa inset — its own slightly cooler water panel, as in the reference, so
   the Ryukyu chain reads as a separate chart rather than as scattered islets. */
.map-inset__panel {
  fill: #e9eff2;
}

.map-inset__frame-rect {
  fill: none;
  stroke: #c5ced8;
  stroke-width: 1;
  stroke-dasharray: 4 3.5;
  vector-effect: non-scaling-stroke;
}

/* --------------------------------------------------------------------------
   Region filter
   --------------------------------------------------------------------------
   Four metro clusters share one canvas, so their markers and badges compete
   for the same few units. The filter removes the other regions, and selecting
   one also zooms to it — filtering alone would leave the surviving markers
   overlapping just as badly.
   -------------------------------------------------------------------------- */
.map-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 14px 22px;
  border-top: 1px solid var(--slate-200);
  background: var(--slate-50);
}

.map-toolbar__label {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--slate-400);
  white-space: nowrap;
}

.map-filter {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
}

.map-filter__chip {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 700;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--slate-200);
  background: var(--white);
  color: var(--slate-600);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

.map-filter__chip:hover {
  border-color: var(--blue-400);
  color: var(--blue-700);
}

.map-filter__chip.is-active {
  background: var(--blue-700);
  border-color: var(--blue-700);
  color: #fff;
}

.map-filter__chip:focus-visible {
  outline: 2px solid var(--blue-700);
  outline-offset: 2px;
}

.map-toolbar__hint {
  font-size: 0.75rem;
  color: var(--slate-400);
  margin: 0;
  flex-basis: 100%;
}

/* --------------------------------------------------------------------------
   Zoom control
   --------------------------------------------------------------------------
   Sits over the canvas so it stays reachable on a phone, where the toolbar
   above scrolls out of view.
   -------------------------------------------------------------------------- */
.map-zoom {
  position: absolute;
  right: 12px;
  bottom: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  z-index: 5;
}

.map-zoom__btn {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  font-size: 0.82rem;
  border-radius: 10px;
  border: 1px solid var(--slate-200);
  background: rgba(255, 255, 255, 0.94);
  color: var(--navy-900);
  cursor: pointer;
  box-shadow: var(--shadow-xs);
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

.map-zoom__btn:hover:not(:disabled) {
  background: var(--white);
  border-color: var(--blue-400);
  color: var(--blue-700);
}

.map-zoom__btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.map-zoom__btn:focus-visible {
  outline: 2px solid var(--blue-700);
  outline-offset: 2px;
}

.map-zoom__btn--reset {
  font-size: 0.74rem;
}

/* Hidden-by-filter / hidden-by-zoom. `visibility` rather than `display` on the
   SVG groups: display:none on an SVG child can drop it from layout in ways that
   make getBoundingClientRect() useless for the badge scoring pass. */
.map-marker.is-out,
.map-badge.is-out,
.feed-item.is-out {
  visibility: hidden;
  pointer-events: none;
}

.map-empty {
  margin: 0;
  padding: 18px 4px;
  font-size: 0.86rem;
  color: var(--slate-500);
  line-height: 1.7;
}

/* Rail casing: a solid white outline beneath each coloured line. This is what
   keeps parallel lines and line-over-land crossings readable. */
.rail-casing {
  fill: none;
  stroke: #ffffff;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0.95;
}

/* Rail line: the coloured line itself. */
.rail-line {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0.95;
}

/* Interchange hub: a small white-ringed station dot. */
.map-hub {
  fill: #1e293b;
  stroke: #ffffff;
  stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
}

.map-hub--strong {
  fill: #0f172a;
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

@media (prefers-reduced-motion: reduce) {
  .live-dot,
  .map-marker__pulse,
  .feed-item__dot {
    animation: none !important;
  }
}

/* --------------------------------------------------------------------------
   Incident markers
   --------------------------------------------------------------------------
   One marker per reported incident, plotted ON its rail line. Sizes (radius,
   glyph scale) are set by JS in user units derived from a target CSS-pixel
   size, so markers stay a constant, readable size on screen at every width.
   -------------------------------------------------------------------------- */
.map-marker {
  cursor: pointer;
  outline: none;
  transition: opacity 0.25s ease;
}

/* Soft coloured ring around the core — reads as a glow at a glance. */
.map-marker__halo {
  fill: none;
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  opacity: 0.4;
}

/* Expanding ring, used to draw the eye to severe / suspended incidents. */
.map-marker__pulse {
  transform-box: fill-box;
  transform-origin: center;
  animation: markerPulse 2.8s ease-out infinite;
  fill: none;
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}

.map-marker__pulse.is-urgent {
  animation-duration: 1.9s;
}

@keyframes markerPulse {
  0% {
    transform: scale(0.55);
    opacity: 0.7;
  }
  80% {
    transform: scale(2.2);
    opacity: 0;
  }
  100% {
    transform: scale(2.2);
    opacity: 0;
  }
}

/* Solid severity-coloured disc. */
.map-marker__core {
  stroke: #ffffff;
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  transition: stroke-width 0.16s ease;
}

.map-marker__hit {
  fill: transparent;
}

/* White glyph strokes. These live in the glyph's own unit space (1 = the marker
   radius) and are scaled by JS via `scale(r)`, so the stroke width grows with
   the marker. `non-scaling-stroke` must NOT be used here: it would reinterpret
   the width as device pixels (0.2px = invisible). The per-glyph width is set as
   an attribute by buildGlyph(); this is just the fallback. */
.map-marker__stroke {
  fill: none;
  stroke: #ffffff;
  stroke-width: 0.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.map-marker__dot {
  fill: #ffffff;
}

.map-marker__fill {
  fill: #ffffff;
  stroke: none;
}

/* Hover / focus / active feedback. */
.map-marker:hover .map-marker__core,
.map-marker:focus-visible .map-marker__core,
.map-marker.is-active .map-marker__core {
  stroke-width: 3.5;
}

.map-marker:hover .map-marker__halo,
.map-marker:focus-visible .map-marker__halo,
.map-marker.is-active .map-marker__halo {
  opacity: 0.85;
}

.map-marker.is-dimmed {
  opacity: 0.28;
}

/* Keyboard focus ring drawn on the marker, not the SVG root. */
.map-marker:focus-visible {
  outline: none;
}

.map-marker:focus-visible .map-marker__halo {
  stroke-width: 2.5;
  opacity: 1;
}

/* --------------------------------------------------------------------------
   City labels
   --------------------------------------------------------------------------
   font-size comes from --label-size, computed by JS so the text stays a
   constant ~11.5px on screen regardless of how far the 0–100 viewBox is
   scaled. The halo is a non-scaling stroke so it stays a true ~2.5px outline
   instead of growing into a blob that eats the glyphs.
   -------------------------------------------------------------------------- */
.map-label {
  font-family: var(--font-sans);
  font-size: var(--label-size, 2.2px);
  font-weight: 700;
  fill: #475569;
  pointer-events: none;
  letter-spacing: 0;
  paint-order: stroke fill;
  stroke: rgba(255, 255, 255, 0.95);
  stroke-width: 2.5;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}

html[lang="ja"] .map-label {
  letter-spacing: 0.02em;
  stroke-width: 2.8;
}

.map-label--strong {
  fill: var(--navy-900);
  font-weight: 800;
}

/* --------------------------------------------------------------------------
   Incident badges + leader lines
   --------------------------------------------------------------------------
   Every incident carries a permanent on-map label ("中央線 25分") so the place
   a delay is happening is readable WITHOUT hovering anything. Position and the
   connected leader line are computed by layoutBadges() in js/transit-map.js.
   -------------------------------------------------------------------------- */
.map-leader {
  fill: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.map-leader.is-dimmed {
  opacity: 0.1 !important;
}

.map-badge {
  position: absolute;
  top: var(--badge-y, 50%);
  left: var(--badge-x, 50%);
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px 2px 6px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid color-mix(in srgb, var(--badge-sev, #64748b) 42%, #ffffff);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.07), 0 5px 14px -8px rgba(15, 23, 42, 0.3);
  font-size: 0.615rem;
  font-weight: 700;
  line-height: 1.25;
  white-space: nowrap;
  color: var(--navy-800);
  cursor: pointer;
  pointer-events: auto;
  transition: opacity 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

/* The coloured tick on the left of every badge is the badge's own status edge
   — a second, redundant cue alongside the marker colour. */
.map-badge::before {
  content: "";
  width: 3px;
  align-self: stretch;
  border-radius: var(--r-pill);
  background: var(--badge-sev, #64748b);
  flex-shrink: 0;
}

.map-badge__code {
  color: var(--slate-600);
  font-weight: 600;
}

.map-badge__val {
  color: var(--badge-sev, #475569);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.map-badge.is-dimmed {
  opacity: 0.3;
}

.map-badge.is-active {
  border-color: var(--blue-400);
  box-shadow: 0 2px 4px rgba(15, 23, 42, 0.1), 0 10px 22px -10px rgba(30, 64, 175, 0.5);
}

.map-badge.is-focus {
  border-color: var(--blue-400);
  background: #ffffff;
  transform: translate(-50%, calc(-50% - 1px));
}

.map-badge:focus-visible {
  outline: 2px solid var(--blue-600);
  outline-offset: 2px;
}

/* Floating tooltip / detail card */
.map-card {
  position: absolute;
  z-index: 20;
  width: 268px;
  max-width: calc(100% - 12px);
  background: var(--white);
  border: 1px solid var(--slate-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-float);
  padding: 14px;
  transform: translate(-50%, calc(-100% - 14px));
  transition: opacity 0.14s ease;
  pointer-events: none;
}

.map-card.is-below {
  transform: translate(-50%, 16px);
}

.map-card[hidden] {
  display: none;
}

.map-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.map-card__cluster {
  font-size: 0.92rem;
  font-weight: 800;
  letter-spacing: -0.015em;
  line-height: 1.25;
}

.map-card__count {
  font-size: 0.68rem;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: var(--r-pill);
  background: var(--slate-100);
  color: var(--slate-600);
  white-space: nowrap;
}

.map-card__list {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.map-line {
  display: grid;
  grid-template-columns: 4px minmax(0, 1fr);
  gap: 9px;
  padding-bottom: 9px;
  border-bottom: 1px dashed var(--slate-200);
}

.map-line:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.map-line__bar {
  border-radius: 3px;
  background: var(--sev-normal);
}

.map-line__name {
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1.3;
}

.map-line__status {
  margin-top: 2px;
  font-size: 0.745rem;
  font-weight: 600;
  line-height: 1.4;
}

.map-line__meta {
  margin-top: 3px;
  font-size: 0.7rem;
  color: var(--slate-500);
  line-height: 1.4;
}

/* Incident feed sidebar */
.feed-panel {
  border-left: 1px solid var(--slate-200);
  background: var(--canvas);
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.feed-head {
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--slate-200);
}

.feed-head h3 {
  font-size: 0.9rem;
  font-weight: 800;
}

.feed-head p {
  margin-top: 3px;
  font-size: 0.75rem;
  color: var(--slate-500);
}

.feed-list {
  list-style: none;
  margin: 0;
  padding: 10px;
  overflow-y: auto;
  max-height: 452px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  flex: 1;
}

.feed-item {
  width: 100%;
  text-align: left;
  display: grid;
  grid-template-columns: 9px minmax(0, 1fr);
  gap: 10px;
  padding: 11px 12px;
  border-radius: var(--r-md);
  background: var(--white);
  border: 1px solid var(--slate-200);
  transition: border-color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
}

.feed-item:hover,
.feed-item.is-active {
  border-color: var(--blue-400);
  box-shadow: var(--shadow-soft);
  transform: translateX(2px);
}

.feed-item__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-top: 5px;
  flex-shrink: 0;
}

.feed-item__line {
  font-size: 0.815rem;
  font-weight: 700;
  line-height: 1.3;
}

.feed-item__meta {
  margin-top: 2px;
  font-size: 0.735rem;
  color: var(--slate-600);
  line-height: 1.42;
}

.feed-item__foot {
  margin-top: 6px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}

.sev-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.665rem;
  font-weight: 800;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: var(--r-pill);
}

.feed-item__rec {
  font-size: 0.665rem;
  font-weight: 600;
  color: var(--slate-500);
  font-variant-numeric: tabular-nums;
}

.feed-empty {
  padding: 28px 18px;
  text-align: center;
  font-size: 0.82rem;
  color: var(--slate-500);
}

.map-disclaimer {
  padding: 12px 24px 16px;
  border-top: 1px solid var(--slate-200);
  background: var(--white);
  font-size: 0.725rem;
  color: var(--slate-500);
  display: flex;
  /* Two lines on phones: `center` sank the info icon 9.4px (EN) / 10px (JA)
     below line 1. `baseline` keeps it beside the first line. */
  align-items: baseline;
  gap: 8px;
}

.map-disclaimer i {
  color: var(--sev-minor);
}

/* --------------------------------------------------------------------------
   8. Vision
   -------------------------------------------------------------------------- */
.vision-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 44px;
  align-items: start;
}

.vision-story {
  position: relative;
  background: linear-gradient(160deg, var(--navy-900) 0%, var(--navy-950) 62%, var(--blue-900) 100%);
  color: #e2e8f0;
  border-radius: var(--r-xl);
  padding: 38px 36px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.vision-story::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(520px 320px at 88% 8%, #000 0%, transparent 72%);
  -webkit-mask-image: radial-gradient(520px 320px at 88% 8%, #000 0%, transparent 72%);
  pointer-events: none;
}

.vision-story > * {
  position: relative;
  z-index: 1;
}

.vision-story h3 {
  color: #fff;
  font-size: 1.32rem;
  margin-bottom: 18px;
}

.vision-story p {
  font-size: 0.955rem;
  line-height: 1.75;
  color: #cbd5e1;
}

.vision-quote {
  margin-top: 24px;
  padding: 16px 18px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.13);
  border-left: 3px solid var(--blue-400);
  font-size: 0.88rem;
  font-weight: 600;
  color: #e2e8f0;
  line-height: 1.62;
}

.pillar-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.pillar {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  padding: 20px;
  background: var(--white);
  border: 1px solid var(--slate-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.pillar:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-soft);
  border-color: var(--slate-300);
}

.pillar__icon {
  width: 46px;
  height: 46px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  background: var(--blue-50);
  color: var(--blue-700);
  font-size: 1.05rem;
}

.pillar h3 {
  font-size: 1rem;
  margin-bottom: 6px;
}

.pillar p {
  font-size: 0.875rem;
  color: var(--slate-600);
  line-height: 1.65;
}

/* --------------------------------------------------------------------------
   9. App preview (device mockups)
   -------------------------------------------------------------------------- */
.phones {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px;
  max-width: 860px;
  margin: 0 auto;
}

.phone-unit {
  text-align: center;
}

.phone {
  position: relative;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
  aspect-ratio: 300 / 612;
  border-radius: 44px;
  padding: 10px;
  background: linear-gradient(155deg, #334155 0%, #0f172a 46%, #1e293b 100%);
  box-shadow: 0 2px 0 rgba(255, 255, 255, 0.16) inset,
    0 40px 70px -32px rgba(15, 23, 42, 0.62), 0 4px 12px -4px rgba(15, 23, 42, 0.4);
}

.phone::after {
  /* side button */
  content: "";
  position: absolute;
  right: -3px;
  top: 148px;
  width: 3px;
  height: 62px;
  border-radius: 3px;
  background: linear-gradient(180deg, #475569, #1e293b);
}

.phone::before {
  /* volume buttons */
  content: "";
  position: absolute;
  left: -3px;
  top: 118px;
  width: 3px;
  height: 44px;
  border-radius: 3px;
  background: linear-gradient(180deg, #475569, #1e293b);
}

.phone-screen {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 35px;
  background: var(--white);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.island {
  position: absolute;
  top: 9px;
  left: 50%;
  transform: translateX(-50%);
  width: 78px;
  height: 22px;
  border-radius: var(--r-pill);
  background: #0f172a;
  z-index: 5;
}

.status-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 20px 4px;
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--navy-900);
  flex-shrink: 0;
}

.status-bar__icons {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.6rem;
}

.app-shell {
  padding: 8px 15px 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}

.app-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.app-topbar__brand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.app-topbar__mark {
  width: 17px;
  height: 17px;
  border-radius: 5px;
  background: var(--navy-900);
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 0.5rem;
}

.app-topbar__avatar {
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--blue-500), var(--blue-700));
  color: #fff;
  font-size: 0.52rem;
  font-weight: 700;
  display: grid;
  place-items: center;
}

.app-h1 {
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.app-h1__sub {
  font-size: 0.62rem;
  color: var(--slate-500);
  font-weight: 600;
  margin-top: 2px;
}

/* live pulse notification inside app */
.app-alert {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 8px;
  /* baseline, NOT center: the title/subtitle wraps, and centring sank this
     badge 13px (JA) / 24px (EN) below the first line, so the alert icon read
     as detached from the text it labels. Measured against the first line's
     glyph box, baseline lands at +2px (JA) / +1px (EN) — effectively beside
     the line it belongs to. Same rule as the page-level pills. */
  align-items: baseline;
  padding: 9px 10px;
  border-radius: 12px;
  background: linear-gradient(135deg, #fff7ed, #ffedd5);
  border: 1px solid #fed7aa;
}

.app-alert--red {
  background: linear-gradient(135deg, #fef2f2, #fee2e2);
  border-color: #fecaca;
}

.app-alert__icon {
  position: relative;
  width: 24px;
  height: 24px;
  border-radius: 8px;
  background: var(--sev-minor);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 0.62rem;
}

.app-alert--red .app-alert__icon {
  background: var(--sev-suspended);
}

.app-alert__icon::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 8px;
  border: 2px solid currentColor;
  animation: alertRing 2.2s ease-out infinite;
}

@keyframes alertRing {
  0% {
    transform: scale(1);
    opacity: 0.7;
  }
  100% {
    transform: scale(1.7);
    opacity: 0;
  }
}

.app-alert__title {
  font-size: 0.672rem;
  font-weight: 800;
  line-height: 1.3;
}

.app-alert__sub {
  font-size: 0.6rem;
  color: #9a3412;
  font-weight: 600;
  margin-top: 1px;
}

.app-alert--red .app-alert__sub {
  color: #991b1b;
}

.app-section-label {
  font-size: 0.575rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--slate-400);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

/* favourite line rows */
.app-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.app-row {
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
  padding: 8px 9px 8px 0;
  border-radius: 10px;
  background: var(--white);
  border: 1px solid var(--slate-200);
}

.app-row__bar {
  height: 26px;
  border-radius: 0 3px 3px 0;
  background: var(--sev-normal);
}

.app-row__name {
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1.25;
}

.app-row__meta {
  font-size: 0.575rem;
  color: var(--slate-500);
  font-weight: 600;
  margin-top: 1px;
}

.app-row__badge {
  font-size: 0.585rem;
  font-weight: 800;
  padding: 3px 7px;
  border-radius: var(--r-pill);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* bypass / route timeline */
.route-card {
  padding: 10px;
  border-radius: 12px;
  background: var(--white);
  border: 1px solid var(--slate-200);
}

.route-stop {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  gap: 8px;
  align-items: start;
}

.route-stop__rail {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
}

.route-stop__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--navy-900);
  margin-top: 3px;
  flex-shrink: 0;
}

.route-stop__dot--flag {
  width: 10px;
  height: 10px;
  background: var(--sev-suspended);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.16);
}

.route-stop__line {
  flex: 1;
  width: 2px;
  background: repeating-linear-gradient(
    180deg,
    var(--slate-300) 0 4px,
    transparent 4px 8px
  );
  min-height: 12px;
}

.route-stop__body {
  padding-bottom: 8px;
}

.route-stop__title {
  font-size: 0.655rem;
  font-weight: 700;
  line-height: 1.3;
}

.route-stop__meta {
  font-size: 0.565rem;
  color: var(--slate-500);
  font-weight: 600;
  margin-top: 1px;
}

.route-bypass {
  margin: 2px 0 8px;
  padding: 8px 9px;
  border-radius: 10px;
  background: linear-gradient(135deg, #ecfdf5, #d1fae5);
  border: 1px solid #a7f3d0;
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  gap: 7px;
  /* baseline, not center — the bypass label wraps, and centring dropped this
     14px badge 12px (JA) / 11px (EN) below line 1. Baseline measures +1px in
     both languages, keeping the check beside the label it belongs to. */
  align-items: baseline;
}

.route-bypass__icon {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--sev-normal);
  color: #fff;
  font-size: 0.44rem;
  display: grid;
  place-items: center;
}

.route-bypass__label {
  font-size: 0.545rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #047857;
}

.route-bypass__text {
  font-size: 0.63rem;
  font-weight: 700;
  color: #065f46;
  line-height: 1.3;
  margin-top: 1px;
}

.app-cta {
  margin-top: auto;
  padding: 11px 14px;
  border-radius: 12px;
  background: var(--blue-700);
  color: #fff;
  font-size: 0.665rem;
  font-weight: 800;
  display: flex;
  /* The label wraps to two lines in the narrow mockup; centring put the PDF
     icon 7px down between the lines (EN). Baseline keeps it on line 1. */
  align-items: baseline;
  justify-content: center;
  gap: 7px;
  text-align: center;
  line-height: 1.28;
  box-shadow: 0 10px 20px -12px rgba(30, 64, 175, 0.95);
}

.app-note {
  font-size: 0.545rem;
  color: var(--slate-500);
  font-weight: 600;
  text-align: center;
  padding-bottom: 12px;
}

/* phone tab bar */
.app-tabbar {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 9px 8px 14px;
  border-top: 1px solid var(--slate-200);
  background: var(--white);
  flex-shrink: 0;
}

.app-tabbar span {
  font-size: 0.8rem;
  color: var(--slate-400);
}

.app-tabbar span.is-active {
  color: var(--blue-700);
}

.phone-caption {
  margin-top: 26px;
}

.phone-caption h3 {
  font-size: 1.14rem;
  margin-bottom: 10px;
}

.phone-caption p {
  font-size: 0.9rem;
  color: var(--slate-600);
  line-height: 1.68;
}

.callout-list {
  margin-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-align: left;
}

.callout {
  display: grid;
  grid-template-columns: 19px minmax(0, 1fr);
  gap: 9px;
  align-items: start;
  font-size: 0.845rem;
  color: var(--slate-700);
  line-height: 1.5;
}

.callout i {
  color: var(--sev-normal);
  font-size: 0.82rem;
  margin-top: 4px;
}

/* --------------------------------------------------------------------------
   10. Benefits
   -------------------------------------------------------------------------- */
.benefit-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 22px;
}

/* Four cards of unequal text length: on mid widths they would wrap into a
   lopsided 3+1, so the grid steps down deliberately rather than by accident. */
@media (max-width: 1080px) {
  .benefit-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .benefit-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.benefit-card {
  position: relative;
  padding: 30px 26px 28px;
  background: var(--white);
  border: 1px solid var(--slate-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.benefit-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg, var(--blue-700), var(--blue-400));
  opacity: 0;
  transition: opacity 0.22s ease;
}

.benefit-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-card);
  border-color: var(--slate-300);
}

.benefit-card:hover::before {
  opacity: 1;
}

.benefit-index {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: var(--slate-400);
}

.benefit-icon {
  margin: 18px 0 18px;
  width: 52px;
  height: 52px;
  border-radius: 15px;
  display: grid;
  place-items: center;
  font-size: 1.16rem;
  background: linear-gradient(140deg, var(--navy-900), var(--blue-700));
  color: #fff;
  box-shadow: 0 12px 24px -14px rgba(30, 64, 175, 0.9);
}

.benefit-card h3 {
  font-size: 1.08rem;
  margin-bottom: 11px;
}

.benefit-card p {
  font-size: 0.9rem;
  color: var(--slate-600);
  line-height: 1.68;
}

.benefit-detail {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--slate-200);
  font-size: 0.815rem;
  color: var(--slate-500);
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   11. Roadmap
   -------------------------------------------------------------------------- */
.roadmap {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
}

.roadmap::before {
  content: "";
  position: absolute;
  top: 22px;
  left: 4%;
  right: 4%;
  height: 2px;
  background: repeating-linear-gradient(90deg, var(--slate-300) 0 8px, transparent 8px 15px);
  z-index: 0;
}

.milestone {
  position: relative;
  z-index: 1;
  background: var(--white);
  border: 1px solid var(--slate-200);
  border-radius: var(--r-lg);
  padding: 24px 20px;
  box-shadow: var(--shadow-xs);
  transition: transform 0.22s ease, box-shadow 0.22s ease;
}

.milestone:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-soft);
}

.milestone__node {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--white);
  border: 3px solid var(--slate-300);
  margin-bottom: 18px;
}

.milestone--done .milestone__node {
  border-color: var(--sev-normal);
  background: var(--sev-normal);
  box-shadow: 0 0 0 5px rgba(16, 185, 129, 0.14);
}

.milestone--active .milestone__node {
  border-color: var(--blue-700);
  background: var(--white);
  box-shadow: 0 0 0 5px rgba(30, 64, 175, 0.15);
  animation: nodeBeat 2.4s ease-in-out infinite;
}

.milestone--key .milestone__node {
  border-color: var(--sev-minor);
  background: var(--sev-minor);
  box-shadow: 0 0 0 5px rgba(245, 158, 11, 0.16);
}

@keyframes nodeBeat {
  0%,
  100% {
    box-shadow: 0 0 0 5px rgba(30, 64, 175, 0.15);
  }
  50% {
    box-shadow: 0 0 0 9px rgba(30, 64, 175, 0.05);
  }
}

.milestone__when {
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--blue-700);
  text-transform: uppercase;
}

.milestone h3 {
  margin: 9px 0 9px;
  font-size: 1rem;
}

.milestone p {
  font-size: 0.845rem;
  color: var(--slate-600);
  line-height: 1.62;
}

.milestone__status {
  display: inline-block;
  margin-top: 15px;
  font-size: 0.665rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--slate-100);
  color: var(--slate-600);
}

.milestone--done .milestone__status {
  background: #ecfdf5;
  color: #047857;
}

.milestone--active .milestone__status {
  background: var(--blue-50);
  color: var(--blue-700);
}

.milestone--key .milestone__status {
  background: #fffbeb;
  color: #b45309;
}

/* --------------------------------------------------------------------------
   12. Pre-registration / notify
   -------------------------------------------------------------------------- */
.notify-section {
  position: relative;
  padding: 96px 0;
  background: linear-gradient(155deg, var(--navy-900) 0%, var(--navy-950) 52%, var(--blue-900) 100%);
  color: #e2e8f0;
  overflow: hidden;
}

.notify-section::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px);
  background-size: 52px 52px;
  mask-image: radial-gradient(700px 400px at 50% 30%, #000 0%, transparent 76%);
  -webkit-mask-image: radial-gradient(700px 400px at 50% 30%, #000 0%, transparent 76%);
  pointer-events: none;
}

.notify-inner {
  position: relative;
  z-index: 1;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}

.notify-inner h2 {
  color: #fff;
  font-size: clamp(1.75rem, 3.3vw, 2.5rem);
}

.notify-inner > p {
  margin-top: 18px;
  font-size: 1.015rem;
  color: #cbd5e1;
  line-height: 1.7;
}

.notify-form {
  margin-top: 34px;
  display: flex;
  gap: 10px;
  padding: 8px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--r-pill);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.notify-form input[type="email"] {
  flex: 1;
  min-width: 0;
  padding: 14px 20px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  background: rgba(255, 255, 255, 0.96);
  color: var(--navy-900);
  font-size: 0.94rem;
  font-weight: 600;
}

.notify-form input[type="email"]::placeholder {
  color: var(--slate-400);
  font-weight: 500;
}

.notify-form input[type="email"]:focus {
  outline: none;
  border-color: var(--blue-400);
  background: #fff;
}

.notify-form .btn {
  background: #fff;
  color: var(--navy-900);
  box-shadow: none;
}

.notify-form .btn:hover {
  background: var(--blue-50);
  transform: translateY(-1px);
}

.notify-form .btn[disabled] {
  opacity: 0.65;
  cursor: progress;
  transform: none;
}

.form-message {
  margin-top: 16px;
  font-size: 0.875rem;
  font-weight: 600;
  min-height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.form-message.is-success {
  color: #6ee7b7;
}

.form-message.is-error {
  color: #fca5a5;
}

.notify-meta {
  margin-top: 8px;
  font-size: 0.79rem;
  color: #94a3b8;
}

.notify-steps {
  margin-top: 44px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  text-align: left;
}

.notify-step {
  padding: 18px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, 0.055);
  border: 1px solid rgba(255, 255, 255, 0.11);
}

.notify-step__num {
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: #93c5fd;
}

.notify-step p {
  margin-top: 8px;
  font-size: 0.85rem;
  color: #e2e8f0;
  line-height: 1.55;
}

/* --------------------------------------------------------------------------
   13. Footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--canvas);
  border-top: 1px solid var(--slate-200);
  padding: 72px 0 32px;
}

.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 44px;
}

.footer-brand p {
  margin-top: 18px;
  font-size: 0.9rem;
  color: var(--slate-600);
  line-height: 1.7;
  max-width: 340px;
}

.footer-col h3 {
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--slate-500);
  margin-bottom: 18px;
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.footer-links a,
.footer-links button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 0.895rem;
  font-weight: 600;
  color: var(--slate-700);
  text-align: left;
  transition: color 0.16s ease, transform 0.16s ease;
}

.footer-links a:hover,
.footer-links button:hover {
  color: var(--blue-700);
  transform: translateX(2px);
}

.footer-links i {
  width: 17px;
  font-size: 0.9rem;
  color: var(--slate-400);
}

.footer-links a:hover i,
.footer-links button:hover i {
  color: var(--blue-700);
}

.footer-bottom {
  margin-top: 54px;
  padding-top: 24px;
  border-top: 1px solid var(--slate-200);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
}

.footer-bottom p {
  font-size: 0.815rem;
  color: var(--slate-500);
}

.footer-bottom nav {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.footer-bottom nav a,
.footer-bottom nav button {
  font-size: 0.815rem;
  font-weight: 600;
  color: var(--slate-500);
  transition: color 0.16s ease;
}

.footer-bottom nav a:hover,
.footer-bottom nav button:hover {
  color: var(--navy-900);
}

/* --------------------------------------------------------------------------
   14. Modal
   -------------------------------------------------------------------------- */
.modal[hidden] {
  display: none;
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 24px;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.modal-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 620px;
  max-height: 82vh;
  overflow-y: auto;
  background: var(--white);
  border-radius: var(--r-xl);
  padding: 34px 32px;
  box-shadow: var(--shadow-float);
}

.modal-panel h2 {
  font-size: 1.32rem;
  margin-bottom: 16px;
  padding-right: 36px;
}

.modal-panel p {
  font-size: 0.925rem;
  color: var(--slate-600);
  line-height: 1.75;
}

.modal-close {
  position: absolute;
  top: 22px;
  right: 22px;
  width: 34px;
  height: 34px;
  border-radius: var(--r-md);
  background: var(--slate-100);
  color: var(--slate-600);
  display: grid;
  place-items: center;
  font-size: 0.9rem;
  transition: background 0.16s ease, color 0.16s ease;
}

.modal-close:hover {
  background: var(--slate-200);
  color: var(--navy-900);
}

/* --------------------------------------------------------------------------
   15. Reveal-on-scroll
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   16. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .primary-nav {
    display: none;
  }

  .nav-toggle {
    display: grid;
  }

  .header-inner {
    justify-content: space-between;
  }

  .map-body {
    grid-template-columns: minmax(0, 1fr);
  }

  .feed-panel {
    border-left: none;
    border-top: 1px solid var(--slate-200);
  }

  .feed-list {
    max-height: 340px;
  }

  .vision-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
  }

  .roadmap {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .roadmap::before {
    display: none;
  }
}

@media (max-width: 900px) {
  .section {
    padding: 78px 0;
  }

  .hero {
    padding: 60px 0 72px;
  }

  .hero-ctas .btn {
    width: 100%;
  }

  .hero-ctas {
    flex-direction: column;
    align-items: stretch;
  }

  .benefit-grid,
  .phones,
  .notify-steps {
    grid-template-columns: minmax(0, 1fr);
  }

  .phones {
    gap: 52px;
  }

  .footer-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 36px;
  }

  .notify-form {
    flex-direction: column;
    border-radius: var(--r-lg);
  }

  .notify-form .btn {
    width: 100%;
  }
}

@media (max-width: 620px) {
  .container {
    padding: 0 18px;
  }

  .section {
    padding: 64px 0;
  }

  /* --- Japanese hero headline fit -------------------------------------
     THE reported mobile defect, and the reason the phone screenshot still shows
     it on the live site: this block had never been deployed. At 320-414px the
     long katakana phrase スマートナビゲーション。 is WIDER than the line at the
     desktop 33.6px, so the browser broke it INSIDE the word and stranded 「ン。」
     on a line of its own — exactly what the screenshot shows.

     `word-break: auto-phrase` cannot fix this: the phrase is a single
     unbreakable unit that is simply WIDER than the measure, so it fits entire
     only if the display size shrinks. Largest size at which it still fits,
     measured on the real page at 375px:
       320px -> 27px    340px -> 29px    360px -> 31px
       375px -> 32px    390px -> 33.6px  414px+ -> 33.6px
     The clamp below deliberately keeps a MARGIN under those ceilings rather
     than sitting on them (8vw = 25.6px at 320px, 30.0px at 375px). The earlier
     value (8.2vw) left under 1px of slack at 320px, so the smallest render
     difference re-broke the word. JA-scoped, so the English headline keeps its
     original 33.6px. */
  html[lang="ja"] .hero-title {
    font-size: clamp(1.35rem, 8vw, 2.1rem);
  }

  .brand-badge {
    display: none;
  }

  .header-actions .btn-sm span {
    display: none;
  }

  .header-actions .btn-sm {
    padding: 10px 13px;
  }

  .stat-strip {
    grid-template-columns: minmax(0, 1fr);
  }

  .stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    text-align: left;
    padding: 15px 18px;
  }

  .stat-label {
    margin-top: 0;
  }

  .map-panel-head {
    padding: 16px 16px;
  }

  .map-stage {
    padding: 12px 10px 18px;
    align-items: center;
    min-height: 0;
  }

  .legend {
    gap: 6px;
  }

  .legend-chip {
    font-size: 0.68rem;
    padding: 5px 9px;
  }

  /* Below 620px the floating card would overflow the canvas, so the incident
     feed (rendered directly under the map) carries the detail view instead. */
  .map-card {
    display: none !important;
  }

  /* Badges are redundant on phones: the feed directly below the map lists every
     incident with its line name, status and recovery estimate, and keeping the
     badges would crowd the map to the point of unreadability. */
  .map-badge,
  .map-leader {
    display: none !important;
  }

  .map-stage {
    align-items: center;
    min-height: 0;
  }

  .roadmap {
    grid-template-columns: minmax(0, 1fr);
  }

  .vision-story {
    padding: 28px 22px;
  }

  .modal-panel {
    padding: 26px 20px;
  }

  .map-disclaimer {
    padding: 12px 16px 14px;
    font-size: 0.68rem;
  }
}

/* --------------------------------------------------------------------------
   Narrow phones (<=400px) — header fit
   --------------------------------------------------------------------------
   Below 375px the header did not fit its own contents: the brand lockup plus
   the four action controls (language switch, bell, PDF, hamburger) need 374px,
   so a 320px viewport scrolled sideways by 54px and a 360px one by 14px.
   Measured page overflow before / after, at the widths where it occurred:
     before  320:+54  340:+34  360:+14  375:0  390:0
     after   320:0    340:0    360:0    375:0  390:0
   Only spacing and the small controls tighten — nothing a phone user needs is
   hidden, and the language switch stays fully legible. */
@media (max-width: 400px) {
  .container { padding: 0 14px; }
  .header-inner { gap: 10px; }
  .header-actions { gap: 7px; }
  .lang-btn { padding: 5px 9px; font-size: 0.71rem; }
  .nav-toggle { width: 37px; height: 37px; }
  .header-actions .btn-sm { padding: 8px 10px; }
}
