/*
 * Styles shared by the Thymeleaf pages and the Vaadin app.
 *
 * Values come from tokens.css - never a literal colour, size or font here.
 */

/*
 * The board has to be on <html>, not only on <body>.
 *
 * Lumo paints html with --lumo-base-color, which is mapped to the CARD surface so
 * that fields render on white. Left there, the page beyond the body's own box - the
 * strip that scrolls into view under a long form - came up white while the form sat
 * on the board.
 */
html {
	background: var(--ta-color-bg);
}

/* Event imagery stays landscape and subordinate to the invitation, never a social feed billboard. */
.ta-events__cover,
.ta-event__cover,
.ta-event-cover-editor__preview {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: var(--lumo-border-radius-l);
}

/* The list cover is its own rule so shrinking a card cannot shrink the event page's band.
 * At a card's width this is a quiet strip of about 10rem, not the 29rem billboard a
 * full-width 16:9 cover became on a wide list. */
.ta-events__cover {
	max-height: 11rem;
	margin-bottom: var(--ta-space-s);
	border-radius: var(--lumo-border-radius-m);
}

.ta-event__cover {
	margin: var(--ta-space-s) 0 var(--ta-space-m);
}

.ta-event-cover-editor,
.ta-signup-question-editor {
	gap: var(--ta-space-s);
}

.ta-event-cover-editor__empty {
	margin: 0;
	padding: var(--ta-space-l);
	text-align: center;
	color: var(--ta-color-text-secondary);
	background: var(--lumo-contrast-5pct);
	border-radius: var(--lumo-border-radius-l);
}

.ta-event-cover-editor__actions,
.ta-signup-question-editor__custom {
	align-items: center;
}

.ta-event-cover-editor__upload::part(primary-buttons) {
	display: flex;
}

.ta-signup-question-editor__questions {
	gap: var(--ta-space-xs);
}

.ta-signup-question-editor__question {
	box-sizing: border-box;
	padding: var(--ta-space-xs) var(--ta-space-s);
	background: var(--lumo-contrast-5pct);
	border-radius: var(--lumo-border-radius-m);
}

.ta-signup-question-editor__remove {
	min-width: 2.5rem;
	color: var(--ta-color-error);
}

.ta-signup-answers {
	gap: var(--ta-space-xs);
}

.ta-signup-answers__title {
	margin: var(--ta-space-s) 0 0;
	font-family: var(--ta-font-family);
	font-size: var(--lumo-font-size-m);
}

.ta-signup-answers__row {
	box-sizing: border-box;
	padding: var(--ta-space-xs) 0;
}

.ta-signup-answers__label {
	display: flex;
	flex-direction: column;
}

/* Nothing is chosen until the member chooses, so an unanswered question stays
 * visibly unanswered - which a checkbox could not express. Pill shape and the
 * chosen wash are the reaction picker's, so the two choice surfaces read alike. */
.ta-signup-answers__chips {
	flex: 0 0 auto;
	flex-wrap: wrap;
	gap: var(--ta-space-xs);
	align-items: center;
}

.ta-signup-answers__chip {
	--vaadin-button-background: var(--ta-color-surface);
	--vaadin-button-border-color: var(--ta-color-border);
	--vaadin-button-text-color: var(--ta-color-text);
	--vaadin-button-padding: 0 var(--ta-space-s);
	min-width: 2.75rem;
	min-height: 2.75rem;
	margin: 0;
	border-radius: 999px;
}

.ta-signup-answers__chip--chosen {
	--vaadin-button-background: color-mix(in srgb, var(--ta-color-primary) 12%, var(--ta-color-surface));
	--vaadin-button-border-color: var(--ta-color-primary);
	--vaadin-button-text-color: var(--ta-color-text);
	font-weight: 600;
}

.ta-signup-answers__total,
.ta-event-organizer__question-answers,
.ta-event-organizer__question-totals {
	color: var(--ta-color-text-secondary);
	font-size: var(--lumo-font-size-s);
}

.ta-event-organizer__question-totals {
	box-sizing: border-box;
	padding: var(--ta-space-s);
	background: var(--lumo-contrast-5pct);
	border-radius: var(--lumo-border-radius-m);
}

/* The two checkboxes are the whole of the organiser's side, so they are spaced as a
 * short list rather than styled into a panel that would imply more settings inside. */
.ta-practical-needs-editor {
	gap: var(--ta-space-xs);
}

.ta-practical-needs-editor__need {
	margin-top: var(--ta-space-xs);
}

.ta-signup-practical {
	gap: var(--ta-space-xs);
}

.ta-signup-practical__title {
	margin: var(--ta-space-s) 0 0;
	font-family: var(--ta-font-family);
	font-size: var(--lumo-font-size-m);
}

.ta-signup-practical__row {
	box-sizing: border-box;
	flex-wrap: wrap;
	padding: var(--ta-space-xs) 0;
}

/* Deliberately the sign-up answer chips' shape and wash: they sit in the same dialog,
 * a few rows apart, and two choice surfaces that behaved alike but looked different
 * would read as two different kinds of control. */
.ta-signup-practical__choices {
	flex: 0 0 auto;
	flex-wrap: wrap;
	gap: var(--ta-space-xs);
	align-items: center;
}

.ta-signup-practical__chip {
	--vaadin-button-background: var(--ta-color-surface);
	--vaadin-button-border-color: var(--ta-color-border);
	--vaadin-button-text-color: var(--ta-color-text);
	--vaadin-button-padding: 0 var(--ta-space-s);
	min-height: 2.75rem;
	margin: 0;
	border-radius: 999px;
}

.ta-signup-practical__chip--chosen {
	--vaadin-button-background: color-mix(in srgb, var(--ta-color-primary) 12%, var(--ta-color-surface));
	--vaadin-button-border-color: var(--ta-color-primary);
	--vaadin-button-text-color: var(--ta-color-text);
	font-weight: 600;
}

.ta-event-practical__title,
.ta-event-practical__need-title {
	margin: 0;
}

.ta-event-practical__need {
	width: 100%;
	gap: var(--ta-space-xs);
}

/* Seekers are one wrapping line and offers are one row each, which is the panel's whole
 * argument made visible: a driver matches against seats, so the people looking for one
 * are a total, and the people with spare seats are individually askable. */
.ta-event-practical__seeking,
.ta-event-practical__offering {
	display: flex;
	width: 100%;
	box-sizing: border-box;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: var(--ta-space-xs);
	padding: var(--ta-space-xs) 0;
}

.ta-event-practical__direction {
	min-width: 9rem;
	color: var(--ta-color-text-secondary);
}

/* The seeker's number sits next to their name, so it needs its own gap: the row's
 * column-gap does not reach inside this span, and without it the name and the count
 * run together as "Astrid L1". */
.ta-event-practical__party {
	display: inline-flex;
	align-items: baseline;
	column-gap: var(--ta-space-xs);
	margin-right: var(--ta-space-s);
}

.ta-event-practical__count,
.ta-event-practical__help {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

.ta-event-practical__seeking a,
.ta-event-practical__offering a {
	color: var(--ta-color-primary);
	font-weight: 600;
}

/* An announcement is not a post, and the card says so before it is read: no numbered
 * gutter, no reaction strip, no reply affordance - a byline, a time and prose. What it
 * does share is the member chip, so the same person reads the same way in both. */
.ta-event-broadcasts__title {
	margin: 0;
}

.ta-event-broadcasts__help {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

.ta-event-broadcasts__item {
	width: 100%;
	box-sizing: border-box;
	padding: var(--ta-space-s);
	background: var(--lumo-contrast-5pct);
	border-radius: var(--lumo-border-radius-m);
}

.ta-event-broadcasts__byline {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: var(--ta-space-xs);
}

.ta-event-broadcasts__sent {
	color: var(--ta-color-text-secondary);
	font-size: var(--lumo-font-size-s);
}

/* The author's own line breaks are the only structure the text has, so they are the
 * only structure it gets - and pre-wrap is what keeps them, so a body that is two
 * paragraphs in the composer is two paragraphs on the page rather than one run-on line. */
.ta-event-broadcasts__body {
	margin: var(--ta-space-xs) 0 0;
	white-space: pre-wrap;
}

@media (max-width: 34rem) {
	.ta-signup-question-editor__custom {
		flex-wrap: wrap;
	}

	.ta-signup-question-editor__custom > vaadin-text-field {
		flex-basis: 100%;
	}
}

body {
	margin: 0;
	background: var(--ta-color-bg);
	color: var(--ta-color-text);
	font-family: var(--ta-font-family);
	font-size: var(--ta-font-size-m);
	line-height: var(--ta-line-height-body);
}

/*
 * The member shell has one job: keep the three durable destinations available without
 * competing with the cards inside each route. On a phone it is a thumb-reachable tab
 * bar; with room it becomes a quiet rail rather than spending another card surface.
 */
.ta-member-shell {
	min-height: 100dvh;
	box-sizing: border-box;
}

.ta-member-shell__content {
	min-width: 0;
	box-sizing: border-box;
	padding: var(--ta-space-m) var(--ta-space-m)
		calc(4.75rem + env(safe-area-inset-bottom));
}

.ta-member-shell__nav {
	position: fixed;
	z-index: 10;
	inset: auto 0 0;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--ta-space-xs);
	padding: var(--ta-space-xs) var(--ta-space-s)
		calc(var(--ta-space-xs) + env(safe-area-inset-bottom));
	background: var(--ta-color-surface);
	border-top: 1px solid var(--ta-color-border);
	box-shadow: 0 -0.25rem 1rem rgb(27 42 36 / 8%);
}

.ta-member-shell__brand {
	display: none;
}

.ta-member-shell__primary-nav {
	display: contents;
}

.ta-member-shell__link {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 2px;
	min-height: 44px;
	border-radius: var(--ta-radius-m);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	line-height: 1.1;
	text-decoration: none;
}

.ta-member-shell__link:hover,
.ta-member-shell__link--active {
	color: var(--ta-color-primary);
}

.ta-member-shell__link--active {
	font-weight: 600;
	background: rgb(47 93 80 / 8%);
}

@media (min-width: 48rem) {
	.ta-member-shell {
		display: grid;
		grid-template-columns: 14rem minmax(0, 1fr);
	}

	.ta-member-shell__nav {
		position: sticky;
		top: 0;
		align-self: start;
		grid-column: 1;
		display: flex;
		flex-direction: column;
		align-items: stretch;
		gap: var(--ta-space-xs);
		/* height rather than min-height: the padding is part of this rail, and the
		 * bottom profile link must stay inside the viewport rather than slip below it. */
		height: 100dvh;
		box-sizing: border-box;
		padding: var(--ta-space-l) var(--ta-space-m);
		border-top: 0;
		border-right: 1px solid var(--ta-color-border);
		box-shadow: none;
	}

	.ta-member-shell__brand {
		display: flex;
		align-items: center;
		width: fit-content;
		/* The mark is the rail's small home point; navigation remains left-aligned below. */
		margin: 0 auto var(--ta-space-m);
		text-decoration: none;
	}

	.ta-member-shell__logo {
		display: block;
		width: 7rem;
		height: 7rem;
		object-fit: contain;
	}

	.ta-member-shell__primary-nav {
		display: flex;
		flex-direction: column;
		gap: var(--ta-space-xs);
	}

	.ta-member-shell__link {
		flex-direction: row;
		justify-content: flex-start;
		gap: var(--ta-space-s);
		padding: 0 var(--ta-space-s);
		font-size: var(--ta-font-size-m);
	}

	.ta-member-shell__profile {
		margin-top: auto;
	}

	.ta-member-shell__content {
		grid-column: 2;
		min-height: 100dvh;
		padding-bottom: var(--ta-space-xl);
	}
}

.page {
	max-width: var(--ta-content-max-width);
	margin: 0 auto;
	padding: var(--ta-space-l) var(--ta-space-m) var(--ta-space-xl);
}

.page h1 {
	font-size: var(--ta-font-size-xxl);
	line-height: var(--ta-line-height-tight);
	margin: 0 0 var(--ta-space-m);
}

.page h2 {
	font-size: var(--ta-font-size-l);
	line-height: var(--ta-line-height-tight);
	margin: var(--ta-space-l) 0 var(--ta-space-s);
}

.lede {
	font-size: var(--ta-font-size-l);
	color: var(--ta-color-text-secondary);
}

/*
 * The marketing pages' button. Marigold, because on a page with one thing to do the
 * affirmative colour is the whole point of having one - it was spruce, which made the
 * only action on the front page the same colour as every heading and link on it.
 *
 * The rule is at most one per screen region, not "only on sign-up": on a community
 * that is not open there is no sign-up, and then LOG IND is the one action and wears
 * it. landing.html decides which; this file only knows what the two look like.
 */
.button {
	display: inline-block;
	padding: var(--ta-space-s) var(--ta-space-m);
	border-radius: var(--ta-radius-m);
	border: 1px solid transparent;
	background: var(--ta-color-affirm);
	color: var(--ta-color-affirm-text);
	font-weight: 600;
	text-decoration: none;
}

.button:hover {
	background: var(--ta-color-affirm-hover);
}

/*
 * The other one. A button rather than a bare link, because a bare link beside a solid
 * button reads as an afterthought and is a poor target for a thumb - the same reason
 * the login page's Google button stopped being an anchor.
 */
.button--secondary {
	background: var(--ta-color-surface);
	border-color: var(--ta-color-border);
	color: var(--ta-color-primary);
	font-weight: 400;
}

.button--secondary:hover {
	background: var(--ta-color-surface);
	border-color: var(--ta-color-primary);
}

.site-footer {
	max-width: var(--ta-content-max-width);
	margin: 0 auto;
	padding: var(--ta-space-m);
	border-top: 1px solid var(--ta-color-border);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.site-footer a {
	color: inherit;
	margin-right: var(--ta-space-m);
}

/*
 * Profile editor.
 *
 * Deliberately minimal. The palette in tokens.css is still the placeholder set the
 * skeleton was stood up with, and UX_DESIGN.md's real direction (spruce, marigold,
 * rust; Familjen Grotesk over Source Serif 4) has not been turned into tokens yet.
 * Anything expressive written now would have to be rewritten then - so this does
 * layout and grouping only, entirely through tokens, and survives the swap.
 */
.ta-profile {
	display: grid;
	/* 32rem is wide enough for a card to retain its own field hierarchy. min() makes
	 * the same rule safe on a narrow phone, where one card simply owns the whole row. */
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 32rem), 1fr));
	align-items: start;
	gap: var(--ta-space-l);
	padding: var(--ta-space-m);
	/*
	 * A member settings page contains independent cards, not one giant form. It can
	 * therefore be wider than a form, but stops before a desktop turns every card
	 * into an empty billboard. Each card owns its own field measure.
	 */
	max-width: var(--ta-profile-layout-max);
	margin: 0 auto;
	box-sizing: border-box;
}

/* Page words and the completion errand describe the whole page, never one card. */
.ta-profile > h1,
.ta-profile > .ta-profile__welcome,
.ta-profile > .ta-profile__completion-card,
.ta-profile > .ta-profile__elsewhere-row {
	grid-column: 1 / -1;
}

.ta-profile > h1 {
	margin: 0;
}

/*
 * A column packs its own cards; only the columns themselves are grid items.
 *
 * The cards used to be the grid items directly, and an auto-fit grid gives every row
 * the height of its tallest cell. The portrait - three lines and four buttons - sat
 * beside the full profile form and was followed by a void the height of that form, and
 * "Indstillinger" then had to start a row of its own with an empty cell beside it. No
 * amount of `align-items` fixes that: the gap is the row, not the alignment inside it.
 * Two stacks have no shared rows to be ragged.
 */
.ta-profile__column {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: var(--ta-space-l);
	/* A grid item's automatic minimum is its content, which a long address line or an
	 * unbroken email would otherwise use to push the column past its track. */
	min-width: 0;
}

/* AccountSection retains its identity (not display: contents) so a return from a
 * provider can still scroll to it. Inside its column it is simply the stack's next
 * two cards, not a second responsive pair. */
.ta-profile__account {
	display: flex;
	flex-direction: column;
	gap: var(--ta-space-l);
	margin: 0;
	min-width: 0;
}

/* A card title is never reused as an internal section heading. The old shared class
 * created the empty band above account titles and made “Adgangskode” look unrelated
 * to both titles and labels. */
.ta-card__title {
	margin: 0 0 var(--ta-space-m);
	font-size: var(--ta-font-size-m);
	color: var(--ta-color-text-secondary);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

/* Two-factor and password are real subdivisions of one card: quieter than its title,
 * stronger than a field label. */
.ta-card__section-title {
	margin: var(--ta-space-m) 0 var(--ta-space-xs);
	font-size: var(--ta-font-size-m);
	font-weight: 600;
}

.ta-profile__welcome {
	color: var(--ta-color-text-secondary);
}

.ta-card__save {
	margin-top: var(--ta-space-m);
}

.ta-profile__settings-fields {
	max-width: 34rem;
}

.ta-profile__uploads-link {
	display: inline-block;
	margin-top: var(--ta-space-m);
	color: var(--ta-color-primary);
}

.ta-profile__uploads-link:hover {
	text-decoration: underline;
}

/* The events list is a calendar before it is a catalogue. Date headers therefore
 * group cards; the understated meeting area is the public orientation clue, never
 * the hidden coordinate used for distance. */
.ta-events {
	width: 100%;
	max-width: 82rem;
	box-sizing: border-box;
	margin: 0 auto;
	padding: var(--ta-space-m);
}

.ta-events__discovery {
	align-items: flex-start;
	gap: var(--ta-space-l);
}

.ta-events__list {
	flex: 1 1 48rem;
	min-width: 0;
	gap: var(--ta-space-s);
}

.ta-events__filter-rail {
	flex: 0 0 clamp(19rem, 24vw, 23rem);
	position: sticky;
	top: var(--ta-space-m);
	box-sizing: border-box;
}

.ta-events__filter-title {
	margin: 0;
	font-size: var(--ta-font-size-l);
}

.ta-events__filter-controls {
	gap: var(--ta-space-m);
}

.ta-events__scope {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--ta-space-s);
}

.ta-events__filter-actions {
	flex-wrap: wrap;
}

.ta-events__filter-actions vaadin-button {
	flex: 1 1 auto;
}

/* A saved search is one small object: its selected name and every
 * operation on that object live together. Splitting “save” from “remove” across a
 * long filter form made it needlessly hard to tell what the buttons applied to. */
.ta-events__saved-actions {
	flex-wrap: wrap;
}

.ta-events__saved-actions vaadin-button {
	flex: 1 1 auto;
}

/* The labels teach the three operations on a wide rail. In the mobile sheet they
 * would consume the whole first screen before a member reaches a single criterion,
 * so the same operations become one stable row: save, save-as, and a recognisable
 * bounded bin. Nothing moves into an undiscoverable overflow menu. */
.ta-events__saved-action--compact {
	display: none;
}

.ta-events__header {
	gap: var(--ta-space-m);
}

.ta-events__header h1 {
	min-width: 0;
}

.ta-events__actions {
	flex-wrap: nowrap;
	justify-content: flex-end;
}

/* On phones this is the filter state, not merely a command labelled “Filters”.
 * Both lines are inside a real button so the whole compact summary opens the
 * same form that is permanently visible in the desktop rail. */
.ta-events__filter-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--ta-space-s);
	min-height: var(--lumo-size-l);
	padding: var(--ta-space-xs) var(--ta-space-s);
	border: 1px solid var(--ta-color-border);
	border-radius: var(--lumo-border-radius-m);
	background: var(--ta-color-surface);
	color: var(--ta-color-primary);
	font: inherit;
	text-align: left;
	cursor: pointer;
}

.ta-events__filter-toggle:hover {
	background: var(--lumo-contrast-5pct);
}

.ta-events__filter-toggle:focus-visible {
	outline: 3px solid var(--lumo-primary-color-50pct);
	outline-offset: 2px;
}

.ta-events__filter-summary-text {
	display: flex;
	flex-direction: column;
	line-height: 1.2;
}

.ta-events__filter-summary-text span:first-child {
	font-weight: 600;
}

.ta-events__filter-summary-text span:last-child {
	font-size: var(--ta-font-size-s);
	color: var(--ta-color-text-secondary);
}

.ta-events__filter-summary-chevron {
	flex: 0 0 auto;
}

/* The rail is already the open filter form on a wide screen. Leaving the sheet
 * trigger there as well created two independent-looking copies of the same state. */
@media (min-width: 64.0625rem) {
	.ta-events__filter-toggle {
		display: none;
	}
}

/* The heading names the week; the card names the day. Grouping by day printed the same
 * date twice and left the grid below it mostly one-card rows. */
.ta-events__week {
	position: sticky;
	top: 0;
	z-index: 1;
	padding: var(--ta-space-xs) 0;
	background: var(--ta-color-bg);
	margin: var(--ta-space-l) 0 var(--ta-space-xs);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.ta-events__week:first-child {
	margin-top: 0;
}

/* One rule gives both readings the list needed: equal-width cards several abreast on a
 * desktop, exactly one per row on a phone. The `min()` floor matters - a bare 20rem track
 * is wider than a 320px viewport once the page padding is taken off, and holds the page
 * open sideways. Never CSS columns or masonry: they reflow column-major, which scatters
 * the sticky headings and stops `position: sticky` applying at all. */
.ta-events__grid,
.ta-forum__grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
	gap: var(--ta-space-s);
	width: 100%;
}

.ta-events__card {
	height: 100%;
	gap: var(--ta-space-xs);
}

/* The utility face: weekday, day and time, with no year - the heading above has the week. */
.ta-events__when {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	font-weight: 600;
	text-transform: uppercase;
}

/* Last in the card and pushed to its floor, so a row of equal-height cards shares one
 * baseline for who is inviting you rather than ending wherever the text happened to stop. */
.ta-events__organizer {
	margin-top: auto;
	padding-top: var(--ta-space-xs);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	display: flex;
	align-items: baseline;
	gap: var(--ta-space-xs);
	min-width: 0;
}

/* Who is inviting you, on the event page. Same pair as the card's line, with the page's
   room for it. */
.ta-event__organizer {
	display: flex;
	align-items: baseline;
	gap: var(--ta-space-xs);
	margin-top: var(--ta-space-xs);
	color: var(--ta-color-text-secondary);
}

.ta-events__seats {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--ta-space-xs);
	margin-top: var(--ta-space-xs);
}

.ta-events__seat-dots {
	color: var(--ta-color-primary);
	letter-spacing: 0.1em;
}

.ta-events__seat-count {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

/* An event card is one clear link, rather than a title link hidden inside a card.
 * The entire invitation is the target, which is both easier to tap and truthful. */
.ta-events__card-link {
	display: block;
	color: inherit;
	text-decoration: none;
	border-radius: var(--ta-radius-l);
}

/*
 * Only the title underlines.
 *
 * Lumo underlines any hovered anchor, and text decoration propagates to in-flow
 * descendants - so on a card that IS a link, one rule underlines the date, the
 * price, the meeting area and the organiser line all at once. Resetting it here
 * and re-applying it to the title alone keeps the affordance and drops the mess.
 */
.ta-events__card-link:hover,
.ta-events__card-link:focus-visible {
	text-decoration: none;
}

.ta-events__card-link:hover .ta-events__title,
.ta-events__card-link:focus-visible .ta-events__title {
	text-decoration: underline;
}

.ta-events__card-link:focus-visible {
	outline: 3px solid var(--ta-color-primary);
	outline-offset: 3px;
}

/*
 * Pointing at a card lifts the note off the board.
 *
 * Not a zoom: scale() would overlap the neighbouring cards in the grid, resample
 * the cover photo, and move the card's edge under a stationary cursor, which makes
 * the hover flicker along the boundary. A lift says the same thing and stays put.
 *
 * Hover-capable pointers only - on touch there is no un-hover, so a tapped card
 * would stay lifted until something else was tapped.
 */
@media (hover: hover) and (pointer: fine) {
	.ta-events__card {
		transition: box-shadow 120ms ease-out, transform 120ms ease-out;
	}

	.ta-events__card-link:hover .ta-events__card {
		box-shadow: var(--ta-shadow-card-raised);
		transform: translateY(-2px);
	}
}

/* The lift is a state, not an animation: reduced motion keeps it and drops the travel. */
@media (prefers-reduced-motion: reduce) {
	.ta-events__card {
		transition: none;
	}
}

.ta-events__title {
	font-size: var(--ta-font-size-l);
	font-weight: 600;
}

.ta-events__meeting-area {
	color: var(--ta-color-text-secondary);
}

/* Dot-joined prose read as a subtitle. A pill says "vocabulary you can search by" - and
 * carries no hash mark, because `#` already means a post reference in this app. */
.ta-events__tags {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ta-space-xs);
	margin: var(--ta-space-xs) 0;
}

.ta-events__tag {
	padding: 0.1rem var(--ta-space-s);
	background: var(--lumo-contrast-5pct);
	border: 1px solid var(--ta-color-border);
	border-radius: 999px;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	white-space: nowrap;
}

.ta-events__relation {
	color: var(--ta-color-primary);
	font-size: var(--ta-font-size-s);
	font-weight: 600;
}

/* Tags add a compact line of orientation without turning an event card into a
 * parade of pills. Their meaning is discovery, not a second title. */
.ta-events__tags {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-events__price {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

/* The event page pairs the invitation with exactly one decision card.  There is no
 * separate “capacity” screen: the member sees the available fact beside the action. */
.ta-event {
	max-width: 52rem;
	margin: 0 auto;
}

.ta-event__facts,
.ta-event__signup {
	gap: var(--ta-space-m);
}

.ta-event__back {
	align-self: flex-start;
	color: var(--ta-color-primary);
}

.ta-event__title {
	margin: 0;
}

.ta-event__status {
	display: inline-flex;
	align-self: flex-start;
	margin: 0;
	padding: var(--ta-space-xs) var(--ta-space-s);
	border-radius: var(--lumo-border-radius-m);
	background: var(--lumo-contrast-5pct);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-event__status--cancelled {
	background: color-mix(in srgb, var(--ta-color-error) 10%, transparent);
	color: var(--ta-color-error);
}

.ta-event__organizer-actions {
	width: 100%;
	margin-top: var(--ta-space-s);
}

.ta-event__cancel {
	--vaadin-button-text-color: var(--ta-color-error);
	--vaadin-button-border-color: var(--ta-color-error);
	--vaadin-button-border: 1px solid var(--ta-color-error);
}

.ta-event__description,
.ta-event__payment,
.ta-event__location,
.ta-event__capacity,
.ta-event__signup-help {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

.ta-event__party {
	width: 100%;
	flex-wrap: wrap;
}

/* The address an organiser withheld, once it is this reader's to have - and, before
 * that, the date it arrives. Set apart from the public facts above it with a quiet
 * inset rather than a warning colour: it is not an alarm, it is the half of the
 * invitation that waits. The left edge is the only ornament, so the block still reads
 * as part of the same card at a phone width. */
.ta-event__participant-details {
	width: 100%;
	margin-top: var(--ta-space-s);
	padding: var(--ta-space-s) var(--ta-space-m);
	border-left: 3px solid var(--ta-color-primary);
	border-radius: 0 var(--ta-radius-m) var(--ta-radius-m) 0;
	background: var(--ta-color-bg);
}

.ta-event__participant-details-title {
	font-weight: 600;
	color: var(--ta-color-primary);
}

.ta-event__participant-details-line {
	margin: var(--ta-space-xs) 0 0;
	white-space: pre-wrap;
}

.ta-event__participant-details-label {
	font-weight: 600;
}

.ta-event__participant-details-note {
	margin: var(--ta-space-xs) 0 0;
	color: var(--ta-color-text-secondary);
	font-size: var(--lumo-font-size-s);
}


.ta-event__party vaadin-integer-field {
	flex: 1 1 12rem;
}

/* Participant management starts where the event is read. Two disclosure rows preserve
 * the distinction between attendees and waiting parties without creating another page
 * for a handful of names; long lists stay closed until the organiser asks for them. */
.ta-event-organizer__title {
	margin: 0;
}

.ta-event-organizer__capacity,
.ta-event-organizer__help,
.ta-event-organizer__party,
.ta-event-organizer__attendance-state {
	color: var(--ta-color-text-secondary);
	font-size: var(--lumo-font-size-s);
}

.ta-event-organizer__attendance-actions {
	width: 100%;
}

.ta-event-organizer__list {
	width: 100%;
}

.ta-event-organizer__rows {
	padding-top: var(--ta-space-xs);
}

/* No rule between rows. The padding is the separation: a line per name turned a short
 * list of people into a table, and there is nothing in a row that needs fencing off from
 * the row below it. */
.ta-event-organizer__participant {
	box-sizing: border-box;
	gap: var(--ta-space-m);
	padding: var(--ta-space-s) 0;
}

.ta-event-organizer__participant > vaadin-vertical-layout {
	min-width: 0;
}

.ta-event-organizer__participant a {
	color: var(--ta-color-primary);
	font-weight: 600;
}

/* Name and party on one line, so the list is read down a single left edge. The suffix
 * wraps under a long name rather than pushing the row wider. */
.ta-event-organizer__name {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: var(--ta-space-xs);
}

.ta-event-organizer__actions {
	margin-left: auto;
	flex-wrap: wrap;
	justify-content: flex-end;
}

.ta-event-organizer__payment {
	width: 9rem;
}

.ta-event-organizer__remove {
	--vaadin-button-text-color: var(--ta-color-error);
	--vaadin-button-border-color: var(--ta-color-error);
}

@media (max-width: 36rem) {
	.ta-event-organizer__participant {
		align-items: flex-start;
		flex-direction: column;
	}

	.ta-event-organizer__actions {
		margin-left: 0;
	}
}

/* The same two disclosure rows a member sees on their own event, minus everything only
 * an organiser may do. Names read down one left edge; the party suffix rides on the name
 * line and wraps under a long one, exactly as it does in the organiser's list. */
.ta-event-participants__title {
	margin: 0;
}

.ta-event-participants__help,
.ta-event-participants__party {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

/* Bordered rather than merely grey, and it has to be: it sits on the same line as the
 * party suffix, which is already quiet text, and "Bo K (+ 1 gaest) Inaktiv" in one colour
 * reads as one phrase. The word carries no cause - paused and suspended are this same
 * marker, and only an administrator sees which. */
/*
 * The member chip. One appearance wherever a member is named, in three densities that
 * differ in spacing and weight and never in what they say. .ta-member__inactive is also
 * emitted by RichTextService beside a rendered @mention, which is why the marker rule
 * stands on its own rather than inside a density.
 */
.ta-member {
	display: inline-flex;
	align-items: baseline;
	gap: var(--ta-space-xs);
}

.ta-member--card,
.ta-member--row {
	max-width: 100%;
}

/*
 * The round portrait frame UX_DESIGN.md asks for, and the monogram that stands in for it.
 * Sized per density so a chip never dictates the height of the line it sits in: the
 * portrait is set in em, so it tracks whatever type size the surrounding surface uses.
 */
.ta-member__avatar {
	flex: none;
	width: 1.75em;
	height: 1.75em;
	border-radius: 50%;
	object-fit: cover;
	/* The board, which is the recess in this palette - chips sit on a note. Secondary
	   ink on it is 5.7:1, so a monogram clears body-text contrast. */
	background: var(--ta-color-bg);
	align-self: center;
}

.ta-member__avatar--monogram {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: 0.75em;
	line-height: 1;
	font-weight: 600;
	color: var(--ta-color-text-secondary);
	/* The em sizing above is relative to this element's own reduced font-size, so the
	   circle has to be restated or the monogram is visibly smaller than a portrait. */
	width: 2.33em;
	height: 2.33em;
}

.ta-member--inline .ta-member__avatar {
	width: 1.5em;
	height: 1.5em;
}

.ta-member--inline .ta-member__avatar--monogram {
	width: 2em;
	height: 2em;
}

.ta-member__name {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ta-member--card .ta-member__name {
	font-weight: 500;
}

.ta-member__inactive {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	line-height: 1;
	padding: 0.15rem 0.4rem;
	border: 1px solid var(--ta-color-border);
	border-radius: var(--ta-radius-s);
	white-space: nowrap;
}

/*
 * Beside a rendered @mention the marker is emitted on its own by RichTextService, with no
 * chip around it to supply the flex gap - so it buys its own space, from the name before
 * it and from whatever punctuation follows.
 */
.ta-prose .ta-member__inactive {
	margin-inline: 0.25rem;
}

.ta-event-participants__list {
	width: 100%;
}

.ta-event-participants__rows {
	padding-top: var(--ta-space-xs);
}

/* Names only, so the padding is the whole separation - see .ta-event-organizer__participant. */
.ta-event-participants__participant {
	display: flex;
	width: 100%;
	box-sizing: border-box;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: var(--ta-space-xs);
	padding: var(--ta-space-xs) 0;
}

.ta-event-participants__participant a {
	color: var(--ta-color-primary);
	font-weight: 600;
}

.ta-events__availability-actions {
	align-items: center;
}

.ta-events__availability-label--mobile {
	display: none;
}

.ta-events__availability-day-mask {
	display: inline-flex;
	gap: 0.1rem;
}

.ta-events__availability-day-letter {
	border-radius: 0.25rem;
	padding: 0 0.16rem;
}

.ta-events__availability-day-letter--selected {
	background: var(--ta-color-primary);
	color: var(--ta-color-surface);
}

.ta-events__availability-help {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

.ta-events__availability-clear {
	min-width: auto;
}

.ta-events__availability-options {
	align-items: center;
}

/* A week is a column of decisions, not a small card for every other weekday.
 * The one surrounding card becomes two columns only when the member really
 * distinguishes even from odd ISO weeks. */
.ta-events__availability-weeks {
	box-sizing: border-box;
	padding: var(--ta-space-m);
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--ta-space-l);
}

.ta-events__availability-weeks--alternating {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Times need room for two pickers and a weekday. Keeping the weeks next to one
 * another would make both choices harder to read than the week distinction is. */
.ta-events__availability-weeks--times {
	grid-template-columns: minmax(0, 1fr);
}

.ta-events__availability-week {
	min-width: 0;
}

.ta-events__availability-week-title {
	margin: 0 0 var(--ta-space-s);
	font-family: var(--ta-font-sans);
	font-size: var(--ta-font-size-m);
}

.ta-events__availability-week-heading {
	justify-content: flex-start;
}

.ta-events__availability-week-heading--unlabelled {
	justify-content: flex-start;
}

.ta-events__availability-week-heading .ta-events__availability-week-title {
	margin: 0;
}

.ta-events__availability-days {
	display: flex;
	flex-direction: column;
	gap: var(--ta-space-xs);
	margin-top: var(--ta-space-s);
}

.ta-events__availability-day {
	align-items: center;
	box-sizing: border-box;
	padding: 0;
}

.ta-events__availability-day vaadin-checkbox {
	flex: 1 1 9rem;
}

.ta-events__availability-day vaadin-time-picker {
	flex: 1 1 6rem;
}

/* Passive time fields deliberately borrow the disabled field's visual language,
 * but remain clickable: a click is how someone says this weekday should have a
 * time. Keyboard users do not encounter them until the weekday is selected. */
.ta-events__availability-time--passive {
	--vaadin-input-field-background: var(--lumo-contrast-10pct);
	--vaadin-input-field-value-color: var(--lumo-disabled-text-color);
	--vaadin-input-field-icon-color: var(--lumo-disabled-text-color);
}

.ta-events__availability-time--passive::part(input-field) {
	color: var(--lumo-disabled-text-color);
}

.ta-events__availability-time-actions {
	align-items: center;
}

/*
 * One location question, two answers - the profile form's address question, repeated for
 * the event. The control that saves a member typing anything at all is the first thing
 * they meet; the quiet bridge names typing as the other choice. See
 * .ta-profile__address-question, which these deliberately duplicate: a shared rule would
 * have to live in whichever view was styled first.
 */
.ta-events__place-question {
	gap: var(--ta-space-s);
}

.ta-events__place-alternative {
	align-self: center;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	margin: var(--ta-space-xs) 0;
}

.ta-events__locate {
	width: 100%;
	margin: 0;
}

@media (max-width: 38rem) {
	.ta-events__availability-label--desktop {
		display: none;
	}

	.ta-events__availability-label--mobile {
		display: inline;
	}

	.ta-events__availability-day {
		align-items: center;
		flex-wrap: nowrap;
		gap: var(--ta-space-xs);
	}

	.ta-events__availability-day vaadin-checkbox {
		flex: 1 1 0;
		min-width: 0;
	}

	.ta-events__availability-day vaadin-time-picker {
		/* 6rem fits both 17.00 and a locale such as 5:00 PM with the clock
		 * affordance. The weekday receives the remaining width, so the three
		 * controls stay one useful row on an ordinary phone. */
		flex: 0 1 6rem;
		min-width: 0;
	}
}

@media (max-width: 44rem) {
	.ta-events__availability-weeks--alternating {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* The timed private details are a real subsection, not another field helper.
 * Their heading tells the organiser who receives these facts; its small lead tells
 * them when, once for the whole group rather than under every field. */
.ta-events__editor-section {
	margin: var(--ta-space-m) 0 0;
	font-family: var(--ta-font-family);
	font-size: var(--ta-font-size-m);
	font-weight: 600;
}

.ta-events__editor-section-help {
	margin: calc(-1 * var(--ta-space-s)) 0 0;
	color: var(--ta-color-text-secondary);
}

/* The age range is an ordinary optional fact about the event, not another major
 * editor section. The shared label and compact from/to pair make that visible. */
.ta-events__editor-field-label {
	font-size: var(--ta-font-size-m);
	font-weight: 500;
}

.ta-events__editor-child-age-range {
	width: 100%;
}

.ta-events__editor-child-age-range vaadin-integer-field {
	flex: 0 1 8rem;
	max-width: 9rem;
}

.ta-events__editor-child-age-years {
	margin-bottom: 0.7rem;
	color: var(--ta-color-text-secondary);
}

/* The event editor's two actions are deliberately short enough to keep one stable row,
 * including on a phone. Both remain visibly bounded buttons. */
.ta-events__editor-footer {
	display: flex;
	justify-content: flex-end;
	gap: var(--ta-space-s);
}

/* Finding a location is an exception, not a second half of the form. The help lives in
 * its own small dialog and splits its two genuinely different answers into two blocks. */
.ta-location-guide {
	gap: var(--ta-space-m);
}

.ta-location-guide__introduction {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

.ta-location-guide__maps {
	align-self: flex-start;
}

.ta-location-guide__methods {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--ta-space-s);
	width: 100%;
}

.ta-location-guide__method {
	box-sizing: border-box;
	padding: var(--ta-space-m);
	border: 1px solid var(--ta-color-border);
	border-radius: var(--ta-radius-m);
	background: var(--lumo-contrast-5pct);
}

.ta-location-guide__method h3 {
	margin: 0 0 var(--ta-space-xs);
	font-family: var(--ta-font-family);
	font-size: var(--ta-font-size-m);
	font-weight: 600;
}

.ta-location-guide__method p {
	margin: 0;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-location-guide__method .ta-location-guide__how-to {
	margin-top: var(--ta-space-m);
	color: var(--ta-color-text);
	font-weight: 600;
}

.ta-location-guide__method .ta-location-guide__instruction {
	margin-top: var(--ta-space-xs);
}

.ta-location-guide__footer {
	display: flex;
	justify-content: flex-end;
}

@media (max-width: 36rem) {
	.ta-events__header {
		flex-direction: column;
		align-items: flex-start;
	}

	.ta-events__actions {
		width: 100%;
		justify-content: space-between;
	}

	.ta-events__actions vaadin-button {
		flex: 0 1 auto;
		white-space: nowrap;
	}

	.ta-events__actions .ta-events__filter-toggle {
		flex: 1 1 auto;
	}

	.ta-events__create {
		margin-left: auto;
	}

	.ta-location-guide__methods {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 64rem) {
	.ta-events__saved-actions {
		flex-wrap: nowrap;
		align-items: stretch;
	}

	.ta-events__saved-action--desktop {
		display: none;
	}

	.ta-events__saved-action--compact {
		display: inline-flex;
		flex: 0 1 auto;
		white-space: nowrap;
	}

	.ta-events__saved-actions > .ta-events__saved-remove-icon {
		flex: 0 0 2.5rem;
		min-width: 2.5rem;
		padding: 0;
	}

	.ta-events__saved-actions > vaadin-button:not(.ta-events__saved-action--desktop):not(.ta-events__saved-remove-icon) {
		flex: 1 1 auto;
	}

	.ta-events__filter-rail {
		display: none;
	}

	.ta-events__discovery {
		display: block;
	}

}

/* A private image inventory is visual first. The source order stays chronological, while
 * flex bases calculated from the real image dimensions make each row a justified gallery:
 * different aspect ratios, no empty desktop width, and no CSS-column reordering trap. */
.ta-uploads {
	width: 100%;
	max-width: var(--ta-gallery-max-width);
	box-sizing: border-box;
	margin: 0 auto;
	padding: var(--ta-space-m);
}

.ta-uploads__intro,
.ta-uploads__quota,
.ta-uploads__size,
.ta-uploads__uses,
.ta-uploads__empty {
	color: var(--ta-color-text-secondary);
}

.ta-uploads__intro {
	margin: 0;
}

.ta-uploads__quota {
	display: block;
	margin-bottom: var(--ta-space-s);
	font-size: var(--ta-font-size-s);
}

.ta-uploads__empty {
	margin: 0;
}

.ta-uploads__size {
	font-size: var(--ta-font-size-s);
	margin-bottom: var(--ta-space-xs);
}

.ta-uploads__uses {
	gap: var(--ta-space-xs);
	margin-left: var(--ta-space-m);
}

.ta-uploads__actions {
	width: 100%;
	flex-wrap: wrap;
}

.ta-image-gallery {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: var(--ta-space-m);
	width: 100%;
}

.ta-image-gallery__image {
	display: block;
	width: 100%;
	aspect-ratio: var(--ta-image-aspect, 1);
	object-fit: cover;
	border-radius: var(--ta-radius-m);
	background: var(--lumo-contrast-5pct);
}

.ta-uploads__tile {
	min-width: 9rem;
	overflow: hidden;
	border: 1px solid var(--ta-color-border);
	border-radius: var(--ta-radius-m);
	background: var(--ta-color-surface);
}

.ta-uploads__tile--selected {
	border-color: var(--ta-color-primary);
	box-shadow: 0 0 0 1px var(--ta-color-primary);
}

.ta-uploads__tile .ta-image-gallery__image {
	border-radius: 0;
	cursor: pointer;
}

.ta-uploads__details {
	box-sizing: border-box;
	min-height: 4.7rem;
	padding: var(--ta-space-s) var(--ta-space-s) 0;
}

.ta-uploads__metadata {
	align-items: center;
}

.ta-uploads__metadata .ta-uploads__size {
	margin: 0;
}

.ta-uploads__metadata vaadin-checkbox {
	margin-left: auto;
}

.ta-uploads__use {
	color: var(--ta-color-primary);
	text-decoration: none;
}

.ta-uploads__use:hover {
	text-decoration: underline;
}

.ta-uploads__use-kind {
	margin-top: var(--ta-space-xs);
	font-weight: 600;
}

.ta-uploads__post-references-list {
	margin-left: var(--ta-space-m);
}

.ta-uploads__section-heading {
	display: block;
	margin-top: var(--ta-space-m);
	font-weight: 600;
}

.ta-uploads__consequences p {
	margin: 0 0 var(--ta-space-xs);
}

.ta-uploads__consequences {
	margin-left: var(--ta-space-m);
}

.ta-uploads__consequences p:last-child {
	margin-bottom: 0;
}

.ta-image-gallery__pick {
	/* A real image is the clickable object. This deliberately is not a Vaadin
	 * button with an image treated as a 1em icon: its measured box is the image. */
	box-sizing: border-box;
	min-width: 7rem;
	overflow: hidden;
	padding: 0;
	border: 2px solid transparent;
	border-radius: var(--ta-radius-m);
	background: transparent;
}

.ta-image-gallery__pick:hover {
	border-color: var(--ta-color-primary);
	cursor: pointer;
}

.ta-image-gallery__pick:focus-visible {
	outline: 3px solid var(--ta-color-affirm);
	outline-offset: 2px;
}

.ta-image-gallery__pick .ta-image-gallery__image {
	border-radius: calc(var(--ta-radius-m) - 2px);
}

/* A portrait is a small profile attribute, not a second profile form. */
.ta-profile-picture {
	margin: 0 0 var(--ta-space-m);
	gap: var(--ta-space-m);
}

/* Outside the profile card, so no save button appears to govern something that saves
 * itself. It sits against the board rather than on a surface of its own, which is what
 * says "attribute", not "second form". */
.ta-profile__portrait {
	box-sizing: border-box;
	width: 100%;
	padding: 0 var(--ta-space-m);
	align-items: center;
	/* Its column already spaces its cards. The editor's own bottom margin is for the
	 * layouts that place it without one, and here it just made this one gap wider. */
	margin-bottom: 0;
}

.ta-profile-picture__portrait,
.ta-profile-picture__empty {
	width: 5rem;
	height: 5rem;
	border-radius: 50%;
	flex: 0 0 auto;
}

.ta-profile-picture__portrait {
	object-fit: cover;
	background: var(--lumo-contrast-5pct);
}

.ta-profile-picture__empty {
	display: grid;
	place-items: center;
	box-sizing: border-box;
	padding: var(--ta-space-xs);
	border: 1px dashed var(--ta-color-border);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	text-align: center;
}

.ta-profile-picture__words {
	gap: var(--ta-space-xs);
}

.ta-profile-picture__title {
	font-weight: 600;
}

.ta-profile-picture__help {
	margin: 0;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-profile-picture__actions {
	gap: var(--ta-space-s);
	flex-wrap: wrap;
}

/* Upload has an unnecessarily prominent drop area for this one-file action. */
.ta-profile-picture__upload {
	width: auto;
}

.ta-profile-picture__upload::part(drop-label) {
	display: none;
}

.ta-profile-picture__crop-frame {
	display: block;
	position: relative;
	overflow: hidden;
	width: min(100%, 26rem);
	aspect-ratio: 1;
	/* A portrait is shown everywhere as a circle; the crop preview must make the
	   member choose what will actually be visible, not unseen square corners. */
	border-radius: 50%;
	margin: 0 auto;
	background: var(--ta-color-bg);
	touch-action: none;
	user-select: none;
	cursor: grab;
}

.ta-profile-picture__crop-frame:active {
	cursor: grabbing;
}

.ta-profile-picture__crop-image {
	position: absolute;
	top: 0;
	left: 0;
	max-width: none;
	max-height: none;
	/* The fixed frame receives every gesture. Never let the browser start its own
	   image drag, which only shows a ghost image and does not alter the crop. */
	pointer-events: none;
	-webkit-user-drag: none;
	transform-origin: top left;
	will-change: transform;
}

.ta-profile-picture__crop-help {
	margin: var(--ta-space-s) 0 0;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	text-align: center;
}

/* Created beside Vaadin's overlay so that a laptop webcam can be previewed and
 * captured without pretending a desktop file chooser is a camera. */
.ta-camera-overlay {
	position: fixed;
	inset: 0;
	display: grid;
	place-items: center;
	padding: var(--ta-space-m);
	background: rgb(27 42 36 / 55%);
	z-index: 20000;
}

.ta-camera {
	box-sizing: border-box;
	width: min(100%, 42rem);
	padding: var(--ta-space-m);
	border-radius: var(--ta-radius-l);
	background: var(--ta-color-surface);
	box-shadow: 0 1rem 3rem rgb(27 42 36 / 35%);
}

.ta-camera__preview {
	display: block;
	width: 100%;
	max-height: min(68vh, 34rem);
	border-radius: var(--ta-radius-m);
	background: var(--ta-ink);
	object-fit: contain;
}

.ta-camera__actions {
	display: flex;
	justify-content: flex-end;
	gap: var(--ta-space-s);
	margin-top: var(--ta-space-m);
}

.ta-camera__actions button {
	min-height: 2.5rem;
	padding: 0 var(--ta-space-m);
	border: 1px solid var(--ta-color-border);
	border-radius: var(--ta-radius-s);
	background: var(--ta-color-surface);
	color: var(--ta-color-primary);
	font: inherit;
	cursor: pointer;
}

.ta-camera__actions .ta-camera__capture {
	border-color: transparent;
	background: var(--ta-color-affirm);
	color: var(--ta-color-affirm-text);
	font-weight: 600;
}

.ta-camera__actions button:focus-visible {
	outline: 3px solid var(--ta-color-primary);
	outline-offset: 2px;
}

/*
 * Forum: a reading column, not a compressed administration form. Its quiet signature
 * is the #n rail at the head of every post: the numbers make a flat conversation
 * navigable without pretending it is a nested comment tree.
 */
.ta-forum {
	width: 100%;
	max-width: 48rem;
	box-sizing: border-box;
	margin: 0 auto;
	padding: var(--ta-space-m);
}

/* A discussion earns more horizontal room than the overview. It changes from one
 * reading column to reader-and-writer at the same 70rem measure that previously capped
 * the one-column view: a comfortable post is more useful than postponing the writing
 * context until an almost full-screen window. Both columns then grow evenly, but stop
 * at the useful single-column maximum. Container queries follow the space this view
 * actually received, not a guessed viewport. */
.ta-forum--thread {
	max-width: var(--ta-discussion-layout-max);
	container-type: inline-size;
}

/* On an event the conversation is part of the event card, not a card nested inside
 * another page layout. It keeps the same posts/actions but gives the parent the measure. */
.ta-event__discussion > .ta-forum--embedded {
	max-width: none;
	margin: 0;
	padding: 0;
}

.ta-forum__post--embedded,
.ta-forum--embedded .ta-forum__composer {
	box-sizing: border-box;
	padding: var(--ta-space-m);
	border-radius: var(--ta-radius-s);
	background: var(--lumo-contrast-5pct);
}

.ta-forum__post.ta-forum__post--embedded {
	--ta-post-reveal-base: var(--lumo-contrast-5pct);
}

.ta-forum__pagination {
	justify-content: center;
	flex-wrap: wrap;
}

.ta-pagination__position {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

/* Discussion pages remain Mongo-sized batches, but their boundary disappears during
 * ordinary reading. The real button is retained for keyboards, screen readers and
 * browsers without IntersectionObserver; it becomes visible when focused or needed. */
.ta-forum__boundary {
	position: relative;
	display: flex;
	min-height: 1px;
	justify-content: center;
	align-items: center;
}

.ta-forum__boundary-fallback {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	clip-path: inset(50%);
	overflow: hidden;
	white-space: nowrap;
}

.ta-forum__boundary-fallback:focus,
.ta-forum__boundary--manual .ta-forum__boundary-fallback {
	position: static;
	width: auto;
	height: auto;
	padding: 0 var(--lumo-space-m);
	margin: 0;
	clip-path: none;
	overflow: visible;
}

.ta-forum__boundary-progress {
	display: none;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-forum__boundary--busy {
	min-height: var(--lumo-size-s);
}

.ta-forum__boundary--busy .ta-forum__boundary-progress {
	display: inline;
}

.ta-forum__embedded-actions,
.ta-forum__composer-actions {
	flex-wrap: wrap;
	align-items: center;
}

.ta-forum__thread-layout,
.ta-forum__post-list {
	display: grid;
	width: 100%;
	min-width: 0;
	gap: var(--ta-space-m);
}

/* History is a bounded reader, not part of the page's own scroll. Loading an older
 * Mongo page must never push the event, its signup card, the discussion heading or
 * the composer away from the member. Padding keeps card shadows and the #n pulse
 * inside the clipped surface; the quiet inset edge makes the second scrollbar an
 * intentional conversation boundary rather than an accidental overflow box. */
.ta-forum__post-list {
	box-sizing: border-box;
	/* svh is deliberate: a mobile browser's collapsing chrome must not resize a
	 * conversation while the member is using its own scroll container. */
	height: clamp(18rem, 68svh, 46rem);
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-gutter: stable;
	/* Thin, not absent. The thumb cannot tell the truth about extent - the window
	 * retains at most five Mongo pages and a #n jump starts a new one elsewhere - but it
	 * is the only pointer affordance for a member without a wheel or a touch screen, and
	 * the only cue that there is more below. Full width, it read as a second page
	 * scrollbar sitting beside the first; thin, it stays a boundary. clanie-comealong#31. */
	scrollbar-width: thin;
	/* Posts keep their own height. A fixed-height grid hands its leftover space to the
	 * auto rows, so a conversation with one or two short posts used to be a column of
	 * cards each padded out with the empty half of a row it never asked for. Packing the
	 * rows at the start leaves the reader exactly the measure it had - the space simply
	 * ends up below the last post instead of inside every one of them.
	 * clanie-comealong#39. */
	align-content: start;
	/* A real border stays above the clipped contents. The former inset shadow was
	 * painted below child cards, so the first and last card appeared to cross the
	 * reader frame. The wider breathing room also contains each card's own shadow. */
	padding: var(--ta-space-m);
	scroll-padding-block: var(--ta-space-m);
	border: 1px solid color-mix(in srgb, var(--ta-color-border) 55%, transparent);
	border-radius: var(--ta-radius-s);
}

.ta-forum__post-list--viewport {
	height: var(--ta-conversation-reader-height, max(18rem, calc(100dvh - 12rem)));
}

.ta-forum--embedded .ta-forum__post-list {
	height: clamp(18rem, 54svh, 36rem);
}

.ta-forum__post-list:focus-visible {
	outline: 0.2rem solid color-mix(in srgb, var(--ta-color-primary) 72%, transparent);
	outline-offset: 0.1rem;
}

/* The page window deliberately replaces and prepends DOM nodes. During that one
 * operation, let its measured post anchor make the correction; native browser
 * anchoring doing the same job as well moves the reader roughly one post too far.
 * The class comes straight off afterwards, so a late-loading image can still use
 * the browser's ordinary anchoring. */
.ta-forum__post-list--manual-anchor {
	overflow-anchor: none;
}

/* The previous, well-proportioned single-column cutoff. CSS container-query conditions
 * cannot read custom properties, so the 70rem rule is deliberately written beside the
 * tokens that define the columns' eventual maximum. */
@container (min-width: 70rem) {
	.ta-forum--thread .ta-forum__thread-layout {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		align-items: start;
	}

	.ta-forum--thread .ta-forum__composer {
		position: sticky;
		top: var(--ta-space-m);
		max-height: calc(100dvh - 2 * var(--ta-space-m));
		overflow-y: auto;
		overscroll-behavior: contain;
		margin-top: 0;
	}
}

.ta-forum__heading {
	gap: var(--ta-space-m);
}

.ta-forum__heading h1 {
	margin: 0;
}

.ta-forum__heading-actions {
	margin-left: auto;
}

.ta-forum__mentions-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	min-height: var(--lumo-size-m);
	padding: 0 var(--lumo-space-m);
	border: 1px solid var(--ta-color-border);
	border-radius: var(--lumo-border-radius-m);
	background: var(--ta-color-surface);
	color: var(--ta-color-primary);
	font-weight: 400;
	text-decoration: none;
}

.ta-mentions__excerpt {
	margin: var(--ta-space-s) 0 0;
}

.ta-forum__list {
	margin: 0;
}

.ta-forum__discussion {
	display: block;
	height: 100%;
	box-sizing: border-box;
	color: inherit;
	text-decoration: none;
}

.ta-forum__discussion-content {
	gap: var(--ta-space-xs);
}

/* Same two rules as the event card, for the same reasons - see .ta-events__card-link.
 * This card is the anchor itself rather than a card wrapped in one, so the lift and
 * the underline reset land on the same element. */
.ta-forum__discussion:hover,
.ta-forum__discussion:focus-visible {
	text-decoration: none;
}

.ta-forum__discussion:hover .ta-forum__discussion-title,
.ta-forum__discussion:focus-visible .ta-forum__discussion-title {
	text-decoration: underline;
}

@media (hover: hover) and (pointer: fine) {
	.ta-forum__discussion {
		transition: box-shadow 120ms ease-out, transform 120ms ease-out;
	}

	.ta-forum__discussion:hover {
		box-shadow: var(--ta-shadow-card-raised);
		transform: translateY(-2px);
	}
}

@media (prefers-reduced-motion: reduce) {
	.ta-forum__discussion {
		transition: none;
	}
}

.ta-forum__discussion:focus-visible {
	outline: 3px solid var(--ta-color-primary);
	outline-offset: 3px;
}

.ta-forum__discussion-title {
	color: var(--ta-color-text);
	font-size: var(--ta-font-size-l);
	font-weight: 600;
	text-decoration: none;
}

.ta-forum__back:hover {
	text-decoration: underline;
}

.ta-forum__discussion-meta,
.ta-forum__back,
.ta-forum__removed {
	color: var(--ta-color-text-secondary);
}

.ta-forum__empty {
	margin: 0;
	color: var(--ta-color-text-secondary);
}

.ta-forum__post {
	/* The header needs a breath before the prose. The prose and its footer are one
	 * unit: an image or final line should sit straight above its actions. */
	gap: 0;
	scroll-margin-block-start: var(--ta-space-m);
	--ta-post-reveal-base: var(--ta-color-surface);
}

/* A #n reference is the forum's signature navigation. Pulse the whole card from
 * its resting surface to pale marigold and back after the scroll has settled:
 * unlike a ring at the viewport edge, it remains unmistakable among all posts. */
.ta-forum__post--revealed {
	animation: ta-post-reveal 0.85s ease-in-out;
}

@keyframes ta-post-reveal {
	0% {
		background-color: var(--ta-post-reveal-base);
	}

	38% {
		background-color: color-mix(in srgb, var(--ta-color-affirm) 30%, var(--ta-post-reveal-base));
	}

	100% {
		background-color: var(--ta-post-reveal-base);
	}
}

@media (prefers-reduced-motion: reduce) {
	.ta-forum__post--revealed {
		animation: none;
		background-color: color-mix(in srgb, var(--ta-color-affirm) 30%, var(--ta-post-reveal-base));
	}
}

.ta-forum__post-header {
	width: 100%;
	gap: var(--ta-space-s);
	flex-wrap: wrap;
	margin-bottom: var(--ta-space-xs);
}

.ta-forum__post-number {
	color: var(--ta-color-primary);
	font-weight: 600;
}

.ta-forum__post-author {
	font-weight: 600;
}

.ta-forum__post-time,
.ta-forum__post-edited {
	color: var(--ta-color-text-secondary);
	font-size: 0.75rem;
	white-space: nowrap;
}

.ta-forum__post-footer {
	width: 100%;
	margin-top: 0;
	align-items: center;
}

/* Always keep one stable reaction surface in the footer. Updating a reaction
 * replaces only this surface; `display: contents` means an empty one consumes no
 * space and a populated one lays out exactly like the former direct reaction bar. */
.ta-forum__reaction-slot {
	display: contents;
}

.ta-forum__post-action {
	--vaadin-button-background: color-mix(in srgb, var(--ta-color-primary) 6%, var(--ta-color-surface));
	--vaadin-button-border-color: var(--ta-color-border);
	--vaadin-button-text-color: var(--ta-color-primary);
	/* The outer target remains the accessible 40/32 px, independently of the
	 * compact inner icon box below. */
	--vaadin-button-padding: 0;
	min-width: 2.5rem;
	min-height: 2.5rem;
	margin: 0;
	padding: 0;
	border-radius: 999px;
}

.ta-forum__post-action--delete {
	--vaadin-button-text-color: var(--ta-color-error);
}

.ta-forum__post-actions {
	margin-left: auto;
	gap: var(--ta-space-xs);
}

.ta-forum__post-actions .ta-forum__reaction-add {
	min-width: 2.5rem;
	min-height: 2.5rem;
}

.ta-forum__reactions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ta-space-xs);
}

.ta-forum__reaction,
.ta-forum__reaction-add,
.ta-forum__reaction-choice {
	--vaadin-button-background: var(--ta-color-surface);
	--vaadin-button-border-color: var(--ta-color-border);
	--vaadin-button-text-color: var(--ta-color-text);
	min-width: 2.25rem;
	border-radius: 999px;
}

.ta-forum__reaction--chosen {
	--vaadin-button-background: color-mix(in srgb, var(--ta-color-primary) 12%, var(--ta-color-surface));
	--vaadin-button-border-color: var(--ta-color-primary);
}

.ta-forum__reaction-picker {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	box-sizing: border-box;
	width: 100%;
	padding: var(--ta-space-xs);
	gap: var(--ta-space-xs);
}

/* This is a fixed, deliberately small vocabulary. Never make it a one-line
 * scroller: every reaction must be visible when the palette opens. */
.ta-forum__reaction-picker .ta-forum__reaction-choice {
	--vaadin-button-padding: 0;
	flex: 0 0 2.5rem;
	width: 2.5rem;
	min-width: 2.5rem;
	min-height: 2.5rem;
	margin: 0;
}

.ta-forum__reaction-picker .ta-forum__reaction-choice::part(label) {
	padding: 0;
}

.ta-forum__post-body p:first-child {
	margin-top: 0;
}

.ta-forum__post-body p:last-child {
	margin-bottom: 0;
}

/* Markdown puts an image inside a final paragraph. Removing the paragraph's
 * margin alone leaves the image's own bottom margin between it and the actions. */
.ta-forum__post-body > :last-child img:last-child {
	margin-bottom: 0;
}

.ta-forum__composer {
	gap: var(--ta-space-s);
	margin-top: var(--ta-space-m);
}

/* The mobile hint is one compact sentence. A wider writing surface lets each
 * distinct action stand on its own line, so attaching a picture cannot read as
 * a third kind of @-reference. */
.ta-composer__help-line + .ta-composer__help-line::before {
	content: " ";
}

@media (min-width: 48rem) {
	.ta-composer__help-line {
		display: block;
	}

	.ta-composer__help-line + .ta-composer__help-line {
		margin-top: var(--ta-space-xs);
	}

	.ta-composer__help-line + .ta-composer__help-line::before {
		content: none;
	}
}

/* A reference picker is an optional, keyboard-first aid beside the writing field. */
.ta-reference-caret-anchor {
	position: fixed;
	width: 1px;
	height: 1px;
	pointer-events: none;
}

.ta-reference-picker {
	gap: 0;
	border: 1px solid var(--ta-color-border);
	border-radius: var(--ta-radius-s);
	overflow: hidden;
	background: var(--ta-color-surface);
}

.ta-reference-picker__choice {
	--vaadin-button-background: transparent;
	--vaadin-button-border: 0;
	--vaadin-button-text-color: var(--ta-color-text);
	--vaadin-button-font-weight: 400;
	justify-content: flex-start;
	min-height: 2.5rem;
	border-radius: 0;
	text-align: left;
}

.ta-reference-picker__choice:hover {
	--vaadin-button-background: var(--ta-color-bg);
}

.ta-reference-picker__choice--active {
	--vaadin-button-background: var(--lumo-contrast-5pct);
}

.ta-member-profile {
	max-width: var(--ta-content-max-width);
	margin: 0 auto;
	padding: var(--ta-space-m);
}

.ta-member-profile__name {
	margin: 0;
}

.ta-member-profile__back {
	align-self: flex-start;
	margin-bottom: var(--ta-space-s);
	color: var(--ta-color-text-secondary);
}

.ta-member-profile__back:hover {
	text-decoration: underline;
}

.ta-member-profile__city,
.ta-member-profile__inactive,
.ta-member-profile__full-name,
.ta-member-profile__common-more {
	display: block;
	margin-top: var(--ta-space-xs);
	color: var(--ta-color-text-secondary);
}

.ta-member-profile__common-title {
	margin: var(--ta-space-l) 0 var(--ta-space-xs);
}

.ta-member-profile__common-event {
	display: block;
	margin-top: var(--ta-space-xs);
	color: var(--ta-color-primary);
}

.ta-member-profile__picture {
	width: 7rem;
	height: 7rem;
	margin-top: var(--ta-space-m);
	object-fit: cover;
	border-radius: 50%;
}

.ta-member-profile__about {
	margin: var(--ta-space-m) 0 0;
}

.ta-member-profile__reliability {
	display: block;
	margin-top: var(--ta-space-m);
	color: var(--ta-color-text-secondary);
}

/* An attached image is a small proof of what will be published, not a second editor. */
.ta-forum__attachments {
	gap: var(--ta-space-xs);
}

.ta-composer-toolbar {
	container-type: inline-size;
	box-sizing: border-box;
	width: 100%;
	max-width: 100%;
	padding: 0;
	border: 0;
	background: transparent;
	gap: 0;
}

/* The toolbar belongs to the field, not to the card around it. VerticalLayout's
 * theme spacing has changed across Vaadin versions, so state that relationship
 * directly instead of relying only on setSpacing(false) in Java. */
.ta-forum__composer-input {
	gap: 0;
}

.ta-forum__composer-input > .ta-composer-toolbar,
.ta-forum__composer-input > vaadin-text-area {
	margin-top: 0;
	margin-bottom: 0;
}

/* A forum composer is a writing surface, not a compact form field. Lumo adds 4 px
 * around the host and another 7 px inside the input container; together those made
 * the toolbar appear detached from its text area. Keep horizontal breathing room,
 * but let the two components meet vertically. */
.ta-forum__composer-input > vaadin-text-area {
	padding-block: 0;
	--vaadin-input-field-padding: 0 var(--ta-space-s);
}

.ta-forum__composer-input > vaadin-text-area::part(input-field) {
	padding-block: 0;
}

.ta-composer-toolbar__strip {
	gap: var(--ta-space-xs);
	padding: 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	width: fit-content;
	max-width: 100%;
	flex: 0 1 auto;
}


.ta-composer-toolbar__group {
	gap: var(--ta-space-xs);
	flex: 0 0 auto;
}

.ta-composer-toolbar__format-compact {
	display: none;
}

.ta-composer-toolbar[data-ta-format-compact] .ta-composer-toolbar__format-direct,
.ta-composer-toolbar[data-ta-format-compact] .ta-composer-toolbar__format-separator {
	display: none;
}

.ta-composer-toolbar[data-ta-format-compact] .ta-composer-toolbar__format-compact {
	display: flex;
}

.ta-composer-toolbar__separator {
	width: 1px;
	height: 1.75rem;
	margin: 0 var(--ta-space-xs);
	background: var(--ta-color-border);
}

.ta-composer-toolbar__button,
.ta-composer-toolbar__upload vaadin-button {
	--vaadin-button-background: transparent;
	--vaadin-button-text-color: var(--ta-color-primary);
	--vaadin-button-border-color: transparent;
	--vaadin-button-font-weight: 400;
	/* Keep the target; the label part below drops its default internal padding. */
	--vaadin-button-padding: 0;
	min-width: 2.5rem;
	min-height: 2.5rem;
	margin: 0;
	padding: 0;
	border-radius: var(--ta-radius-s);
	color: var(--ta-color-primary);
}

/* `padding` above reaches the host. Lumo also pads the shadow-DOM label part;
 * that is the 6 px above and below the icon visible in browser inspection. */
.ta-forum__post-action::part(label),
.ta-composer-toolbar__button::part(label),
.ta-composer-toolbar__upload vaadin-button::part(label) {
	padding-block: 0;
}

.ta-composer-toolbar__button:hover,
.ta-composer-toolbar__upload vaadin-button:hover {
	--vaadin-button-background: var(--lumo-contrast-5pct);
}

/* Touch needs 40 px targets. A mouse gets the same controls in a quieter 32 px density. */
@media (hover: hover) and (pointer: fine) {
	.ta-composer-toolbar__button,
	.ta-composer-toolbar__upload vaadin-button,
	.ta-forum__post-action,
	.ta-forum__post-actions .ta-forum__reaction-add {
		min-width: 2rem;
		min-height: 2rem;
	}
}

.ta-composer__label,
.ta-composer__help {
	display: block;
}

.ta-composer__label {
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-m);
}

.ta-composer__help {
	margin-top: var(--ta-space-xs);
	color: var(--ta-color-text-secondary);
}

.ta-composer-toolbar__upload {
	width: auto;
	min-width: 0;
}

/* Upload owns transport only. The attachment preview below the editor owns the visible state. */
.ta-forum__image-upload::part(drop-label),
.ta-forum__image-upload > vaadin-upload-file-list {
	display: none;
}

.ta-composer-format-picker {
	min-width: 13rem;
	padding: var(--ta-space-xs);
}

.ta-composer-format-picker__choice {
	--vaadin-button-background: transparent;
	--vaadin-button-border-color: transparent;
	--vaadin-button-text-color: var(--ta-color-primary);
	justify-content: flex-start;
	min-height: 2.5rem;
}

.ta-composer-format-picker__choice:hover {
	--vaadin-button-background: var(--lumo-contrast-5pct);
}

.ta-composer-toolbar__emoji-trigger {
	font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
	font-size: 1.25rem;
}

.ta-composer-toolbar--dragging {
	border-style: dashed;
	border-color: var(--ta-color-primary);
	background: var(--lumo-contrast-5pct);
}

.ta-composer-toolbar--dragging::after {
	content: attr(data-drop-hint);
	margin-left: auto;
	padding-right: var(--ta-space-xs);
	color: var(--ta-color-primary);
	font-size: var(--ta-font-size-s);
}

.ta-composer-emoji-picker {
	display: grid;
	grid-template-columns: repeat(8, 2.25rem);
	gap: var(--ta-space-xs);
	padding: var(--ta-space-s);
}

.ta-composer-emoji-picker__choice {
	--vaadin-button-background: transparent;
	--vaadin-button-border: 0;
	min-width: 2.25rem;
	min-height: 2.25rem;
	padding: 0;
	font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
	font-size: 1.25rem;
}

.ta-composer-emoji-picker__choice:hover {
	--vaadin-button-background: var(--lumo-contrast-5pct);
}

.ta-forum__attachment-list {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: var(--ta-space-s);
	width: 100%;
}

.ta-forum__attachment-progress {
	display: flex;
	align-items: center;
	gap: var(--ta-space-s);
	min-height: 1.5rem;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-forum__attachment-progress[hidden] {
	display: none;
}

.ta-forum__attachment-progress-text {
	white-space: nowrap;
}

.ta-forum__attachment-progress-track {
	width: min(12rem, 40vw);
	height: 0.3rem;
	overflow: hidden;
	border-radius: 999px;
	background: var(--lumo-contrast-10pct);
}

.ta-forum__attachment-progress-bar {
	width: 0;
	height: 100%;
	border-radius: inherit;
	background: var(--ta-color-primary);
	transition: width 120ms linear;
}

.ta-forum__attachment-progress--processing::before {
	width: 0.6rem;
	height: 0.6rem;
	border: 2px solid var(--ta-color-primary);
	border-right-color: transparent;
	border-radius: 50%;
	content: "";
	animation: ta-spin 800ms linear infinite;
}

@keyframes ta-spin {
	to {
		transform: rotate(360deg);
	}
}

@media (prefers-reduced-motion: reduce) {
	.ta-forum__attachment-progress-bar {
		transition: none;
	}

	.ta-forum__attachment-progress--processing::before {
		animation: none;
	}
}

.ta-forum__attachment {
	position: relative;
	min-width: 7rem;
	overflow: hidden;
	border-radius: var(--ta-radius-s);
	background: var(--lumo-contrast-5pct);
}

.ta-forum__attachment-image {
	display: block;
	width: 100%;
	height: auto;
	border-radius: inherit;
}

.ta-forum__attachment-remove {
	--vaadin-button-background: var(--ta-color-surface);
	--vaadin-button-border-color: var(--ta-color-error);
	--vaadin-button-text-color: var(--ta-color-error);
	position: absolute;
	top: var(--ta-space-xs);
	right: var(--ta-space-xs);
	min-width: 2rem;
	min-height: 2rem;
	padding: 0;
	border: 1px solid var(--ta-color-error);
	border-radius: 50%;
	box-shadow: 0 1px 3px rgb(27 42 36 / 25%);
}

.ta-prose img {
	display: block;
	max-width: 100%;
	height: auto;
	margin: var(--ta-space-s) 0;
	border-radius: var(--ta-radius-s);
}

@media (max-width: 34rem) {
	.ta-forum__heading {
		align-items: flex-start;
		flex-direction: column;
	}

	.ta-forum__heading-actions {
		width: 100%;
		margin-left: 0;
	}

	.ta-forum__mentions-link {
		flex: 0 0 auto;
	}

	.ta-forum__heading-actions vaadin-button {
		flex: 1 1 auto;
		white-space: nowrap;
	}
}

/*
 * Member-written text.
 *
 * The serif is not a decorative choice and not "body copy" - it marks text a PERSON
 * typed, as against text the application did. An event description, a post, an
 * about-me. Applying it to the app's own labels and buttons would spend the
 * distinction and leave the serif meaning nothing.
 */
.ta-prose {
	font-family: var(--ta-font-family-prose);
	line-height: var(--ta-line-height-body);
}

/*
 * The same thing for a Vaadin field, and it needs its own class rather than reusing
 * .ta-prose on the host. A field is not a block of prose: it is a label the APP
 * wrote plus a value a MEMBER wrote, and the class has to land on only the second.
 * Putting .ta-prose on the host set the "Om mig" label in the serif - a heading
 * nobody typed - which inverts the exact distinction this is drawing.
 *
 * The control is slotted light DOM, so a descendant selector reaches it; the label
 * lives in the shadow root and is untouched.
 */
.ta-prose-field textarea,
.ta-prose-field input {
	font-family: var(--ta-font-family-prose);
	line-height: var(--ta-line-height-body);
}

/*
 * A note pinned to the board.
 *
 * The page is the board and content sits on notes - cards being LIGHTER than the
 * page is what creates that read. A form rendered straight onto the board misses it
 * entirely and looks like an unstyled page, which is what the profile editor did
 * until 2026-08-17.
 */
.ta-card {
	background: var(--ta-color-surface);
	border-radius: var(--ta-radius-l);
	padding: var(--ta-space-m);
	box-shadow: var(--ta-shadow-card);
}

/*
 * Dates, counts, and #n references. Earned rather than decorative: #n is this app's
 * signature mechanic, and monospace is what makes a reference read as a reference
 * rather than as prose.
 */
.ta-numeric {
	font-family: var(--ta-font-family-mono);
	font-variant-numeric: tabular-nums;
}

/*
 * The affirmative button - the one action of a screen region.
 *
 * Marigold, with ink on it. Not white: white on marigold is 2.2:1 and fails, while
 * ink is 7.0:1 (tokens.css computes both).
 *
 * THE RULE THAT KEEPS THIS MEANINGFUL IS "AT MOST ONE PER SCREEN REGION", not "only
 * on sign-up". If a region has two competing actions, neither one gets this class and
 * both are plain primary buttons - the orange thing has to be unambiguous or it stops
 * being a signal at all.
 *
 * Implemented by rebinding Lumo's primary variables on this element rather than by
 * styling the button's insides: vaadin-button builds its own background from
 * --lumo-primary-color, so scoping that here reaches it without any knowledge of
 * Vaadin's shadow DOM.
 */
.ta-button-affirm {
	--lumo-primary-color: var(--ta-color-affirm);
	--lumo-primary-text-color: var(--ta-color-affirm-text);
	--lumo-primary-contrast-color: var(--ta-color-affirm-text);
}

/*
 * One address question, two answers. The location control used to sit below the input,
 * where a member had already begun typing before seeing it. It is now the first equal
 * choice and fills the same single settings column as the address field; the quiet bridge
 * names typing as the other choice instead of making either look like an afterthought.
 */
.ta-profile__address-question {
	gap: var(--ta-space-s);
}

.ta-profile__locate {
	width: 100%;
	margin: 0;
}

.ta-profile__address-alternative {
	align-self: center;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
	margin: var(--ta-space-xs) 0;
}

/*
 * Said only when the address saved is not the address typed - a floor and door stripped
 * off, because the register holds buildings and we store nothing we do not measure a
 * distance with. Quiet: it is a receipt, not a warning, and the member did nothing wrong.
 */
.ta-profile__matched {
	margin-top: calc(var(--ta-space-s) * -1);
	margin-bottom: var(--ta-space-m);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

/*
 * One suggestion: the building on top, where it is underneath.
 *
 * A list of "Skovvej 15, 2750 Ballerup" repeated down the page is read by its
 * differences, and on one long line those sit at both ends. Two lines put the varying
 * part where the eye already is, and give a finger on a phone something the height of two
 * lines to land on rather than the height of one.
 *
 * The chevron spans both rows on the right: it means this row leads somewhere rather than
 * finishing the job, which is the one thing about this field that used to need explaining
 * and now does not - in either language, without taking a line.
 */
.ta-address-row {
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: center;
	gap: 0 var(--ta-space-s);
	width: 100%;
	line-height: var(--ta-line-height-tight);
}

.ta-address-row__what {
	grid-column: 1;
}

.ta-address-row__where {
	grid-column: 1;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-address-row > vaadin-icon {
	grid-column: 2;
	grid-row: 1 / -1;
	width: var(--ta-font-size-s);
	height: var(--ta-font-size-s);
	color: var(--ta-color-text-secondary);
}

/*
 * The five signed-out pages: sign in, sign up, finish signing up, forgotten password,
 * new password. One note in the middle of the board with one thing to do on it.
 *
 * Narrow on purpose. A login form stretched across a laptop reads as an unfinished
 * page, and every one of these is two or three fields - the measure is what makes it
 * look deliberate rather than sparse.
 */
.ta-signed-out {
	padding: var(--ta-space-l) var(--ta-space-m);
}

.ta-signed-out__card {
	width: 100%;
	max-width: 26rem;
}

.ta-signed-out__heading {
	margin: 0 0 var(--ta-space-s);
	font-size: var(--ta-font-size-l);
}

.ta-signed-out__explanation {
	margin: 0 0 var(--ta-space-m);
	color: var(--ta-color-text-secondary);
}

/*
 * Rust on a note, which is the surface it is legible on - 4.2:1 against the board is
 * under the 4.5 body text needs, and these pages are the one place a member reads an
 * error carefully.
 */
.ta-signed-out__error {
	color: var(--ta-color-error);
	font-weight: 600;
}

/*
 * "eller fortsæt med" between the ways in. Two rules and a few words, with the same air
 * above as below - it separates equals, so a divider that sat closer to one of them
 * would be saying something about which one matters.
 *
 * It carries the verb the provider buttons gave up in order to fit beside each other.
 * That is also what makes a second "or" BETWEEN those two buttons unnecessary: this one
 * covers both of them, and repeating it at a smaller scale would put the same word on
 * the card three times.
 */
.ta-signed-out__divider {
	margin: var(--ta-space-l) 0;
	gap: var(--ta-space-s);
	align-items: center;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

/*
 * A one-pixel box with a background, not a border on a taller one. An <hr> keeps its
 * own height and draws the line along its TOP edge, so centring it in the row put the
 * rules a few pixels above the word between them - close enough to look like a
 * mistake and not close enough to name.
 */
.ta-signed-out__divider hr {
	flex: 1;
	align-self: center;
	height: 1px;
	margin: 0;
	border: 0;
	background: var(--ta-color-border);
}

/*
 * The card is three things - a password, another way in, and a choice about this
 * machine - and on a screen with room it should read as three. This is the first
 * thing given up when there is not room: a login form you have to scroll is worse
 * than one that sits close together.
 */
@media (max-height: 760px) {
	.ta-signed-out__divider {
		margin: var(--ta-space-m) 0;
	}
}

/*
 * The other ways in, below the divider: two buttons that share one row while the row
 * is wide enough for both, and become a column when it is not.
 *
 * flex-wrap and a basis, NOT a media query. What runs out of room is the card, which is
 * 26rem at most and narrower than that on a phone - the viewport is a proxy for it and
 * a poor one, and a proxy would have to be re-guessed the day the card changes width.
 * The basis is what decides: two buttons plus the gap need about 19rem, so they sit
 * side by side on any normal screen and stack on a small phone, with nothing to keep in
 * step. min-width:0 because a flex item will otherwise refuse to shrink below its
 * label, which is how a wrapping row silently becomes an overflowing one.
 */
.ta-signed-out__providers {
	flex-wrap: wrap;
	gap: var(--ta-space-s);
}

.ta-signed-out__providers vaadin-button {
	flex: 1 1 9rem;
	min-width: 0;
}

/*
 * The face of a provider button, wherever one appears - the login page offers them as
 * ways in, the account section as accounts to connect, and they are the same control on
 * the same two brands.
 *
 * The same shape as the sign-in button above, because they are answers to one question -
 * but not the same width, and not the same colour. Marigold is for the one thing this
 * page is for; these are the alternative, and two of them side by side under a divider
 * already say so without help. That is why they are vaadin-buttons rather than styled
 * anchors: an anchor had to reproduce the button's box and got it two pixels wrong,
 * which is exactly the sort of thing nobody can name and everybody notices.
 *
 * Their face is set through vaadin-button's OWN properties rather than by painting the
 * host: both the base styles and the Lumo layer read --vaadin-button-background,
 * --vaadin-button-text-color and the border hooks, so this reaches inside without any
 * knowledge of the shadow DOM and without borrowing a global token to do it. (Rebinding
 * --lumo-contrast-5pct here would also have worked, and would have been the thing
 * tokens.css warns against: the contrast scale is not a place to put named colours.)
 *
 * Two border hooks because the two layers spell it differently - --vaadin-button-border
 * in Lumo, --vaadin-button-border-color in the base styles. Each is inert where it is
 * not read.
 */
.ta-provider-button {
	--vaadin-button-background: var(--ta-color-surface);
	--vaadin-button-text-color: var(--ta-color-primary);
	--vaadin-button-border: 1px solid var(--ta-color-border);
	--vaadin-button-border-color: var(--ta-color-border);
}

/*
 * "Har du ikke en profil? Opret en" - a question under the field it is about, with the
 * answer clickable. Small and quiet: it is for the member this page turns away, not for
 * the one who is about to type their password.
 */
.ta-signed-out__field-helper {
	align-items: baseline;
	gap: 0.3em;
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

.ta-signed-out__field-helper vaadin-button {
	font-size: inherit;
}

/*
 * Remember this browser. Below both ways in, and separated from them by the same
 * labelled divider - "og" - that separates the two ways in from each other. It governs
 * everything above it, and a control tucked under the Google button reads as part of
 * the Google button. The word is what makes the sentence: sign in with a password OR
 * with Google, AND stay signed in here.
 */
.ta-signed-out__remember {
	width: 100%;
}

.ta-signed-out__remember-help {
	margin-top: var(--ta-space-xs);
	color: var(--ta-color-text-secondary);
	font-size: var(--ta-font-size-s);
}

/*
 * One connected account: mark, brand and state on the left, the one action beside them.
 *
 * This is a grid, not a wrapping flex row. The provider's long last-way-in explanation
 * belongs beneath its name; it must never push Afbryd into an unrelated second row.
 * The action therefore has a stable, no-wrap column of its own.
 */
.ta-profile__connection {
	display: grid;
	grid-template-columns: minmax(0, 1fr) max-content;
	gap: var(--ta-space-m);
	align-items: start;
	padding: var(--ta-space-s) 0;
}

.ta-profile__connection-what {
	gap: var(--ta-space-s);
	min-width: 0;
	width: 100%;
}

.ta-profile__connection-words {
	min-width: 0;
	width: 100%;
}

.ta-profile__connection-name {
	font-weight: 600;
}

.ta-profile__connection-words .ta-profile__welcome {
	display: block;
	margin-top: var(--ta-space-xs);
}

.ta-profile__connection .ta-provider-button {
	white-space: nowrap;
}

.ta-profile__connection img {
	width: 18px;
	height: 18px;
}

/*
 * The two things at the foot of the profile that are not the profile: the way to the
 * password page, and the way out. Both leave the page rather than doing something on
 * it - see ProfileView.
 */
.ta-profile__elsewhere-row {
	margin-top: var(--ta-space-m);
	align-items: baseline;
	gap: var(--ta-space-m);
}

.ta-profile__elsewhere {
	display: inline-block;
	color: var(--ta-color-primary);
	font-size: var(--ta-font-size-m);
	/*
	 * Signing out is a button because it does something rather than goes somewhere, and
	 * it stood out for it: Lumo sets a button's weight to 500 against the anchor's 400,
	 * which reads as darker and heavier. Two controls that do the same KIND of thing
	 * should not differ over which HTML element they happen to be.
	 */
	--vaadin-button-font-weight: 400;
	--vaadin-button-text-color: var(--ta-color-primary);
}

/* Both underline, for the same reason: they leave the page. */
.ta-profile__elsewhere:hover {
	text-decoration: underline;
}

.ta-profile__elsewhere:hover::part(label) {
	text-decoration: underline;
}
