diff --git a/assets/css/style.css b/assets/css/style.css
index 79bef7e..b94bbd2 100644
--- a/assets/css/style.css
+++ b/assets/css/style.css
@@ -136,6 +136,57 @@ nav a {
box-sizing: border-box;
}
+.portal-nav__menu-toggle {
+ display: none;
+ flex-shrink: 0;
+ margin-left: auto;
+ padding: 10px 12px;
+ border: 0;
+ border-radius: 10px;
+ background: transparent;
+ cursor: pointer;
+ color: var(--primary);
+}
+
+.portal-nav__menu-toggle:focus-visible {
+ outline: 2px solid var(--primary);
+ outline-offset: 3px;
+}
+
+.portal-nav__menu-toggle-icon {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 18px;
+}
+
+.portal-nav__menu-toggle-bar {
+ display: block;
+ width: 22px;
+ height: 2px;
+ border-radius: 1px;
+ background: currentColor;
+ transition: transform 0.2s ease, opacity 0.2s ease;
+}
+
+.portal-nav__menu-toggle-bar+.portal-nav__menu-toggle-bar {
+ margin-top: 5px;
+}
+
+.portal-nav.portal-nav--open .portal-nav__menu-toggle-bar:nth-child(1) {
+ transform: translateY(7px) rotate(45deg);
+}
+
+.portal-nav.portal-nav--open .portal-nav__menu-toggle-bar:nth-child(2) {
+ opacity: 0;
+}
+
+.portal-nav.portal-nav--open .portal-nav__menu-toggle-bar:nth-child(3) {
+ transform: translateY(-7px) rotate(-45deg);
+}
+
.portal-nav>ul {
display: flex;
flex-wrap: wrap;
@@ -205,7 +256,7 @@ nav a {
color: #3a300a;
}
-/* 淪陷瞬間 · 全員發瘋:第一層向下;第二/三層向右飛出(僅 ≤767px 直向堆疊,避免 1024 平板也壓成直排) */
+/* 淪陷瞬間 · 全員發瘋:第一層向下;第二/三層向右飛出(≥992px);≤991px 漢堡+直向堆疊 */
.portal-nav .portal-submenu .portal-nav__subgroup {
position: relative;
z-index: 0;
@@ -349,7 +400,7 @@ nav a {
display: flex;
}
-@media (min-width: 768px) {
+@media (min-width: 992px) {
.portal-nav .portal-nav__subgroup>.portal-submenu-nested {
position: absolute !important;
@@ -396,7 +447,63 @@ nav a {
}
}
-@media (max-width: 767px) {
+@media (max-width: 991px) {
+
+ .portal-nav__menu-toggle {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .portal-nav>ul {
+ display: none;
+ flex: 1 1 100%;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: flex-start;
+ gap: 0;
+ width: 100%;
+ margin-top: 4px;
+ padding: 8px 0 12px;
+ border-top: 1px solid rgba(255, 204, 0, 0.2);
+ }
+
+ .portal-nav.portal-nav--open>ul {
+ display: flex;
+ }
+
+ .portal-nav>ul>li {
+ width: 100%;
+ position: relative;
+ }
+
+ .portal-nav>ul>li>a {
+ justify-content: flex-start;
+ width: 100%;
+ min-height: 44px;
+ padding: 10px 8px;
+ box-sizing: border-box;
+ }
+
+ .portal-nav>ul>li:hover>.portal-submenu,
+ .portal-nav>ul>li:focus-within>.portal-submenu {
+ display: none;
+ }
+
+ .portal-nav>ul>li.open>.portal-submenu {
+ display: grid;
+ }
+
+ .portal-nav .portal-submenu {
+ position: static;
+ width: 100%;
+ min-width: 0;
+ margin-top: 4px;
+ padding: 6px 8px 10px;
+ box-shadow: none;
+ border-radius: 10px;
+ background: rgba(255, 255, 255, 0.06);
+ }
.portal-nav .portal-submenu .portal-nav__subgroup-head::after,
.portal-nav .portal-nav__subgroup-head--nested::after {
@@ -422,9 +529,17 @@ nav a {
.portal-nav .portal-nav__subgroup:hover>.portal-submenu-nested,
.portal-nav .portal-nav__subgroup:focus-within>.portal-submenu-nested {
+ display: none;
+ }
+
+ .portal-nav .portal-nav__subgroup.open>.portal-submenu-nested {
display: flex;
}
+ .portal-nav .portal-submenu .portal-nav__subgroup-head {
+ cursor: pointer;
+ }
+
.portal-nav .portal-submenu-nested--tier3,
.portal-nav .portal-nav__subgroup--nested:hover>.portal-submenu-nested--tier3,
.portal-nav .portal-nav__subgroup--nested:focus-within>.portal-submenu-nested--tier3 {
@@ -444,6 +559,10 @@ nav a {
.portal-nav .portal-nav__subgroup--nested:hover>.portal-submenu-nested--tier3,
.portal-nav .portal-nav__subgroup--nested:focus-within>.portal-submenu-nested--tier3 {
+ display: none;
+ }
+
+ .portal-nav .portal-nav__subgroup--nested.open>.portal-submenu-nested--tier3 {
display: flex;
}
}
@@ -1566,7 +1685,7 @@ footer a .mark_b {
padding-right: 10px;
}
-@media (min-width: 768px) {
+@media (min-width: 992px) {
.map-page .portal-nav .portal-submenu .portal-nav__subgroup-head::after {
right: auto;
@@ -1597,7 +1716,18 @@ footer a .mark_b {
}
}
-@media (max-width: 767px) {
+@media (max-width: 991px) {
+
+ .map-page .portal-nav>ul>li>a {
+ justify-content: flex-end;
+ text-align: right;
+ }
+
+ .map-page .portal-nav .portal-submenu a,
+ .map-page .portal-nav .portal-submenu .portal-nav__subgroup-head {
+ text-align: right;
+ justify-content: flex-end;
+ }
.map-page .portal-nav .portal-nav__subgroup>.portal-submenu-nested,
.map-page .portal-nav .portal-nav__subgroup:hover>.portal-submenu-nested,
diff --git a/assets/css/tablet.css b/assets/css/tablet.css
index 4211d79..21286fc 100644
--- a/assets/css/tablet.css
+++ b/assets/css/tablet.css
@@ -1,5 +1,20 @@
/* iPad/平板 RWD — max-width ≤1180px(含 iPad 直/橫與小平板/小筆電) */
+/* 頂欄漢堡:與 style.css 992 斷點一致,避免本檔 1180 規則把選單列壓回橫排 */
+@media (max-width: 991px) {
+
+ .portal-nav>ul {
+ flex: 1 1 100%;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ align-items: stretch;
+ }
+
+ .portal-nav>ul>li>a {
+ flex-direction: row;
+ }
+}
+
@media (max-width: 1180px) {
html:has(.portal-nav) {
@@ -45,7 +60,7 @@
justify-content: center;
}
- nav ul {
+ nav:not(.portal-nav):not(.bilivideo-episode-nav) ul {
gap: clamp(12px, 2vw, 20px);
}
diff --git a/assets/js/portal-nav.js b/assets/js/portal-nav.js
index 1e497df..09821ae 100644
--- a/assets/js/portal-nav.js
+++ b/assets/js/portal-nav.js
@@ -22,6 +22,27 @@
/** 主選單欄 `mouseleave` 後延遲關閉(ms),方便移入子選單或右側飛出層,避免略偏就關閉 */
const SUBMENU_CLOSE_DELAY_MS = 650;
+ /** 橫向+右側飛出子選單;≤991px 改漢堡+直向展開(對齊常見 992 斷點) */
+ const PORTAL_NAV_DESKTOP_MIN_PX = 992;
+
+ function isPortalNavDesktop() {
+ return window.matchMedia(`(min-width: ${PORTAL_NAV_DESKTOP_MIN_PX}px)`).matches;
+ }
+
+ function setPortalNavMenuOpen(nav, open) {
+ nav.classList.toggle("portal-nav--open", open);
+ const toggle = nav.querySelector(".portal-nav__menu-toggle");
+ if (toggle) {
+ toggle.setAttribute("aria-expanded", open ? "true" : "false");
+ toggle.setAttribute("aria-label", open ? "關閉選單" : "開啟選單");
+ }
+ if (!open) {
+ nav.querySelectorAll(":scope > ul > li.open, .portal-nav__subgroup.open").forEach((el) => {
+ el.classList.remove("open");
+ });
+ }
+ }
+
function pickSoonPhrase() {
return NAV_SOON_PHRASES[Math.floor(Math.random() * NAV_SOON_PHRASES.length)];
}
@@ -212,7 +233,14 @@
function buildPortalNavInnerHTML(rp) {
return `
-