/* ============================================================
 * _components.css — 全站共用元件層
 * ------------------------------------------------------------
 * 載入順序：_tokens.css → _components.css → page CSS
 * 用途：提供 .btn / .modal / .pill 的 canonical 預設樣式。
 * Page CSS 因 cascade 在後，仍能覆寫本層；新頁面可直接用這些 class。
 * ============================================================ */

/* utility：取代被砍掉的 tailwind .hidden（多頁 JS classList.add/remove('hidden') 仰賴這個） */
.hidden { display: none !important; }

/* ── Turnstile widget wrapper（全站共用，data-size="flexible" → widget 自動 fit 父容器寬） ── */
.ts-wrap { min-height: 65px; margin: .5rem 0; display: flex; flex-direction: column; justify-content: center; align-items: center; }
.ts-hint { font-size: .72rem; color: var(--text-dim); line-height: 1.4; margin: 0 0 .4rem; text-align: center; transition: opacity .2s ease; }
.ts-wrap.is-ready .ts-hint { display: none; }
/* flexible 模式有 300px CF 硬下限；極窄手機（≤340px，iPhone SE 直立）保留 scale 兜底 */
@media (max-width: 340px) {
  .ts-wrap > div { transform: scale(.88); transform-origin: center top; }
  .ts-wrap { min-height: 58px; }
}

/* ── Auth pages 共用的 success/error 面板（forgot-password / reset-password / verify-email / bind-email / confirm-delete） ── */
.success-state,
.error-state { text-align: center; padding: .25rem 0; }
.success-icon-wrap,
.error-icon-wrap {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; border-radius: 50%; margin-bottom: 1rem;
}
.success-icon-wrap { background: rgba(34,168,101,.10); border: 1px solid rgba(34,168,101,.25); color: #22a865; }
.error-icon-wrap   { background: rgba(248,113,113,.10); border: 1px solid rgba(248,113,113,.25); color: #f87171; }
.success-icon-wrap svg,
.error-icon-wrap svg { width: 24px; height: 24px; }
.success-title,
.error-title   { font-size: 1rem; font-weight: 600; color: var(--text); margin-bottom: .35rem; }
.success-desc,
.error-desc    { font-size: .85rem; color: var(--text-muted); white-space: pre-line; line-height: 1.65; }
.success-countdown { font-size: .75rem; color: var(--text-dim); margin-top: .75rem; }
.success-back-btn  { display: inline-block; width: auto; margin-top: 1.25rem; padding: .55rem 1.5rem; text-decoration: none; }
/* .text-center utility for vertically centred panels */
.text-center { text-align: center; }

/* ── Button base ─────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .65rem 1.4rem;
  font-family: var(--font-body); font-size: .88rem; font-weight: 500;
  border-radius: 8px; border: none; cursor: pointer;
  text-decoration: none; line-height: 1.2;
  transition: filter .18s ease, transform .18s ease,
              background .18s ease, border-color .18s ease, color .18s ease;
}
.btn:disabled { opacity: .55; cursor: not-allowed; }

/* ── Button variants ─────────────────────────────── */
.btn-primary {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .65rem 1.4rem;
  background: var(--accent); color: #fff;
  font-family: var(--font-body); font-size: .88rem; font-weight: 500;
  border-radius: 8px; border: none; cursor: pointer;
  transition: filter .18s ease, transform .18s ease;
}
.btn-primary:hover:not(:disabled) { filter: brightness(1.08); transform: translateY(-1px); }
.btn-primary:disabled { opacity: .55; cursor: not-allowed; }

.btn-ghost {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .65rem 1.2rem;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body); font-size: .88rem; font-weight: 400;
  border-radius: 10px; border: 1px solid var(--border); cursor: pointer;
  transition: background .18s ease, border-color .18s ease, color .18s ease;
}
.btn-ghost:hover:not(:disabled) {
  background: var(--hover-overlay);
  border-color: var(--border-mid);
  color: var(--text);
}
.btn-ghost:disabled { opacity: .55; cursor: not-allowed; }

.btn-danger {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .65rem 1.4rem;
  background: #dc2626; color: #fff;
  font-family: var(--font-body); font-size: .88rem; font-weight: 500;
  border-radius: 8px; border: none; cursor: pointer;
  transition: filter .18s ease, transform .18s ease;
}
.btn-danger:hover:not(:disabled) { filter: brightness(1.06); transform: translateY(-1px); }
.btn-danger:disabled { opacity: .55; cursor: not-allowed; }

/* ── Pill ────────────────────────────────────────── */
.pill {
  display: inline-flex; align-items: center;
  padding: .18rem .55rem;
  border-radius: 6px;
  font-size: .72rem;
  background: var(--accent-dim);
  color: var(--accent);
  border: 1px solid var(--accent-glow);
}

/* ── Modal ───────────────────────────────────────── */
.modal-bd {
  display: none;
  position: fixed; inset: 0;
  z-index: var(--z-modal);
  background: rgba(0,0,0,.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  align-items: center; justify-content: center;
  padding: 1rem;
}
.modal-bd.open { display: flex; }

.modal-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  width: 100%; max-width: 560px;
  max-height: 85vh; overflow-y: auto;
  box-shadow: 0 24px 64px rgba(0,0,0,.32);
}

.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.4rem;
  border-bottom: 1px solid var(--border-dim);
}
.modal-head h2 { font-size: .9rem; font-weight: 600; color: var(--text); }

.modal-close {
  background: none; border: none;
  color: var(--text-dim); cursor: pointer;
  padding: .25rem; border-radius: 6px;
  transition: color .18s, background .18s;
}
.modal-close:hover { color: var(--text); background: var(--hover-overlay); }
.modal-close svg { width: 18px; height: 18px; display: block; }

.modal-body {
  padding: 1.25rem 1.4rem;
  display: flex; flex-direction: column; gap: .85rem;
  font-size: .86rem;
}

.modal-footer {
  padding: 1rem 1.4rem;
  border-top: 1px solid var(--border-dim);
  display: flex; align-items: center; justify-content: flex-end; gap: .65rem;
}

/* ── Toast（Phase 2 notify.js 消費） ───────────────── */
.toast-stack {
  position: fixed;
  top: 1rem; right: 1rem;
  z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: .5rem;
  pointer-events: none;
  max-width: min(92vw, 420px);
}
.toast {
  pointer-events: auto;
  background: var(--bg-surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: 10px;
  padding: .75rem 1rem;
  font-size: .85rem;
  line-height: 1.5;
  box-shadow: 0 10px 32px rgba(0,0,0,.18);
  cursor: pointer;
  opacity: 0;
  transform: translateX(20px);
  transition: opacity .25s ease, transform .25s ease;
  word-break: break-word;
}
.toast.show    { opacity: 1; transform: translateX(0); }
.toast.leaving { opacity: 0; transform: translateX(20px); }
.toast-success { border-left-color: #22a865; }
.toast-error   { border-left-color: #dc2626; }
.toast-warning { border-left-color: #f59e0b; }
.toast-info    { border-left-color: var(--accent); }

@media (max-width: 640px) {
  .toast-stack { top: auto; bottom: 1rem; left: 1rem; right: 1rem; max-width: none; }
  .toast { transform: translateY(20px); }
  .toast.show    { transform: translateY(0); }
  .toast.leaving { transform: translateY(20px); }
}

/* ── Skeleton primitives（Phase 3 loading 三段式用）─── */
/* 用法：
 *   <div class="sk-text">
 *     <div class="sk sk-line sk-lg"></div>
 *     <div class="sk sk-line"></div>
 *     <div class="sk sk-line" style="width:60%"></div>
 *   </div>
 *   <div class="sk sk-block" style="height:160px"></div>
 *   <div class="sk sk-circle"></div>
 * Shimmer 兩 mode 自動（用 --bg-surface ↔ --bg-elevated 漸層）。 */
@keyframes sk-shimmer {
  0%   { background-position: -100% 0; }
  100% { background-position:  100% 0; }
}
.sk {
  background: linear-gradient(
    90deg,
    var(--bg-surface) 25%,
    var(--bg-elevated) 50%,
    var(--bg-surface) 75%
  );
  background-size: 200% 100%;
  animation: sk-shimmer 1.5s ease-in-out infinite;
  border-radius: 6px;
}
.sk-line   { height: 1em; margin: .35em 0; }
.sk-line.sk-sm { height: .75em; }
.sk-line.sk-lg { height: 1.4em; }
.sk-line:last-child { margin-bottom: 0; }
.sk-block  { width: 100%; height: 120px; border-radius: 10px; }
.sk-circle { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0; }
.sk-text   { display: flex; flex-direction: column; gap: .4em; }

@media (prefers-reduced-motion: reduce) {
  .sk { animation: none; }
}

/* ── Empty state（fetch 無資料 / 篩選結果為空）────── */
/* 用法：
 *   <div class="empty-state">
 *     <div class="empty-state-icon">📭</div>
 *     <div class="empty-state-title">尚無資料</div>
 *     <div class="empty-state-sub">目前還沒有任何項目。</div>
 *     <button class="btn-primary">前往新增</button>
 *   </div>
 */
.empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding: 3rem 1.5rem;
  gap: .55rem;
  color: var(--text-muted);
}
.empty-state-icon {
  font-size: 2.25rem;
  line-height: 1;
  opacity: .55;
  margin-bottom: .35rem;
}
.empty-state-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
}
.empty-state-sub {
  font-size: .85rem;
  line-height: 1.55;
  color: var(--text-muted);
  max-width: 32ch;
}
.empty-state .btn,
.empty-state .btn-primary,
.empty-state .btn-ghost,
.empty-state .btn-danger { margin-top: .65rem; }

/* ── Form input focus ring（B3 follow-up）──────────────
 * forgot-password / reset-password / bind-email / dashboard 4 頁的 form input
 * 用 Tailwind 任意 utility `focus:border-brand-500/60 focus:ring-2 focus:ring-brand-500/20`，
 * 但 brand-500 + opacity 修飾子在 JIT 沒 build 出來 → focus 沒視覺反饋。
 * 在這裡無條件 map 到 var(--accent) / var(--accent-glow)，所有頁面共用。 */
.focus\:border-brand-500\/60:focus { border-color: var(--accent) !important; }
.focus\:ring-brand-500\/20:focus {
  box-shadow: 0 0 0 3px var(--accent-glow) !important;
  outline: none;
}

/* ── Sidebar foot controls（B3 follow-up：原 12 份 CSS 各自一份，集中於此）──
 * HTML 用 .sb-footer / .sb-foot-icons / .sb-foot-btn / .lang-dropdown / .lang-opt
 * dashboard 額外保留 .db-lang-opt（JS hook，CSS 無 rule）與 #db-lang-drop（JS getElementById） */
.sb-footer{display:flex;align-items:center;gap:.5rem;position:relative}
.sb-foot-icons{display:flex;gap:.25rem}
.sb-foot-btn{width:30px;height:30px;border:none;background:none;border-radius:7px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-dim);transition:background .18s ease,color .18s ease}
.sb-foot-btn:hover{background:var(--hover-overlay);color:var(--text-muted)}
.sb-foot-btn svg{width:14px;height:14px}
.sb-foot-btn .icon-theme{width:22px;height:22px}
.tool-btn .icon-theme{width:22px;height:22px;display:block}
.m-theme-btn .icon-theme{width:22px;height:22px;display:block}
.lang-dropdown{position:absolute;bottom:calc(100% + .45rem);left:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:10px;padding:.35rem;box-shadow:0 -4px 24px rgba(0,0,0,.16);display:none;flex-direction:column;gap:.1rem;z-index:200;min-width:128px}
.lang-dropdown.open{display:flex}
.lang-opt{display:block;width:100%;padding:.4rem .72rem;border:none;background:transparent;border-radius:7px;font-family:var(--font-sans);font-size:.8rem;color:var(--text-muted);cursor:pointer;text-align:left;transition:background .15s ease,color .15s ease;white-space:nowrap}
.lang-opt:hover{background:var(--hover-overlay);color:var(--text)}
.lang-opt.active{color:var(--accent);font-weight:500;background:var(--accent-dim)}

/* ── Sidebar core（B3 follow-up：原 12 份 CSS 各自一份，集中於此）──
 * 公開頁 9 + dashboard + admin-requisitions + login + 404 共用。
 * .sb-item 含 button reset，dashboard 用 <button> 也吃這套；對 <a> 無害。
 * .sb-item.danger 給登出/刪除類 nav。
 * .sb-login-link / .m-login-btn 只在公開頁出現，dashboard / admin / login 沒 DOM 不影響。 */
.sb-brand{display:flex;align-items:center;gap:.6rem;padding:1.35rem 1.25rem 1.1rem;flex-shrink:0;text-decoration:none}
.sb-logo-img{height:76px;width:auto;display:block;flex-shrink:0}
.sb-nav{flex:1;overflow-y:auto;padding:.5rem .75rem;display:flex;flex-direction:column;gap:.18rem;scrollbar-width:none}
.sb-nav::-webkit-scrollbar{display:none}
.sb-item{display:flex;align-items:center;gap:.7rem;padding:.6rem .85rem;border-radius:10px;font-family:var(--font-body);font-size:.875rem;font-weight:400;color:var(--text-muted);text-decoration:none;background:transparent;border:none;width:100%;text-align:left;cursor:pointer;transition:background .18s ease,color .18s ease}
.sb-item:hover{background:#6c6ee512;color:var(--text)}
.sb-item.active{background:var(--accent-dim);color:var(--accent);font-weight:500}
.sb-item.active .sb-icon{color:var(--accent);opacity:1}
.sb-icon{width:16px;height:16px;flex-shrink:0;color:var(--text-dim);opacity:.7;transition:color .18s ease,opacity .18s ease}
.sb-item:hover .sb-icon{color:var(--text-muted);opacity:.9}
.sb-item.danger{color:rgba(229,115,115,.9)}
.sb-item.danger:hover{background:rgba(229,115,115,.08);color:#e57373}
.sb-label{line-height:1;white-space:nowrap}
.sb-bottom{flex-shrink:0;padding:.75rem;border-top:1px solid var(--border-dim)}
.sb-cta{background:linear-gradient(140deg,#6c6ee51f,#5b8bf514);border:1px solid rgba(108,110,229,.16);border-radius:14px;padding:1rem;margin-bottom:.75rem;position:relative;overflow:hidden}
.sb-cta::before{content:"";position:absolute;top:-12px;right:-12px;width:60px;height:60px;border-radius:50%;background:#6c6ee514;pointer-events:none}
.sb-cta-desc{font-size:.72rem;color:var(--text-muted);line-height:1.5;margin-bottom:.75rem}
.sb-cta-btn{display:inline-flex;align-items:center;justify-content:center;width:100%;padding:.5rem;background:var(--accent);color:#fff;font-family:var(--font-body);font-size:.78rem;font-weight:500;border-radius:8px;text-decoration:none;transition:filter .18s ease,transform .18s ease}
.sb-cta-btn:hover{filter:brightness(1.08);transform:translateY(-1px)}
.sb-login-link{display:flex;align-items:center;gap:.5rem;padding:.42rem .65rem;margin:0 .5rem .18rem;border-radius:8px;text-decoration:none;font-size:.79rem;font-weight:500;color:var(--text-dim);transition:color .18s,background .18s}
.sb-login-link:hover{color:var(--accent);background:var(--bg-elevated)}
.sb-login-link svg{width:14px;height:14px;flex-shrink:0}
.sb-login-link[hidden],.m-login-btn[hidden]{display:none!important}
.body-lock{overflow:hidden!important}
.m-login-btn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:8px;color:var(--text-dim);text-decoration:none;transition:color .18s}
.m-login-btn:hover{color:var(--text)}
.m-login-btn svg{width:17px;height:17px}
.sb-copyright{font-family:var(--font-mono);font-size:.6rem;color:var(--text-dim);letter-spacing:.04em;margin-left:auto;white-space:nowrap}

/* ============================================================
 * Mobile topbar + overlay — canonical baseline
 * 改前各頁 CSS（index/about/portfolio/concert/meeting/ai-assistant/
 * requisition/privacy/404/login）各自一份 m-* 規則 drift；統一收歸到此。
 * 取 index 半透明 topbar + 第 1 類 active scale / label transitions。
 * ============================================================ */
.m-topbar{display:none;position:fixed;top:0;left:0;right:0;z-index:50;background:color-mix(in srgb,var(--bg-titlebar) 92%,transparent);backdrop-filter:blur(20px) saturate(1.5);-webkit-backdrop-filter:blur(20px) saturate(1.5);border-bottom:1px solid var(--border-dim);transition:background .3s ease,border-color .3s ease}
.m-tb-inner{display:flex;align-items:center;justify-content:space-between;padding:0 1.25rem;height:52px}
.m-tb-brand{display:flex;align-items:center;gap:.55rem;text-decoration:none}
.m-logo-img{height:68px;width:auto;display:block;flex-shrink:0}
.m-tb-right{display:flex;align-items:center;gap:.85rem}
.m-theme-btn{width:36px;height:36px;border:1px solid rgba(108,110,229,.14);background:#6c6ee512;border-radius:9px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#6c6ee5;flex-shrink:0;padding:0;transition:background .2s ease,border-color .2s ease}
.m-theme-btn svg{width:14px;height:14px;display:block}
.theme-dark .m-theme-btn{border-color:#ffffff4d;background:#ffffff0f;color:#fff}
.m-ham-btn{display:flex;flex-direction:column;justify-content:center;gap:6px;width:36px;height:36px;border:1px solid rgba(108,110,229,.22);background:#6c6ee51a;border-radius:9px;cursor:pointer;padding:0 10px;flex-shrink:0;transition:background .2s ease,border-color .2s ease}
.m-ham-line{display:block;width:100%;height:1.5px;background:#6c6ee5;border-radius:2px;transform-origin:center;transition:transform .32s cubic-bezier(.23,1,.32,1)}
.m-ham-btn.is-open .m-ham-line:nth-child(1){transform:translateY(3.75px) rotate(45deg)}
.m-ham-btn.is-open .m-ham-line:nth-child(2){transform:translateY(-3.75px) rotate(-45deg)}
.theme-dark .m-ham-btn{border-color:#ffffff4d;background:#ffffff0f}
.theme-dark .m-ham-line{background:#fff}

.m-overlay{display:none;position:fixed;inset:0;z-index:49;background:#0a0c1c00;transition:background .35s ease;pointer-events:none}
.m-overlay.is-open{background:#0a0c1c52;pointer-events:auto}
.m-ov-wrap{position:absolute;bottom:0;left:0;right:0;background:var(--bg-surface);border-radius:22px 22px 0 0;border:1px solid var(--border);border-bottom:none;box-shadow:0 -4px 24px #6c6ee514,0 -1px #6c6ee50f;display:flex;flex-direction:column;max-height:88svh;overflow:hidden;transform:translateY(100%);transition:transform .42s cubic-bezier(.22,1,.36,1)}
.m-overlay.is-open .m-ov-wrap{transform:translateY(0)}
.m-ov-handle{width:36px;height:4px;background:#6c6ee52e;border-radius:100px;margin:12px auto 0;flex-shrink:0}
.m-ov-head{display:flex;align-items:center;justify-content:space-between;padding:.85rem 1.4rem .65rem;flex-shrink:0}
.m-ov-brand{display:flex;align-items:center;gap:.55rem}
.m-ov-logo-img{height:72px;width:auto;display:block}
.m-ov-status{display:flex;align-items:center;gap:.4rem;background:rgba(34,168,101,.10);border:1px solid rgba(34,168,101,.18);border-radius:100px;padding:.22rem .65rem}
.m-ov-status-dot{width:5px;height:5px;border-radius:50%;background:#22a865;flex-shrink:0;animation:dot-pulse 2.5s ease-in-out infinite}
.m-ov-status-txt{font-family:var(--font-sans);font-size:.68rem;font-weight:500;color:#22a865}
@keyframes dot-pulse{0%,100%{opacity:1}50%{opacity:.45}}
.m-ov-nav{flex:1;overflow-y:auto;padding:.35rem .75rem .5rem;display:flex;flex-direction:column;gap:.18rem;scrollbar-width:none}
.m-ov-nav::-webkit-scrollbar{display:none}
.m-ov-item{display:flex;align-items:center;gap:.75rem;padding:.72rem .85rem;border-radius:12px;text-decoration:none;background:transparent;border:1px solid transparent;text-align:left;opacity:0;transform:translateY(10px);transition:opacity .32s cubic-bezier(.22,1,.36,1),transform .32s cubic-bezier(.22,1,.36,1),background .18s ease,border-color .18s ease;transition-delay:calc(var(--i,0)*.04s + .12s)}
.m-overlay.is-open .m-ov-item{opacity:1;transform:translateY(0)}
.m-ov-item:active{background:#6c6ee50f;transform:scale(.98)}
.m-ov-item.active{background:var(--accent-dim);border-color:#6c6ee524}
.m-ov-icon-wrap{width:32px;height:32px;border-radius:9px;background:var(--hover-overlay);display:flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--text-dim);transition:background .18s ease,color .18s ease}
.m-ov-item.active .m-ov-icon-wrap{background:#6c6ee51f;color:var(--accent)}
.m-ov-icon{width:15px;height:15px}
.m-ov-label{flex:1;font-family:var(--font-sans);font-size:.9rem;font-weight:400;color:var(--text-muted);line-height:1;transition:color .18s ease}
.m-ov-item.active .m-ov-label{color:var(--accent);font-weight:500}
.m-ov-chevron{width:6px;height:10px;color:var(--text-dim);flex-shrink:0;opacity:.5}
.m-ov-cta{flex-shrink:0;padding:.75rem 1.2rem calc(1.25rem + env(safe-area-inset-bottom));border-top:1px solid rgba(108,110,229,.07);opacity:0;transform:translateY(8px);transition:opacity .32s ease .42s,transform .32s ease .42s}
.m-overlay.is-open .m-ov-cta{opacity:1;transform:translateY(0)}
.m-ov-cta-btn{display:flex;align-items:center;justify-content:center;width:100%;padding:.78rem 1rem;background:linear-gradient(135deg,#7370ec,#5b8bf5);color:#fff;font-family:var(--font-sans);font-size:.9rem;font-weight:600;border-radius:12px;text-decoration:none;box-shadow:0 4px 16px #6c6ee547;transition:filter .18s ease,transform .18s ease}
.m-ov-cta-btn:active{filter:brightness(.96);transform:scale(.98)}

.m-ov-lang-row{display:flex;gap:.5rem;margin-top:.75rem}
.m-ov-lang-opt{flex:1;padding:.42rem .2rem;border:1px solid var(--border-dim);background:transparent;border-radius:8px;font-family:var(--font-sans);font-size:.72rem;color:var(--text-muted);cursor:pointer;transition:border-color .18s,color .18s,background .18s;text-align:center}
.m-ov-lang-opt:hover{border-color:var(--border);color:var(--text)}
.m-ov-lang-opt.active{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}
.m-top-lang-drop{position:fixed;top:58px;right:1.25rem;background:var(--bg-surface);border:1px solid var(--border);border-radius:10px;padding:.35rem;box-shadow:0 4px 24px rgba(0,0,0,.16);display:none;flex-direction:column;gap:.1rem;z-index:60;min-width:128px}
.m-top-lang-drop.open{display:flex}

@media (max-width:768px){
  .m-topbar,.m-overlay{display:block}
}
