/* ============================================================
   Daimond — the phone shell
   ------------------------------------------------------------
   The mobile paradigm, rotated 90° from the desktop's two-seat
   stage. On a phone the CONVERSATION is the floor and is never
   left; a "thing" (Web, Doc, Message, Compose, Tools) rises as a
   draggable bottom SHEET over it, and at its half detent you see
   the thing AND the tail of the chat at once — the daimon still
   beside the thing, only stacked instead of splayed. Diamonds and
   Chats live in a left DRAWER; the four dwellable destinations
   (Chat, Email, Files, Agents) sit on the bottom bar.

   This file owns the drawer, the sheet and the hamburger. The
   plain rearranging (one destination at a time, touch targets)
   stays in responsive.css. Everything here is confined to the
   phone breakpoint so desktop is untouched.
   ============================================================ */

/* The hamburger and the sheet exist only on a phone. */
#drawer-btn { display: none; }
#msheet     { display: none; }
#scrim      { display: none; }

@media (max-width: 760px) {

	/* ── The hamburger ─────────────────────────────────────────
	   Far left of the top bar, within thumb reach is less important
	   here than convention: the menu lives where a menu lives. */
	#drawer-btn {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 38px;
		height: 38px;
		margin-right: 2px;
		padding: 0;
		background: none;
		border: none;
		border-radius: var(--radius);
		color: var(--text-primary);
		cursor: pointer;
	}
	#drawer-btn .ic { width: 22px; height: 22px; }
	#drawer-btn:active { background: var(--accent-soft); }

	/* ── The left drawer: Diamonds + Chats + Admin ─────────────────
	   The whole rail, slid in from the left over a scrim. It keeps
	   its own internal split (Diamonds/Chats above, Admin below), so
	   nothing about the rail's contents changes — only where it is. */
	.panel.rail {
		position: fixed !important;
		z-index: 80;
		top: 0;
		bottom: 0;
		left: 0;
		width: min(86vw, 344px) !important;
		max-width: 344px;
		height: 100dvh !important;
		margin: 0;
		/* Opaque, or the drawer is see-through: a desktop rail column never
		   needed a background, but a floating drawer does. */
		background: var(--bg-primary);
		border-right: 1px solid var(--border);
		/* The drawer is fixed to the viewport, so it is outside #app's frame and
		   has to hold the hardware off its own contents: installed, its first
		   control sat under the status bar and its last under the home
		   indicator. */
		padding: calc(8px + var(--safe-t)) 8px calc(8px + var(--safe-b)) calc(8px + var(--safe-l));
		transform: translateX(-100%);
		transition: transform .28s cubic-bezier(.32, .72, 0, 1);
		box-shadow: 0 0 40px rgba(0, 0, 0, .45);
		will-change: transform;
		overflow-y: auto;
		overscroll-behavior: contain;
	}
	/* The drawer is the scroller, and nothing inside it may be. Two competing
	   scroll regions inside a 100dvh column meant the lists absorbed every
	   shortfall instead of overflowing: at 320x568 the Diamonds list came out
	   15px tall and the Chats list 2px, with three Diamonds in the store and not
	   one complete row visible in either. In landscape it was worse -- the
	   search box and the two rail buttons were pushed ABOVE the drawer's top
	   edge, unreachable, with scrollHeight equal to clientHeight so there was
	   nothing to scroll back to.

	   One column, its natural height, scrolled by the drawer. That is the phone
	   idiom anyway, and it retires the rail-split handle here: there are no
	   longer two regions for it to divide. */
	/* The Admin panel rises from the identity row, which is right on a desktop
	   where the rail is a full-height column and there is room above it. In the
	   drawer there is not: at 390x844 the identity row sits ~310px down and the
	   panel is `min(70vh, 540px)` tall, so it grew UPWARDS off the screen and its
	   own head -- the title and the × -- landed 214px above the top edge, out of
	   reach with no way to scroll to it. Measured, not guessed.

	   Pinned to the top of the drawer instead, and capped to the drawer's own
	   height. The rail carries a `transform`, which makes it the containing block
	   for a fixed descendant, so these insets resolve against the drawer's
	   padding box rather than the viewport -- the panel is the drawer's width and
	   moves in and out with it. */
	.panel.rail .admin-body {
		position: fixed;
		top: 0;
		bottom: auto;
		left: 0;
		right: 0;
		margin-bottom: 0;
		max-height: calc(100dvh - 16px - var(--safe-t) - var(--safe-b));
	}
	/* ── EACH LIST SCROLLS, AS IT DOES ON A DESKTOP ───────────────────
	   These three rules used to say the opposite -- `overflow: visible` on both
	   lists and `flex: none` on the top half -- which made the drawer one long
	   scroll: a rail of fifteen Diamonds pushed Chats entirely below the fold,
	   and finding a chat meant scrolling past every Diamond first. Reported from
	   a phone.

	   Two bounded sections instead, as the desktop has, with the rail itself
	   still scrolling so the Admin block below them stays reachable. The caps are
	   in `dvh` rather than pixels because the drawer is measured against the
	   visible viewport, which on a phone changes as the address bar comes and
	   goes.

	   `overscroll-behavior: contain` is what makes two scrollers inside a third
	   bearable on touch: a flick that reaches the end of a list stops there
	   rather than dragging the whole drawer with it. */
	.panel.rail .rail-top {
		/* Takes the room that is left rather than a share of the viewport. Capping
		   this in `dvh` was the first attempt and it was wrong twice over: BOTH
		   lists live inside it, so the cap squeezed the pair into the top of the
		   drawer and left a third of the screen empty underneath. */
		flex: 1 1 auto;
		min-height: 0;
		display: flex;
		flex-direction: column;
		overflow: hidden;
	}
	/* The two lists then split that room between them and scroll inside it, which
	   is exactly what they do on a desktop. The floor stops either one collapsing
	   to nothing when the other is long. */
	.panel.rail .diamond-list,
	.panel.rail .session-list {
		flex: 1 1 0;
		min-height: 5.5rem;
		overflow-y: auto;
		overscroll-behavior: contain;
		-webkit-overflow-scrolling: touch;
	}
	.panel.rail .admin { flex: none; }
	.panel.rail #handle-rail-split { display: none; }

	body.drawer-open .panel.rail { transform: translateX(0); }
	@media (prefers-reduced-motion: reduce) {
		.panel.rail { transition: none; }
	}

	/* The scrim dims and catches the tap that closes the drawer. The
	   sheet has NO scrim on purpose — the chat above it stays live. */
	#scrim {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 70;
		background: rgba(0, 0, 0, .38);
		opacity: 0;
		pointer-events: none;
		transition: opacity .28s ease;
	}
	body.drawer-open #scrim { opacity: 1; pointer-events: auto; }

	/* ── The sheet: a thing, over the chat ─────────────────────
	   Anchored to the bottom, ABOVE the bar, so the bar is always
	   reachable and a destination is one tap away. The detent changes
	   the sheet's HEIGHT (not a translate), so its foot — the "Ask
	   about this" pill — is on screen at every detent, which is the
	   whole point: the thing, and the ear for it, together. No
	   transition WHILE dragging (`.dragging`), so it tracks the finger. */
	#msheet {
		display: flex;
		flex-direction: column;
		position: fixed;
		z-index: 40;
		left: 0;
		right: 0;
		bottom: calc(var(--mnav-h) + var(--safe-b));
		height: 0;					/* closed; the controller sets the detent height */
		background: var(--bg-primary);
		border-top-left-radius: 16px;
		border-top-right-radius: 16px;
		border: 1px solid var(--border);
		border-bottom: none;
		box-shadow: 0 -8px 40px rgba(0, 0, 0, .38);
		overflow: hidden;
		/* The DETENT sets the height instantly (no relayout animation, which is
		   janky with an iframe inside); the open/close SLIDE is a transform, which
		   the compositor handles smoothly. Closed = slid fully below its own foot. */
		transform: translateY(110%);
		transition: transform .3s cubic-bezier(.32, .72, 0, 1);
		will-change: transform;
	}
	#msheet.open { transform: translateY(0); }
	#msheet.dragging { transition: none; }
	@media (prefers-reduced-motion: reduce) {
		#msheet { transition: none; }
	}

	/* The grabber: the drag handle, and the only place a vertical drag
	   moves the sheet rather than scrolling the thing inside it. */
	.msheet-grab {
		flex: none;
		display: flex;
		align-items: center;
		gap: 8px;
		padding: 8px 12px 6px;
		cursor: grab;
		touch-action: none;			/* the grabber owns the vertical gesture */
		border-top-left-radius: 16px;
		border-top-right-radius: 16px;
	}
	.msheet-grab:active { cursor: grabbing; }
	.msheet-bar {
		position: absolute;
		left: 50%;
		transform: translateX(-50%);
		top: 7px;
		width: 38px;
		height: 4px;
		border-radius: 3px;
		background: var(--border);
	}
	.msheet-title {
		flex: 1;
		min-width: 0;
		margin-top: 6px;
		font-size: var(--fs-sm);
		font-weight: 600;
		color: var(--text-muted);
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	.msheet-close {
		margin-top: 0;
		/* 40px, matching the guest's own lifted controls that now sit beside it
		   (see `#msheet .panel > .railhead`): two icon buttons on one row at two
		   different sizes read as two different kinds of control. It is also the
		   larger thumb target of the two, which on a phone is the right way to
		   settle a tie. */
		width: 40px;
		height: 40px;
		flex: none;
		display: flex;
		align-items: center;
		justify-content: center;
		background: none;
		border: none;
		border-radius: var(--radius);
		color: var(--text-muted);
		font-size: var(--fs-3xl);
		line-height: 1;
		cursor: pointer;
	}
	.msheet-close:active { background: var(--accent-soft); }

	/* The thing itself fills the room between the grabber and the ask
	   pill. The moved panel keeps its own header and controls. */
	.msheet-scroll {
		flex: 1;
		min-height: 0;
		display: flex;
		flex-direction: column;
		overflow: hidden;
	}
	#msheet .panel {
		display: flex !important;
		flex-direction: column;
		height: 100% !important;
		width: 100% !important;
		min-width: 0 !important;
		border: none;
		border-radius: 0;
	}
	/* The sheet already names what it is holding, in the grabber. A guest that
	   carries its own head then said it twice, one line apart and in two
	   different cases -- "Spending" over "SPENDING". The guest keeps its
	   controls; the sheet keeps the title. */
	/* Dropping the name left a row holding nothing but its controls, and it kept
	   a full band of the sheet to itself: 44px directly under the sheet's own
	   closer, with the whole width beside the one refresh button empty. It read
	   as a title that had gone missing rather than one that had moved. Lift the
	   strip into the grabber's row, just left of the closer, where a panel's
	   controls sit everywhere else in the app. Positioned against `#msheet`
	   (the nearest positioned ancestor), so it costs the body nothing: 8px is
	   the grabber's own top padding and 52px clears the 32px closer and its
	   12px of padding. Only Spending is ever raised into a sheet with this kind
	   of head -- the other three are bottom-bar destinations, which keep their
	   names and their own rows. */
	#msheet .panel > .railhead {
		position: absolute;
		top: 8px;
		/* 12px of grabber padding, the 40px closer, and 8px between them. */
		right: 60px;
		z-index: 1;
		padding: 0;
		justify-content: flex-end;
	}
	/* Beside the sheet's own borderless closer, a bordered box reads as the
	   heavier of two controls that do the same kind of job. Same size, same
	   weight, same ink. */
	#msheet .panel > .railhead button {
		width: 40px;
		height: 40px;
		background: none;
		border: none;
		color: var(--text-muted);
	}
	#msheet .panel > .railhead button:active { background: var(--accent-soft); }
	#msheet .panel > .railhead > span:first-child { display: none; }
	/* THE LIFT IS FOR A HEAD HOLDING ONE OR TWO ICON BUTTONS, and the comment
	   above it named Spending as the only panel raised with one. That stopped
	   being true when the Improve panel became Social: its head carries FOUR
	   labelled chips, an information mark and a closer. The strip is out of flow
	   with no left bound, so on a 390px screen it ran off the left edge, and the
	   rule above squared every chip to a 40px icon box — "Messages" and "People"
	   drawn one on top of the other, each clipped, and not one of them showing
	   which view was on. Screenshot: dev/shots/social-phone.png, 2026-08-17.

	   So this head stays IN FLOW and takes a row of its own, which is where four
	   chips fit and where a fifth would wrap rather than disappear. */
	#msheet #panel-social > .railhead {
		position: static;
		padding: 4px 6px;
		justify-content: flex-start;
		flex-wrap: wrap;
		row-gap: 3px;
	}
	/* And a chip keeps its own shape: a word, and a pill saying whether its view
	   is the one showing. The thumb floor is taken as a HEIGHT, which is the half
	   of the rule above that was ever about a finger. */
	/* The chips carry `margin-left: auto` so they sit right of a heading. The
	   heading is hidden in the sheet, so that auto margin only pushed them into
	   the corner and left the row lopsided. */
	#msheet #panel-social > .railhead .imp-chips { margin-left: 0; }
	#msheet #panel-social > .railhead .imp-chip {
		width: auto;
		height: auto;
		min-height: 30px;
		padding: 0 10px;
		background: none;
		border: 1px solid var(--border-strong);
		color: var(--text-secondary);
	}
	#msheet #panel-social > .railhead .imp-chip.on {
		background: var(--accent-soft);
		border-color: var(--accent);
		color: var(--accent-text);
	}
	/* The lifted strip is out of flow, so the title's box still runs the full
	   width and a long panel name would ellipsise UNDER the buttons. Give the
	   title back the room the strip is standing in. */
	#msheet:has(.panel > .railhead) .msheet-title { padding-right: 40px; }
	/* A guest whose own head says what the sheet has just said. This USED to
	   name Tools as the only such panel; rendering all nine showed Message over
	   Message, Graph over Graph, and a blank 44px band over Doc. The test cannot
	   live here -- a `.ctitle` is the panel's name while it is empty and a live
	   title once it holds a URL, a filename or a subject, and no selector tells
	   those apart -- so `DaimondSheet.open` makes it when the guest is raised
	   and marks the head. See hideRedundantHead in mobile.js. */
	#msheet .panel > .chead.head-said-twice,
	#msheet .panel > .railhead.head-said-twice { display: none; }
	/* The Terminal's head is not droppable -- Start and Stop live in it, and a
	   terminal you cannot start is not a terminal -- so only the duplicated NAME
	   goes. What is left is the program's own title and the two controls, which
	   is what the head is for. */
	#msheet .panel.termpanel > .chead > .ctitle { display: none; }
	/* With the name gone and no program running there is no title either, so the
	   Terminal's head drew the same blank band Spending's did: 44px under the
	   sheet's own closer holding two buttons at the far right. Same answer --
	   lift the controls into the grabber's row, and let what remains collapse to
	   the height of whatever the program calls itself (nothing, until one is
	   started) rather than to a header's minimum. */
	#msheet .panel.termpanel > .chead {
		min-height: 0;
		padding: 0 14px;
		border-bottom: none;
	}
	#msheet .panel.termpanel > .chead > .chead-right {
		position: absolute;
		top: 8px;
		right: 60px;
		z-index: 1;
		gap: 4px;
	}
	#msheet .panel.termpanel > .chead > .chead-right button {
		width: 40px;
		height: 40px;
		background: none;
		border: none;
		color: var(--text-muted);
	}
	#msheet .panel.termpanel > .chead > .chead-right button:active { background: var(--accent-soft); }
	#msheet:has(.panel.termpanel) .msheet-title { padding-right: 96px; }

	/* The ask pill: the composer, relocated. "Ask about THIS" is the
	   whole thesis — read the thing, and the daimon is still there to
	   be asked about it. It posts to the one conversation on the floor. */
	.msheet-ask {
		flex: none;
		display: flex;
		align-items: center;
		gap: 8px;
		padding: 8px 10px calc(8px + var(--safe-b));
		border-top: 1px solid var(--border);
		background: var(--bg-secondary);
	}
	.msheet-ask.hidden { display: none; }
	#msheet-ask-input {
		flex: 1;
		min-width: 0;
		font-size: var(--fs-xl);			/* 16px keeps iOS Safari from zooming on focus */
		padding: 10px 13px;
		border: 1px solid var(--border-strong);
		border-radius: 20px;
		background: var(--bg-primary);
		color: var(--text-primary);
	}
	#msheet-ask-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
	#msheet-ask-send {
		flex: none;
		width: 42px;
		height: 42px;
		border: none;
		border-radius: 50%;
		background: var(--accent);
		color: var(--on-fill, #fff);
		font-size: var(--fs-xl-2xl);
		cursor: pointer;
	}
	#msheet-ask-send:disabled { opacity: .4; }

	/* While a sheet is up, the destination behind it is always the
	   chat floor. Its own input bar is hidden — the ask pill speaks
	   for it — so two composers can never disagree. */
	body.sheet-open .ai .chat-input-bar { visibility: hidden; }

	/* ── The footer: the panel chip row, scrolled sideways ─────
	   The bar sits ABOVE the sheet, so a panel is always one tap away and the
	   sheet's foot rests just above it (see #msheet bottom).

	   It held four hard-wired destinations until 2026-08-28 -- Chat, Email,
	   Files, Agents -- and the owner's verdict was that it "is currently useless
	   to me": four of the seventeen panels named, the other thirteen reachable
	   only through the drawer. It carries the chip row now, which is the same row
	   the desktop header carries, moved rather than copied (`placeChips`,
	   js/mobile.js).

	   ITS HEIGHT IS `--mnav-h`, plus the home indicator's inset, and that variable
	   is the only place the number is written. `#msheet { bottom }` below reads
	   it, and js/mobile.js MEASURES the bar rather than carrying a fourth copy:
	   there were three -- 54 in variables.css, 58 in this file and 58 in the shell
	   -- and `dev/verify_sweep_mobile.mjs` exists partly because a sheet placed
	   from one of them lands over a bar drawn from another. */
	.mnav { position: relative; z-index: 60; }

	/* The strip itself. It SCROLLS rather than fitting: "A chip is its label.
	   Below that width it is not a shorter chip, it is an unreadable one" --
	   css/improve.css, on the Social panel's chips, and it is the same rule here.
	   So every chip takes the width its label needs (`flex: none` below) and the
	   strip carries the rest of them past the edge.
	   THE SAFE INSET IS ON THE SCROLLER, not on the bar, so the last chip scrolls
	   clear of the home indicator instead of ending under it. A chip you cannot
	   reach is the same class of fault as a chip that moves while you reach. */
	#mnav .panel-tags {
		display: flex !important;
		flex: 1 1 auto;
		align-items: center;
		min-width: 0;
		gap: 8px;
		margin: 0;
		/* 8 + 44 + 9 + the bar's 1px rule = `--mnav-h`, which is where the number
		   lives and what the sheet's foot is placed from. */
		padding: 8px 14px calc(9px + var(--safe-b));
		overflow-x: auto;
		overflow-y: hidden;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		/* The scrollbar would eat the height the chips need and, on a phone, is
		   drawn over them for a second and then gone -- so the fact that the row
		   scrolls is carried by the fade at its ends instead (`data-more` below). */
		scrollbar-width: none;
		/* A chip scrolled to is scrolled clear of the fade rather than under it. */
		scroll-padding-inline: 22px;
	}
	#mnav .panel-tags::-webkit-scrollbar { display: none; }
	/* A THUMB'S TARGET. 44px is the AAA figure and it is what the four buttons
	   this row replaced already met, so the row that replaced them may not be
	   smaller: `dev/verify_sweep_mobile.mjs` reports anything under it, and it
	   reported these chips at 40 before this line said 44. */
	#mnav .ptag,
	#mnav .ptag-more {
		flex: none;
		min-height: 44px;
		/* AND 44 ACROSS. A two-letter label -- "AI" -- came to 43px with the
		   padding, which `dev/verify_sweep_mobile.mjs` reported at every phone
		   width. It is a floor and not a width: a chip is still its label, and a
		   longer one takes the room it needs. */
		min-width: 44px;
		justify-content: center;
		display: inline-flex;
		align-items: center;
		padding: 0 14px;
		font-size: var(--fs-xs);
	}
	#mnav .ptag-group { flex: none; gap: 8px; }
	#mnav .ptag-div { margin: 0 2px; }

	/* SCROLLABLE MUST LOOK SCROLLABLE. A strip that runs to the edge and stops
	   reads as a truncated list, and a scrollbar would cost the height the chips
	   are using. A soft fade at whichever end has more beyond it says the same
	   thing and costs nothing: `data-more` is set by `markScroll` in js/mobile.js
	   from the strip's own scroll position, so it is never a decoration that
	   claims something untrue. Half a chip showing through the fade is the other
	   half of the signal. */
	#mnav .panel-tags[data-more="end"]   { mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent 100%); }
	#mnav .panel-tags[data-more="start"] { mask-image: linear-gradient(to right, transparent 0, #000 34px); }
	#mnav .panel-tags[data-more="both"]  { mask-image: linear-gradient(to right, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%); }
	#mnav .panel-tags[data-more="end"]   { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent 100%); }
	#mnav .panel-tags[data-more="start"] { -webkit-mask-image: linear-gradient(to right, transparent 0, #000 34px); }
	#mnav .panel-tags[data-more="both"]  { -webkit-mask-image: linear-gradient(to right, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%); }

	/* ── No iOS auto-zoom ───────────────────────────────────────
	   Safari zooms IN (and never back out) when a focused control is
	   under 16px. Every form control is 16px on a phone so focusing a
	   name box, a filter, or a dialog field never jerks the view. */
	input, textarea, select,
	.settings-select, .dlg-input, .dlg-select, .files-filter-input {
		font-size: var(--fs-xl) !important;
	}

	/* ── Modals fit the phone ──────────────────────────────────
	   The settings modal hosts an admin view (Models / Credits) that
	   already carries its OWN header — the right title and a top-right
	   ×. Show that (it is hidden on desktop) and drop the modal's own
	   generic "Settings" heading and bottom Close, which duplicated it
	   with the wrong title and no corner close. And size to the DYNAMIC
	   viewport so a tall form scrolls inside instead of dragging. */
	.modal { padding: 12px; align-items: flex-start; }
	.modal-card {
		width: 100%;
		max-width: 520px;
		margin: 0 auto;
		max-height: calc(100dvh - 24px);
		padding: 16px;
	}
	/* The About card's two bleeding children cancel the card's padding out, so
	   they have to be told it changed here. Without this the splash hangs 8px
	   past the card on each side and the rule above the signature does the same. */
	.about-card { --about-pad: 16px; }
	/* The create screen asks for more room than the shared 80vh (see app.css) and
	   takes 92vh -- but `vh` counts the strip behind the address bar, which a
	   phone does not show, so on a phone the card ran past the fold and cut
	   "Create account" in half. The dynamic viewport is the honest measure, and
	   the card scrolls inside it. */
	#identity-modal .modal-card { max-height: calc(100dvh - 24px); }
	/* The hosted view's own head is the card's heading everywhere now, and the
	   bottom Close is hidden everywhere with it (both in app.css), so nothing
	   about the settings card needs saying twice here. */
	/* The view's own × sits top-right and is the close. Make it a clear target. */
	#settings-slot .admin-back { font-size: var(--fs-4xl); padding: 4px 10px; }
}

/* A wider phone / small tablet in landscape gets a roomier sheet and
   drawer, but the same paradigm. The single 760 cliff is deliberately
   the only structural switch for now; this is a comfort tweak. */
@media (max-width: 760px) and (min-width: 560px) and (orientation: landscape) {
	.panel.rail { width: 380px !important; }
}
