/*
**
**  Fridge - a shared pin-board of cards.
**  @ /app/plugins/fridge/css/fridge.css
**
**  Layout notes:
**  - What a card offers to do with it is one menu behind the dots at its foot,
**    on the line the author's name ends. They come up with the card the pointer
**    is on, and stay up for good where there is no pointer at all (see "card
**    actions").
**  - Saving and discarding are buttons at that same foot, and only while the
**    card is being edited.
*/

/* ------------------------------------------------------------------ board -- */

#fridge-back {
	position: relative;
}

#fridge-main {
	position: relative; /* The messages hang off the foot of the board, see .fridge-status. */
	background-color: var(--f-color-bg-0);
}

.fridge-list {
	list-style-type: none;
	margin: 0;
	min-height: 30px;
	background-color: var(--f-color-bg-0);
}

.fridge-list ul {
	padding: 0;
	list-style: none;
}

.fridge-loading {
	position: absolute;
	right: 35px;
	top: 10px;
}

/* ! Not used? Causes awkward blank space when adding an "empty" fridge */
.fridge-sort:not(:has(li)) {
	display: none;
}

/* ------------------------------------------------------------------ cards -- */

.fridge-card {
	background: var(--f-color-bg-1);
	width: auto;
	height: auto;
	margin-bottom: 0.25rem;
	margin-inline: 0;
	border-radius: var(--f-radius);
	box-shadow: 0 5px 20px color-mix(in srgb, var(--f-color-shadow) 5%);
	box-shadow: 0 3px 5px color-mix(in srgb, var(--f-color-shadow) 50%, transparent);
	/* box-shadow: 0 5px 20px rgba(0, 0, 0, 0.4), 0 2px 5px rgba(0, 0, 0, 0.3); */
	position: relative;
	display: flex;
	flex-direction: column;

	&:hover {
		box-shadow: 0 3px 5px var(--f-color-shadow);
		/* box-shadow: var(--f-drop-shadow); */
	}
}

.fridge-card:not(:first-child) {
	margin-top: 3px;
}

/*
 * Plain text flow, so the author can run inline with it: it is floated to the
 * right and therefore lands on the last line of the card text rather than on a
 * line of its own. A flex item would always be its own column.
 *
 * Positioned, because the dots hang off its foot (see "card actions"), which
 * measures itself against this line-height and this bottom padding.
 */
.fridge-card > p {
	order: 3;
	position: relative;
	padding: 0.75rem 2.75rem 0.75rem 0.75rem;
	margin: 0;
	line-height: 1.3;
}

.fridge-card-head {
	order: 1;
	margin: 0;
	padding: 0;
	position: relative;
	border: 0 !important;
	box-sizing: border-box !important;
}

/*
 * The editor stands where the text it edits stands: same order in the column,
 * same box. Anything else makes the card jump sideways at the double-click.
 */
.fridge-edit-card-form {
	order: 2;
	padding: 4px 0.75rem 12px;
}

.fridge-can-edit .fridge-content {
	cursor: pointer;
}

.fridge-content {
	word-wrap: break-word;
	overflow-wrap: anywhere;
}

/*
 * One card, picked out of the board: what a link from a notification mail lands
 * on (see highlightCard() in js/fridge.js). It is the same treatment one person
 * gets, for the same reason (`.item-avatar.highlight` below): a tinted card was
 * easy to walk past on a full board, so the board takes the colour out of the
 * rest for as long as it lasts, and the card is then the only thing left to
 * look at rather than something that has to be found first.
 *
 * Colour only, no transform: SortableJS reads a transform back as the current
 * position of whatever it is moving, see .fridge-drag-helper.
 */
#fridge-main.is-highlighting-card .fridge-card:not(.highlight) {
	opacity: 0.4;
	filter: grayscale(85%);
}

.fridge-card {
	transition:
		opacity 0.2s ease,
		filter 0.2s ease;
}

.fridge-card.highlight {
	z-index: 10;
	box-shadow:
		0 0 0 3px var(--f-color-alert),
		0 2px 10px rgb(0 0 0 / 40%);
}

.fridge-card.highlight.is-flashing {
	animation: fridge-highlight-flash 0.7s ease-in-out 2;
}

.fridge-card-author {
	float: right;
	position: relative;
	top: 0.5em;
	max-width: 40%;
	margin-inline-start: 0.5rem;
	overflow: hidden;
	text-align: right;
	text-overflow: ellipsis;
	white-space: nowrap;
	/*
	 * A float hangs from the top of the line it lands on, so a shorter line box
	 * would leave the author riding above the text. 0.65 × 2 is the paragraph's
	 * own 1.3 line box, whatever font size the theme sets, so both boxes are the
	 * same height and the small text sits centred on the line with the sentence.
	 */
	font-size: 0.8em;
	line-height: 2;
	color: var(--f-color-text-2);
	visibility: hidden;
}

.fridge-card:hover .fridge-card-author,
.fridge-card:focus-within .fridge-card-author {
	visibility: visible;
}

/* The height is managed in js/fridge.js, growing with the content. */
.fridge-edit-card {
	display: block;
	box-sizing: border-box;
	width: 100%;
	margin: 0;
	resize: none;
	overflow: hidden;
	min-height: 50px;
}

.fridge-card.loading,
.fridge-card .loading {
	opacity: 0.6;
}

/* ---------------------------------------------------------- card actions -- */

/*
 * The dots: the whole of what a card offers to do with it. They sit at the foot
 * of the card, right of the author's name, out of the text's way, and come up
 * with the card the pointer is on, the same way that name does. Where there is
 * no pointer to come up with (see "small screens") they are simply always
 * there, because a screen with no hover to give would otherwise never see the
 * card's actions at all.
 *
 * Faded, not hidden: `visibility` would take the button out of the tab order,
 * and a keyboard is the other way to reach the menu. The card's own
 * `:focus-within` brings them up for it.
 *
 * `.dots` is the shared look of every menu button in Spaces; the menu itself is
 * spaces-markup's and lives in the top layer, so the card's own corner cannot
 * clip it.
 */
.fridge-card-menu {
	position: absolute;
	inset-block-end: 0;
	inset-inline-end: 0;
	z-index: 2;
	/*
	 * As wide as the gutter the paragraph keeps free, and as tall as the last
	 * line of the card plus the paragraph's foot under it: that is the box the
	 * author's name sits in, so the dots come out on the same line as the name
	 * whatever the card says. Not a fixed 2.75rem square, which on a one-line
	 * card would stand up into the avatars above and take the clicks meant for a
	 * face. `font-size`, so that line is the paragraph's and not the button's.
	 */
	inline-size: 2.75rem;
	font-size: inherit;
	block-size: calc(1.3em + 12px);
	color: var(--f-color-text-2);
	opacity: 0;
	transition: opacity 0.15s ease;
}

/* The theme puts a floor under every button, which would undo that height. */
.fridge-card-menu.button {
	min-block-size: 0;
}

.fridge-card:hover .fridge-card-menu,
.fridge-card:focus-within .fridge-card-menu,
.fridge-card-menu[aria-expanded='true'] {
	opacity: 1;
}

.fridge-card-menu:hover,
.fridge-card-menu:focus-visible,
.fridge-card-menu[aria-expanded='true'] {
	color: var(--f-color-text-0);
}

/*
 * Saving and discarding an edit. They are the card's own buttons because they
 * belong to the state it is in, and they are only there while it is in it. They
 * stand at the foot of the card beside the author, which is where a card keeps
 * what can be done with it: the dots the rest of the time, these two while the
 * editor is open.
 */
.fridge-card-icons {
	display: none;
	direction: ltr;
	flex-direction: row;
	flex-wrap: nowrap;
	justify-content: flex-end;
}

.fridge-card-icon {
	display: flex;
	direction: ltr;
	border: 1px solid var(--f-color-bg-0);
	flex: 0 0 auto;
	justify-content: center;
	align-items: center;
	min-width: 2.75rem;
	min-height: 2.75rem;
	cursor: pointer;
	font-size: 15px;
	color: var(--f-color-text-2);
	box-shadow: 1px 1px 0 var(--f-color-bg-0);
	background-color: var(--f-color-bg-1);
	border-radius: var(--f-radius);
	box-sizing: content-box;
	margin: 0 0 0 0.25rem;
}

.fridge-card-icon:hover,
.fridge-card-icon:focus-visible {
	color: var(--f-color-text-0);
	background-color: var(--f-color-bg-2);
}

.editing-card .fridge-card-icons {
	display: flex;
}

/*
 * With the text gone into the editor above, the paragraph is the card's foot
 * and nothing else: the author's name and the two buttons, side by side. The
 * name is a flex item while that lasts, so the float and the nudge that hang it
 * on a line of text have nothing to do here; and the dots are gone, so the
 * gutter that was being kept free for them goes with them.
 */
.editing-card > p {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 0.5rem;
	padding-inline-end: 0.75rem;
	padding-block-end: 0.5rem;
}

.editing-card .fridge-card-author {
	top: 0;
}

/* While editing, the card is the edit form and nothing else. */
.fridge-edit-card-form {
	display: none;
}

.editing-card .fridge-edit-card-form {
	display: block;
}

.editing-card .fridge-content,
.editing-card .fridge-card-menu {
	display: none;
}

/* ---------------------------------------------------------------- avatars -- */

.fridge-avatar-block {
	background-color: var(--f-color-bg-1);
}

.fridge-avatar-block,
.fridge-avatar-goal {
	/* An avatar is as wide as a grid column, and square, up to this cap. */
	--f-avatar-max: 45px;

	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(40px, auto));
	width: 100%;
	border: 0;
}

.fridge-avatar-goal {
	min-height: 4px;
	height: auto;
	margin: 0 !important;
	transition: min-height 0.2s ease-in-out;
}

.item-avatar {
	cursor: pointer;
	position: relative;
}

.fridge-can-edit .item-avatar,
.fridge-can-edit .item-avatar img {
	cursor: move;
}

.item-avatar::before {
	content: "";
	display: block;
	padding-bottom: 100%;
}

.item-avatar:first-child {
	border-radius: var(--f-radius) 0 0 0;
}

.item-avatar:nth-child(8) {
	border-radius: 0 var(--f-radius) 0 0;
}

.item-avatar > :first-child {
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
}

/*
 * One person, picked out of the board: while a name is being typed into the add
 * field, and for a few seconds after "Show on all cards" in an avatar's menu
 * (see highlightUser() in js/fridge.js).
 *
 * A lit avatar on its own was easy to miss among fifty small faces, so the board
 * takes the colour out of the others for as long as it lasts. What is being
 * looked for is then the only thing left to look at, which is a difference that
 * carries across the whole board rather than one that has to be found first.
 */
#fridge-main.is-highlighting .item-avatar:not(.highlight) {
	opacity: 0.4;
	filter: grayscale(85%);
}

/*
 * Colour only: a transition on transform here would be read back by SortableJS
 * as the current position of whatever it is moving, see .fridge-drag-helper.
 */
.item-avatar {
	transition:
		opacity 0.2s ease,
		filter 0.2s ease;
}

.item-avatar.highlight {
	z-index: 10;
	transform: scale(1.15);
	border-radius: 2px;
	box-shadow:
		0 0 0 3px var(--f-color-alert),
		0 2px 10px rgb(0 0 0 / 40%);
	filter: brightness(108%) saturate(115%);
}

/*
 * Two beats when the highlight arrives on its own (from the menu or a link, not
 * from typing): a still picture that simply appears can be missed on a board the
 * pointer is not looking at. Shared with .fridge-card.highlight.
 */
@keyframes fridge-highlight-flash {
	0%,
	100% {
		box-shadow:
			0 0 0 3px var(--f-color-alert),
			0 2px 10px rgb(0 0 0 / 40%);
	}
	50% {
		box-shadow:
			0 0 0 6px var(--f-color-alert),
			0 2px 14px rgb(0 0 0 / 45%);
	}
}

.item-avatar.highlight.is-flashing {
	animation: fridge-highlight-flash 0.7s ease-in-out 2;
}

.fridge-avatar-goal .item-avatar {
	display: block;
	overflow: hidden;
	background-color: var(--f-color-bg-1);
}

.fridge-avatar-block .item-avatar,
.fridge-avatar-block .fridge-avatar,
.fridge-avatar-goal .item-avatar,
.fridge-avatar-goal .fridge-avatar {
	width: 100%;
	max-width: var(--f-avatar-max);
}

.fridge-avatar-block img,
.fridge-avatar-goal img {
	width: 100%;
	height: auto;
	position: absolute;
	z-index: 1;
	transform: scale(1) !important;
}

.fridge-avatar-block .fridge-avatar,
.fridge-avatar-block img {
	/* Make sure the avatars on top don't show the "remove" state. */
	opacity: 1 !important;
}

.fridge-avatar {
	position: relative;
	width: auto;
	height: 49.9px;
	overflow: hidden;
}

/*
 * The theme's search marker. It is decorative and invisible until an avatar is
 * highlighted, but it is a real 14px box in the top right corner, and every
 * click that lands in it is a click the avatar below never sees.
 */
.fridge-avatar .image-search-highlight-dot {
	pointer-events: none;
}

.image-search-highlight-dot {
	position: absolute;
	right: 3px;
	top: 3px;
	height: 14px;
	width: 14px;
	border-radius: 50%;
	display: block;
	overflow: hidden;
	font-family: "empty";
	font-size: 350px;
	line-height: 0;
	color: yellow;
	z-index: 9;
	word-break: break-all;
}

@font-face {
	font-family: empty;
	src: url(empty.ttf);
	font-weight: 400;
}

/* -------------------------------------------------------- drag and drop  -- */

.fridge-can-edit:not(.is-dragging-avatar) .fridge-card:hover {
	cursor: move;
}

.fridge-can-edit.is-dragging-avatar .fridge-card {
	overflow: visible;
}

/* Every card offers its avatar strip as a target while an avatar is in the air. */
.fridge-card-head.drop-zone {
	background: repeating-linear-gradient(
		-48deg,
		var(--f-color-bg-1),
		var(--f-color-bg-1) 5px,
		var(--f-color-bg-2) 5px,
		var(--f-color-bg-2) 12px
	);
	box-shadow: inset 0 2px 6px 0 var(--f-color-bg-2);
	transition: border-color 300ms cubic-bezier(0, 0, 0.2, 1);
}

/*
 * An empty strip opens up to make room. It has to end up at exactly the height
 * the avatar will have, or the card jumps at the moment of the drop. That height
 * is the width of a grid column, which no fixed min-height can know, so the
 * placeholder is a square item in that same grid and measures itself.
 * A strip that already holds avatars is that tall anyway and stays as it is.
 */
.fridge-avatar-goal:not(:has(.item-avatar))::after {
	content: "";
	max-width: var(--f-avatar-max);
	max-height: 0;
	aspect-ratio: 1;
	transition: max-height 0.2s ease-in-out;
}

.drop-zone .fridge-avatar-goal:not(:has(.item-avatar))::after {
	max-height: var(--f-avatar-max);
}

/*
 * SortableJS classes:
 * - fridge-drag-armed       the original, from the moment it is picked up
 * - fridge-drag-placeholder the same element standing in for the drop position
 * - fridge-drag-helper      the copy that follows the pointer (on <body>)
 */
.fridge-drag-armed {
	transform: scale(1.04);
	transition: transform 0.1s ease-out;
}

/*
 * `transform: none` is not decoration. This class is put on the element a
 * moment before the copy above is made, and SortableJS places that copy by
 * measuring the element and then dividing the measurement by whatever scale the
 * element carries. Anything still scaled at that moment (the pick-up pop, or a
 * highlight lit on the same avatar) therefore starts the copy a few percent of
 * the way up the window: about 20px for a board halfway down it, and more the
 * further down the element sits.
 *
 * `transition: none` is the half of it that is easy to miss. A scale eased away
 * over 100ms is still almost all there when the copy is measured a frame later,
 * so it has to be dropped outright rather than animated out.
 *
 * The second selector says the same thing over again for no other reason than
 * to outrank `.item-avatar.highlight` above.
 */
.fridge-drag-placeholder,
.item-avatar.fridge-drag-placeholder {
	transform: none;
	transition: none;
	opacity: 0.4;
	filter: grayscale(80%);
}

.fridge-card.fridge-drag-placeholder {
	box-shadow: inset 0 0 0 2px var(--f-color-border-1);
}

/*
 * The helper is cloned off the element while it still wears the chosen class,
 * so it inherits whatever that class sets. A transition on it is fatal:
 * SortableJS writes the helper's position as a transform on every pointer move
 * and reads that same transform back on the next one, so a half-finished
 * transition is read as the current position and the helper only ever creeps a
 * fraction of the way after the pointer. An animation would fight over the
 * transform in the same way, and the clone of an avatar that is still arriving
 * would carry one. All three are reset here, right where the copy is styled.
 */
.fridge-drag-helper {
	transform: none;
	transition: none;
	animation: none;
	box-shadow: 0 6px 16px rgb(0 0 0 / 25%);
	opacity: 0.95;
	cursor: grabbing;
}

/* ------------------------------------------------------ removing avatars -- */

/*
 * Taking somebody off a card. The card menu on their avatar is the reliable
 * route (it is reachable with a keyboard and needs no gesture); the drop zone
 * below the board is the one that makes the dragging gesture discoverable.
 */
.fridge-remove-zone {
	position: sticky;
	bottom: 0;
	z-index: 100;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	max-height: 0;
	padding: 0 0.75rem;
	overflow: hidden;
	opacity: 0;
	border-radius: var(--f-radius);
	background-color: var(--f-color-bg-2);
	color: var(--f-color-text-1);
	font-size: 0.85rem;
	/* Kept in the flow at zero height, so appearing shifts nothing around. */
	transition:
		max-height 0.15s ease-out,
		padding 0.15s ease-out,
		opacity 0.15s ease-out;
}

.is-removable-drag .fridge-remove-zone {
	max-height: 4rem;
	padding: 0.75rem;
	opacity: 1;
}

/*
 * The avatar hovering over the zone is the drop placeholder, and the label says
 * everything already, so it is only taken out of sight. Not `display: none`:
 * that would zero its box, and SortableJS measures it to work out the drop.
 */
.fridge-remove-zone .item-avatar {
	visibility: hidden;
	width: 1px;
	max-width: 1px;
	margin: 0;
}

.fridge-remove-zone:has(.item-avatar) {
	background-color: var(--f-color-alert);
	color: #fff;
}

/* -------------------------------------------------------------- add card -- */

.fridge-add-card {
	overflow: hidden;
	width: 100%;
	display: none;
}

.fridge-can-edit .fridge-add-card {
	display: flex;
}

.fridge-add-card + .fridge-sort {
	margin-top: 8px;
}

#fridge-input {
	margin: 0;
	width: 100%;
	border-radius: 0 0 0 var(--f-radius);
	border: 0;
	border-top: 1px solid var(--f-color-border-0);
}

.fridge-add-button {
	font-size: 21px;
	line-height: 17px;
	cursor: pointer;
	border-radius: 0 0 var(--f-radius) 0;
}

/* ------------------------------------------------------------- feedback  -- */

/*
 * What the board has to say, over the foot of the board rather than in it.
 *
 * A row in the flow pushed the avatars, the add field and every card down the
 * moment anything was reported, and pulled them back up again when it went, so
 * the board jumped twice per message. Out of the flow it costs no height at all,
 * which is why it is a layer and not a collapsing row like .fridge-remove-zone:
 * that one is the last thing on the board and has nothing below it to shift.
 *
 * It stays inside the widget on purpose. A message about a card belongs with the
 * card it is about, and an "undo" belongs within reach of what it would undo —
 * a toast in the corner of the screen is neither.
 */
.fridge-status {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	/* Under the drop zone (100) and the offline curtain (99): a message must not
	   cover what a drag is aiming at, nor outrank "you are offline". */
	z-index: 98;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.5rem 0.75rem;
	font-size: 0.85rem;
	line-height: 1.3;
	background-color: var(--f-color-bg-2);
	color: var(--f-color-text-0);
	border-radius: var(--f-radius);
	box-shadow: 0 -2px 8px rgb(0 0 0 / 15%);
	animation: fridge-status-in 0.15s ease-out;
}

/* Kept on the `hidden` attribute the board already toggles: with the bar out of
   the flow, showing it is no longer a layout change, so nothing else is needed. */
.fridge-status[hidden] {
	display: none;
}

/* It slides up out of the foot it is attached to. */
@keyframes fridge-status-in {
	from {
		transform: translateY(100%);
		opacity: 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	.fridge-status {
		animation: none;
	}
}

.fridge-status.is-error {
	background-color: var(--f-color-alert);
	color: #fff;
}

/* Pushes the action and close buttons to the far end of the bar. */
.fridge-status > span {
	margin-inline-end: auto;
}

.fridge-status-action {
	flex: 0 0 auto;
	padding: 0.15rem 0.6rem;
	border: 1px solid currentcolor;
	border-radius: var(--f-radius);
	background: none;
	color: inherit;
	font-size: inherit;
	font-weight: 600;
	line-height: 1.4;
	cursor: pointer;
}

.fridge-status-action:hover,
.fridge-status-action:focus-visible {
	background-color: var(--f-color-bg-1);
}

.fridge-status-close {
	padding: 0 0.25rem;
	background: none;
	border: 0;
	color: inherit;
	font-size: 1.1rem;
	line-height: 1;
	cursor: pointer;
}

#fridge-offline-block {
	display: none;
	position: absolute;
	inset: 0;
	z-index: 99;
	background-color: rgb(0 0 0 / 45%);
}

#fridge-offline-block.is-offline {
	display: block;
}

#fridge-offline {
	margin: 0;
	padding: 0.5rem;
	position: absolute;
	left: 5px;
	right: 5px;
	top: 5px;
	text-align: center;
	background-color: var(--f-color-bg-1);
	color: var(--f-color-text-0);
	border-radius: var(--f-radius);
}

/*
 * Changes that arrive from somebody else, see playOnce() in js/fridge.js. The
 * cards moving out of each other's way is SortableJS's own animation, the same
 * one a drag uses; these are only the arrivals and departures, which have no
 * before or after position to glide between.
 */
@keyframes fridge-pop-in {
	from {
		opacity: 0;
		transform: scale(0.4);
	}
}

@keyframes fridge-pop-out {
	to {
		opacity: 0;
		transform: scale(0.4);
	}
}

@keyframes fridge-card-in {
	from {
		opacity: 0;
		transform: translateY(-0.75rem);
	}
}

.item-avatar.is-entering {
	animation: fridge-pop-in 0.25s ease-out;
}

.item-avatar.is-leaving {
	animation: fridge-pop-out 0.2s ease-in forwards;
	pointer-events: none; /* On its way out it is a picture, not a target. */
}

.fridge-card.is-new {
	animation: fridge-card-in 0.3s ease-out;
}

@keyframes fridge-shake {
	0%,
	100% {
		transform: translateX(0);
	}
	20%,
	60% {
		transform: translateX(-6px);
	}
	40%,
	80% {
		transform: translateX(6px);
	}
}

.fridge-shake {
	animation: fridge-shake 0.4s ease;
}

@media (prefers-reduced-motion: reduce) {
	.fridge-shake,
	.fridge-drag-armed,
	.fridge-remove-zone,
	.item-avatar,
	.item-avatar.is-entering,
	.item-avatar.is-leaving,
	.item-avatar.highlight.is-flashing,
	.fridge-card,
	.fridge-card-menu,
	.fridge-card.highlight.is-flashing,
	.fridge-card.is-new {
		animation: none;
		transition: none;
	}
}

/* -------------------------------------------------------------- dialogs  -- */

.fridge-dialog {
	width: min(30rem, calc(100vw - 2rem));
	padding: 1.25rem;
	border: 0;
	border-radius: var(--f-radius);
	background-color: var(--f-color-bg-1);
	color: var(--f-color-text-0);
	box-shadow: 0 8px 30px rgb(0 0 0 / 25%);
}

.fridge-dialog::backdrop {
	background-color: rgb(0 0 0 / 45%);
}

.fridge-dialog h3 {
	margin: 0 0 0.5rem;
	font-size: 1.1rem;
}

.fridge-dialog p {
	margin: 0 0 1rem;
	color: var(--f-color-text-2);
}

.fridge-dialog-actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 0.5rem;
	margin-top: 1rem;
}

.fridge-dialog-actions .button {
	margin: 0;
}

.fridge-message-form label {
	display: block;
	margin-bottom: 0.75rem;
	font-size: 0.85rem;
}

.fridge-message-form input,
.fridge-message-form textarea {
	display: block;
	width: 100%;
	margin-top: 0.25rem;
}

.fridge-message-form textarea {
	resize: vertical;
}

/* Who the mail goes to: one chip per person, a face and a name. */

.fridge-dialog .fridge-recipients-label {
	margin: 0 0 0.25rem;
	font-size: 0.85rem;
}

.fridge-recipients {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
	margin: 0 0 0.75rem;
	padding: 0;
	list-style: none;
	/* A roomful stays a scroll rather than a dialog taller than the screen. */
	max-height: 7.5rem;
	overflow-y: auto;
}

.fridge-recipient {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.15rem 0.6rem 0.15rem 0.15rem;
	border-radius: 999px;
	background-color: var(--f-color-bg-2);
	font-size: 0.8rem;
	line-height: 1.4;
}

.fridge-recipient img {
	width: 1.5rem;
	height: 1.5rem;
	border-radius: 50%;
	object-fit: cover;
}

.fridge-dialog-actions .fridge-mail-cc-label {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin: 0;
	margin-inline-end: auto;
	font-size: 0.85rem;
	white-space: nowrap;
	cursor: pointer;
}

.fridge-dialog-actions .fridge-mail-cc {
	display: inline-block;
	width: auto;
	margin: 0;
}

.fridge-dialog .fridge-mail-status {
	margin: -0.25rem 0 0;
	font-size: 0.85rem;
}

.fridge-dialog .fridge-mail-status[hidden] {
	display: none;
}

.fridge-dialog .fridge-mail-status.is-error {
	color: var(--f-color-alert);
}

.fridge-message-dialog.is-sending .fridge-message-form {
	opacity: 0.65;
}

.fridge-message-dialog.is-sent .fridge-message-form > :not(.fridge-mail-status) {
	display: none;
}

.fridge-message-dialog.is-sent .fridge-mail-status {
	margin: 0.75rem 0 0;
}

.fridge-message-dialog .fridge-dialog-actions .button:not(.hollow).is-loading {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}

.fridge-message-dialog .fridge-dialog-actions .button:not(.hollow).is-loading::before {
	content: "";
	width: 0.8em;
	height: 0.8em;
	border: 2px solid currentcolor;
	border-inline-end-color: transparent;
	border-radius: 50%;
	animation: fridge-spin 0.7s linear infinite;
}

@keyframes fridge-spin {
	to {
		transform: rotate(1turn);
	}
}

@media (prefers-reduced-motion: reduce) {
	.fridge-message-dialog .fridge-dialog-actions .button:not(.hollow).is-loading::before {
		animation: none;
	}
}

/* ------------------------------------------------------- widget wrapper  -- */

/* Fixes a "border around nothing" while the accordion is open. */
.widget_fridge_widget .card,
.widget_fridge_widget .card .accordion {
	transition: border-width 0.2s ease-out;
}

.widget_fridge_widget .card:has(.accordion-item.is-active),
.widget_fridge_widget .card .accordion:has(.accordion-item.is-active) {
	border-width: 0;
}

/* -------------------------------------------------------- small screens  -- */

@media (max-width: 640px), (hover: none) {
	.fridge-card-author {
		visibility: visible;
	}

	.fridge-card-menu {
		opacity: 1;
	}

	/* iOS zooms into any field with a font-size below 16px. */
	#fridge-input,
	.fridge-message-form input,
	.fridge-message-form textarea,
	.fridge-edit-card {
		font-size: 16px;
	}

	.fridge-add-button {
		min-width: 2.75rem;
	}

	.fridge-dialog {
		width: calc(100vw - 1.5rem);
		padding: 1rem;
	}

	.fridge-dialog-actions .button {
		flex: 1 1 8rem;
		min-height: 2.75rem;
	}

	.fridge-message-dialog .fridge-dialog-actions .button {
		flex: 0 1 auto;
		min-width: 5rem;
	}
}

/*
 * Touch: a card is picked up with a press-and-hold (SortableJS `delay`), so the
 * browser must not select text or open its own menu on that gesture.
 */
@media (pointer: coarse) {
	.fridge-can-edit .fridge-card,
	.fridge-can-edit .item-avatar {
		-webkit-touch-callout: none;
		user-select: none;
	}

	.fridge-can-edit .fridge-card.editing-card {
		user-select: auto;
	}

	/* A little more room to drop an avatar on. */
	.drop-zone .fridge-avatar-goal {
		min-height: 48px;
	}
}
