/**
 * Fuzzy Menu — command palette.
 *
 * Every rule is scoped to the palette's own ids and fm- prefixed classes, with
 * one deliberate exception: the loupe in the top bar, which borrows the theme's
 * bar vocabulary and so has to name itself after it. The sidebar keeps its
 * module list untouched.
 *
 * The colours below are the host theme's indigo family, so the palette looks
 * native on BlueSilk, but they are declared here rather than read from the theme
 * so the plugin also looks deliberate on a theme that has no such variables.
 */

/* ---------------------------------------------------------------- palette -- */

/*
 * On :root, not on a wrapper: the search button lives in the top bar and the
 * palette lives on <body>, so there is no single element that contains both.
 * Every name is --fm- prefixed, so nothing here can collide with the theme.
 */
:root {
	--fm-bg: #1d2f55;
	--fm-bg-2: #253c6b;
	--fm-fg: #fffcf5;
	--fm-fg-dim: #c5cae9;
	--fm-line: rgba(255, 255, 255, 0.14);
	--fm-line-soft: rgba(255, 255, 255, 0.07);
	--fm-sel: #3459a1;
	--fm-hover: rgba(255, 255, 255, 0.07);
	--fm-hi: #ffd166;
	--fm-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
}

/* ---------------------------------------------------------------- the loupe -- */

/*
 * The magnifier is drawn in CSS (a ring plus a handle) so the plugin ships no
 * image and no icon font, and needs no extra CSP allowance.
 */
.fm-search-btn__glass {
	position: relative;
	flex: none;
	width: 16px;
	height: 16px;
	border: 2px solid currentColor;
	border-radius: 50%;
}

.fm-search-btn__glass::after {
	content: "";
	position: absolute;
	right: -5px;
	bottom: -3px;
	width: 7px;
	height: 2px;
	border-radius: 1px;
	background: currentColor;
	transform: rotate(45deg);
	transform-origin: left center;
}

/* ------------------------------------------------- the trigger in the bar -- */

/*
 * The same button, dressed for the top bar: no word, no key cap, just the
 * loupe at the right-hand end of the row of icon buttons, its shortcut read
 * on hover from the title attribute — which is how Imprimer, Aide and
 * Déconnexion beside it already do it.
 *
 * The bar paints its own children (`#footer span`, with !important) so the
 * ring cannot be recoloured from here. Opacity carries the feedback instead,
 * at the value the theme itself gives its icons, so the loupe sits at the same
 * weight as the rest of the row and lifts when pointed at.
 */
.fm-bar-btn {
	position: relative;
	float: right;
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	width: 24px;
	height: 24px;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 6px;
	background: none;
	color: inherit;
	opacity: 0.69;
	cursor: pointer;
	transition: opacity 0.15s ease, background-color 0.15s ease;
}

.fm-bar-btn:hover,
.fm-bar-btn:focus-visible {
	opacity: 1;
	background-color: rgba(255, 255, 255, 0.1);
}

.fm-bar-btn:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 2px;
}

/*
 * The bar is 24px tall, so the ring is shrunk until the handle fits inside it.
 * The handle reaches past the ring on the right, hence the 2px pull back: an
 * icon whose handle is not counted reads as off-centre.
 */
.fm-bar-btn .fm-search-btn__glass {
	width: 14px;
	height: 14px;
	transform: translateX(-2px);
}

/* ------------------------------------------------------------- the overlay -- */

#fuzzy-menu-overlay {
	position: fixed;
	inset: 0;
	z-index: 9990;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	background: rgba(12, 18, 38, 0.32);
	-webkit-backdrop-filter: blur(10px) saturate(120%);
	backdrop-filter: blur(10px) saturate(120%);
	/*
	 * Closed: transparent and click-through, but still laid out.
	 *
	 * Not `visibility: hidden`. A hidden element cannot take focus, and with a
	 * transition on `visibility` the value in effect the instant the open class
	 * lands is timing dependent — which is how the palette came to open with the
	 * search field unfocused, and the arrow keys dead with it.
	 *
	 * `inert`, set by the script while closed, is what actually keeps the closed
	 * palette out of the tab order and off the accessibility tree.
	 */
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.16s ease;
}

#fuzzy-menu-overlay.fm-open {
	opacity: 1;
	pointer-events: auto;
}

/*
 * Half the window, and capped.
 *
 * Centred on the window rather than on the content area, so the sidebar does
 * not push it off axis. Half the width rather than nearly all of it: the
 * palette is a thing you glance at and dismiss, not a page that takes the
 * screen over.
 *
 * Capped so it stays reasonable on a large screen, and `min-width: 0` so it can
 * shrink rather than push the page sideways. Below 1200px the two columns no
 * longer fit in half the window and it stacks, further down.
 */
#fuzzy-menu-panel {
	display: grid;
	/*
	 * Quatre lignes, quatre enfants : head, tabs, cols, foot.
	 *
	 * Il n'y en avait que trois déclarées. Les onglets tombaient donc sur la
	 * ligne `1fr` et les colonnes sur une ligne `auto`, dimensionnée au contenu :
	 * avec une longue liste, la ligne `1fr` se réduisait à rien — les onglets
	 * étaient écrasés et invisibles — et elle ne regrossissait qu'à mesure que
	 * la liste raccourcissait. D'où des onglets Utilisateurs et Élèves qui
	 * n'apparaissaient qu'une fois le menu filtré.
	 *
	 * C'est aussi la colonne qui doit porter le `1fr` : c'est elle qui défile,
	 * et il lui faut une hauteur bornée pour que son `overflow-y` serve à
	 * quelque chose.
	 */
	grid-template-rows: auto auto minmax(0, 1fr) auto;
	width: min(50vw, 900px);
	height: min(50vh, 640px);
	max-height: 80vh;
	min-width: 0;
	min-height: 320px;
	overflow: hidden;
	border: 1px solid rgba(255, 255, 255, 0.16);
	border-radius: 14px;
	background: linear-gradient(135deg, var(--fm-bg) 0%, var(--fm-bg-2) 100%);
	box-shadow: var(--fm-shadow);
	color: var(--fm-fg);
	transform: scale(0.985);
	transition: transform 0.16s ease;
}

#fuzzy-menu-overlay.fm-open #fuzzy-menu-panel {
	transform: scale(1);
}

/* ------------------------------------------------------------------ header -- */

.fm-head {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 12px 16px;
	border-bottom: 1px solid var(--fm-line);
}

.fm-head__glass {
	position: relative;
	flex: none;
	width: 18px;
	height: 18px;
	border: 2px solid var(--fm-fg-dim);
	border-radius: 50%;
}

.fm-head__glass::after {
	content: "";
	position: absolute;
	right: -6px;
	bottom: -3px;
	width: 8px;
	height: 2px;
	border-radius: 1px;
	background: var(--fm-fg-dim);
	transform: rotate(45deg);
	transform-origin: left center;
}

#fuzzy-menu-input {
	flex: 1;
	min-width: 0;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--fm-fg);
	font: inherit;
	font-size: 19px;
	line-height: 1.4;
}

#fuzzy-menu-input::placeholder {
	color: rgba(255, 255, 255, 0.45);
}

#fuzzy-menu-input:focus {
	outline: none;
}

.fm-head__count {
	flex: none;
	font-size: 13px;
	color: var(--fm-fg-dim);
	white-space: nowrap;
}

/* ------------------------------------------------------------------ tabs -- */

.fm-tabs {
	display: flex;
	gap: 4px;
	padding: 8px 16px 0;
}

.fm-tab {
	padding: 6px 12px;
	border: 0;
	border-bottom: 2px solid transparent;
	background: transparent;
	color: var(--fm-fg-dim);
	font: inherit;
	font-size: 14px;
	cursor: pointer;
}

.fm-tab:hover {
	color: var(--fm-fg);
}

.fm-tab[aria-selected="true"] {
	color: var(--fm-fg);
	border-bottom-color: var(--fm-hi);
	font-weight: 600;
}

.fm-tab:focus-visible {
	outline: 2px solid var(--fm-hi);
	outline-offset: -2px;
	border-radius: 4px;
}

/* ---------------------------------------------------------------- columns -- */

.fm-cols {
	display: grid;
	grid-template-columns: 1fr 1fr;
	min-height: 0;
}

.fm-col {
	display: flex;
	flex-direction: column;
	min-width: 0;
	min-height: 0;
	overflow: hidden;
}

.fm-col--right {
	border-left: 1px solid var(--fm-line);
}

.fm-col__head {
	display: flex;
	align-items: center;
	gap: 8px;
	flex: none;
	padding: 8px 16px;
	border-bottom: 1px solid var(--fm-line-soft);
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--fm-fg-dim);
}

.fm-col__body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: thin;
}

.fm-list {
	margin: 0;
	padding: 4px 0;
	list-style: none;
}

/* Section header inside a module group. */
.fm-list__section {
	padding: 10px 16px 4px;
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.07em;
	color: var(--fm-fg-dim);
}

.fm-item {
	display: flex;
	align-items: baseline;
	gap: 8px;
	margin: 0 8px;
	padding: 6px 8px;
	border-radius: 7px;
	cursor: pointer;
}

.fm-item:hover {
	background: var(--fm-hover);
}

.fm-item[aria-selected="true"] {
	background: var(--fm-sel);
}

.fm-item__label {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.fm-item__meta {
	flex: none;
	font-size: 12px;
	color: var(--fm-fg-dim);
}

.fm-item[aria-selected="true"] .fm-item__meta {
	color: rgba(255, 255, 255, 0.8);
}

.fm-item__mod {
	flex: none;
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--fm-fg-dim);
}

.fm-item mark {
	padding: 0 1px;
	border-radius: 2px;
	background: transparent;
	color: var(--fm-hi);
	font-weight: 700;
}

.fm-item[aria-selected="true"] mark {
	color: #ffe9a8;
}

.fm-empty {
	padding: 18px 16px;
	font-size: 14px;
	color: var(--fm-fg-dim);
}

/* -------------------------------------------------------------- the fiche -- */

.fm-fiche {
	padding: 14px 16px;
}

.fm-fiche__sub {
	margin: 0 0 12px;
	font-size: 13px;
	color: var(--fm-fg-dim);
}

.fm-fiche__rows {
	margin: 0;
}

.fm-fiche__row {
	display: flex;
	gap: 10px;
	padding: 5px 0;
	border-top: 1px solid var(--fm-line-soft);
	font-size: 13px;
}

.fm-fiche__row dt {
	flex: none;
	width: 92px;
	color: var(--fm-fg-dim);
}

.fm-fiche__row dd {
	flex: 1;
	min-width: 0;
	margin: 0;
	overflow-wrap: anywhere;
}

.fm-fiche__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 14px;
}

.fm-fiche__action {
	display: inline-block;
	padding: 5px 10px;
	border: 1px solid var(--fm-line);
	border-radius: 7px;
	background: rgba(255, 255, 255, 0.05);
	color: var(--fm-fg);
	font-size: 13px;
	text-decoration: none;
	cursor: pointer;
}

.fm-fiche__action:hover,
.fm-fiche__action:focus-visible {
	background: rgba(255, 255, 255, 0.14);
}

/* The arrow keys land here from the list, so the focused button needs to read as
 * focused, not only as hovered. */
.fm-fiche__action:focus-visible {
	outline: 2px solid var(--fm-hi);
	outline-offset: 1px;
}

/* ------------------------------------------------------------- contextual -- */

/*
 * Miller columns: each cascade level is one column, appended to the right as the
 * user descends. Level columns scroll horizontally when a program declares more
 * levels than fit.
 */
.fm-cascade {
	display: flex;
	align-items: stretch;
	min-height: 0;
	flex: 1;
	overflow-x: auto;
	overflow-y: hidden;
}

.fm-cascade__col {
	display: flex;
	flex-direction: column;
	flex: 1 0 190px;
	min-width: 190px;
	max-width: 320px;
	min-height: 0;
	border-left: 1px solid var(--fm-line-soft);
}

.fm-cascade__col:first-child {
	border-left: 0;
}

.fm-cascade__head {
	flex: none;
	padding: 8px 12px;
	border-bottom: 1px solid var(--fm-line-soft);
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--fm-fg-dim);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.fm-cascade__body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
}

.fm-breadcrumb {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
}

.fm-breadcrumb__sep {
	color: var(--fm-fg-dim);
}

/* A crumb that is not the deepest one goes back to that level. */
.fm-breadcrumb__link {
	cursor: pointer;
	text-decoration: underline;
	text-decoration-color: var(--fm-line);
	text-underline-offset: 3px;
}

.fm-breadcrumb__link:hover {
	text-decoration-color: var(--fm-hi);
}

/* ------------------------------------------------------------------ footer -- */

.fm-foot {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	padding: 8px 16px;
	border-top: 1px solid var(--fm-line);
	font-size: 12px;
	color: var(--fm-fg-dim);
}

.fm-foot kbd {
	padding: 1px 5px;
	border: 1px solid var(--fm-line);
	border-radius: 4px;
	background: rgba(255, 255, 255, 0.05);
	font-family: inherit;
	font-size: 11px;
	color: var(--fm-fg);
}

/* ------------------------------------------------------------- responsive -- */

/*
 * Below this the two columns stop being readable, so they stack and the panel
 * takes the full width. The sidebar is already full width below 874px (theme
 * rule), so it goes to the full width, gutters included.
 *
 * 1200px, and not 1000 : at half the window the two columns run out of room
 * well before the window itself is narrow.
 */
@media (max-width: 1199px) {
	#fuzzy-menu-panel {
		width: calc(100vw - 24px);
		min-width: 0;
	}

	#fuzzy-menu-overlay {
		padding: 12px;
	}

	.fm-cols {
		grid-template-columns: 1fr;
		grid-template-rows: 1fr 1fr;
	}

	.fm-col--right {
		border-left: 0;
		border-top: 1px solid var(--fm-line);
	}
}

/* ---------------------------------------------------------------- a11y/motion -- */

@media (prefers-reduced-motion: reduce) {
	#fuzzy-menu-overlay,
	#fuzzy-menu-panel,
	.fm-bar-btn {
		transition: none;
	}
}
