/* mobile.css — phone layer (≤ 44rem). Loaded after app.css. Every rule lives
   inside a max-width or pointer:coarse media query so desktop is untouched. */

@media (max-width: 44rem) {
	:root {
		--mobile-tabs-h: calc(3.5rem + env(safe-area-inset-bottom));
		/* Measured height of the one-row phone header (.ed-bar, sticky at top).
		   A two-line title makes it taller; the header's higher z-index keeps it
		   on top, so the sticky panel below just tucks under it. */
		--ed-bar-h: 3.3rem;
	}

	/* ---- Bottom tab bar ---- */
	.mobile-tabs {
		position: fixed;
		inset: auto 0 0 0;
		z-index: 40;
		display: grid;
		grid-template-columns: repeat(5, minmax(0, 1fr));
		height: var(--mobile-tabs-h);
		padding-bottom: env(safe-area-inset-bottom);
		background: var(--paper);
		border-top: 1px solid var(--line);
	}
	.mobile-tabs .dropdown-menu { display: contents; }
	.mobile-tab {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 0.15rem;
		min-height: 3.5rem;
		padding: 0;
		border: 0;
		border-radius: 0;
		background: none;
		box-shadow: none;
		font-family: var(--sans);
		font-size: 0.66rem;
		font-weight: 500;
		letter-spacing: 0.02em;
		color: var(--ink-faint);
		text-decoration: none;
		transition: color var(--dur-fast) var(--ease);
	}
	.mobile-tab .ic { width: 1.35rem; height: 1.35rem; }
	.mobile-tab[aria-current="page"],
	.mobile-tab[aria-expanded="true"] { color: var(--ink); }
	.mobile-tab[aria-current="page"] .ic { color: var(--accent); }
	.mobile-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
	/* Basecoat popover opens downward; flip it above the bar. */
	.mobile-tab-canon [data-popover] {
		position: fixed;
		top: auto;
		left: 0.75rem;
		right: 0.75rem;
		bottom: calc(var(--mobile-tabs-h) + 0.5rem);
		width: auto;
	}
	.mobile-tab-canon [role="menuitem"] { min-height: 2.75rem; }
	.mobile-tab-canon [role="menuitem"][aria-current] { background: var(--accent-wash); }

	/* Pages that render the tab bar need room above it. */
	body:has(.mobile-tabs) .page { padding-bottom: calc(var(--mobile-tabs-h) + 1rem); }

	/* Old pill nav is replaced by the tab bar. */
	.ed-nav { display: none; }

	/* ---- Header: one row (back · kicker+title · theme) ---- */
	.ed-bar {
		grid-template-columns: auto minmax(0, 1fr) auto;
		grid-template-areas: "back meta right";
		row-gap: 0;
		padding: 0.5rem 0.9rem;
	}
	.ed-right {
		display: flex;
		grid-area: right;
		gap: 0.25rem;
	}
	.ed-count { display: none; }
	.ed-title {
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
		white-space: normal;
		font-size: 1rem;
		line-height: 1.25;
	}
	/* "Pengaturan terjemahan" / "Dashboard agent" only make sense inside a
	   story, so reveal them on the pages that carry the story tab bar — not on
	   /login, / or /arena, which share the same ThemeToggle markup. */
	body:has(.mobile-tabs) .theme-picker-extra { display: block; }
	.theme-picker-extra a[role="menuitem"] { min-height: 2.5rem; }

	/* ---- Composer: hidden until #composer-open, then a full-screen sheet ---- */
	/* Same specificity as app.css's `.editor-page { --composer-clearance: 19rem }`
	   but loads later, so it wins: no composer sits under the prose any more.
	   (app.css's `:has(.composer...)` 11rem rule never matches here — .composer
	   is a sibling of main.editor-page, not a descendant.) Measured padding-bottom
	   is 72px either way; `body:has(.mobile-tabs) .page` owns it. */
	.editor-page { --composer-clearance: 0rem; }
	.composer { display: none; }
	.composer-fab {
		display: grid;
		place-items: center;
		position: fixed;
		right: 1rem;
		bottom: calc(var(--mobile-tabs-h) + 1rem);
		z-index: 41;
		width: 3.25rem;
		height: 3.25rem;
		padding: 0;
		border-radius: 50%;
		background: var(--ink);
		color: var(--paper);
		box-shadow: var(--shadow-sm);
	}
	.composer-fab .ic { width: 1.35rem; height: 1.35rem; }
	#composer-open:checked ~ .composer-fab { display: none; }
	#composer-open:checked ~ #composer {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 50;
		height: 100dvh;
		overflow-y: auto;
		padding: 0 0 calc(1rem + env(safe-area-inset-bottom));
		background: var(--paper);
		pointer-events: auto;
	}
	body:has(#composer-open:checked) { overflow: hidden; }
	#composer-open:checked ~ #composer .composer-dock {
		max-width: none;
		gap: 0.6rem;
		padding-inline: 0.85rem;
	}
	.composer-sheet-head {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 0.5rem;
		position: sticky;
		top: 0;
		z-index: 1;
		margin-inline: -0.85rem;
		padding: 0.5rem 0.5rem 0.5rem 0.9rem;
		background: var(--paper);
		border-bottom: 1px solid var(--line);
	}
	.composer-sheet-title {
		font-family: var(--serif);
		font-weight: 600;
		font-size: 1rem;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}
	.composer-sheet-head .btn { width: 2.75rem; height: 2.75rem; }
	/* Desktop reveals context chips on :focus-within and collapses them
	   otherwise; in the full-screen sheet that collapse fires mid-tap
	   whenever focus briefly leaves one field for another (e.g. tapping the
	   Manual/Generate switch), shifting the tab row under the tap. The sheet
	   is already a dedicated writing screen, so app.css scopes that collapse to
	   `#composer-open:not(:checked)` — nothing to re-declare here, and in
	   particular no `display` value that would override the ≤25rem grid.
	   Keep the row's own overflow contained so nothing escapes the sheet. */
	#composer-open:checked ~ #composer .context-row { overflow-x: auto; }

	/* The composer starts at `display: none` on phones, so composer-autogrow.js
	   measures a scrollHeight of 0 at load and pins the field to `height: 0`.
	   The sheet re-measures on open, but the floor belongs in CSS so the field
	   is a usable three-line writing surface even if that script never runs. */
	#composer-open:checked ~ #composer textarea[name="prompt"],
	#composer-open:checked ~ #composer textarea[name="content"] { min-height: 5.5rem; }

	/* ---- Chapter side panels sit above the manuscript, collapsed ---- */
	.chapter-side:not(.is-open) .side-tab-panels { display: none; }
	/* Phones put the rail above the manuscript. app.css already sets
	   `order: -1` on it, but order does nothing in the block layout the
	   ≤72rem shelf uses, so switch this page to a column flex; `stretch`
	   (not the desktop grid's `start`) keeps the rail full width, otherwise
	   the strip shrink-wraps to ~246px and its last chip hangs off-screen. */
	.editor-page {
		display: flex;
		flex-direction: column;
		align-items: stretch;
	}
	.chapter-side { margin-bottom: 0.75rem; }
	/* Only the strip sticks, not the whole rail: a sticky box taller than the
	   screen pins its top and its lower half can never be scrolled into view,
	   which is what a long Integritas panel is. Parked under the sticky header
	   (.ed-bar, z-index 5) so the two never overlap. */
	.side-tab-bar {
		position: sticky;
		top: var(--ed-bar-h);
		z-index: 4;
		padding-block: 0.5rem;
		background: var(--paper);
	}

	/* ---- Page intros fold; primary buttons go full width ---- */
	.page-intro { display: block; margin: 0 0 1rem; }
	.page-intro > summary {
		display: list-item;
		min-height: 2.75rem;
		line-height: 2.75rem;
		font-family: var(--sans);
		font-size: 0.85rem;
		color: var(--ink-soft);
		cursor: pointer;
	}
	.page-intro > .rules-intro,
	.page-intro > .skills-intro { margin: 0.25rem 0 0.75rem; font-size: 0.98rem; }
	.char-intro-bar { flex-direction: column; align-items: stretch; gap: 0.5rem; }
	.char-intro-bar .btn,
	.skills-toolbar .btn { width: 100%; min-height: 2.75rem; }

	/* ---- Continuity: compact cards ---- */
	/* Basecoat's card padding (16px block + 16px inline + a 16px row gap) makes
	   one repeated phrase 95px tall, so five of them fill a phone screen. */
	.continuity-list { gap: 0.4rem; }
	.continuity-finding { padding-block: 0.55rem; gap: 0.4rem; }
	.continuity-finding > section { padding-inline: 0.75rem; gap: 0.35rem; }

	/* ---- Facts: compact filter, bulk delete only when something is selected ---- */
	/* The closed chapter-filter listbox is 361px wide at left 33px and pushed
	   scrollWidth to 394px in the audit. */
	.fact-controls .select [data-popover] { max-width: calc(100vw - 3.5rem); }
	.fact-bulkbar .fact-bulk-delete[disabled] { display: none; }
	.fact-bulkbar { flex-direction: row; align-items: center; }

	/* R14: the search input full width, then one row with both selects and the
	   status tabs (app.css stacks all four into a column at ≤ 34rem).
	   `display: contents` lifts the search and the chapter select out of
	   .fact-filter-row so the control bar's own grid can place all five parts.
	   The sideways scrolling lives on the segmented control, not on
	   .fact-controls: a scroll container there would clip both select
	   listboxes, which drop below the bar. */
	.facts-workspace .fact-controls,
	#facts-workspace .fact-controls {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.15fr);
		grid-template-areas:
			"search   search  search"
			"snapshot chapter tabs"
			"bulk     bulk    bulk";
		align-items: center;
	}
	.fact-controls > .fact-filter-row { display: contents; }
	.fact-controls .fact-search { grid-area: search; }
	.fact-controls > .fact-filter-row > .select { grid-area: chapter; }
	.fact-controls .fact-tabs {
		justify-self: stretch;
		min-width: 0;
		overflow-x: auto;
		scrollbar-width: none;
	}
	.fact-controls .fact-tabs::-webkit-scrollbar { display: none; }
	.fact-controls .fact-tab { flex: 0 0 auto; }

	/* app.css parks the undo toast 9.5rem up for the desktop composer; on a
	   phone that lands it under the floating write button (z-index 41). */
	#undo-slot {
		bottom: calc(var(--mobile-tabs-h) + 0.75rem);
		z-index: 42;
	}

	/* Basecoat only fades a closed popover out (visibility + opacity), so it
	   still takes layout space: the "+ tokoh" listbox added ~267px of dead
	   scroll below the page, and the closed Kanon menu pushed the document
	   ~50px wide. Hidden means hidden here; the fade is not missed. */
	[data-popover][aria-hidden="true"] { display: none; }

	/* An open select listbox must clear the fixed tab bar (z-index 40). app.css
	   already lifts the .select root to z-index 60, but every page body is
	   `.page { position: relative; z-index: 1 }` — a stacking context that caps
	   everything inside it at 1, so a listbox near the foot of the page paints
	   under the bar and its options cannot be tapped. (On the facts page a
	   second trap nests inside it: .fact-controls has backdrop-filter.) Same
	   "lift the root" trick as app.css, one context further out: above the bar,
	   still below the composer sheet at 50, and only while a listbox is open. */
	/* Trade-off: while a listbox is open the whole page paints above the tab bar
	   and #undo-slot, so content in that band can show over them. Transient, and
	   the page is scroll-locked meanwhile — accepted, not worth fixing. */
	.page:has(.select > [data-popover][aria-hidden="false"]) { z-index: 45; }

	/* ---- Relations graph ---- */
	#relation-graph { height: 60dvh; max-height: 60dvh; touch-action: none; }
}

@media (pointer: coarse) {
	/* Touch: tools are out of the way until the paragraph is tapped, then one
	   horizontally scrolling row under the text (never overlapping it).
	   Hidden visually but NOT removed: `display: none` would drop Edit,
	   Rewrite, Listen and Delete out of the tab order and the accessibility
	   tree on every touch device, leaving a pointer tap on a non-focusable
	   <p> as the only way in (WCAG 2.1.1). Clipped instead, so Tab still
	   reaches them and the :focus-within rule below opens the row.
	   That rule keys on focus inside .para-tools, not anywhere in the
	   paragraph: .para-insert is a child of .para-wrap too, and opening the
	   row on its focus shifted the divider ~58px out from under the tap that
	   had just focused it. */
	.prose > .para-wrap:first-child { margin-top: 0; }
	.para-wrap:not(.para-edit):not(.rw-form) > .para-tools {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
	}
	.para-wrap.is-tools-open:not(.para-edit):not(.rw-form) > .para-tools,
	.para-wrap:not(.para-edit):not(.rw-form) > .para-tools:focus-within {
		/* Grid, not a sideways-scrolling row: a paragraph with every tool is
		   ~420px wide in a 363px column, and a scrolled row hides its first
		   icon behind the card edge, which reads as uneven left/right gaps.
		   Equal columns keep both rows evenly spaced. */
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(2.75rem, 1fr));
		position: static;
		width: auto;
		height: auto;
		overflow: visible;
		clip-path: none;
		margin-top: 0.4rem;
		opacity: 1;
		transform: none;
	}
	.para-wrap.is-tools-open:not(.para-edit):not(.rw-form) > .para-tools .ptool,
	.para-wrap:not(.para-edit):not(.rw-form) > .para-tools:focus-within .ptool {
		flex: 0 0 auto;
		min-width: 2.75rem;
		min-height: 2.75rem;
		opacity: 1;
		transform: none;
	}
}
