/*
 * Server-rendered agenda (MEP_Agenda_Renderer). Deliberately plain and low-specificity: this
 * renders in the LIGHT DOM of somebody else's theme, so it inherits fonts and colours and only
 * asserts layout. Nothing here may make a `hidden` node visible — filtering depends on it.
 */

.mep-agenda [hidden] {
	display: none !important;
}

/*
 * ── reserving the space the enhanced controls will take ───────────────────────
 *
 * The controls bar, the day tablist and the per-session star all ship `hidden` and are un-hidden
 * by agenda.js once they are wired. Revealing them dropped the whole programme down the page the
 * moment the script ran — measured on a throttled connection, that one reveal was the entire
 * layout shift of the page.
 *
 * So these three keep their box and lose only their paint. `visibility: hidden` is as inert as
 * `display: none` for the thing that matters here — the subtree is out of the tab order, out of
 * hit-testing and off the accessibility tree, so a reader still cannot use a control JS has not
 * wired — but it is laid out, so un-hiding it costs nothing.
 *
 * Scoped to these three by their data attributes, never `[hidden]` in general: `hidden` is also
 * what the FILTER sets on sessions and days, and a filtered-out session must still collapse.
 *
 * With no JS at all there is nothing to reveal, so the reservation would be an empty band. Modern
 * browsers say so via `scripting`, below, and collapse it back.
 */
.mep-agenda [data-mep-agenda-controls][hidden] {
	display: flex !important;
	visibility: hidden;
}

.mep-agenda [data-mep-day-tabs][hidden] {
	display: block !important;
	visibility: hidden;
}

.mep-agenda [data-mep-star][hidden] {
	display: inline-flex !important;
	visibility: hidden;
}

@media (scripting: none) {
	.mep-agenda [data-mep-agenda-controls][hidden],
	.mep-agenda [data-mep-day-tabs][hidden],
	.mep-agenda [data-mep-star][hidden] {
		display: none !important;
	}
}

.mep-agenda {
	--mep-track-colour: currentColor;
}

.mep-agenda-title {
	margin: 0 0 0.25rem;
}

.mep-agenda-meta {
	margin: 0 0 1.5rem;
	font-size: 0.9rem;
	opacity: 0.75;
}

/*
 * Who presents each track, said once under the header. Deliberately quieter than the meta line
 * above it: this is attribution, not a sponsor banner, so it must never read louder than the
 * track names it credits.
 */
.mep-agenda-credits {
	list-style: none;
	margin: 0 0 1.5rem;
	padding: 0;
	font-size: 0.85rem;
	opacity: 0.7;
}

/* Straight under the venue/timezone line rather than a paragraph away from it. */
.mep-agenda-meta + .mep-agenda-credits {
	margin-top: -1rem;
}

.mep-agenda-credit {
	margin: 0;
}

/*
 * No tap/click flash on the controls. Safari and Chrome paint a translucent grey box over a
 * button the moment it is pressed, which on the chips and the day tabs reads as a rendering
 * glitch rather than feedback — they already have :hover and :active states of their own, and a
 * keyboard user still gets the focus ring, which is what actually has to stay visible.
 */
.mep-agenda button,
.mep-agenda [role='tab'],
.mep-agenda summary,
.mep-agenda label {
	-webkit-tap-highlight-color: transparent;
}

/*
 * A mouse click must not leave a ring behind. :focus-visible is the browser's own judgement about
 * whether focus should be shown — keyboard yes, pointer no — so the outline is scoped to it
 * rather than removed, which would strip the ring from keyboard users too.
 *
 * The day PANEL belongs on this list even though nothing focuses it deliberately: it carries
 * tabindex="0" so a keyboard reader can scroll it, which also means clicking anywhere inside — a
 * card, the gap between two, a stray drag over a title — moves focus there and left the browser's
 * default ring drawn around the whole day. On a dark card that ring is a white box around the
 * entire list, coming and going as you click about, which is how it was reported.
 */
.mep-agenda button:focus:not(:focus-visible),
.mep-agenda [role='tab']:focus:not(:focus-visible),
.mep-agenda [role='tabpanel']:focus:not(:focus-visible),
.mep-agenda summary:focus:not(:focus-visible) {
	outline: none;
}

/* ── filter controls (hidden until agenda.js wires them) ──────────────────── */

.mep-agenda-controls {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.75rem;
	margin: 0 0 1.5rem;
}

.mep-track-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

/* Preview notice: administrators only, and never on a visitor's page. Deliberately plain — it is a
   warning, not part of the design, and it should look like it does not belong on the page. */
.mep-preview-note {
	margin: 0 0 0.75rem;
	padding: 0.5rem 0.75rem;
	border-left: 3px solid #b8860b;
	background: #fff8e1;
	color: #4a3a00;
	font-size: 0.85rem;
}

.mep-track-chip {
	padding: 0.25rem 0.75rem;
	border: 1px solid var(--mep-track-colour);
	border-radius: 999px;
	background: transparent;
	color: inherit;
	font: inherit;
	font-size: 0.85rem;
	line-height: 1.6;
	cursor: pointer;
	/* Picking a track is a state change with no other visible cue on the chip itself, so the tint
	   arrives rather than snapping. */
	transition:
		transform 160ms var(--scs-ease-out, ease),
		background-color 160ms var(--scs-ease-out, ease),
		border-color 160ms var(--scs-ease-out, ease),
		box-shadow 160ms var(--scs-ease-out, ease);
}

/* A chip with a logo becomes logo + name on one line. Chips without one are untouched — the span is
   always emitted, so the layout is the same box either way and nothing shifts when a logo is added.
   The logo is capped in em, not px: it then tracks the chip's own font size through every skin. */
.mep-track-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
}

/* Height-capped and width-auto so any aspect ratio fits: partner marks are square as often as they
   are wide, and a mark must never dictate the chip's height. */
.mep-track-chip-logo {
	max-height: 1.25em;
	max-width: 5em;
	width: auto;
	/* Reserve nothing and demand nothing: the image is decorative, so it never stretches the row. */
	flex: 0 0 auto;
	object-fit: contain;
}

.mep-track-chip[aria-pressed='true'] {
	border-color: var(--mep-track-colour);
	box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--mep-track-colour) 15%, transparent);
	font-weight: 600;
}

/* ── speaker filter: a disclosure over a scrollable checkbox list ──────────── */
/* Hundreds of speakers is normal, so the list scrolls inside the disclosure rather than pushing the
   agenda off the screen. Closed, it costs one line. */

.mep-speaker-filter {
	font-size: 0.85rem;
}

.mep-speaker-filter > summary {
	display: flex;
	gap: 0.4rem;
	align-items: baseline;
	padding: 0.25rem 0.75rem;
	border: 1px solid rgba(128, 128, 128, 0.5);
	border-radius: 999px;
	cursor: pointer;
	list-style: none;
}

.mep-speaker-filter > summary::-webkit-details-marker {
	display: none;
}

.mep-speaker-filter-selected:not(:empty) {
	font-weight: 600;
}

.mep-speaker-filter-search {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin: 0.5rem 0 0.35rem;
}

.mep-speaker-filter-search input {
	flex: 1 1 auto;
	min-width: 0;
	padding: 0.25rem 0.5rem;
	font: inherit;
}

.mep-speaker-options {
	max-height: 16rem;
	margin: 0;
	padding: 0;
	overflow-y: auto;
	border: 1px solid rgba(128, 128, 128, 0.3);
	border-radius: 4px;
	list-style: none;
}

.mep-speaker-option-label {
	display: flex;
	gap: 0.4rem;
	align-items: baseline;
	padding: 0.2rem 0.5rem;
	cursor: pointer;
}

.mep-speaker-option-org,
.mep-speaker-option-count {
	opacity: 0.7;
}

.mep-speaker-option-count {
	margin-left: auto;
	white-space: nowrap;
}

.mep-agenda-search {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.85rem;
}

.mep-agenda-search input {
	padding: 0.25rem 0.5rem;
	font: inherit;
}

.mep-agenda-count {
	margin: 0;
	font-size: 0.85rem;
	opacity: 0.75;
}

.mep-agenda-none {
	margin: 1rem 0;
	opacity: 0.75;
}

/*
 * Collapsed detail (opt-in, and only ever created by agenda.js). Kept in the base sheet so the
 * behaviour is the same for every skin: display:none rather than `hidden`, because `hidden` is what
 * the filter sets and the two must not overwrite each other on the same node.
 */
/*
 * The fold ANIMATES: a grid whose single row track goes 1fr -> 0fr, which the browser interpolates
 * both ways. display:none could only snap, and animating height needs a number nobody has.
 * min-height:0 on the child is what lets the track actually reach zero.
 */
.mep-agenda .mep-session-detail {
	display: grid;
	grid-template-rows: 1fr;
	transition: grid-template-rows 240ms var(--scs-ease-out, ease);
}

.mep-agenda .mep-session-detail--closed {
	grid-template-rows: 0fr;
}

.mep-agenda .mep-session-detail > * {
	min-height: 0;
	overflow: hidden;
}

/* The inner wrapper holds every part, so the fold has exactly one row to collapse. */
.mep-agenda .mep-session-detail-inner > :first-child {
	margin-top: 0;
}

/*
 * Everything this sheet moves, off in one place. The skin has a block of its own; this one covers
 * an agenda rendered with no skin at all.
 */
@media (prefers-reduced-motion: reduce) {
	.mep-agenda .mep-session-detail,
	.mep-agenda .mep-track-chip,
	.mep-agenda .mep-agenda-day-tab,
	.mep-agenda .mep-star-mark::before,
	.mep-agenda .mep-session-more::after,
	.mep-agenda .mep-session.mep-session--settling {
		transition: none;
	}

	.mep-agenda .mep-agenda-day--entering,
	.mep-agenda .mep-session.mep-session--entering {
		animation: none;
	}
}

.mep-session-more {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	padding: 0;
	border: 0;
	background: none;
	color: inherit;
	font: inherit;
	font-size: 0.85rem;
	text-decoration: underline;
	text-underline-offset: 0.2em;
	cursor: pointer;
	opacity: 0.85;
}

.mep-session-more:hover {
	opacity: 1;
}

.mep-session-more::after {
	content: '';
	width: 0.4em;
	height: 0.4em;
	border-right: 1.5px solid currentColor;
	border-bottom: 1.5px solid currentColor;
	transform: translateY(-0.15em) rotate(45deg);
	transition: transform 120ms ease;
}

.mep-session-more[aria-expanded='true']::after {
	transform: translateY(0.1em) rotate(-135deg);
}

/* ── day tabs (hidden until agenda.js wires them) ─────────────────────────── */

.mep-agenda-days {
	margin: 0 0 1.5rem;
	border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent);
}

.mep-agenda-days-list {
	display: flex;
	flex-wrap: nowrap;
	gap: 0.25rem;
	/* A long programme on a phone scrolls sideways rather than wrapping into a block of buttons. */
	overflow-x: auto;
	scrollbar-width: thin;
	margin-bottom: -1px;
}

/*
 * The tabs share the row. flex-basis 0 makes the share equal regardless of label length, so a
 * three-day programme reads as three equal steps; min-width keeps a long themed name from
 * squeezing its neighbours to nothing, and the row falls back to scrolling once the days no
 * longer fit.
 */
.mep-agenda-day-tab {
	flex: 1 1 0;
	min-width: 7rem;
}

.mep-agenda-day-tab {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.1rem;
	padding: 0.6rem 0.9rem;
	border: 0;
	border-bottom: 2px solid transparent;
	background: none;
	color: inherit;
	font: inherit;
	line-height: 1.25;
	text-align: left;
	cursor: pointer;
	opacity: 0.7;
	transition:
		opacity 160ms var(--scs-ease-out, ease),
		border-color 160ms var(--scs-ease-out, ease);
}

.mep-agenda-day-tab:hover {
	opacity: 1;
}

.mep-agenda-day-tab[aria-selected='true'] {
	opacity: 1;
	font-weight: 600;
	border-bottom-color: currentColor;
}

/* Dimmed, not disabled: a filter that empties a day must not eat the focus ring. */
.mep-agenda-day-tab[data-mep-day-empty='true'] {
	opacity: 0.35;
}

.mep-agenda-day-tab-title {
	white-space: nowrap;
}

.mep-agenda-day-tab-date {
	font-size: 0.8rem;
	font-weight: 400;
	opacity: 0.8;
	white-space: nowrap;
}

/* Written by agenda.js, and only while "my schedule" is on. Not space-reserved like the controls
   above: it appears in answer to a click, which is not an unexpected shift, and a permanently
   reserved empty line under every tab is a cost paid on every page view for it. */
.mep-agenda-day-tab-count:not(:empty) {
	font-size: 0.75rem;
	font-weight: 400;
	opacity: 0.7;
}

/* ── the timezone picker ──────────────────────────────────────────────────── */

.mep-agenda-timezone {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-size: 0.85rem;
	/* Sits apart from the filters: it changes how the agenda reads, not what it contains. */
	margin-left: auto;
}

.mep-agenda-timezone-label {
	opacity: 0.75;
	white-space: nowrap;
}

.mep-agenda-timezone select {
	font: inherit;
	font-size: 0.85rem;
	padding: 0.3rem 0.4rem;
	color: inherit;
	background: transparent;
	border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
	border-radius: 0.35rem;
	max-width: 14rem;
}

/* ── days and sessions ───────────────────────────────────────────────────── */

/* The tab strip owns which day is on screen. Separate from `hidden`, which the filter owns — a day
   can be both off-tab and filtered empty, and neither may clobber the other. */
.mep-agenda--enhanced .mep-agenda-day[data-mep-day-off='true'] {
	display: none;
}

/*
 * Switching day swaps one panel for another in a single frame, which reads as a flicker rather than
 * a move. The incoming panel settles in instead.
 *
 * Class, not a rule on [data-mep-day-off='false']: agenda.js selects the first day as it wires the
 * tabs, and that attribute write would then animate the whole programme on page load. It adds the
 * class only for a switch the reader asked for.
 */
.mep-agenda-day--entering {
	animation: mep-day-in 200ms var(--scs-ease-out, ease-out);
}

@keyframes mep-day-in {
	from {
		opacity: 0;
		transform: translateY(6px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

/* Stacked (no JS, or a single-day agenda): days follow one another. Once tabs are live only one
   panel is on screen, so the gap between them would be a gap above the sessions. */
.mep-agenda-day + .mep-agenda-day {
	margin-top: 2rem;
}

.mep-agenda--enhanced .mep-agenda-day + .mep-agenda-day {
	margin-top: 0;
}

.mep-agenda-day-title {
	margin: 0 0 0.75rem;
	font-size: 1.1rem;
}

/* A themed day: the title is the heading above, this is its standfirst. */
.mep-agenda-day-description {
	margin: -0.5rem 0 1rem;
	font-size: 0.9rem;
	opacity: 0.8;
}

.mep-agenda .mep-sessions {
	list-style: none;
	margin: 0;
	padding: 0;
}

/*
 * ── filtering ────────────────────────────────────────────────────────────────
 * Picking a focus used to swap the list in one frame: rows blinked out and everything below
 * jumped up to meet the gap. The result still lands in that same frame — `hidden` goes on with
 * the click, and the count and the day tallies are true immediately — and these two states are
 * painted over the top of a list that has ALREADY changed.
 *
 * A row that goes does not animate, deliberately. The rule at the top of this sheet is that
 * nothing may paint a `hidden` node, and every filtered-out row is one; fading it out would mean
 * holding it on screen after it stopped counting, which is also how it would stay readable, and
 * reachable, mid-animation. So the movement is carried by the rows that REMAIN: they are
 * transformed back to where they were and released (--settling), which is what reads as the list
 * re-forming rather than snapping shut. A row that ARRIVES fades up (--entering).
 *
 * Transform and opacity only. Nothing here animates a size or a spacing, so a filter cannot move
 * a neighbour or bill a layout shift.
 */

/* agenda.js writes the starting translate inline, then clears it on the next frame with this
   class on — so the transition is the only thing that animates, and a row that did not move never
   gets the class at all. Doubled class: the skins style .mep-session with equal specificity and
   load after this sheet. */
.mep-agenda .mep-session.mep-session--settling {
	transition: transform 220ms var(--scs-ease-out, ease-out);
	will-change: transform;
}

.mep-agenda .mep-session.mep-session--entering {
	animation: mep-session-in 200ms var(--scs-ease-out, ease-out);
}

@keyframes mep-session-in {
	from {
		opacity: 0;
		transform: translateY(6px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

.mep-agenda .mep-session {
	position: relative;
	padding: 1rem 0;
	border-bottom: 1px solid rgba(128, 128, 128, 0.25);
}

/* ── "add to my schedule" star (hidden until agenda.js wires it) ──────────── */

.mep-star {
	position: absolute;
	top: 0.9rem;
	right: 0;
	padding: 0.1rem 0.35rem;
	border: 0;
	background: transparent;
	color: inherit;
	font: inherit;
	line-height: 1;
	cursor: pointer;
}

.mep-star-mark::before {
	content: '\2606'; /* hollow star */
	font-size: 1.25rem;
	opacity: 0.55;
	/* The glyph swaps outright — only the weight of it fades. */
	transition: opacity 120ms ease;
}

.mep-star[aria-pressed='true'] .mep-star-mark::before {
	content: '\2605'; /* filled star */
	opacity: 1;
}

.mep-star:hover .mep-star-mark::before,
.mep-star:focus-visible .mep-star-mark::before {
	opacity: 1;
}

/* Leave room for the star so a long title never runs under it. Reserved whether or not the star has
   been revealed yet: narrowing the title once agenda.js runs rewraps it, and a rewrapped title is a
   layout shift on every row of the programme. Two rem of unused gutter costs a no-JS reader
   nothing visible. */
.mep-agenda .mep-session-time,
.mep-agenda .mep-session-title {
	padding-right: 2rem;
}

.mep-agenda .mep-session--break {
	opacity: 0.8;
}

.mep-agenda .mep-session-time {
	margin: 0;
	font-size: 0.9rem;
	font-variant-numeric: tabular-nums;
	opacity: 0.75;
}

.mep-agenda .mep-session-title {
	margin: 0.15rem 0 0;
	font-size: 1.05rem;
}

.mep-session-facts {
	margin: 0.25rem 0 0;
	font-size: 0.85rem;
	opacity: 0.75;
}

/* Time and facts are one cell (see the renderer): unskinned this is just a block, so the two lines
   stack exactly as they did when they were siblings. */
.mep-session-when {
	margin: 0;
}

.mep-session-abstract {
	margin-top: 0.5rem;
}

.mep-session-abstract > :first-child {
	margin-top: 0;
}

.mep-session-abstract > :last-child {
	margin-bottom: 0;
}

/* ── track badges ────────────────────────────────────────────────────────── */

.mep-session-tracks {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: 0.375rem;
	margin: 0.5rem 0 0;
	padding: 0;
}

.mep-track {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	padding: 0.15rem 0.6rem;
	border: 1px solid var(--mep-track-colour);
	border-left-width: 4px;
	border-radius: 4px;
	font-size: 0.8rem;
	line-height: 1.6;
}

.mep-track-logo {
	max-height: 1.1rem;
	width: auto;
}

.mep-track-presented-by {
	opacity: 0.75;
}

/* ── speakers ────────────────────────────────────────────────────────────── */

.mep-agenda .mep-session-speakers {
	list-style: none;
	/* 220px, not 180: a hyphenated name ("Doreen Bogdan-Martin") broke across two lines in a
	   180px track, and a wrapped name is what threw the cards beside it out of alignment. */
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: 1.25rem 1.5rem;
	margin: 0.75rem 0 0;
	padding: 0;
	font-size: 0.85rem;
	color: inherit;
}

/*
 * Photo beside a single text column, both top-aligned. Flex rather than the fixed three-row grid
 * this used to be: the rows assumed every card had a name, a role and a position, so a card
 * missing one (most cards carry no role now) or wrapping one drifted out of step with its
 * neighbours. A column with one gap has nothing to drift.
 */
.mep-agenda .mep-speaker {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
}

.mep-speaker-text {
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
	/* Without this a long name refuses to wrap and pushes the card wider than its track. */
	min-width: 0;
}

/*
 * object-fit: cover on a square box either way, so a portrait is cropped rather than squashed and
 * the two shapes differ only in the corner. Site-wide (Settings -> EMS Speakers), because which one
 * is right is a brand decision rather than a per-page one.
 */
.mep-speaker-photo {
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	border-radius: 50%;
	object-fit: cover;
}

.mep-agenda--photos-square .mep-speaker-photo {
	border-radius: 6px;
}

.mep-agenda .mep-speaker-name {
	margin: 0;
	font-size: inherit;
	font-weight: 600;
	/* The name is the one line allowed to break inside a word — a long hyphenated surname in a
	   narrow track has nowhere else to go. */
	overflow-wrap: break-word;
}

.mep-speaker-role,
.mep-speaker-position {
	opacity: 0.75;
}

/* Only Moderator and Chair reach this now, so it is a billing, not a repeated label. */
.mep-speaker-role {
	font-weight: 600;
	letter-spacing: 0.02em;
}

/*
 * Short bio, behind a disclosure. Collapsed by default because an agenda repeats a speaker on every
 * session they appear on; the text is in the light DOM either way, so a crawler and the keyword box
 * still see it.
 */
.mep-agenda .mep-speaker-bio {
	margin-top: 0.15rem;
}

.mep-agenda .mep-speaker-bio > summary {
	cursor: pointer;
	opacity: 0.75;
}

.mep-speaker-bio-text {
	margin-top: 0.35rem;
}

.mep-speaker-bio-text > :first-child {
	margin-top: 0;
}

.mep-speaker-bio-text > :last-child {
	margin-bottom: 0;
}

/* ── email my schedule (hidden until agenda.js wires it) ──────────────────── */

.mep-agenda-schedule {
	margin: 1.5rem 0 0;
	padding: 1rem 1.25rem;
	border: 1px solid rgba(128, 128, 128, 0.3);
	border-radius: 6px;
}

.mep-agenda-schedule-title {
	margin: 0 0 0.25rem;
	font-size: 1.05rem;
}

.mep-agenda-schedule-intro {
	margin: 0 0 0.75rem;
	font-size: 0.9rem;
	opacity: 0.8;
}

.mep-agenda-schedule-email {
	display: block;
	font-size: 0.85rem;
}

.mep-agenda-schedule input[type='email'] {
	padding: 0.35rem 0.5rem;
	font: inherit;
}

.mep-agenda-schedule-send {
	padding: 0.35rem 0.9rem;
	border: 1px solid currentColor;
	border-radius: 4px;
	background: transparent;
	color: inherit;
	font: inherit;
	cursor: pointer;
}

.mep-agenda-schedule-status {
	margin: 0.5rem 0 0;
	font-size: 0.85rem;
}

/*
 * Honeypot. Off-screen rather than display:none or [hidden], so a naive bot still "sees" the field
 * and fills it — which is the whole signal. A person never reaches it: it is out of the tab order
 * and aria-hidden in the markup.
 */
.mep-agenda .mep-hp {
	position: absolute;
	left: -9999px;
	top: auto;
	width: 1px;
	height: 1px;
	overflow: hidden;
}
