/* serve/machi_ui/diary/diary.css — 麻吉 Hey Machi shell (global brand header + ⓘ about link,
 * 720px column, island tab bar). 台灣風土 tokens COPIED verbatim from
 * ../machi.css per the contract — machi.css is never modified and never linked from here.
 * Unlike the one-screen main page, this page SCROLLS: a diary grows. Feature styles live in
 * live.css / journal.css / ask.css / data.css (their agents own those files); this file is
 * shell-only. It also owns the SHARED layout tokens every surface consumes (see [C1] below) and
 * the one shared toast (.mToast — app.js's MachiDiary.toast). Zero dependencies, no build step. */

:root {
  color-scheme: light;
  --bg: #f7f2e8;         /* 宣紙 rice-paper warm white / 電鍋 cream enamel */
  --surface: #fffdf8;    /* fresh paper sheet — finalized turns */
  --surface-2: #edf3ec;  /* 青瓷 celadon wash — the in-progress turn */
  --line: #e3daca;       /* deckle-edge beige hairlines */
  --text: #2b2a26;       /* 墨色 calligraphy ink, never pure black */
  --muted: #6b6355;      /* 茶湯褐 steeped-oolong brown */
  --faint: #736a5a;      /* aged cement — timestamps, placeholder (AA at small sizes) */
  --brand: #1c6b54;      /* 大同電鍋綠／鐵窗花綠 — idle mic, live accents, focus */
  --brand-ink: #fffdf8;  /* text on brand */
  --rec: #b3402a;        /* 印泥朱紅 cinnabar seal red — recording + errors */
  --warn: #8f5b12;       /* 龍眼蜜 longan-honey amber — busy / limits */
  --warn-ink: #fffdf8;   /* text on warn */
  --link: #2b5a8a;       /* 花磚 Majolica-tile cobalt — links */
  --gold: #b8862b;       /* 金紙 joss gold — decorative hairlines only, never body text */
  --radius: 16px;
  --maxw: 720px;
  --serif: "Songti TC", "Noto Serif TC", "Noto Serif CJK TC", "PMingLiU", serif;
  --kai: "Kaiti TC", "BiauKai", "DFKai-SB", "Kaiti SC", "Songti TC", "Noto Serif TC", serif;
  --sans: "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", "Heiti TC",
          system-ui, -apple-system, "Segoe UI", sans-serif;

  /* ---- shared layout tokens [C1] — DEFINED HERE ONCE, consumed read-only elsewhere -------------
   * live.css / journal.css may USE these; no other file may define or redefine
   * them, and surface-local tokens stay on the surface's own root (--lv* on #viewLive, never
   * here). Two values per token below: iPhone with a home indicator / everything else.
   *   --safeB      home-indicator inset, floored at 12px so Safari's collapsed toolbar and
   *                non-notch devices still clear the edge            34px / 12px
   *   --navH       #tabbar height = 1px border + 5px pad + 44px tab + 5px pad + 1px border.
   *                Change it ONLY together with the #tabbar rule below.
   *   --navLift    island offset above --safeB (the #tabbar bottom)
   *   --navSafe    top edge of the island — NOTHING may render below this line   104px / 82px
   *   --dockGap    gap between the island and a surface-owned fixed dock (開講's mic)
   *   --bottomSafe scroll runway for a surface with NO dock          168px / 146px
   *                (the trailing 64px is the only tunable — it lands the owner's ~150–170px band)
   *   --mainPadTop .diaryMain top padding shared by both primary tabs
   *   --heroPadTop / --heroH  the measured header box (padding + brand + tagline). --heroH uses
   *                the ≥720px line boxes (85px full / 65px compact) because OVER-subtracting is
   *                the safe direction for a surface that pins a footer: it floats a few px high
   *                instead of adding dead scroll.
   */
  --safeB: max(env(safe-area-inset-bottom, 0px), 12px);
  --navH: 56px;
  --navLift: 14px;
  --navSafe: calc(var(--safeB) + var(--navLift) + var(--navH));
  --dockGap: 14px;
  --bottomSafe: calc(var(--navSafe) + 64px);
  --mainPadTop: 18px;
  --heroPadTop: max(env(safe-area-inset-top, 0px), 12px);
  --heroH: calc(var(--heroPadTop) + 85px);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

html { height: 100%; }
body {
  /* flex column so .diaryMain can hand a REAL height budget to the surface inside it: 開講's
   * transcript sizes itself with flex instead of guessing the chrome with 100dvh arithmetic. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;   /* fallback */
  min-height: 100dvh;  /* stable under the mobile URL-bar collapse */
  background-color: var(--bg);
  /* 磨石子 terrazzo speckle — same ground as the main page; content sits on opaque cards */
  background-image:
    radial-gradient(rgba(159, 174, 155, 0.16) 1px, transparent 1.5px),
    radial-gradient(rgba(184, 134, 43, 0.10) 1px, transparent 1.5px),
    radial-gradient(rgba(179, 64, 42, 0.07) 1.2px, transparent 1.7px);
  background-size: 46px 46px, 34px 34px, 74px 74px;
  background-position: 0 0, 17px 23px, 39px 11px;
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--link); text-underline-offset: 3px; }
a:hover { color: var(--text); }
:focus-visible { outline: 3px solid var(--brand); outline-offset: 3px; border-radius: 6px; }
::selection { background: var(--brand); color: var(--brand-ink); }

/* ---- top safe-area mask (round-6 §E.4) ----------------------------------------------------------
   Opaque strip under the iPhone status bar so scrolled text never collides with the clock.
   Zero-height on devices without a top inset. Above page chrome (tabbar 20, toast 30, ⓘ menu 65
   is header-anchored below the inset); the feedback scrim/sheet (70/71) dim over it, standard. */
.safeTop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: env(safe-area-inset-top, 0px);
  background: var(--bg);
  z-index: 60;
  pointer-events: none;
}

/* ---- compact header ---------------------------------------------------------------------------- */
.diaryHero {
  position: relative;                /* anchors the top-right ⓘ about icon */
  text-align: center;
  padding: var(--heroPadTop) 20px 10px;
}
.diaryHero .brand {
  font-family: var(--serif);
  font-size: clamp(1.55rem, 6.5vw, 2.1rem);
  font-weight: 900;
  line-height: 1.15;
  letter-spacing: 0.02em;
}
.diaryHero .brand .latin { color: var(--brand); font-weight: 700; font-size: 0.62em; }
.diaryHero .tagline {
  margin-top: 12px;
  font-family: var(--kai);
  color: var(--muted);
  font-size: clamp(0.92rem, 3.4vw, 1.05rem);
  letter-spacing: 0.03em;
}

/* ---- compact header experiment (retired) ----------------------------------------------------------
 * 開講 keeps its full presence — it is the page you arrive on. The two reading tabs give the
 * height back to the content: every clamp stop is exactly 0.75× its full-size counterpart, the
 * paddings shrink less so the 44px ⓘ button (top 8px → 52px) still fits inside the 65px header.
 * Header box 84px → 65px past the safe inset (−22.8%); with --mainPadTop 18px → 12px the chrome
 * above the first content pixel goes 102px → 77px (−24.5%). Keyed on body[data-tab], which
 * app.js stamps on every tab change AND once at execute time — a #journal deep link paints
 * compact on the FIRST frame. Deliberately NOT animated: the whole view swaps on a tab tap and a
 * moving header would pull the eye off the content. */
/* 2026-08-17, owner's call handed to the integrator: the header is now the SAME on all three
   tabs, and shrinks by STATE instead. Tabs are places; a header that resizes as you move between
   places reads as a layout bug, and the tagline 「你願意留下的，麻吉會記得。」 is the same promise on
   every one of them. What genuinely deserves the space back is RECORDING — so the rule below keys
   on body[data-rec], published by live.js's setMicMode. (Round 7's per-tab compression lived here;
   restoring it is a matter of re-adding the two selectors.) */
body[data-rec="1"] {
  --mainPadTop: 10px;
  --heroPadTop: max(env(safe-area-inset-top, 0px), 8px);
  --heroH: calc(var(--heroPadTop) + 44px);
}
body[data-rec="1"] .diaryHero {
  padding: var(--heroPadTop) 20px 6px;
}
body[data-rec="1"] .diaryHero .brand {
  font-size: clamp(1.1rem, 4.6vw, 1.5rem);
}
body[data-rec="1"] .diaryHero .tagline {
  display: none;                       /* the promise is made; you are already keeping it */
}

/* The island nav gets out of the way while you are talking (owner, 2026-08-17). Not display:none —
   it animates out and, crucially, stays out of the accessibility tree via inert-ish semantics so a
   swipe cannot land on a tab mid-sentence. The dock reclaims the freed height through --lvNavSafe. */
body[data-rec="1"] #tabbar {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;                  /* out of the a11y tree, not just invisible */
  transform: translateX(-50%) translateY(10px);
  transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s linear 0.22s;
}
body[data-rec="1"] #viewLive {
  --lvNavSafe: var(--safeB);           /* no island to clear: give the page its height back */
}

/* top-right ⓘ — now a BUTTON toggling the popover menu (round-6 §D.3); same line-style icon */
.aboutIcon {
  position: absolute;
  top: max(env(safe-area-inset-top), 8px);
  right: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;                       /* generous tap target */
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.2s ease;
}
.aboutIcon:hover,
.aboutIcon[aria-expanded="true"] { color: var(--brand); }
.aboutIcon svg { width: 22px; height: 22px; }

/* ⓘ popover menu — 關於麻吉 / 意見回饋, two items since 2026-08-15 (wired by app.js) */
#infoMenu {
  position: absolute;
  top: calc(max(env(safe-area-inset-top), 8px) + 50px);
  right: 12px;
  min-width: 164px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 0 10px 30px rgba(43, 42, 38, 0.18);
  text-align: left;
  z-index: 65;
}
#infoMenu [role="menuitem"] {
  display: block;
  width: 100%;
  padding: 10px 14px;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: var(--text);
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
#infoMenu [role="menuitem"]:hover { background: var(--surface-2); color: var(--brand); }

/* ---- content column (phone-first, 720px) -------------------------------------------------------- */
.diaryMain {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  /* Flex column + flex:1 so the surface inside gets the leftover viewport height as a REAL
     budget (開講's transcript is flex:1 inside it — no 100dvh arithmetic anywhere). */
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  /* Top padding breathes where the per-page <h2> used to sit (the island nav names the page
     now). The BOTTOM is per-tab, below: a docked surface pays its own clearance. */
  padding: var(--mainPadTop) 20px 0;
}

/* Island clearance for the dockless 日記 tab — paid by the shell so no surface file can
 * forget it. --bottomSafe = --navSafe + 64px → 168px / 146px, the owner's ~150–170px band.
 * (journal.css must NOT add it a second time.)
 * 開講 is excluded: #viewLive owns a fixed mic dock and reserves its own space
 * (--lvDockReserve), so paying here too would steal that many px from the transcript. The
 * :has() line is the handshake — live.js stamps data-mic on #viewLive the moment it takes over
 * the dock; until then (or in an engine without :has) the shell keeps the legacy clearance. */
body:not([data-tab="live"]) .diaryMain { padding-bottom: var(--bottomSafe); }
body[data-tab="live"] .diaryMain { padding-bottom: calc(var(--navSafe) + 26px); }
body[data-tab="live"] .diaryMain:has(#viewLive[data-mic]) { padding-bottom: 0; }

/* ---- island tab bar — iPhone floating pill ------------------------------------------------------- */
#tabbar {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--safeB) + var(--navLift));   /* --safeB floors the inset at 12px */
  display: flex;
  gap: 4px;
  padding: 5px;
  width: max-content;
  max-width: calc(100vw - 24px);
  border-radius: 999px;
  background: rgba(255, 253, 248, 0.78);   /* --surface, translucent under the blur */
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border: 1px solid var(--line);
  box-shadow: 0 6px 24px rgba(43, 42, 38, 0.18);
  z-index: 20;
  transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s linear 0s;
}
@media (prefers-reduced-motion: reduce) {
  #tabbar { transition: none; }
}
#tabbar .tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 44px;              /* generous tap target */
  min-width: 44px;
  padding: 0 18px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.2s ease, color 0.2s ease;
}
#tabbar .tab svg { width: 18px; height: 18px; flex: none; }
#tabbar .tab:active { transform: scale(0.97); }
#tabbar .tab.active {
  background: var(--brand);      /* 電鍋綠 fill on the active tab */
  color: var(--brand-ink);
}

/* ---- toast — ONE pill for the whole app (app.js: MachiDiary.toast) --------------------------------
 * A short, polite acknowledgement that costs no layout: position:fixed, so nothing on the page
 * moves when it appears, and role="status" (set in app.js) announces it without stealing focus.
 * Geometry: it must clear whatever is pinned at the bottom of the CURRENT tab.
 *   default (日記)         --navSafe + --dockGap + 6px  = 124px / 102px above the viewport floor
 *   開講                   the same, plus the TALL mic dock (--lvDock 150px + the 12px the dock
 *                          reserve adds) = 286px / 264px. The tall value is used in every 開講
 *                          state on purpose: when the dock shrinks to its 56px puck the toast
 *                          simply sits a little higher, whereas reading the live dock's height
 *                          from here would break the moment that state changed. */
.mToast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--navSafe) + var(--dockGap) + 6px);
  transform: translateX(-50%) translateY(8px);
  /* width:max-content is load-bearing: a fixed box with left:50% and auto width can only be as
     wide as the half-viewport to its right (195px at 390px), so a two-line message used to wrap
     into three. An explicit width lets max-width do the capping instead. */
  width: max-content;
  max-width: min(90vw, 420px);
  padding: 9px 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--sans);
  font-size: 0.86rem;
  line-height: 1.55;
  text-align: center;
  box-shadow: 0 3px 14px rgba(43, 42, 38, 0.16);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
  z-index: 30;                  /* the documented ladder: tabbar 20, toast 30, safe-top mask 60 */
}
.mToast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
body[data-tab="live"] .mToast {
  bottom: calc(var(--navSafe) + var(--dockGap) + 150px + 12px + 6px);   /* clears the pinned mic */
}

@media (prefers-reduced-motion: reduce) {
  #tabbar .tab { transition: none; }
  #tabbar .tab:active { transform: none; }
  .aboutIcon { transition: none; }
  .mToast { transition: none; }
}
