/* diary/journal.css — 麻吉日記 journal styles, owned by fe-journal.
 * 台灣風土 tokens (--bg/--brand/--rec/…) and the bottom-spacing tokens (--navSafe/--bottomSafe/…)
 * come from diary.css :root on the same page. This file CONSUMES them read-only and defines no
 * shared token; the only locals are the page tokens on .jrPage (--jrMarginX / --jrTextX geometry,
 * --jrFs / --jrLine type rhythm, --jrRule / --jrRule0 the ruled lines), scoped to this surface
 * exactly like live.css keeps its --lv* on #viewLive. The jr- prefix is deliberate duplication:
 * 開講's page ships the same numbers under --lv*, and this file must never depend on a token
 * scoped to #viewLive. --jrRule / --jrRule0 hardcode --faint's hex (#736a5a); if --faint is ever
 * re-toned, retone them here and in live.css together. */

/* ---- island clearance ---------------------------------------------------------------------------
 * NOT paid here. 日記 owns no fixed dock, so diary.css's
 *   body:not([data-tab="live"]) .diaryMain { padding-bottom: var(--bottomSafe) }
 * already reserves --navSafe + 64px (168px / 146px) for this surface. Adding padding-bottom to
 * #viewJournal as well would double it into ~300px of dead scroll — the round-6 rule that used to
 * live here (padding-bottom: 32px) is deliberately gone. Nothing in this file may render below
 * --navSafe; the last card and the weekly card both sit inside the shell's runway. */

/* ---- week strip -------------------------------------------------------------------------------- */
.jrStrip {
  display: flex;
  align-items: stretch;
  gap: 2px;
  margin: 6px 0 4px;
}
.jrChips {
  display: flex;
  flex: 1;
  gap: 3px;
  min-width: 0;
}
.jrChip {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 7px 0 8px;
  border: 1px solid transparent;
  border-radius: 14px;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.jrChipWd { font-size: 0.7rem; color: var(--muted); }
.jrChipDom {
  font-size: 1.05rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.jrChip.today .jrChipDom { color: var(--brand); }
.jrChip.sel { background: var(--brand); border-color: var(--brand); }
.jrChip.sel .jrChipDom,
.jrChip.sel.today .jrChipDom { color: var(--brand-ink); }
.jrChip.sel .jrChipWd { color: var(--brand-ink); opacity: 0.85; }

.jrNav {
  min-width: 34px;
  min-height: 44px;
  border: none;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrNav:hover { color: var(--text); }
.jrCal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.jrCal svg { width: 20px; height: 20px; }

/* ---- month grid -------------------------------------------------------------------------------- */
.jrMonth {
  margin: 6px 0 2px;
  padding: 10px 12px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.jrMonthHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.jrMonthLabel {
  font-family: var(--serif);
  font-weight: 700;
  letter-spacing: 0.04em;
}
.jrGrid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.jrGrid .jrState { grid-column: 1 / -1; }
.jrGridHead {
  text-align: center;
  font-size: 0.7rem;
  color: var(--faint);
  padding: 4px 0 6px;
}
.jrGridDay {
  position: relative;
  min-height: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrGridDay.today .jrGridNum { color: var(--brand); font-weight: 700; }
.jrGridDay.sel { background: var(--brand); border-color: var(--brand); }
.jrGridDay.sel .jrGridNum { color: var(--brand-ink); }
.jrDot {
  width: 5px;
  height: 5px;
  margin-top: 3px;
  border-radius: 50%;
  background: var(--brand);          /* 電鍋綠 dot = this day has diary entries */
}
.jrGridDay.sel .jrDot { background: var(--brand-ink); }

/* ---- day view ---------------------------------------------------------------------------------- */
.jrDayTitle {
  margin: 14px 2px 10px;
  font-family: var(--serif);
  font-size: 1.15rem;
  font-weight: 900;
  letter-spacing: 0.03em;
}

.jrRollup, .jrSummary {
  margin: 0 0 12px;
  padding: 12px 14px;
  background: var(--surface-2);      /* 青瓷 wash — the day's 今日摘要 rollup */
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
}
.jrRollupTag {
  font-family: var(--kai);
  font-size: 0.8rem;
  color: var(--brand);
  letter-spacing: 0.14em;
  margin-bottom: 4px;
}
.jrRollupText, .jrSummaryText {
  font-family: var(--kai);
  font-size: 1.02rem;
  line-height: 1.75;
  letter-spacing: 0.02em;
}

.jrCards {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.jrCard {
  display: flex;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  padding: 13px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
  font-family: inherit;
  font-size: 0.98rem;
  text-align: left;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.15s ease;
}
.jrCard:hover { border-color: var(--brand); }
.jrCard:active { transform: scale(0.99); }
.jrCardTime {
  color: var(--faint);
  font-variant-numeric: tabular-nums;
  font-size: 0.88rem;
  flex: none;
}
.jrCardTitle {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.jrCardDur {
  color: var(--muted);
  font-size: 0.82rem;
  flex: none;
}

/* ---- shared audio bits (rail, m:ss readout, ▶ sizes) ---------------------------------------------
 * The rail is a 3px hairline in --line with a --brand fill: it reads as progress, never as chrome.
 * Duration metadata on these Cues-less webm blobs is Infinity/NaN, so the JS drives the fill from
 * the API's duration_s (or the clip window) — the CSS just has to be honest about width 0. */
.jrAuLine {
  display: flex;
  align-items: center;
  gap: 10px;
}
.jrAuTime {
  flex: none;
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.jrRail {
  flex: 1;
  min-width: 36px;
  height: 3px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.jrRailFill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--brand);
  transition: width 0.12s linear;
}

.jrPlay {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  padding: 13px 4px 13px 14px;
  border: none;
  background: transparent;
  color: var(--brand);               /* 電鍋綠 — the one accent on the row */
  font-family: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrPlay:hover { color: var(--text); }
.jrPlayBig { font-size: 1.15rem; }
.jrPlayLg {
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}
.jrPlayLg:hover { color: var(--brand); border-color: var(--brand); }
.jrPlaySm {
  min-width: 30px;
  min-height: 30px;
  padding: 0;
  font-size: 0.9rem;
}

/* ---- audio-first day card ------------------------------------------------------------------------
 * The recording IS the entry: ▶ + length + rail lead, the title labels the clip, the wall clock is
 * metadata. .jrAu keeps TWO real buttons (play / open detail) — a play control nested inside the
 * card button would be invalid HTML and swallow taps. Rows with no audio keep the plain .jrCard. */
.jrCard.jrAu {
  padding: 0;
  gap: 0;
  align-items: stretch;              /* the play button is a full-height tap target */
  cursor: default;
}
.jrCard.jrAu .jrCardMain {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  padding: 11px 14px 11px 6px;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 0.98rem;
  text-align: left;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrCard.jrAu .jrCardTitle { flex: none; }
.jrCard.jrAu .jrCardTime { font-size: 0.8rem; }

/* a card that also carries a clip chip: the wrapper takes the border, the card goes flat */
.jrCardWrap {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color 0.15s ease;
}
.jrCardWrap:hover { border-color: var(--brand); }
.jrCardWrap > .jrCard.jrAu {
  border: none;
  border-radius: 0;
  background: transparent;
}
.jrCardWrap > .jrCard.jrAu:hover { border-color: transparent; }
.jrCardWrap > .jrCard.jrAu:active { transform: none; }
.jrCardWrap > .jrClipRow { margin: 0 12px 12px 12px; }

/* ---- 麻吉揀的一段 clip chip ------------------------------------------------------------------------
 * 金紙 gold left edge, the same accent .jrRollup uses for "麻吉 wrote this". */
.jrClip {
  margin: 10px 0 0;
  padding: 9px 12px 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
}
.jrClipHead {
  display: flex;
  align-items: center;
  gap: 8px;
}
.jrClipTag {
  font-family: var(--kai);
  font-size: 0.82rem;
  color: var(--brand);
  letter-spacing: 0.1em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.jrClipLine {
  margin-top: 6px;
  font-size: 0.95rem;
  line-height: 1.6;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.jrWhy {
  margin-top: 4px;
  font-family: var(--kai);
  color: var(--muted);
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  line-height: 1.6;
}

/* ---- weekly card 「這禮拜 · 麻吉上愛的一段」 ---------------------------------------------------------
 * Belongs to the WEEK, so it sits above the day's title. The honesty note is not decoration: 麻吉
 * only ever read the words. */
.jrWeek {
  margin: 8px 0 4px;
  padding: 12px 14px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
}
.jrWeekTag {
  font-family: var(--kai);
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.16em;
}
.jrWeekHead {
  margin: 2px 0 9px;
  font-family: var(--serif);
  font-size: 1.05rem;
  font-weight: 900;
  letter-spacing: 0.03em;
}
.jrWeekPlay {
  display: flex;
  align-items: center;
  gap: 10px;
}
.jrWeekText {
  margin-top: 9px;
  font-family: var(--kai);
  font-size: 1rem;
  line-height: 1.7;
  letter-spacing: 0.02em;
}
.jrWeekWhen {
  margin-top: 6px;
  color: var(--faint);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}
.jrWeekGo {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  margin-top: 2px;
  padding: 0 4px;
  border: none;
  background: transparent;
  color: var(--link);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrWeekGo:hover { color: var(--text); }
.jrWeekNote {
  margin-top: 2px;
  font-family: var(--kai);
  color: var(--faint);
  font-size: 0.78rem;
  line-height: 1.6;
  letter-spacing: 0.02em;
}

/* ---- session detail ---------------------------------------------------------------------------- */
.jrBack {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin: 4px 0 6px;
  padding: 0 6px;
  border: none;
  background: transparent;
  color: var(--link);
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrBack:hover { color: var(--text); }
.jrDetailTitle {
  margin: 0 2px 2px;
  font-family: var(--serif);
  font-size: 1.3rem;
  font-weight: 900;
  letter-spacing: 0.02em;
  line-height: 1.35;
}
.jrDetailMeta {
  margin: 0 2px 12px;
  color: var(--faint);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

/* 原聲 ｜ 逐字稿 ｜ 麻吉整理 — three PEER views of ONE session. This is a segmented control INSIDE
 * the detail, never another app tab: #tabbar still holds exactly 開講 / 日記. */
.jrSeg {
  display: flex;
  gap: 2px;
  margin: 0 0 12px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}
.jrSegBtn {
  flex: 1;
  min-width: 0;
  min-height: 42px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.jrSegBtn.on { background: var(--surface-2); color: var(--brand); }
.jrSegBtn[disabled] { color: var(--faint); opacity: 0.5; cursor: default; }
.jrPane { margin: 0; }
.jrPaneNote {
  margin: 10px 2px 0;
  font-family: var(--kai);
  color: var(--muted);
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  line-height: 1.7;
}

/* the 原聲 pane's player row: a ringed ▶ + '0:00 / 4:03' + a full-width rail */
.jrDetailAudio {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 2px 2px 0;
}

/* ---- 逐字稿 — the SAME page the user watched being written on 開講 (round 8) --------------------------
 * ONE paper container per session, not a card per ASR segment. The look mirrors live.css's .lvPage
 * (which is scoped under #viewLive, so it is duplicated here under jr- names — this file never edits
 * live.css): a warm sheet, TWO paper cues — a left margin line and very faint horizontal rules
 * (no texture, no handwriting font, no spiral binding) — the recording's date・time once in the
 * head, then the transcript as flowing paragraphs. Segments are inline spans joined with NO
 * separator (the ASR emits 。，？), so the reader never sees where the endpointer cut; paragraph
 * breaks come from journal.js's paragraphsOf(). Body type is live.css's transcript type EXACTLY
 * (clamp(1.25rem,4.5vw,1.6rem) / 1.6 / 500) — same page, same ink.
 *
 * THE RULES (round 9). One rule per VISUAL line, never per ASR segment: the rules are a tiled
 * background on .jrTurns whose period IS the line box, so the text sits ON them at every width.
 * The two numbers that must never drift apart are --jrLine (the tile height) and .jrTurns'
 * line-height — both are the SAME expression, and line-height is set as a LENGTH so every line box
 * inside the ruled area is exactly one pitch tall no matter what font-size a descendant carries
 * (.jrPlayInline is 0.55em; the m:ss stamp is abspos). The rule is painted at the TOP of the tile,
 * so offset 0 is the ruled sheet's own top edge and every rule below it is the BOTTOM edge of a
 * line box — no optical lift, no background-position nudge. padding-top: var(--jrLine) is the one
 * blank ruled line under the head; a paragraph break costs exactly one more (.jrPara's margin).
 * Unlike 開講 the journal does NOT fill the sheet to the bottom with empty rules: a page you are
 * writing into keeps ruling ahead of you, a finished 逐字稿 ends where the words end. */
.jrPage {
  --jrMarginX: 24px;   /* margin-line axis. live.css uses 22/34; the journal sits 4px wider so a */
  --jrTextX: 38px;     /* five-char m:ss stamp (12:03) hangs on the axis without touching the edge */
  --jrFs: clamp(1.25rem, 4.5vw, 1.6rem);   /* live.css .lvPageBody's type, verbatim */
  --jrLine: calc(var(--jrFs) * 1.6);       /* THE pitch: the line box, stated once */
  --jrRule: rgba(115, 106, 90, 0.09);      /* = --faint #736a5a at 9% — ~1/2.7 of --line's weight */
  --jrRule0: rgba(115, 106, 90, 0);        /* the SAME hue at 0 alpha, not `transparent`: a hard */
                                           /* stop between two hues can composite a grey tinge */
  --jrNote: rgba(115, 106, 90, 0.42);      /* --faint at 42%: the dotted rule under a voice note */
  --jrNowWash: #dae7df;                    /* 電鍋綠 at ~16% over the sheet, SOLID (two offset box- */
                                           /* shadows must not stack alpha) — the sentence being heard */
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 1px 3px rgba(43, 42, 38, 0.05);
}
.jrPage::before {                    /* paper cue 1: the left margin line (cue 2 = .jrTurns' rules,
                                        which are deliberately ~1/2.7 of this line's weight) */
  content: "";
  position: absolute;
  top: 14px;
  bottom: 14px;
  left: var(--jrMarginX);
  width: 1px;
  background: var(--line);
  pointer-events: none;
}
.jrPageHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 40px;
  padding: 6px 16px 0 var(--jrTextX);
}
.jrPageDate {                        /* the ONE header timestamp: 「8月15日・下午 8:54」 */
  font-family: var(--sans);
  font-size: 0.84rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.jrPageTools {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.jrPageEdit {
  min-width: 54px;
  min-height: 36px;
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--brand);
  font-family: var(--sans);
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(28, 107, 84, 0.10);
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.jrPageEdit:hover,
.jrPageEdit:focus-visible,
.jrPageEdit[aria-pressed="true"] {
  border-color: var(--brand);
  background: var(--surface-2);
}

/* One restrained page-level save line.  It never replaces the ink: a failed POST leaves the
 * corrected sentence exactly where it is and offers an explicit retry beside the explanation. */
.jrCorrectionState {
  min-height: 24px;
  padding: 0 16px 2px var(--jrTextX);
  color: var(--faint);
  font-family: var(--sans);
  font-size: 0.74rem;
  line-height: 1.5;
  letter-spacing: 0.02em;
}
.jrCorrectionState[hidden] { display: none; }
.jrCorrectionState.isError { color: var(--rec); }
.jrCorrectionRetry {
  margin-left: 8px;
  padding: 2px 8px;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  touch-action: manipulation;
}
.jrCorrectionRetry[hidden] { display: none; }
/* the page body: paragraphs only, ON the rules. The box is pulled out to the margin-line axis
 * (margin-left: --jrMarginX) and the inset is given back as padding, so the rules START on the
 * axis while the text still begins at --jrTextX — neither token moves. The 1px band sits at the
 * TOP of the tile; with background-origin: padding-box the tile origin is this box's padding-box
 * top, so rules land at 0, L, 2L … and the first text line box spans [L, 2L] and rests on 2L. */
.jrTurns {
  margin: 0 16px 0 var(--jrMarginX);
  padding: var(--jrLine) 0 16px calc(var(--jrTextX) - var(--jrMarginX));
  font-size: var(--jrFs);            /* mirror live.css .lvPageBody — EXACTLY */
  line-height: var(--jrLine);        /* a LENGTH, not the 1.6 ratio: see the block comment above */
  font-weight: 500;
  color: var(--text);
  overflow-wrap: anywhere;
  text-align: left;
  background-image: linear-gradient(to bottom, var(--jrRule) 0, var(--jrRule) 1px,
                                    var(--jrRule0) 1px, var(--jrRule0) 100%);
  background-size: 100% var(--jrLine);
  background-position: 0 0;
  background-repeat: repeat-y;
  background-origin: padding-box;
  background-clip: padding-box;
}
.jrPara {
  position: relative;                /* the containing block for the margin stamp (below) */
  margin: 0 0 var(--jrLine);         /* a paragraph break costs exactly ONE blank ruled line */
}
.jrPara:last-child { margin-bottom: 0; }

/* a turn is an INLINE span inside its paragraph — a sentence in flowing text, not a row. `.gap` is
 * still set by journal.js when the previous sentence did not end in punctuation, but it no longer
 * carries a margin: THE SEPARATOR IS A REAL SPACE TEXT NODE that journal.js writes between the two
 * spans (see paneText). A start-margin renders as a stray leading INDENT whenever that sentence
 * happens to open a new visual line — ~5px right of every other line, which on ruled paper reads
 * as a broken left edge (round-9 verify). White-space processing removes a collapsible space at
 * BOTH ends of a line, so a real space can only ever show BETWEEN two sentences on the SAME line.
 * live.css does this with `.lvSeg.gap::before { content: " " }`; the journal cannot, because
 * .jrTurn::before is already taken by the .jrNow playback stamp — hence the text node.
 * Segment timestamps are NOT rendered here: they surface only while that sentence is being
 * played (.jrNow, below). */
.jrTurn {
  color: var(--text);
  border-radius: 6px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-color 0.25s ease;
}

/* 修改 mode is an affordance, not a second transcript layout.  Every finalized sentence remains
 * flowing ink; a dotted underline says it can be tapped, and only the active sentence gains the
 * small inline save/cancel pair. */
.jrCorrectionMode .jrTurn {
  cursor: text;
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-decoration-color: rgba(28, 107, 84, 0.45);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  -webkit-tap-highlight-color: rgba(28, 107, 84, 0.10);
}
.jrCorrectionMode .jrMachiMark { display: none; }
.jrTurnEditable:focus-visible {
  outline: 2px solid rgba(28, 107, 84, 0.48);
  outline-offset: 3px;
}
.jrTurnEditing {
  background-color: var(--surface-2);
  box-shadow: 3px 0 0 var(--surface-2), -3px 0 0 var(--surface-2);
  text-decoration: none !important;
}
.jrTurnEditing .jrPlayInline { display: none; }
.jrTurnEditing .jrTurnText { text-decoration: none !important; }
.jrTurnText[contenteditable="true"] {
  outline: none;
  caret-color: var(--brand);
  cursor: text;
}
.jrEditActions {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 0 0.2em;
  white-space: nowrap;
  vertical-align: 0.1em;
}
.jrEditAction {
  min-height: 32px;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(28, 107, 84, 0.10);
}
.jrEditSave { border-color: var(--brand); color: var(--brand); }
.jrEditAction:hover,
.jrEditAction:focus-visible { background: var(--surface-2); }

/* a turn that carries offsets is its own voice note — the real payoff, and it needs no AI. It is
 * a span[role=button] rather than a <button> because a button is an ATOMIC inline box: a long
 * sentence would drop to its own line instead of wrapping mid-sentence, i.e. the card grid again.
 * The whole sentence is the tap target; the small ▶︎/⏸ before it is the affordance. */
.jrTurnPlay {
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(28, 107, 84, 0.10);
}
/* (the air before a voice note's ▶︎ is the same real space text node — see .jrTurn above; a
   margin-inline-start here was the worse half of the same bug, since it applied to EVERY playable
   sentence after the first, i.e. most sentences of any recorded session) */
.jrTurnPlay:active { background-color: var(--surface-2); }
.jrPlayInline {                      /* small and quiet: an affordance, not a bullet */
  color: var(--brand);
  opacity: 0.62;
  font-size: 0.55em;
  margin-right: 0.2em;
  vertical-align: 0.14em;
  line-height: 1;
}
.jrTurn.isPlaying .jrPlayInline,
.jrTurn.jrNow .jrPlayInline { opacity: 1; }
/* .jrTurnText — the sentence ink inside every turn; the wrapper lets correction mode edit text
 * without ever making the adjacent ▶︎ icon part of the saved transcript. Every voice note in a
 * paragraph gets a faint DOTTED rule under its own words, well above the paper's ruled line; a turn
 * without offsets (.jrTurnQuiet) gets no rule because it is not a playable clip. */
.jrTurnPlay .jrTurnText {
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--jrNote);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
  text-decoration-skip-ink: auto;
}
.jrTurnPlay:hover .jrTurnText,
.jrTurnPlay:focus-visible .jrTurnText { text-decoration-color: rgba(28, 107, 84, 0.55); }
/* the tap has been taken but the blob / seek is still loading (⋯): a whisper of the wash */
.jrTurn.isLoading { background-color: var(--surface-2); }
/* .jrTurnQuiet — a turn with no offsets inside an otherwise playable session. In flowing text it
 * needs no alignment fix any more (the round-7 padding-left was for the row layout); the class is
 * kept on the node for the DOM contract and for anyone styling it later. */
/* the sentence 麻吉 picked (highlight.seq): a faint 金紙 marker stroke under the ink — the same gold
 * the rollup/clip spines use, decoration only, never coloured body text */
.jrTurnPick {
  background-image: linear-gradient(to top, rgba(184, 134, 43, 0.30) 0, rgba(184, 134, 43, 0.30) 0.16em,
                                    transparent 0.16em);
}

/* A sourced live-memory route lands on ONE canonical sentence.  This is stronger than the normal
 * 麻吉整理 marker but remains ink-on-paper: no modal, no autoplay, no layout-changing callout. */
.jrTurnTarget {
  background-color: rgba(184, 134, 43, 0.16);
  box-shadow: 3px 0 0 rgba(184, 134, 43, 0.16), -3px 0 0 rgba(184, 134, 43, 0.16);
  scroll-margin-block: 30vh;
}
.jrTurnTarget:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

/* Persisted, server-validated live Machi cues stay quiet in the finished diary.  A highlight is a
 * small marker stroke; a memory gets one tappable sprout that reuses the exact deep-link contract. */
.jrTurnMachiHighlight,
.jrTurnMachiMemory {
  background-image: linear-gradient(to top, rgba(28, 107, 84, 0.20) 0,
                                    rgba(28, 107, 84, 0.20) 0.13em,
                                    transparent 0.13em);
}
.jrMachiMark {
  display: inline;
  margin: 0 0.14em;
  padding: 0.05em 0.14em;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--brand);
  font: inherit;
  font-size: 0.68em;
  line-height: 1;
  vertical-align: 0.12em;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(28, 107, 84, 0.10);
}
.jrMachiMark:hover,
.jrMachiMark:focus-visible { background: var(--surface-2); }

/* ---- playback: the sentence being heard, and the ONLY place a segment timestamp shows -------------
 * journal.js toggles .jrNow on the turn whose [t0, t1] contains the shared player's currentTime
 * (whole-session play or a window, from ANY control on the page). The wash is the 青瓷 in-progress
 * colour 開講 uses; the m:ss stamp is the turn's offset (data-mss = t0), hung on the margin axis
 * beside the sentence's first line via the abspos-static-position rule (top:auto → the line the
 * pseudo would have started on), so revealing it never reflows the text. */
.jrTurn.jrNow,
.jrTurn.isPlaying {
  background-color: var(--jrNowWash);
  /* The wash used to be `0 0 0 3px` — a SPREAD, which grows the slab vertically too. On ruled
   * paper that is not a free choice: the rule sits half-a-leading above the next line's content
   * box (measured 2px with PingFang TC at --jrLine 32), so ANY spread at or above the half-leading
   * paints over it, and the half-leading is a font metric — the played sentence would erase the
   * rule on some devices and not others. Two offset copies give the same padded look sideways with
   * ZERO vertical growth, so the rules always run through the highlight, as a real marker pen does. */
  box-shadow: 3px 0 0 var(--jrNowWash), -3px 0 0 var(--jrNowWash);
}
/* The dotted voice-note rule turns solid brand while that sentence is heard. isPlaying is the
 * tapped control; jrNow is whichever sentence the shared clock is actually inside. */
.jrTurn.jrNow .jrTurnText,
.jrTurn.isPlaying .jrTurnText {
  text-decoration-style: solid;
  text-decoration-color: var(--brand);
}
.jrTurn.jrNow::before {
  content: attr(data-mss);
  position: absolute;
  right: calc(100% + 4px);           /* right edge 4px left of the text column → over the axis */
  top: auto;                         /* static position = the sentence's first line */
  margin-top: 0.8em;                 /* baseline geometry puts the box high in the line; centre it */
  padding: 0 4px;
  border-radius: 999px;
  background: var(--jrNowWash);
  color: var(--brand);
  font-family: var(--sans);
  font-size: 0.5em;                  /* em of the page type, so the stamp scales with the line box */
  font-weight: 700;
  line-height: 1.7;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}

/* ---- states (loading / empty / error) ----------------------------------------------------------- */
.jrState {
  padding: 22px 0;
  text-align: center;
  color: var(--muted);
  font-family: var(--kai);
  font-size: 1rem;
  letter-spacing: 0.03em;
}
.jrErr { color: var(--rec); }
.jrRetry {
  display: block;
  margin: 0 auto 14px;
  padding: 8px 20px;
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--brand);
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.jrRetry:hover { border-color: var(--brand); }

@media (prefers-reduced-motion: reduce) {
  .jrChip, .jrCard, .jrCardWrap, .jrSegBtn, .jrTurn, .jrPageEdit { transition: none; }
  .jrCard:active { transform: none; }
  .jrRailFill { transition: none; }
}
