{
  "sha": "31db04c68fa534b6924b855582c02729c096b59a",
  "message": "Fix iPad portrait responsive layout (#153)\n\nAdd a tablet breakpoint for compact navigation, prevent horizontal overflow, prioritize the main news column, stack the radar layout, and cover the breakpoint with regression tests.",
  "author": {
    "login": "nnneeeooo-nnneeeooo",
    "name": "",
    "email": ""
  },
  "committer": {
    "login": "web-flow",
    "name": "",
    "email": ""
  },
  "created_at": "2026-08-29T18:01:40Z",
  "files": [
    {
      "filename": "static/app.js",
      "previous_filename": "",
      "status": "modified",
      "additions": 1,
      "deletions": 1,
      "changes": 2
    },
    {
      "filename": "static/site.css",
      "previous_filename": "",
      "status": "modified",
      "additions": 38,
      "deletions": 13,
      "changes": 51
    },
    {
      "filename": "tests/test_mobile_layout.py",
      "previous_filename": "",
      "status": "modified",
      "additions": 5,
      "deletions": 1,
      "changes": 6
    }
  ],
  "diff": "@@ -102,7 +102,7 @@\\n     document.addEventListener(\"keydown\", function (event) {\\n       if (event.key === \"Escape\") setNavOpen(false);\\n     });\\n-    var desktopNav = window.matchMedia(\"(min-width: 721px)\");\\n+    var desktopNav = window.matchMedia(\"(min-width: 901px)\");\\n     desktopNav.addEventListener(\"change\", function (event) {\\n       if (event.matches) setNavOpen(false);\\n     });\\n@@ -563,31 +563,56 @@ a.flash-row:hover { color: inherit; }\\n   .changelog-group { grid-template-columns: 96px minmax(0, 1fr); }\\n }\\n \\n-@media (max-width: 720px) {\\n-  .utility-row { padding: 8px 12px; gap: 8px 12px; }\\n-  .utility-date { flex-basis: 100%; }\\n-  .utility-update { margin-left: 0; }\\n+/* Tablet portrait (including the 820px-wide iPad Air): use the compact\\n+   navigation before the full desktop nav starts scrolling or squeezing. */\\n+@media (max-width: 900px) {\\n+  .page { width: 100%; overflow-x: clip; }\\n   .brand-row {\\n-    padding: 9px 12px; gap: 12px; flex-wrap: nowrap;\\n+    padding: 9px 16px; gap: 12px; flex-wrap: wrap;\\n     justify-content: space-between;\\n   }\\n-  .brand-link { flex: 0 1 224px; min-width: 0; }\\n-  .brand-logo { max-width: 224px; }\\n-  .brand-name { font-size: 18px; }\\n-  .brand-tagline { font-size: 9px; letter-spacing: .11em; white-space: nowrap; }\\n-  .nav-toggle { display: inline-flex; flex-shrink: 0; }\\n+  .brand-link { flex: 0 1 280px; min-width: 0; }\\n+  .brand-logo { max-width: 280px; }\\n+  .nav-toggle { display: inline-flex; flex-shrink: 0; margin-left: auto; }\\n   .site-nav {\\n-    order: 3; width: 100%; margin: 0; padding: 4px 0 0; overflow: visible;\\n-    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;\\n+    order: 3; width: 100%; flex: 0 0 100%; margin: 0; padding: 4px 0 0;\\n+    overflow: visible; display: grid;\\n+    grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px;\\n     white-space: normal;\\n   }\\n   .js .site-nav { display: none; }\\n   .js .site-nav.is-open { display: grid; }\\n   .nav-link {\\n-    min-height: 44px; padding: 10px 12px; display: flex; align-items: center;\\n+    min-width: 0; min-height: 44px; padding: 10px 12px;\\n+    display: flex; align-items: center;\\n     border: 1px solid var(--color-divider); border-bottom-width: 1px;\\n+    overflow-wrap: anywhere;\\n   }\\n   .nav-link.active { border-color: var(--color-accent); }\\n+  .center-col { order: 1; }\\n+  .rail-left {\\n+    order: 2; border-top: 2px solid var(--color-divider); border-bottom: 0;\\n+  }\\n+  .rail-right { order: 3; }\\n+  .radar-layout { grid-template-columns: minmax(0, 1fr); min-height: 0; }\\n+  .radar-map { min-height: 520px; }\\n+  .radar-list-panel { border-left: 0; border-top: 1px solid var(--color-divider); }\\n+  .radar-list { max-height: 360px; }\\n+}\\n+\\n+@media (max-width: 720px) {\\n+  .utility-row { padding: 8px 12px; gap: 8px 12px; }\\n+  .utility-date { flex-basis: 100%; }\\n+  .utility-update { margin-left: 0; }\\n+  .brand-row {\\n+    padding: 9px 12px; gap: 12px;\\n+    justify-content: space-between;\\n+  }\\n+  .brand-link { flex: 0 1 224px; min-width: 0; }\\n+  .brand-logo { max-width: 224px; }\\n+  .brand-name { font-size: 18px; }\\n+  .brand-tagline { font-size: 9px; letter-spacing: .11em; white-space: nowrap; }\\n+  .site-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }\\n   .ticker-label { padding: 7px 10px; font-size: 11px; letter-spacing: .08em; }\\n   .marquee-track { --ticker-duration: 130s; }\\n   .ticker-pass {\\n@@ -83,10 +83,14 @@ def main() -> None:\\n         \"China Airlines Adjusts Two Taoyuan-Fukuoka Flights After Airport Restrictions\")\\n     assert len(en_short.split()) <= 14 and \"…\" not in en_short\\n \\n+    assert \"@media (max-width: 900px)\" in css\\n     assert \"@media (max-width: 720px)\" in css\\n+    assert \".page { width: 100%; overflow-x: clip; }\" in css\\n+    assert \"grid-template-columns: repeat(3, minmax(0, 1fr))\" in css\\n     assert \".js .site-nav.is-open { display: grid; }\" in css\\n     assert \"grid-template-columns: repeat(2, minmax(0, 1fr))\" in css\\n     assert \".center-col { order: 1;\" in css\\n+    assert \".radar-layout { grid-template-columns: minmax(0, 1fr); min-height: 0; }\" in css\\n     assert '\". . summary summary\"' in css\\n     assert '\"summary summary\"' in css\\n     assert \".summary-preview--feed { grid-area: summary; margin-top: 7px; }\" in css\\n@@ -106,7 +110,7 @@ def main() -> None:\\n     assert \".marquee-track .ticker-pass:nth-child(2) { display: none; }\" in css\\n     assert 'setAttribute(\"aria-expanded\"' in script\\n     assert 'event.key === \"Escape\"' in script\\n-    assert 'matchMedia(\"(min-width: 721px)\")' in script\\n+    assert 'matchMedia(\"(min-width: 901px)\")' in script\\n     assert 'matches ? 32 : 52' in script\\n     assert 'style.setProperty(\"--ticker-duration\"' in script\\n "
}
