/*
 * App shell — sidebar, topbar, content area.
 *
 * Ported from docs/mockup.html. Variables only (see tokens.css).
 * Breakpoints are the mockup's: 1100px (grids collapse) and 820px (off-canvas
 * sidebar).
 */

/*
 * ===========================================================================
 * THE SHELL IS A FIXED-HEIGHT BOX WITH SCROLLING PANES INSIDE IT
 * ===========================================================================
 *
 * `.app` is exactly the viewport and never scrolls. Everything that scrolls is
 * inside it: the sidebar scrolls its own nav, `.content` scrolls the page. The
 * header is a sibling of the scrolling region rather than a part of it, which
 * is what makes it impossible for the header to scroll away — not a `position:
 * sticky` that a stacking context could break.
 *
 * `100dvh` AFTER `100vh`, BOTH DECLARED. This is the one line that matters on a
 * phone. `100vh` is the LARGEST viewport — the height the page would have if
 * the browser's URL bar were hidden — so on mobile Safari and Chrome Android
 * `.app` is taller than what you can actually see, the document itself becomes
 * scrollable, and the header scrolls up under the URL bar. That is the reported
 * "top nav disappears", and it is a mobile-only failure: on a desktop browser,
 * where there is no retracting chrome, `100vh` and `100dvh` are the same number
 * and the header never moves. Older browsers that do not know `dvh` ignore the
 * second declaration and keep the first.
 */
/*
 * ===========================================================================
 * THE PAGE ITSELF DOES NOT SCROLL — STATED, NOT INFERRED
 * ===========================================================================
 *
 * `.app` below is exactly the viewport and every scroller lives inside it, so
 * in principle nothing can extend the document. In practice one page reported
 * 62px of document overflow at 390px (the lead-sources manager) that no element
 * accounts for: `.overlay`, `.cmdk`, `.toasts` and `#progress` are all
 * `position: fixed` and inset, the modal was measured and cleared, and `.app`
 * is `overflow: hidden` at exactly 100dvh. Whatever produces it, the moment the
 * document can scroll, the header scrolls away with it — which is bug one.
 *
 * So the invariant is asserted at the root rather than deduced from the boxes
 * below. Measured, in this order, because the first attempt was wrong:
 *
 *   no rule                  wheel → header moves on that page
 *   `overflow: hidden` on <body>   still scrolled; the VIEWPORT's scrollbar is
 *                            governed by the root element, not by <body>
 *   `overflow: hidden` on <html>   wheel → scrollY stays 0, header stays at 0
 *
 * `> body` as well, because once the root is not `visible` the propagation from
 * <body> to the viewport stops and <body> becomes a scroll container of its own.
 *
 * The class is on the shell layout's <html> only. @auth.latte does not carry it
 * — the signed-out screens are meant to scroll, and they have no header to lose.
 */
html.app-shell,
html.app-shell > body {
	overflow: hidden;
}

.app {
	display: flex;
	height: 100vh;
	height: 100dvh;
	overflow: hidden;
}

/* ---------- Sidebar ---------- */

/*
 * THE SIDEBAR IS ITS OWN SCROLL CONTAINER.
 *
 * It had no `overflow-y` at all, and `.app` above it is `overflow: hidden`, so
 * a nav taller than the viewport was simply CLIPPED — the items past the fold
 * were not just hard to reach, they were unreachable by any means. Measured
 * across every full page in this application at 1400×900 and 390×844 with the
 * nav groups expanded: the sidebar overflowed its box on all of them, and on
 * none of them could it scroll. Expanding Telephony (Wallboard, Live calls,
 * Call history, Supervision log, Extensions, Trunks) is the case in the report,
 * but it was never specific to telephony.
 *
 * `min-height: 0` is not decoration. This is a flex item in a row, and a flex
 * item's default `min-height: auto` refuses to shrink below its content — which
 * would let the nav push the sidebar taller than `.app` and put us right back
 * where we started, with `overflow-y: auto` on a box that never overflows.
 *
 * The whole sidebar scrolls, brand and user chip included, rather than just the
 * nav list. Pinning them would mean a second nested scroller and a fixed
 * subtraction to keep in step with two paddings; a long nav is the rare case,
 * and one scroller that always works beats two that agree until somebody edits
 * a padding.
 */
.sidebar {
	width: var(--sidebar-w);
	flex-shrink: 0;
	background: var(--surface);
	border-right: 1px solid var(--border);
	display: flex;
	flex-direction: column;
	padding: 14px 10px 12px;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;

	/* Thin and quiet, but really there. Firefox and the rest. */
	scrollbar-width: thin;
	scrollbar-color: var(--border-strong) transparent;
}

/* WebKit/Blink, which ignores scrollbar-width. */
.sidebar::-webkit-scrollbar {
	width: 6px;
}

.sidebar::-webkit-scrollbar-track {
	background: transparent;
}

.sidebar::-webkit-scrollbar-thumb {
	background: var(--border-strong);
	border-radius: 3px;
}

.sidebar::-webkit-scrollbar-thumb:hover {
	background: var(--text-3);
}

.brand {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 4px 8px 14px;
}

.brand-mark {
	width: 28px;
	height: 28px;
	border-radius: 8px;
	background: var(--brand-gradient);
	display: grid;
	place-items: center;
	color: var(--on-primary);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: -.5px;
}

.brand-name {
	font-weight: 600;
	font-size: 14px;
	letter-spacing: -.2px;
}

.brand-env {
	font-size: 10px;
	color: var(--text-3);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: .6px;
}

.nav-section {
	margin-top: 10px;
}

.nav-label {
	font-size: 10.5px;
	font-weight: 600;
	color: var(--text-3);
	text-transform: uppercase;
	letter-spacing: .7px;
	padding: 0 10px;
	margin-bottom: 4px;
}

.nav-item {
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
	padding: 7px 10px;
	border-radius: 8px;
	color: var(--text-2);
	font-weight: 500;
	font-size: 13px;
	transition: background .12s, color .12s;
	text-align: left;
}

.nav-item .icon {
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	stroke-width: 1.8;
}

.nav-item:hover {
	background: var(--surface-2);
	color: var(--text);
}

.nav-item.active {
	background: var(--primary-soft);
	color: var(--primary);
	font-weight: 600;
}

.nav-item .count {
	margin-left: auto;
	font-size: 11px;
	font-weight: 600;
	color: var(--text-3);
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: 0 6px;
	line-height: 18px;
}

.nav-item.active .count {
	background: var(--surface);
	border-color: var(--primary-soft-border);
	color: var(--primary);
}

.sidebar-spacer {
	flex: 1;
}

.user-chip {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 10px;
	border-radius: 8px;
	transition: background .12s;
	width: 100%;
	text-align: left;
}

.user-chip:hover {
	background: var(--surface-2);
}

.user-chip .meta {
	line-height: 1.25;
	min-width: 0;
}

.user-chip .n {
	font-size: 12.5px;
	font-weight: 600;
}

.user-chip .e {
	font-size: 11px;
	color: var(--text-3);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* ---------- Main column ---------- */

.main {
	flex: 1;
	display: flex;
	flex-direction: column;
	min-width: 0;
}

/*
 * The header. It does not need `position: sticky` and deliberately does not
 * have it: it is a flex item OUTSIDE `.content`, which is the only scroller in
 * this column, so there is no scroll for it to be sticky against. A sticky
 * header can be broken by a stacking context somebody adds three levels up; a
 * header that is not in the scrolling region cannot.
 *
 * The height is a token because the notification dropdown has to hang from the
 * bottom of this element on a narrow screen, where it is anchored to the
 * viewport rather than to the bell.
 */
.topbar {
	height: var(--topbar-h);
	flex-shrink: 0;
	background: var(--surface);
	border-bottom: 1px solid var(--border);
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 0 20px;
}

/* The topbar is a fixed-height row and the crumb is the only part of it whose
   width comes from data, so the crumb is the part that has to yield: a record
   named "Maximiliana Konstantina Von Habsburg-Lothringen Della Rovere" wrapped
   to three lines at 390px and pushed the search box and the bell off the row.
   `min-width: 0` lets it shrink; the ellipsis says it did. */
.crumbs {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: 13px;
	color: var(--text-3);
	font-weight: 500;
	min-width: 0;
	overflow: hidden;
}

.crumbs b {
	color: var(--text);
	font-weight: 600;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* The parent crumb ("Leads") goes before the record's name does — it is the one
   the sidebar already tells you. */
.crumbs .crumb-parent,
.crumbs .crumb-sep {
	flex: 0 0 auto;
	white-space: nowrap;
}

.search-trigger {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: 8px;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: 8px;
	padding: 5px 10px;
	color: var(--text-3);
	font-size: 12.5px;
	min-width: 220px;
	transition: border-color .12s;
}

.search-trigger:hover {
	border-color: var(--border-strong);
}

.search-trigger .icon {
	width: 14px;
	height: 14px;
	stroke-width: 2;
}

.search-trigger kbd {
	margin-left: auto;
	font-family: var(--mono);
	font-size: 10px;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: 4px;
	padding: 1px 5px;
	color: var(--text-3);
}

/* ---------- Content ---------- */

.content {
	flex: 1;
	overflow-y: auto;
	padding: 24px 28px;
}

.page {
	animation: fadeUp .18s ease;
}

@keyframes fadeUp {
	from {
		opacity: 0;
		transform: translateY(4px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

.page-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 20px;
}

.page-title {
	font-size: 19px;
	font-weight: 700;
	letter-spacing: -.3px;
}

.page-sub {
	color: var(--text-3);
	font-size: 13px;
	margin-top: 2px;
}

.page-actions {
	display: flex;
	gap: 8px;
	align-items: center;
}

/* ---------- A record's header: identity, cues, controls ----------

   The detail-page variant of .page-head, shared by every entity module through
   components/record-head.latte. Three rules do the work, and each replaces a
   way the old flat row broke:

     the identity column may SHRINK (min-width: 0), so a long record name is
     ellipsised instead of shoving the controls off the right edge;

     the controls column may NOT grow (flex: 0 0 auto), so it is as wide as its
     buttons and no wider — it used to take 1006px of an 1112px page;

     a CUE is not a button and has its own line, so a pill with avatars and a
     sentence in it can no longer stretch the row it sits in. */
.page-head.is-record {
	align-items: center;
}

.record-identity {
	min-width: 0;
	flex: 1 1 auto;
}

.record-title {
	margin: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.record-cues {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-1);
	margin-top: var(--space-1);
	min-width: 0;
}

.record-controls {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	flex: 0 0 auto;
	flex-wrap: wrap;
	gap: var(--space-2);
}

.record-verbs {
	display: flex;
	align-items: center;
	gap: var(--space-1);
}

/* The "More" menu opens leftwards from the right edge of the page, which is
   where its button is; the default right: 0 already does that. It only needs
   room for a sentence-length item ("Convert to a contact"). */
.record-menu {
	min-width: 210px;
}

/* A CONTRIBUTED ACTION IS A .btn, because that is what the zone's contract
   asks a module for, and this is the host restyling what landed in its menu
   rather than asking every module to render two shapes. */
.dropdown-menu .btn {
	width: 100%;
	justify-content: flex-start;
	gap: 9px;
	padding: 7px 9px;
	border: 0;
	background: transparent;
	border-radius: 7px;
	font-size: 12.5px;
	font-weight: 500;
	color: var(--text-2);
	box-shadow: none;
}

.dropdown-menu .btn:hover {
	background: var(--surface-2);
	color: var(--text);
}

.dropdown-menu .btn.btn-danger {
	color: var(--red);
}

/* At tablet width the head already stacks (below), so the controls take the
   full row and align left with the title rather than hanging off the right. */
@media (max-width: 820px) {
	/*
	 * The head stacks here (below), and a stacked head must align its children
	 * to the start — `.page-head.is-record { align-items: center }` outranks
	 * the stacking rule's `stretch` on specificity alone, which centred the
	 * record's name and its cue on every phone.
	 */
	.page-head.is-record {
		align-items: stretch;
	}

	.record-controls {
		justify-content: flex-start;
		width: 100%;
	}
}

/* On a phone the words go and the icons stay: Back, Prev and Next become the
   arrows they already are, and "More" becomes its dots. Every one of them
   carries an aria-label at every width, so nothing loses its name — see
   components/list-nav.latte. */
@media (max-width: 560px) {
	/*
	 * THE NAVIGATION COMPACTS; THE VERBS DO NOT.
	 *
	 * Back, Prev and Next are arrows that already mean what they say, and the
	 * position ("1 of 72") between them carries the sense — so the words go and
	 * the group shrinks to about 190px. Email, Edit and More keep their labels,
	 * because four anonymous icons in a row is a header nobody can use and
	 * these are the three things a person came to the page to do. Everything
	 * here carries an aria-label at every width regardless — see
	 * components/list-nav.latte.
	 */
	.list-nav .btn-word {
		display: none;
	}

	.list-nav {
		padding-right: 6px;
		margin-right: 2px;
	}
}

.section {
	margin-bottom: 26px;
}

.section-head {
	font-size: 11px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: .6px;
	color: var(--text-3);
	margin-bottom: 10px;
}

.stack {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
}

.grid-2 {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 14px;
	align-items: start;
}

.menu-btn {
	display: none;
}

/* ---------- Responsive (mockup breakpoints) ---------- */

@media (max-width: 1100px) {
	.kpi-grid {
		grid-template-columns: repeat(2, 1fr);
	}

	.grid-2 {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 820px) {
	/*
	 * Off-canvas. `100dvh` for the same reason `.app` has it: a drawer sized to
	 * the largest viewport is a drawer whose last nav item sits behind the URL
	 * bar. It keeps the `overflow-y: auto` it inherits from the rule above —
	 * which is the case that matters most, because a phone has the least height
	 * and therefore the longest overflow.
	 */
	.sidebar {
		position: fixed;
		left: -260px;
		z-index: 55;
		height: 100vh;
		height: 100dvh;
		transition: left .2s;
		box-shadow: var(--shadow-lg);
	}

	.sidebar.open {
		left: 0;
	}

	.menu-btn {
		display: grid !important;
	}

	.content {
		padding: 16px;
	}

	.search-trigger {
		min-width: 0;
	}

	.search-trigger span {
		display: none;
	}

	.field-row {
		grid-template-columns: 1fr;
	}

	/*
	 * Phase 20's responsive pass: a page head with four actions — the roles
	 * and permissions screen — pushed three of them past the right edge of a
	 * 390px phone. The page did not scroll sideways, because .content is a
	 * scroller, so nothing failed the overflow check; the buttons were simply
	 * somewhere the user had to find. Stacking the head and letting the
	 * actions wrap puts every one of them on screen.
	 */
	.page-head {
		flex-direction: column;
		align-items: stretch;
		gap: 12px;
	}

	.page-actions {
		flex-wrap: wrap;
	}
}

/* ---------- Signed-out screens (@auth.latte) ---------- */

/*
 * `100dvh` here too, for the mobile-chrome reason in `.app` — and `min-height`
 * rather than `height`, because a sign-in panel taller than a small phone must
 * be allowed to scroll the page. That is the one screen in this application
 * where a page-level scroll is correct: there is no header to lose.
 */
.auth-shell {
	min-height: 100vh;
	min-height: 100dvh;
	display: grid;
	place-items: center;
	padding: 24px 16px;
}

.auth-panel {
	width: 100%;
	max-width: 380px;
}

.auth-brand {
	display: flex;
	align-items: center;
	gap: 10px;
	justify-content: center;
	margin-bottom: 18px;
}

.auth-foot {
	margin-top: 14px;
	text-align: center;
	font-size: 12.5px;
	color: var(--text-3);
}

.auth-foot a {
	color: var(--primary);
	font-weight: 600;
}

/*
 * A submit button that reads as the link beside it.
 *
 * "Sign in as somebody else" on the two-factor challenge throws away a parked
 * sign-in, which is a state change and therefore a POST carrying a token — but
 * to the person reading the page it is the same kind of thing as "Back to sign
 * in" one line above, and it has to look like it.
 */
.auth-foot form {
	display: inline;
}

.auth-foot .linkish {
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	color: var(--primary);
	font-weight: 600;
	cursor: pointer;
}

.auth-head {
	padding: 20px 20px 0;
}

.auth-head .t {
	font-size: 17px;
	font-weight: 700;
	letter-spacing: -.2px;
}

.auth-head .s {
	font-size: 12.5px;
	color: var(--text-3);
	margin-top: 3px;
}

.check-row {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 12.5px;
	color: var(--text-2);
	font-weight: 500;
}

.check-row input[type="checkbox"] {
	width: 15px;
	height: 15px;
	accent-color: var(--primary);
	cursor: pointer;
}

.form-alert {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 12.5px;
	font-weight: 500;
	color: var(--red);
	background: var(--red-soft);
	border-radius: 8px;
	padding: 9px 11px;
}

.form-alert.info {
	color: var(--blue);
	background: var(--blue-soft);
}

.form-alert .icon {
	width: 15px;
	height: 15px;
}

/* ---------- Sidebar sub-menus ---------- */

.nav-group .nav-item {
	position: relative;
}

.nav-toggle {
	margin-left: auto;
	display: grid;
	place-items: center;
	color: var(--text-3);
	transition: transform .15s;
	padding: 0;
}

.nav-group.open .nav-toggle {
	transform: rotate(180deg);
}

.nav-children {
	display: none;
	margin: 2px 0 2px 22px;
	padding-left: 10px;
	border-left: 1px solid var(--border);
}

.nav-group.open .nav-children {
	display: block;
}

.nav-children .nav-item {
	font-size: 12.5px;
	padding: 5px 10px;
}
