/**
 * Base styles — NIT Raipur USA Alumni Association
 *
 * Every value here comes from tokens.css. If you need a colour or size that is
 * not a token, add the token — do not inline the value (NFR-STYLE-1).
 */

/* ---- Reset-ish ----------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { color-scheme: dark; }

body {
	background-color: var(--c-bg);
	color: var(--c-text);
	font-family: var(--font-sans);
	font-size: var(--fs-base);
	line-height: var(--lh-base);
	-webkit-font-smoothing: antialiased;
}

/* Never let a wide element scroll the page itself (DSN-7).

   `clip`, not `hidden`. `overflow-x: hidden` makes the element a scroll
   container, which becomes the containment context for position: sticky — the
   header would silently stop sticking. `clip` prevents the overflow without
   creating that container. Applied to body only; html stays untouched. */
/* No blanket horizontal-overflow clip on the body.
   `overflow-x: clip` makes the body a clip container, and that silently
   disables `position: sticky` for everything inside it -- the directory's
   filter row (DIR-5) scrolled straight off the top. It was masking overflow
   rather than preventing it in any case; DSN-7 is enforced by an assertion
   that no page scrolls sideways at 1440, 820 or 412px, which finds the actual
   cause instead of hiding it. */
body { max-width: 100%; }

img, svg, video { max-width: 100%; height: auto; }

/* ---- Typography ---------------------------------------------------------- */

h1, h2, h3, h4, h5, h6 {
	font-family: var(--font-display);
	color: var(--c-heading);
	line-height: var(--lh-tight);
	font-weight: var(--fw-semibold);
	margin: 0 0 var(--sp-4);
	text-wrap: balance;
}

h1 { font-size: var(--fs-4xl); letter-spacing: -0.02em; }
h2 { font-size: var(--fs-3xl); letter-spacing: -0.01em; }
h3 { font-size: var(--fs-2xl); }
h4 { font-size: var(--fs-xl); }

/* Section headings carry the accent blue (DSN-10). h1 stays neutral: a page
   title and a section heading are different things and should not look alike. */
h2,
h3,
.nitrusa-section-heading {
	color: var(--c-heading-section);
}

/* Emphasis inside body copy lifts to the strong tone rather than shouting. */
strong, b { color: var(--c-text-strong); font-weight: var(--fw-semibold); }

/* ---- Caption (DSN-10) ----------------------------------------------------
   One named treatment for every small label: page caption, footer headings,
   drawer title, the lockup subline. Small caps rather than uppercase. */
.nitrusa-caps {
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
	text-transform: none;
}

p { margin: 0 0 var(--sp-4); max-width: 70ch; }

a {
	color: var(--c-accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	transition: color var(--transition);
}
a:hover { color: var(--c-accent-hover); }

/* Visible focus everywhere — non-negotiable (DSN-6). */
:focus-visible {
	outline: var(--focus-ring);
	outline-offset: var(--focus-offset);
	border-radius: var(--r-sm);
}

/* ---- Layout -------------------------------------------------------------- */

/* One container owns the page's width and inset. The parent theme's wrapper
   is neutralised rather than also styled, because when both carried the inset
   every page was indented twice. */
body .site.grid-container.container {
	max-width: none;
	padding-inline: 0;
}

.nitrusa-container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--content-inset) var(--sp-5);
}

/* The parent theme lays .site-content out as a flex row, so the shell's <main>
   is a flex item. Without a flex basis it shrinks to its content -- it was
   494px wide in a 1440px viewport, which is why listings never spanned the
   page however the cards themselves were styled. */
main.nitrusa-page {
	flex: 1 1 auto;
	width: 100%;
	min-width: 0;
}

/* The header keeps a tighter inset than the page content: the hamburger belongs
   near the edge, where the eye looks for it. */
.site-header .inside-header {
	padding-inline: var(--sp-5);
}

/* ---- Header lockup (DSN-5: seal at 100px, floating left) ------------------ */

/* Seamless: the header shares the page background and carries no rule beneath
   it, so masthead and content read as one surface.

   `body` prefix is deliberate. GeneratePress emits
   `.site-header{background-color:var(--base-3)}` inline, which through our
   variable bridge paints the header in the surface colour and leaves a visible
   band. Equal specificity made the outcome depend on enqueue order, and the seam
   survived. One extra element beats it outright. */
body .site-header,
body .nitrusa-header {
	background-color: var(--c-bg);
	border-bottom: 0;
	box-shadow: none;
	/* Sticky, so the identity and the way out stay reachable while reading.
	   Below the drawer (z-index 100) and its scrim (90) so neither is covered. */
	position: sticky;
	top: 0;
	z-index: 50;
}

.nitrusa-lockup {
	display: flex;
	/* Bottom-aligned: the wordmark sits on the seal's baseline rather than being
	   centred against it, so the header reads as one horizontal line. */
	align-items: flex-end;
	gap: var(--sp-4);
	padding-block: var(--sp-4);
	text-decoration: none;
}

.nitrusa-lockup__seal {
	flex: 0 0 auto;
	width: var(--seal-size);
	height: var(--seal-size);
	/* The seal is illegible below 96px, so it never shrinks past that (DSN-5). */
	min-width: var(--seal-size-mobile);
	min-height: var(--seal-size-mobile);
}

.nitrusa-lockup__text {
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	/* Right-justified: the lockup sits at the right edge, so the ragged edge
	   belongs on the left. */
	align-items: flex-end;
	text-align: right;
	line-height: var(--lh-tight);
	/* Trims the descender gap so the subline's baseline lands on the seal's
	   bottom edge rather than a few pixels above it. */
	padding-block-end: 2px;
}

.nitrusa-lockup__name {
	font-size: var(--fs-3xl);
	font-weight: var(--fw-bold);
	color: var(--c-text);
	letter-spacing: -0.01em;
	/* The Association's name reads as one unit; wrapping it mid-name looked
	   like a layout fault. It steps down in size instead. */
	white-space: nowrap;
}

.nitrusa-lockup__sub {
	font-size: var(--fs-lg);
	color: var(--c-accent);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
}

/* Below the tablet breakpoint the wordmark stacks under the seal rather than
   the seal shrinking into an unreadable blob. */
@media (max-width: 900px) {
	.nitrusa-lockup__name { font-size: var(--fs-2xl); }
	.nitrusa-lockup__sub  { font-size: var(--fs-base); }
}
@media (max-width: 640px) {
	.nitrusa-lockup { gap: var(--sp-3); }
	.nitrusa-lockup__name { font-size: var(--fs-xl); }
	.nitrusa-lockup__sub  { font-size: var(--fs-sm); }
}

/* ---- The phone header has two things to fit, not one (DSN-35) ------------
   The wordmark sits on the seal's baseline and never wraps, which is right on a
   wide header and is why the phone one was cramped: an unwrappable line took
   whatever width it needed, the identity chip was left with 150px, and a
   signed-in officer read "Of… / Sec…" — the header's one job, saying who you
   are signed in as, defeated by its other one.

   So on a phone the wordmark **top-aligns with the seal and is allowed to
   wrap**. Two short lines beside the seal are no taller than the seal already
   is, so the header does not grow — and the width they give back is the width
   the identity chip needed. */
@media (max-width: 560px) {
	.nitrusa-lockup {
		align-items: flex-start;
		gap: var(--sp-2);
	}
	.nitrusa-lockup__text {
		justify-content: flex-start;
		padding-block-end: 0;
	}
	.nitrusa-lockup__name {
		/* The one place the name may break. It reads as one unit and wrapping it
		   looked like a fault on a wide screen; on a phone the alternative is
		   truncating a member's own name instead, which is worse. */
		white-space: normal;
		text-wrap: balance;
	}

	/* With the lockup narrower, the chip stops being capped at 150px and shows
	   the name it exists to show — but *shrinkable*, not simply uncapped.
	   Uncapped it took its content's width, the actions column would not
	   shrink below it, and the header ran 45px off the side: the identity was
	   readable and the seal was gone. `min-width: 0` is what lets it give way
	   before the row does. */
	.nitrusa-whoami { max-width: none; min-width: 0; }
	.nitrusa-header-actions,
	.nitrusa-header-actions__row { min-width: 0; }

	/* The caption and the section menu say the same word — "Directory" beside
	   a control reading "Directory". The menu says it and can change it, so the
	   caption stands down and gives the row its width back. */
	body:has(.nitrusa-sectionmenu) .nitrusa-caption { display: none; }
}

/* ---- Navigation ---------------------------------------------------------- */

.main-navigation,
.main-navigation .inside-navigation {
	background-color: transparent;
}

.main-navigation a {
	color: var(--c-text-muted);
	font-weight: var(--fw-medium);
	transition: color var(--transition);
}
.main-navigation a:hover,
.main-navigation .current-menu-item > a {
	color: var(--c-text);
}
.main-navigation .current-menu-item > a {
	box-shadow: inset 0 -2px 0 var(--c-highlight);
}

/* ---- Buttons ------------------------------------------------------------- */

/* Deliberately NOT a blanket `button` rule.
   The first version styled every <button>, which turned GeneratePress's menu
   toggle into a large blue slab. Structural controls own their own styling. */
.button,
.wp-block-button__link,
button.nitrusa-button,
input[type="submit"],
#buddypress .generic-button a,
#buddypress input[type="submit"] {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-2);
	/* WCAG 2.5.5 / DSN-7: comfortable touch target on every device. */
	min-height: 44px;
	padding: var(--sp-3) var(--sp-5);
	border: 1px solid transparent;
	border-radius: var(--r-md);
	background-color: var(--c-accent);
	color: var(--c-text-on-accent);
	font: inherit;
	font-weight: var(--fw-semibold);
	line-height: 1;
	cursor: pointer;
	transition: background-color var(--transition), transform var(--transition);
}
.button:hover,
.wp-block-button__link:hover,
button.nitrusa-button:hover,
input[type="submit"]:hover,
#buddypress .generic-button a:hover {
	background-color: var(--c-accent-hover);
	color: var(--c-text-on-accent);
}
.button:disabled, button.nitrusa-button:disabled, input[type="submit"]:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* ---- Menu toggle --------------------------------------------------------- */
/* A navigation control, not a call to action. It should read as part of the
   header, not compete with it. */
.menu-toggle,
.menu-toggle:hover,
.menu-toggle:focus,
button.menu-toggle {
	background-color: transparent;
	color: var(--c-text);
	border: 1px solid var(--c-border-strong);
	border-radius: var(--r-md);
	min-height: 44px;
	padding: var(--sp-2) var(--sp-4);
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
}
.menu-toggle:hover { background-color: var(--c-surface-hover); }

.button--secondary {
	background-color: transparent;
	border-color: var(--c-border-strong);
	color: var(--c-text);
}
.button--secondary:hover {
	background-color: var(--c-surface-hover);
	color: var(--c-text);
}

.button--highlight {
	background-color: var(--c-highlight);
	color: var(--c-text-on-highlight);
}
.button--highlight:hover { background-color: var(--c-highlight-hover); }

/* ---- Forms --------------------------------------------------------------- */

label {
	display: block;
	margin-bottom: var(--sp-2);
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	color: var(--c-text);
}

input[type="text"], input[type="email"], input[type="url"], input[type="tel"],
input[type="password"], input[type="search"], input[type="number"],
select, textarea {
	width: 100%;
	min-height: 44px;
	padding: var(--sp-3);
	background-color: var(--c-bg);
	border: var(--border);
	border-radius: var(--r-md);
	color: var(--c-text);
	font: inherit;
	transition: border-color var(--transition), box-shadow var(--transition);
}
input:focus, select:focus, textarea:focus {
	border-color: var(--c-accent);
	box-shadow: 0 0 0 3px rgb(77 163 255 / 0.2);
}
::placeholder { color: var(--c-text-subtle); opacity: 1; }

.nitrusa-field__error { color: var(--c-error); font-size: var(--fs-sm); margin-top: var(--sp-2); }

/* ---- Cards and surfaces -------------------------------------------------- */

.nitrusa-card {
	background-color: var(--c-surface);
	border: var(--border);
	border-radius: var(--r-lg);
	padding: var(--sp-5);
	transition: border-color var(--transition), background-color var(--transition);
}
.nitrusa-card:hover { border-color: var(--c-border-strong); }

/* ---- Body copy (DSN-21) --------------------------------------------------
   Written content is one colour: --c-text (grey 300). Emphasis is carried by
   weight, not by a second, brighter colour -- bold text was rendering at
   grey 50, so a paragraph containing bold read as two different greys and the
   page looked like it had two body styles. */

/* Prose only. Listings render inside .entry-content too, and an unscoped
   `.entry-content li` outranked every component rule that tried to make a
   listing's own text quieter -- the privilege labels came out as body copy. */
.entry-content,
.entry-content > p,
.entry-content > ul li,
.entry-content > ol li,
.entry-content > dl dd,
.entry-content > blockquote,
.entry-content > table td,
.entry-content > .wp-block-paragraph,
.entry-content > .wp-block-list li {
	color: var(--c-text);
}

.entry-content strong,
.entry-content b,
.nitrusa-page strong,
.nitrusa-page b {
	color: inherit;
	font-weight: var(--fw-semibold);
}

.entry-content em,
.entry-content i { color: inherit; }

/* Prose links stay legible as links. Scoped to text that is actually prose:
   listings are rendered inside .entry-content too, and an unscoped rule turned
   every card title blue when card titles are names, not links to follow. */
.entry-content > p a,
.entry-content > ul a,
.entry-content > ol a,
.entry-content > blockquote a,
.entry-content > .wp-block-paragraph a {
	color: var(--c-accent);
	text-underline-offset: 0.2em;
}

/* Card titles are names. They take the heading colour, never the link colour. */
.nitrusa-ecard__title,
.nitrusa-ecard__title a,
.nitrusa-ecard__link {
	color: var(--c-text-strong);
}

/* ---- Tables: scroll inside their own container, never the page (DSN-7) ---- */

.nitrusa-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table { width: 100%; border-collapse: collapse; }
th, td {
	padding: var(--sp-3);
	text-align: left;
	border-bottom: 1px solid var(--c-border);
}
th { color: var(--c-text-muted); font-size: var(--fs-sm); font-weight: var(--fw-semibold); }

/* ---- Hero ---------------------------------------------------------------- */

.nitrusa-hero {
	padding-block: var(--sp-5) var(--sp-7);
	background-color: var(--c-bg);
}
.nitrusa-hero__lead {
	font-size: var(--fs-xl);
	color: var(--c-text-muted);
	max-width: 55ch;
	margin: 0;
}

/* The artwork sits below the text at full size, in normal flow.
   It was previously absolutely positioned behind the text, which cropped it
   against the section edge and dimmed it to the point of looking like a defect. */
.nitrusa-hero__art {
	display: block;
	width: 100%;
	max-width: 1100px;
	height: auto;
	margin: var(--sp-6) auto 0;
	pointer-events: none;
	user-select: none;
}

/* ---- BuddyBoss surfaces -------------------------------------------------- */
/* Kept to tokens only, so a BuddyBoss update changes markup but not our palette. */

#buddypress {
	color: var(--c-text);
}
#buddypress .dir-search input[type="search"],
#buddypress .dir-search input[type="text"] {
	background-color: var(--c-surface);
}
#buddypress div.item-list-tabs ul li a {
	color: var(--c-text-muted);
}
#buddypress div.item-list-tabs ul li.selected a,
#buddypress div.item-list-tabs ul li a:hover {
	color: var(--c-text);
}
#buddypress .activity-list .activity-item,
#buddypress .profile .bp-widget {
	background-color: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--r-lg);
}

/* ---- Utility ------------------------------------------------------------- */

.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.screen-reader-text:focus-visible {
	position: static !important;
	width: auto; height: auto; clip: auto;
	padding: var(--sp-3); background: var(--c-surface);
}

.nitrusa-muted { color: var(--c-text-muted); }
.nitrusa-stack > * + * { margin-top: var(--sp-4); }

/* ---- Header layout ------------------------------------------------------- */
/* The header row is defined once, in navigation.css, together with the
   hamburger and caption that sit in it. It used to be declared here as well,
   with different values (wrap vs nowrap, centre vs baseline), and which one
   won depended on stylesheet order -- so the header laid out differently on
   mobile than the rule here described. */

/* ---- Widgets and sidebar ------------------------------------------------- */
/* Widget titles inherited the h2 scale, so "Recent Comments" wrapped over three
   lines in a narrow column. */

.widget .widget-title,
.widget h2,
.wp-block-group h2,
.sidebar .wp-block-heading {
	font-size: var(--fs-lg);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-snug);
	margin-bottom: var(--sp-3);
	text-wrap: pretty;
}

.widget, .sidebar .widget {
	border: 1px solid var(--c-border);
	border-radius: var(--r-lg);
}
.widget ul { padding-left: 0; list-style: none; }
.widget li + li { margin-top: var(--sp-2); }

/* ---- Search -------------------------------------------------------------- */
/* The block search renders label, input and button as siblings; without this the
   input collapsed to a small square. */

.wp-block-search__inside-wrapper {
	display: flex;
	gap: var(--sp-2);
	align-items: stretch;
}
.wp-block-search__input {
	flex: 1 1 auto;
	min-width: 0;
}
.wp-block-search__button {
	flex: 0 0 auto;
	white-space: nowrap;
}

/* ---- Article and content surfaces ---------------------------------------- */
/* Belt and braces alongside the variable bridge in tokens.css, for anything
   GeneratePress paints without going through --base-3. */

.inside-article,
.entry-content,
.comments-area,
.page-header {
	color: var(--c-text);
}
.entry-title a { color: var(--c-text); }
.entry-title a:hover { color: var(--c-accent); }
.entry-meta { color: var(--c-text-muted); font-size: var(--fs-sm); }
.entry-meta a { color: var(--c-text-muted); }
.entry-meta a:hover { color: var(--c-accent); }

/* Long single words must not force a horizontal scrollbar (DSN-7) — but
   `anywhere` was the wrong tool. It breaks eagerly ("Active" became "A/ctive")
   and, worse, it shrinks an element's min-content width, which collapsed the
   member grid into tall narrow columns. `break-word` only breaks a word that
   genuinely cannot fit, and leaves intrinsic sizing alone. */
h1, h2, h3, h4, h5, h6, p, a { overflow-wrap: break-word; }

/* ---- Front page ---------------------------------------------------------- */

.nitrusa-hero__lead { margin: 0; }

/* The hero is a centred composition: one line of copy above the artwork, both
   centred on the page rather than ragged against the left inset. */
.nitrusa-section--hero { text-align: center; }
.nitrusa-section--hero .nitrusa-lead {
	max-width: 42ch;
	margin-inline: auto;
	text-wrap: balance;
}
.nitrusa-hero__art {
	display: block;
	margin-inline: auto;
	max-width: 100%;
	height: auto;
}

.nitrusa-section { padding-block: var(--sp-7); }

.nitrusa-cards {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--sp-4);
	grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}
.nitrusa-card__title { font-size: var(--fs-lg); margin-bottom: var(--sp-2); }
.nitrusa-card__title a { text-decoration: none; }

/* ---- BuddyBoss surfaces --------------------------------------------------
   With ReadyLaunch off, BuddyBoss renders through our theme, but ships its own
   light-theme stylesheet. These map its structures onto our tokens.

   Selectors are kept to BuddyBoss's stable container classes rather than deep
   descendant chains, so a template update changes markup inside them without
   silently reverting the palette (ADR-0001). */

#buddypress,
.buddypress-wrap,
.members-directory-wrapper,
.members-directory-container {
	background-color: transparent;
	color: var(--c-text);
}



.buddypress-wrap .member-name,
.buddypress-wrap .member-name a,
.buddypress-wrap .item-title,
.buddypress-wrap .item-title a {
	color: var(--c-text-strong);
	font-weight: var(--fw-semibold);
	text-decoration: none;
}
.buddypress-wrap .member-name a:hover,
.buddypress-wrap .item-title a:hover { color: var(--c-accent); }

.buddypress-wrap .item-meta,
.buddypress-wrap .member-status,
.buddypress-wrap .activity,
.buddypress-wrap .last-activity {
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}

/* Navigation tabs and sub-navs — BuddyBoss paints the selected item white. */
.buddypress-wrap .bp-navs,
.buddypress-wrap .bp-subnavs,
.buddypress-wrap .main-navs {
	background-color: transparent;
	border-bottom: 1px solid var(--c-border);
}
.buddypress-wrap .bp-navs li a,
.buddypress-wrap .bp-subnavs li a {
	background-color: transparent;
	color: var(--c-text-muted);
}
.buddypress-wrap .bp-navs li.current a,
.buddypress-wrap .bp-navs li.selected a,
.buddypress-wrap .bp-subnavs li.current a,
.buddypress-wrap .bp-subnavs li.selected a,
.buddypress-wrap .main-navs li.selected a {
	background-color: var(--c-surface);
	color: var(--c-text-strong);
	border-radius: var(--r-md) var(--r-md) 0 0;
}
.buddypress-wrap .bp-navs li a .count,
.buddypress-wrap .bp-navs li.selected a .count {
	background-color: var(--c-accent);
	color: var(--c-text-on-accent);
}

/* Search and filter row. */
.buddypress-wrap .dir-search input[type="search"],
.buddypress-wrap .dir-search input[type="text"],
.buddypress-wrap .bp-search input,
.buddypress-wrap select {
	background-color: var(--c-bg);
	border: 1px solid var(--c-border-strong);
	color: var(--c-text);
}
.buddypress-wrap .bp-pagination,
.buddypress-wrap .pagination-links a,
.buddypress-wrap .pag-count {
	color: var(--c-text-muted);
}
.buddypress-wrap .pagination-links a:hover,
.buddypress-wrap .pagination-links span.current {
	color: var(--c-text-strong);
}

/* Avatars: give the placeholder something to sit on in the dark. */
.buddypress-wrap .item-avatar img,
.buddypress-wrap img.avatar {
	background-color: var(--c-surface-hover);
	border-radius: var(--r-full);
}

/* ---- Entity card (DSN-12) ------------------------------------------------
   The standard listing pattern for every entity: member, chapter, news item,
   announcement, blog post, event.

       [ icon/avatar ] [ title + info ] [ date + status ]

   The whole card is clickable via a stretched link — one real anchor rather
   than a JavaScript handler, so keyboard, middle-click and right-click all
   behave as links should. */

.nitrusa-ecards {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--sp-3);
}

.nitrusa-ecard {
	position: relative;                 /* containing block for the stretched link */
	display: grid;
	/* `minmax(0, 1fr)`, never a bare `1fr` (DSN-31). A `1fr` track carries an
	   automatic minimum of its content's min-content width, and the *third*
	   cell shares this track on a phone — so one unbreakable value in it, a
	   branch like "Electronics & Telecommunication", widened the middle column
	   past the card and pushed the member's name out through the side. The
	   floor of 0 is what lets the track shrink and the ellipsis engage. */
	grid-template-columns: var(--ecard-lead) minmax(0, 1fr) var(--ecard-aside);
	align-items: start;
	gap: var(--sp-4);
	padding: var(--sp-4) var(--sp-5);
	background-color: var(--c-surface);
	border: var(--border);
	border-radius: var(--r-lg);
	transition: border-color var(--transition), background-color var(--transition);
}
.nitrusa-ecard:hover {
	background-color: var(--c-surface-hover);
	border-color: var(--c-border-strong);
}
/* The focus ring belongs on the card, not the text inside it. */
.nitrusa-ecard:focus-within {
	outline: var(--focus-ring);
	outline-offset: var(--focus-offset);
}

.nitrusa-ecard__figure {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border-radius: var(--r-full);
	background-color: var(--c-bg);
	color: var(--c-icon);
	overflow: hidden;
	flex: 0 0 auto;
}
.nitrusa-ecard__figure img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: var(--r-full);
	/* A transparent or partly transparent avatar shows the card's own ground,
	   not white. */
	background-color: var(--c-bg);
}

/* ---- Entity card: the author cell (CNT-8) --------------------------------
   On a content card the first cell attributes the item rather than picturing
   it, so the avatar gains a name beneath it. The two are one grid child, not
   two: the card is three cells wide by definition (DSN-12) and a fourth column
   would push the date out of its own.

   The name is capped in ch rather than px so the cap follows the type size, and
   it wraps rather than truncating -- a member's name is the one thing on this
   card that must not be shortened to fit. */

.nitrusa-ecard__author {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--sp-2);
	width: 100%;              /* the fixed lead column is the width */
	min-width: 0;
}

.nitrusa-ecard__byline {
	max-width: 100%;
	color: var(--c-text-muted);
	font-size: var(--fs-xs);
	line-height: var(--lh-snug);
	text-align: center;
	overflow-wrap: break-word;   /* never `anywhere` -- DSN-12 */
}

/* Below the third-cell breakpoint the card drops to two columns (DSN-7), and
   the lead column keeps its width so the titles still line up. Laying the
   author out as a row here would be the obvious move and the wrong one: avatar
   plus name side by side is the widest form of the same information, on the
   screen that has the least room for it. */

.nitrusa-ecard__body { min-width: 0; }   /* lets long words wrap instead of overflowing */

.nitrusa-ecard__title {
	margin: 0;
	font-size: var(--fs-lg);
	line-height: var(--lh-snug);
	color: var(--c-text-strong);
}
.nitrusa-ecard__link {
	color: inherit;
	text-decoration: none;
}
.nitrusa-ecard__link::after {
	content: "";
	position: absolute;
	inset: 0;                            /* the stretched link */
	border-radius: inherit;
}
.nitrusa-ecard:hover .nitrusa-ecard__link { color: var(--c-accent); }
.nitrusa-ecard__link:focus-visible { outline: none; }  /* the card shows the ring */

.nitrusa-ecard__meta,
.nitrusa-ecard__excerpt {
	margin: var(--sp-1) 0 0;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	max-width: 70ch;
}

.nitrusa-ecard__aside {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: var(--sp-1);
	text-align: right;
	flex: 0 0 auto;
	/* A grid child's automatic minimum is its min-content width, and this cell
	   holds the longest single values on the card — a branch, a venue, a date
	   with a zone. Without this the cell refuses to shrink and takes the card
	   apart with it (DSN-31). */
	min-width: 0;
	max-width: 100%;
}
.nitrusa-ecard__date {
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	white-space: nowrap;
}

/* An event's date says when it happens, with a time and a zone (EVT-9), so it
   is several times longer than the "Sep 2" the rule above was written for. At
   360px it hung 56px outside its own card. It may wrap -- and only at the
   points the label marks with ordinary spaces, every unit inside it being held
   together with non-breaking ones. */
.nitrusa-ecard--event .nitrusa-ecard__date {
	white-space: normal;
	text-wrap: balance;
}
.nitrusa-ecard__status {
	font-size: var(--fs-xs);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
	padding: 2px var(--sp-2);
	border-radius: var(--r-full);
	white-space: nowrap;
}
/* A privilege label (DSN-20): shown only when a member holds something beyond
   plain membership, so it reads as "this person is different" rather than as a
   field every card carries. */
.nitrusa-ecard__badge {
	font-size: var(--fs-xs);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
	padding: 2px var(--sp-2);
	border-radius: var(--r-full);
	white-space: nowrap;
	color: var(--c-accent);
	background: color-mix(in srgb, var(--c-accent) 14%, transparent);
}

.nitrusa-ecard__status--neutral  { color: var(--c-text-muted); background: var(--c-bg); }
.nitrusa-ecard__status--positive { color: var(--c-success);    background: var(--c-bg); }
.nitrusa-ecard__status--warning  { color: var(--c-warning);    background: var(--c-bg); }
.nitrusa-ecard__status--muted    { color: var(--c-text-subtle); background: transparent; }

/* ---- Entity card: icon-led facts (DSN-22) --------------------------------
   Each value is introduced by its own icon, so a card can be scanned down its
   icons without reading the words. In list view the body's facts sit under the
   name and the third cell's run right-aligned; in grid they stack centred. */

.nitrusa-ecard__facts {
	list-style: none;
	margin: var(--sp-2) 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--sp-1);
	min-width: 0;
	max-width: 100%;
}
.nitrusa-ecard .nitrusa-ecard__fact,
.nitrusa-ecard__fact {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	line-height: var(--lh-snug);
	min-width: 0;
	max-width: 100%;
}
.nitrusa-ecard__fact .nitrusa-icon {
	flex: 0 0 auto;
	width: 16px;
	height: 16px;
	color: var(--c-icon);
}
.nitrusa-ecard__fact-text {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* A contact detail on a card is a link of its own (PRF-C-3): it opens mail or
   dials. It has to sit above the card's stretched link, or every tap on it
   opens the profile instead, and it is in the accent colour so it reads as
   something to press rather than as one more fact. */
.nitrusa-ecard__fact-link {
	position: relative;
	z-index: 1;
	color: var(--c-accent);
	text-decoration: none;
	max-width: 100%;
}
.nitrusa-ecard__fact-link:hover { color: var(--c-accent-hover); text-decoration: underline; }

/* On a touch screen each one is a full-height target (DSN-7). Only there: with
   a mouse, four 44px rows would double the height of every card for nothing. */
@media (pointer: coarse) {
	.nitrusa-ecard__fact-link {
		display: inline-block;
		line-height: var(--touch-target);
		min-width: var(--touch-target);
	}
	.nitrusa-profile__contact {
		display: inline-block;
		line-height: var(--touch-target);
	}
}

/* The third cell is aligned to the right edge, but each row still reads icon
   first: an icon that swaps sides between cells makes the card scan as two
   different components (DSN-22). */
.nitrusa-ecard__facts--aside { margin-top: 0; align-items: flex-end; }

@media (max-width: 560px) {
	/* Stacked under the body, so the third cell sits with the rest of the card
	   rather than staying flush right in a narrow column. */
	.nitrusa-ecard__facts--aside { align-items: flex-start; }
}

/* ---- Privileges, wherever they appear (DSN-24) ---------------------------
   One treatment site-wide: grey 500, at 80% of body size. A privilege is
   context rather than the headline -- somebody scanning a directory is looking
   for people first -- so it sits back from the facts around it. */

.nitrusa-ecard .nitrusa-ecard__fact--privilege,
.nitrusa-ecard__fact--privilege,
.nitrusa-ecard__badge,
.nitrusa-privilege {
	color: var(--c-privilege);
	font-size: var(--fs-privilege);
}

/* Each privilege is a chip: a small bounded label, so two of them read as two
   things rather than as one run of words. They wrap as a set. */
.nitrusa-chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-1);
	min-width: 0;
	max-width: 100%;
}
.nitrusa-chip {
	display: inline-flex;
	align-items: center;
	padding: 1px var(--sp-2);
	border: 1px solid var(--c-privilege);
	border-radius: var(--r-full);
	color: var(--c-privilege);
	font-size: var(--fs-privilege);
	line-height: 1.7;
	/* Must not overflow the cell. Chips wrap as a set, and a single label too
	   long for the cell on its own wraps inside its own chip rather than
	   pushing through the side -- ellipsis would hide which office it is,
	   which is the one thing the chip exists to say. */
	max-width: 100%;
	min-width: 0;
	white-space: normal;
	overflow-wrap: anywhere;
	text-align: center;
}
.nitrusa-ecard__fact--privilege .nitrusa-icon,
.nitrusa-ecard__badge .nitrusa-icon {
	color: var(--c-privilege);
}
.nitrusa-ecard__badge { background: transparent; padding-inline: 0; }

/* ---- Entity card: grid view ---------------------------------------------
   The same card, stacked, for scanning many entities at once. `.grid` is
   toggled onto the list by the host plugin's own view switch, so the toggle
   needs no JavaScript from us.

   Cells are compact and sized by their content (DSN-14): a small avatar, the
   name on one line, one line of context. Long names truncate rather than
   stretching every cell in the row. */

.nitrusa-ecards.grid {
	display: grid;
	/* Wide enough that a name and a privilege label fit without wrapping into
	   a tall cell -- the grid exists to fit many people on screen, and a cell
	   taller than it is wide fits fewer than a list would. */
	grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
	/* Equal cells: 1fr columns give equal widths, and stretching the rows
	   gives equal heights, so the grid reads as a grid rather than as a
	   collection of differently sized tiles. */
	grid-auto-rows: 1fr;
	align-items: stretch;
	gap: var(--sp-3);
}
.nitrusa-ecards.grid > .nitrusa-ecard { height: 100%; }
.nitrusa-ecards.grid .nitrusa-ecard {
	grid-template-columns: 1fr;
	justify-items: center;
	/* Top-justified: cells are stretched to a common height, so without this
	   the shorter ones float their contents down the middle and the row stops
	   reading as a row. */
	align-content: start;
	text-align: center;
	gap: var(--sp-2);
	padding: var(--sp-3);
}
/* Reading order in a grid cell: name, then the two things people scan by
   (branch and year), then where they are, then what they hold.

   The body is set to `display: contents` so the title and its facts become
   children of the card itself. Only then can the third cell be ordered between
   them -- while they sit inside a wrapper, the aside can only come before the
   whole body or after it, and neither is the order asked for. */
.nitrusa-ecards.grid .nitrusa-ecard__body {
	display: contents;
}
.nitrusa-ecards.grid .nitrusa-ecard__figure { order: 1; }
.nitrusa-ecards.grid .nitrusa-ecard__title  { order: 2; }
.nitrusa-ecards.grid .nitrusa-ecard__aside  { order: 3; }   /* branch and year */
.nitrusa-ecards.grid .nitrusa-ecard__meta,
.nitrusa-ecards.grid .nitrusa-ecard__excerpt { order: 4; }
.nitrusa-ecards.grid .nitrusa-ecard__body > .nitrusa-ecard__facts { order: 5; }
.nitrusa-ecards.grid .nitrusa-ecard__actions { order: 0; }

/* Long values -- "Computer Science and Engineering" -- must be trimmed to the
   cell, not pushed through its side. Every box between the cell and the text
   has to be allowed to shrink, or the innermost one keeps its intrinsic width
   and overflows however the outer ones are sized.

   The card itself is deliberately *not* clipped. Clipping it here did trim the
   branch, but it also cut off the privileges menu, which hangs below the card
   on purpose -- an officer in grid view could not grant anything. The text
   elements clip themselves instead, which is where the overflow actually is. */
.nitrusa-ecards.grid .nitrusa-ecard__facts,
.nitrusa-ecards.grid .nitrusa-ecard__title { max-width: 100%; min-width: 0; }
.nitrusa-ecards.grid .nitrusa-ecard__fact {
	max-width: 100%;
	min-width: 0;
}
.nitrusa-ecards.grid .nitrusa-ecard__fact-text {
	min-width: 0;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.nitrusa-ecards.grid .nitrusa-ecard__figure { width: 40px; height: 40px; }
.nitrusa-ecards.grid .nitrusa-ecard__meta { margin-top: 0; }
.nitrusa-ecards.grid .nitrusa-ecard__title {
	font-size: var(--fs-base);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
/* In a grid cell the privileges run on one line, side by side, rather than
   taking a row each: two or three short labels stacked make a short card tall
   for no gain, and they are read as a set anyway. Anything that is not a
   privilege keeps its own line, so the chapter is not jumbled in with them. */
.nitrusa-ecards.grid .nitrusa-ecard__facts {
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	column-gap: var(--sp-3);
	row-gap: var(--sp-1);
}
.nitrusa-ecards.grid .nitrusa-ecard__fact { flex: 0 1 auto; min-width: 0; max-width: 100%; }
.nitrusa-ecards.grid .nitrusa-ecard__fact--privilege { flex: 1 1 100%; justify-content: center; }
.nitrusa-ecards.grid .nitrusa-chips { justify-content: center; }
.nitrusa-ecards.grid .nitrusa-ecard__fact:not(.nitrusa-ecard__fact--privilege) {
	flex: 1 1 100%;
	justify-content: center;
}
.nitrusa-ecards.grid .nitrusa-ecard__facts--aside .nitrusa-ecard__fact { flex-direction: row; }
.nitrusa-ecards.grid .nitrusa-ecard__meta,
.nitrusa-ecards.grid .nitrusa-ecard__excerpt {
	font-size: var(--fs-xs);
	line-height: var(--lh-snug);
}
/* The third cell stays, laid out under the body rather than beside it. Only
   the date goes: a privilege label (DSN-20) and the chapter are exactly what
   someone is scanning a grid for, and hiding the whole cell hid those too. */
.nitrusa-ecards.grid .nitrusa-ecard__aside {
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	text-align: center;
	gap: var(--sp-1);
	width: 100%;
}
.nitrusa-ecards.grid .nitrusa-ecard__date { display: none; }

@media (max-width: 480px) {
	.nitrusa-ecards.grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
}

/* On a phone the third cell drops beneath the body rather than squeezing the
   title into a column two words wide (DSN-7). */
/* ---- The card on a phone: one flow, not three columns (DSN-32) -----------
   Above this width the card is three columns and stays so. Below it, the first
   cell keeping a column of its own for the card's whole height meant a 44px
   avatar with a one-word caption reserved a fifth of a 320px screen all the way
   down, while the title beside it wrapped to four lines in what was left. The
   card fitted; it was not readable.

   So the first cell **floats** and the rest flows around it — beside it while
   it lasts, and into the space beneath it once past. A float rather than a
   grid, because this is the one thing grid cannot express: a grid cell reserves
   its column for the full height of the row, which is exactly the problem. */

@media (max-width: 560px) {
	.nitrusa-ecard {
		/* `flow-root` rather than plain `block`: it contains the float without
		   clipping, so a card whose text is shorter than its first cell still
		   ends below it. `overflow: hidden` would contain it too, and would
		   also cut off the action menu's open panel. */
		display: flow-root;
		/* A phone is where the padding costs the most: at 320px the card's own
		   inset was taking a sixth of the width from the only column with
		   anything to read in it. */
		padding-inline: var(--sp-4);
	}

	.nitrusa-ecard__figure,
	.nitrusa-ecard__author {
		float: inline-start;
		margin-inline-end: var(--sp-3);
		margin-block-end: var(--sp-2);
	}

	/* Fixed height, so what resumes below it resumes at the same place on every
	   card. A caption longer than fits is clipped rather than growing the cell
	   — a deliberate departure from DSN-22's "the byline wraps rather than
	   truncating", which was written for a cell that owned a full-height
	   column. At 60% of body in a fixed box the case barely arises, and the
	   alternative is a ragged list with an unpredictable wrap point. */
	.nitrusa-ecard__author {
		width: var(--ecard-lead-phone);
		height: var(--ecard-lead-h);
		justify-content: flex-start;
		overflow: hidden;
	}

	/* Context, not the headline: the same 60% of body a privilege chip takes
	   (DSN-24). Somebody scanning a listing is reading for the item, not for
	   who filed it. */
	.nitrusa-ecard__byline {
		font-size: var(--fs-privilege);
		line-height: var(--lh-snug);
		/* Clamped to whole lines with an ellipsis. Letting the cell's own
		   `overflow: hidden` do it cut the second line through the middle and
		   showed a row of letter-tops, which reads as broken rather than as
		   shortened. */
		display: -webkit-box;
		-webkit-box-orient: vertical;
		-webkit-line-clamp: 2;
		line-clamp: 2;
		overflow: hidden;
	}

	.nitrusa-ecard__aside {
		flex-direction: row;
		/* Several values on one row wrap as a set rather than running off the
		   side: a date, a status and a fact will not fit side by side at 320px
		   and must not pretend to. */
		flex-wrap: wrap;
		align-items: center;
		justify-content: flex-start;
		text-align: left;
	}

	/* A wrapped bar is rows of sticky chrome above every listing (DSN-33), so
	   below the breakpoint the items give back what they can: less padding
	   between them, and a smaller gap, which is the difference between three
	   rows and two on a 320px screen. The 44px touch target is untouched — that
	   is the one thing not available to trade. */
	.nitrusa-members-bar__list,
	.nitrusa-actionbar {
		gap: 0;
	}
	.nitrusa-members-bar__item > a,
	.nitrusa-members-bar__item > span,
	.nitrusa-actionbar .nitrusa-actions__item {
		padding-inline: var(--sp-2);
		gap: var(--sp-1);
	}

	/* The grid view is untouched. Its cells are stacked and centred by a real
	   grid (`grid-template-columns`, `align-content`, and a body set to
	   `display: contents` so the third cell can be ordered between the title
	   and the facts) — none of which survives being turned into flow layout,
	   and none of which has the problem this section exists to fix. */
	.nitrusa-ecards.grid .nitrusa-ecard {
		display: grid;
	}
	.nitrusa-ecards.grid .nitrusa-ecard__figure,
	.nitrusa-ecards.grid .nitrusa-ecard__author {
		float: none;
		width: auto;
		height: auto;
		margin-inline-end: 0;
	}
}

/* Below the narrowest phone the avatar gives a little more back. The caption
   is already at 60%, so the cell is as narrow as its picture. */
@media (max-width: 400px) {
	.nitrusa-ecard { --ecard-lead-phone: 4rem; }
	.nitrusa-ecard__figure { width: 44px; height: 44px; }
	.nitrusa-ecards.grid .nitrusa-ecard__figure { width: 40px; height: 40px; }
}



/* ---- Page titles are not repeated on the page (IA-4) --------------------
   The header caption already names the page. Visually hidden rather than
   removed, so the document still has an h1 for assistive technology and for
   search engines — the duplication is visual, not structural. */

.page .entry-title,
.page-header .page-title,
.buddypress-wrap > h1,
.buddypress-wrap > .screen-heading,
body.page .entry-header .entry-title {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- BuddyBoss controls take the standard border ------------------------ */

.buddypress-wrap .dir-search input[type="search"],
.buddypress-wrap .dir-search input[type="text"],
.buddypress-wrap .bp-search input,
.buddypress-wrap select,
.buddypress-wrap .component-navigation,
.buddypress-wrap .bp-navs {
	border: var(--border);
	border-radius: var(--r-md);
	background-color: var(--c-bg);
	color: var(--c-text);
}
.buddypress-wrap .bp-navs { border-radius: var(--r-md) var(--r-md) 0 0; }

/* The grid/list view toggle and its buttons. */
.buddypress-wrap .grid-filters button,
.buddypress-wrap .layout-view {
	background-color: var(--c-bg);
	border: var(--border);
	border-radius: var(--r-md);
	color: var(--c-icon);
}
.buddypress-wrap .grid-filters button.active,
.buddypress-wrap .layout-view.active {
	background-color: var(--c-surface-hover);
	color: var(--c-text-strong);
}




/* BuddyBoss's directory scope nav renders a single "All Members" tab, because
   the components that would add others — Connections, Groups filtering — are
   off. A one-item tab bar is a control that cannot do anything, so it is
   hidden. If a second scope is ever enabled, remove this rule. */
.buddypress-wrap .members-type-navs,
.buddypress-wrap .bp-navs.dir-navs.members-nav,
#members-dir-list ~ .members-type-navs {
	display: none;
}



/* ==========================================================================
   BuddyBoss overrides — high specificity, deliberately
   --------------------------------------------------------------------------
   BuddyBoss ships a large stylesheet whose selectors are more specific than
   ours, so earlier `.buddypress-wrap …` rules matched but lost. These use the
   directory's own ids, and `!important` on the handful of properties BuddyBoss
   sets from several places at once.

   This is the documented exception to the no-!important rule in CLAUDE.md:
   overriding a third-party stylesheet we do not control and must not edit
   (ADR-0001). It is confined to this block.
   ========================================================================== */

/* ---- Background: the members area is the same page as everything else ---- */
#buddypress,
.buddypress-wrap,
.bp-wrap,
#members-dir-list,
.members-directory-content,
.members-directory-container,
.members-directory-wrapper,
.bp-list-wrap {
	background-color: transparent !important;
	background-image: none !important;
}

/* ---- Inputs and selects take the standard border (DSN-13) --------------- */
#buddypress input[type="text"],
#buddypress input[type="search"],
#buddypress input[type="email"],
#buddypress select,
#buddypress textarea,
.dir-search input,
.bp-search input,
.bp-dir-search-form input,
#buddypress .select-wrap select,
/* Our own toolbar controls take the same metrics as the platform's, or the
   two bars are the same design at two different heights (DSN-26). */
.nitrusa-toolbar__search input[type="search"],
.nitrusa-toolbar__sort select,
.nitrusa-toolbar__filter select {
	background-color: var(--c-bg) !important;
	border: var(--border) !important;
	border-radius: var(--r-md) !important;
	color: var(--c-text) !important;
	min-height: 44px;
	padding: var(--sp-2) var(--sp-3);
	box-shadow: none !important;
}
#buddypress .select-wrap,
#buddypress .dir-search,
#buddypress .bp-search {
	border: 0 !important;
	background: transparent !important;
}

/* ---- View switch: a segmented push toggle (DSN-26) ----------------------
   The directory's grid/list pair and the album's grid/card/carousel trio are
   the same control: one bordered group, the current option filled. They were
   two components until the photo screen's outlined pills made plain they had
   drifted. */
.grid-filters,
.nitrusa-toolbar__views {
	display: inline-flex !important;
	align-items: stretch;
	height: auto !important;
	border: var(--border) !important;
	border-radius: var(--r-md);
	overflow: hidden;
	background-color: var(--c-bg);
}
.grid-filters .layout-view,
.nitrusa-toolbar__view {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding: 0 var(--sp-3) !important;
	margin: 0;
	border: 0 !important;
	border-radius: 0;
	background-color: transparent;
	color: var(--c-text-muted) !important;
	line-height: 1 !important;
	transition: background-color var(--transition), color var(--transition);
}
.grid-filters .layout-view + .layout-view,
.nitrusa-toolbar__view + .nitrusa-toolbar__view { border-inline-start: var(--border) !important; }
.grid-filters .layout-view:hover,
.nitrusa-toolbar__view:hover { background-color: var(--c-surface-hover); color: var(--c-text) !important; }
.grid-filters .layout-view.active,
.nitrusa-toolbar__view.is-current {
	background-color: var(--c-accent) !important;
	color: var(--c-text-on-accent) !important;
}
.nitrusa-toolbar__view {
	font-size: var(--fs-sm);
	text-decoration: none;
	white-space: nowrap;
}





/* ==========================================================================
   BuddyBoss detail pages — profile, group, and single-item screens (DSN-15)
   --------------------------------------------------------------------------
   Same rationale and same confinement as the block above: BuddyBoss's own
   stylesheet is more specific, so these carry ids and !important where needed.
   ========================================================================== */

/* ---- Profile / group header -------------------------------------------- */
#item-header,
#item-header-content,
#item-header-avatar,
.bb-single-header,
.single-headers,
#buddypress div#item-header {
	background-color: transparent !important;
	border: 0 !important;
	color: var(--c-text);
}

/* The cover placeholder is a pale image; give it our surface instead of a
   light slab at the top of every profile. */
#header-cover-image,
#item-header-cover-image #header-cover-image,
.bb-cover-photo,
#cover-image-container {
	background-color: var(--c-surface) !important;
	background-image: none !important;
	border: var(--border) !important;
	border-radius: var(--r-lg);
}

#item-header .user-nicename,
#item-header h2,
#item-header h1,
.bb-user-name,
#buddypress #item-header-content h2 {
	color: var(--c-text-strong) !important;
}
#item-header .activity,
#item-header .item-meta,
#buddypress #item-header-content .activity {
	color: var(--c-text-muted) !important;
}

/* ---- Item navigation tabs ---------------------------------------------- */
#buddypress div#object-nav,
#buddypress div#subnav,
#buddypress .bp-navs,
#buddypress .bp-subnavs,
#buddypress .main-navs,
.bp-single-plain-nav {
	background-color: transparent !important;
	border: 0 !important;
	border-bottom: var(--border) !important;
	border-radius: 0 !important;
	box-shadow: none !important;
}
#buddypress .bp-navs li a,
#buddypress .bp-subnavs li a,
#buddypress .main-navs li a {
	background-color: transparent !important;
	color: var(--c-text-muted) !important;
	border: 0 !important;
	border-radius: var(--r-md) var(--r-md) 0 0;
}
#buddypress .bp-navs li.current > a,
#buddypress .bp-navs li.selected > a,
#buddypress .bp-subnavs li.current > a,
#buddypress .bp-subnavs li.selected > a,
#buddypress .main-navs li.selected > a {
	background-color: var(--c-surface) !important;
	color: var(--c-text-strong) !important;
	box-shadow: inset 0 -2px 0 var(--c-highlight);
}
#buddypress .bp-navs li a:hover { color: var(--c-text) !important; }

/* ---- Profile field tables ---------------------------------------------- */
/* BuddyBoss renders profile data as a table with white rows; the values were
   pale text on white and effectively unreadable. */
#buddypress table.profile-fields,
#buddypress .bp-tables-user,
#buddypress table.profile-fields tr,
#buddypress table.profile-fields td,
#buddypress table.profile-fields th,
#buddypress .bp-widget table,
#buddypress .bp-profile-data {
	background-color: transparent !important;
	color: var(--c-text) !important;
	border-color: var(--c-border) !important;
}
#buddypress table.profile-fields {
	border: var(--border) !important;
	border-radius: var(--r-lg);
	border-collapse: separate;
	border-spacing: 0;
	overflow: hidden;
	width: 100%;
}
#buddypress table.profile-fields tr:nth-child(even) td,
#buddypress table.profile-fields tr:nth-child(even) th {
	background-color: var(--c-surface) !important;
}
#buddypress table.profile-fields td,
#buddypress table.profile-fields th {
	padding: var(--sp-3) var(--sp-4) !important;
	border-bottom: var(--border) !important;
	vertical-align: top;
}
#buddypress table.profile-fields tr:last-child td,
#buddypress table.profile-fields tr:last-child th { border-bottom: 0 !important; }
#buddypress table.profile-fields .label,
#buddypress table.profile-fields th {
	color: var(--c-text-muted) !important;
	font-weight: var(--fw-semibold);
	width: 30%;
}
#buddypress table.profile-fields .data,
#buddypress table.profile-fields td { color: var(--c-text) !important; }

/* ---- Panels and headings on detail screens ------------------------------ */
#buddypress .bp-widget,
#buddypress .profile,
#buddypress .bp-avatar-nav,
#buddypress .item-body,
#buddypress .bp-messages-content {
	background-color: transparent !important;
	border: 0 !important;
}
#buddypress .bp-widget h2,
#buddypress .screen-heading {
	color: var(--c-heading-section) !important;
	font-size: var(--fs-xl);
	background: transparent !important;
	border: 0 !important;
	padding: 0 0 var(--sp-2) 0 !important;
}

/* ---- Buttons on detail screens ------------------------------------------ */
#buddypress .generic-button a,
#buddypress a.button,
#buddypress input[type="submit"],
#buddypress button.submit {
	background-color: var(--c-accent) !important;
	border: var(--border) !important;
	border-color: transparent !important;
	border-radius: var(--r-md) !important;
	color: var(--c-text-on-accent) !important;
}
#buddypress .generic-button a:hover,
#buddypress a.button:hover { background-color: var(--c-accent-hover) !important; }

/* ---- WordPress single posts (news, blogs, announcements) ---------------- */
.single .entry-content,
.single .entry-header,
.archive .entry-content {
	background-color: transparent;
	color: var(--c-text);
}
.single .entry-title { color: var(--c-heading); }
.single .entry-meta,
.archive .entry-meta { color: var(--c-text-muted); }

/* ---- Page surface and vertical rhythm (DSN-16) --------------------------
   GeneratePress wraps page content in .inside-article and paints it from
   --base-3, which is our surface tone. That made every page except the custom
   front page sit on a lighter panel than the home page. Content sits directly
   on the page background instead. */

/* The wrappers are transparent so the page shell's own background shows
   through. #primary is deliberately NOT in this list: it *is* the shell
   (.nitrusa-page) and owns the page background. Including it here made the
   shell transparent, so the two rules cancelled out and the background came
   from whatever was behind. */
body .inside-article,
body .separate-containers .inside-article,
body .site-content,
body .content-area,
body .entry-content {
	background-color: transparent !important;
	box-shadow: none !important;
}

/* The band under the sticky header (DSN-16).

   This was "halved" twice and was still too deep, because the gap is the sum
   of four separate contributions and only one was being reduced: the content
   wrapper's padding, the main element's margin, the page shell's own padding,
   and BuddyBoss's margin above its directory. Each is set to zero here and the
   whole gap is then owned by one declaration -- .nitrusa-page's block-start
   padding -- so it can be tuned in one place and stays consistent everywhere. */
body .separate-containers .inside-article,
body .separate-containers .page-header,
body .separate-containers .comments-area {
	padding: 0 !important;
}
body .separate-containers .site-main,
body .site-content .content-area,
body .separate-containers .site-content,
body #content.site-content {
	margin-top: 0 !important;
	padding-top: 0 !important;
}
#buddypress,
.buddypress-wrap,
.buddypress-wrap .bb-subnav-filters-container,
.buddypress-wrap > .members-directory-wrapper {
	margin-top: 0 !important;
	padding-top: 0 !important;
}
body .nitrusa-section { padding-block: var(--sp-5); }

/* The directory search control is defined once, in the filter-bar block above.
   An earlier version of it lived here too, laying the form out as a flex row
   with the button beside the field. Both matched, the later one won, and the
   button ended up outside the field it belongs in. */




/* ---- Utilities the dequeued vendor stylesheet used to provide (DSN-19) ---
   Its templates still emit these class names. `bp-screen-reader-text` marks
   labels meant for assistive technology only -- with the stylesheet gone they
   rendered as visible text, so the filter bar read "Search Members... Search
   Reset" in full. They are re-implemented here rather than by restoring 824KB
   of vendor CSS. */

.bp-screen-reader-text,
.screen-reader-text,
.bp-hide {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}
.bp-screen-reader-text:focus,
.screen-reader-text:focus {
	position: static !important;
	width: auto;
	height: auto;
	clip: auto;
	clip-path: none;
	margin: 0;
}

/* The members bar is itself a band of chrome, so the content beneath it needs
   no separate breathing room: the shell's own top spacing sat between the two
   and pushed the search row 45px clear of the bar. Scoped to pages that
   actually have the bar, with the body classes as a fallback for engines
   without :has(). */

body:has(.nitrusa-members-bar) main.nitrusa-page,
body.buddypress main.nitrusa-page,
body.members main.nitrusa-page {
	padding-block-start: var(--sp-4);
	margin-top: 0 !important;
}

/* Except where the listing toolbar follows the bar: that row carries its own
   gap (DSN-26), and adding the page's on top of it pushed the search control
   twice as far from the menu as anything else on the members area. So the gap
   is the page's when nothing follows the bar, and the toolbar's when the
   toolbar is there -- one gap either way. */
body:has(.nitrusa-toolbar) main.nitrusa-page {
	padding-block-start: 0;
}

/* One gap under the bar, owned by the sticky row itself. */
.nitrusa-toolbar { padding-block: 12px; }

/* ---- The members area's menu bar (IA-9) ----------------------------------
   Sticky beneath the site header, carrying the sections of the members area.
   Borderless like the drawer's items: these are places to go, not actions to
   take, and five outlined buttons would read as five things to do. */

.nitrusa-members-bar {
	position: sticky;
	top: var(--header-height);
	z-index: 45;                      /* above the directory's filter row */
	background-color: var(--c-bg);
	border-block-end: 1px solid var(--c-border);
}
.nitrusa-members-bar__list {
	display: flex;
	align-items: stretch;
	gap: var(--sp-1);
	list-style: none;
	margin: 0 auto;
	padding: 0 var(--content-inset);
	max-width: var(--container);
	/* Wraps, never scrolls (DSN-33). It used to be `overflow-x: auto`, which
	   kept the page from scrolling sideways and hid five of the eight items off
	   the side of a phone — Settings among them, and an officer's Approvals and
	   Activity Log. A navigation item that cannot be seen cannot be used, and a
	   horizontal scroller inside a vertically scrolling page is close to
	   undiscoverable on a touch screen. */
	flex-wrap: wrap;
}

.nitrusa-members-bar__item > a,
.nitrusa-members-bar__item > span {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 48px;                 /* touch target (DSN-7) */
	padding: 0 var(--sp-3);
	border: 0;
	background: transparent;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	text-decoration: none;
	white-space: nowrap;
	border-block-end: 2px solid transparent;
	transition: color var(--transition), background-color var(--transition), border-color var(--transition);
}
.nitrusa-members-bar__item > a:hover,
.nitrusa-members-bar__item > a:focus-visible {
	color: var(--c-text);
	background-color: var(--c-surface-hover);
}
.nitrusa-members-bar__item .nitrusa-icon { color: var(--c-icon); flex: 0 0 auto; }

.nitrusa-members-bar__item.is-current > a {
	color: var(--c-text-strong);
	border-block-end-color: var(--c-highlight);
}

/* A section that does not exist yet is shown but never offered as a link. */
.nitrusa-members-bar__item.is-unavailable > span {
	color: var(--c-text-subtle);
	cursor: default;
}
.nitrusa-members-bar__item.is-unavailable .nitrusa-icon { color: var(--c-text-subtle); }

/* A toolbar on a members screen sits below the members bar, not under the
   header alone -- otherwise the two overlap the moment the page scrolls. */
.nitrusa-members-bar ~ * .nitrusa-toolbar,
body:has(.nitrusa-members-bar) .nitrusa-toolbar,
body.members .nitrusa-toolbar {
	top: calc(var(--header-height) + var(--members-bar-height, 49px));
}

/* The result count belongs to the sticky bar itself, not stacked beneath it.
   It answers "did my search work?", which stays useful all the way down a long
   list — and stacking it as a fourth sticky band meant its offset had to be
   computed from three measured heights, which was a pixel out whenever the
   filter row wrapped. It is moved into the bar instead, so there is one band
   and nothing to keep in step (DIR-5). */
.nitrusa-toolbar .bp-pagination.top {
	flex: 0 0 auto;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
}
.nitrusa-toolbar .bp-pagination.top .pag-count,
.nitrusa-toolbar .bp-pagination.top .pag-data,
.nitrusa-toolbar__count {
	margin: 0;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	white-space: nowrap;
}
/* The bar lays out as a row once the count joins it. */
.nitrusa-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.nitrusa-toolbar > .bb-subnav-filters-container,
.nitrusa-toolbar > .subnav-filters,
.nitrusa-toolbar__form { flex: 1 1 320px; margin-block-end: 0; }

/* ---- The listing toolbar: one row, and it stays (DSN-26, DIR-4, DIR-5) ---
   Search on the left with its icon inside the field, then the view switch, the
   sort control and the count. They wrap onto a second line only when the width
   genuinely cannot hold them.

   The row sticks below the chrome while the list scrolls, so search and sort
   stay reachable in a long list instead of being something you have to scroll
   back up to find. Every listing screen uses this one bar -- the directory,
   photos, videos -- because when they were built separately they diverged in
   look and only one of them stuck. */

.nitrusa-toolbar {
	position: sticky;
	top: var(--header-height);
	z-index: 40;
	background-color: var(--c-bg);
	padding-block: var(--sp-3);
	margin-block-end: var(--sp-2);
}
.nitrusa-toolbar__form {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-3);
	min-width: 0;
	margin: 0;
}
.nitrusa-toolbar__title {
	margin: 0 0 var(--sp-2);
	font-size: var(--fs-sm);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
	color: var(--c-caption);
}

.bb-subnav-filters-container,
.subnav-filters {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-3);
	width: 100%;
	margin-block-end: var(--sp-4);
	/* No rule under the filters: the cards below already separate themselves. */
	border: 0;
	box-shadow: none;
}
.subnav-search,
.dir-search,
.nitrusa-toolbar__search {
	flex: 1 1 260px;
	min-width: 0;
	max-width: 420px;
}

#dir-filters,
.component-filters {
	display: flex;
	align-items: center;
	flex: 0 1 auto;
	margin: 0;
	border: 0;
}
.grid-filters,
.nitrusa-toolbar__views { flex: 0 0 auto; margin-inline-start: auto; }

/* The search control is one field with the button inside it, rather than a
   field and a separate coloured block beside it. */
.bp-dir-search-form,
.nitrusa-toolbar__search {
	position: relative;
	display: block;
	width: 100%;
}
.bp-dir-search-form input[type="search"],
.bp-dir-search-form input[type="text"],
.nitrusa-toolbar__search input[type="search"] {
	width: 100%;
	padding-inline-end: 44px;    /* room for the button sitting on top */
}
#buddypress .nouveau-search-submit,
.bp-dir-search-form [type="submit"],
.nitrusa-toolbar__submit {
	position: absolute;
	inset-inline-end: 2px;
	top: 50%;
	transform: translateY(-50%);
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	min-width: 0;
	padding: 0 !important;
	background: transparent !important;
	border: 0 !important;
	border-radius: var(--r-md) !important;
	color: var(--c-icon) !important;
	cursor: pointer;
}
#buddypress .nouveau-search-submit:hover,
.bp-dir-search-form [type="submit"]:hover,
.nitrusa-toolbar__submit:hover {
	background: var(--c-surface-hover) !important;
	color: var(--c-accent) !important;
}

/* Enter submits the form, so a separate reset control is one more thing in the
   row without being the thing anyone came for. */
.search-form_reset { display: none !important; }

/* The sort control carries a sort glyph, so it needs no visible caption. The
   album filter is the same control with a different glyph (MED-10): one
   treatment, so the two read as a pair rather than as two designs. */
.select-wrap { position: relative; display: block; }
#buddypress #dir-filters select,
#dir-filters select,
.component-filters select,
.nitrusa-toolbar__sort select,
.nitrusa-toolbar__filter select {
	min-width: 14rem;
	/* Clear of the glyph: the platform sets its own horizontal padding, which
	   put the first word on top of the icon. */
	padding-inline-start: 42px !important;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234da3ff' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='M4 7h11M4 12h8M4 17h5'/%3E%3Cpath d='M17.5 10.5 20 8l2.5 2.5M20 8v9'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: 10px center;
	background-size: 18px 18px;
	appearance: none;
}
/* Stacked frames, matching the `albums` icon in chrome.php. A sort glyph on a
   filter would say the control does something it does not. */
.nitrusa-toolbar__filter select {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234da3ff' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7.5' y='3.5' width='13' height='11' rx='2'/%3E%3Cpath d='M17 18.5H6A2.5 2.5 0 0 1 3.5 16V7'/%3E%3Cpath d='m8 13 3.5-3 2.5 2 2-1.5 3.5 2.5'/%3E%3C/svg%3E");
}

@media (max-width: 700px) {
	.subnav-search, .dir-search, .nitrusa-toolbar__search { max-width: none; flex-basis: 100%; }
	#dir-filters { width: 100%; }
	#dir-filters select { width: 100%; }
	.grid-filters { margin-inline-start: 0; }

	/* Two rows on a phone, never four: search with the count, then sort with
	   the view switch. Stacked one control per row the bar stood 183px tall --
	   a fifth of the screen given to a control strip, and taller than the space
	   its own container could hold it in, so it slid off under the list anyway.

	   `display: contents` dissolves the form so its children become items of
	   the bar itself and can pair with the controls outside it. That is a
	   layout change only: the form still submits, and search and sort still
	   travel together.

	   The bases are stated rather than left to `auto`, because wrapping is
	   decided by each item's base size: at `auto` the sort took its content
	   width, no longer fitted beside the view switch, and claimed a row of its
	   own. Percentages that add to more than one row but less than two put each
	   pair where it belongs at every phone width. */
	.nitrusa-toolbar__form { display: contents; }
	.nitrusa-toolbar__search { order: 1; flex: 1 1 60%; min-width: 0; max-width: none; }
	.nitrusa-toolbar__count  { order: 2; flex: 0 0 auto; margin-inline-start: auto; }
	.nitrusa-toolbar__filter { order: 3; flex: 1 1 45%; min-width: 0; }
	.nitrusa-toolbar__sort   { order: 4; flex: 1 1 45%; min-width: 0; }
	.nitrusa-toolbar__views  { order: 5; flex: 0 0 auto; margin-inline-start: auto; }
	.nitrusa-toolbar__menu   { order: 6; flex: 0 0 auto; }
	.nitrusa-toolbar__sort select,
	.nitrusa-toolbar__filter select { width: 100%; min-width: 0; }
}

/* ---- Forms: log in, register, and anything else that asks for input -----
   One form treatment for the whole site (DSN-13). The register screen's
   fields are rendered by BuddyBoss from the profile field definitions, so the
   rules are written against plain elements inside .nitrusa-form rather than
   against BuddyBoss's class names -- a new field type then inherits the
   styling instead of needing a new selector. */

.nitrusa-form { max-width: 34rem; }

.nitrusa-form__section { margin-block-end: var(--sp-6); }
.nitrusa-form__section > h2 {
	font-size: var(--fs-sm);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	color: var(--c-heading-section);
	margin-block-end: var(--sp-4);
}

.nitrusa-form fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.nitrusa-form legend {
	color: var(--c-text);
	font-weight: var(--fw-semibold);
	padding: 0;
	margin-block-end: var(--sp-2);
}

.nitrusa-form p,
.nitrusa-form__field { margin-block: 0 var(--sp-4); }

.nitrusa-form label {
	display: block;
	color: var(--c-text);
	font-size: var(--fs-sm);
	font-weight: var(--fw-semibold);
	margin-block-end: var(--sp-2);
}
/* Checkbox and radio labels sit beside their control, not above it. */
.nitrusa-form label > input[type="checkbox"],
.nitrusa-form label > input[type="radio"],
.nitrusa-form input[type="checkbox"] + label,
.nitrusa-form input[type="radio"] + label {
	display: inline;
	font-weight: var(--fw-regular);
	margin: 0 var(--sp-2) 0 0;
}

.nitrusa-form input[type="text"],
.nitrusa-form input[type="email"],
.nitrusa-form input[type="url"],
.nitrusa-form input[type="tel"],
.nitrusa-form input[type="number"],
.nitrusa-form input[type="date"],
.nitrusa-form input[type="password"],
.nitrusa-form select,
.nitrusa-form textarea {
	width: 100%;
	min-height: 44px;                 /* comfortable touch target (DSN-7) */
	padding: var(--sp-2) var(--sp-3);
}
.nitrusa-form textarea { min-height: 8rem; resize: vertical; }

/* Field descriptions BuddyBoss renders under a profile field. */
.nitrusa-form .description,
.nitrusa-form__hint {
	display: block;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	font-weight: var(--fw-regular);
	margin-block-start: var(--sp-1);
}

.nitrusa-form input[type="submit"],
.nitrusa-form button[type="submit"],
.nitrusa-form .button {
	min-height: 44px;
	padding: 0 var(--sp-5);
	background-color: var(--c-accent);
	border: 0;
	border-radius: var(--r-md);
	color: var(--c-text-on-accent);
	font-weight: var(--fw-semibold);
	cursor: pointer;
	transition: background-color var(--transition);
}
.nitrusa-form input[type="submit"]:hover,
.nitrusa-form button[type="submit"]:hover,
.nitrusa-form .button:hover { background-color: var(--c-accent-hover); }

.nitrusa-form__aside {
	margin-block-start: var(--sp-4);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}
.nitrusa-form__sep { color: var(--c-text-subtle); margin-inline: var(--sp-1); }

/* ---- Who you are signed in as (AUTH-3) -----------------------------------
   The top line of the header actions: avatar, first name, privileges. The whole
   badge logs you out, so it carries a visible label saying so rather than
   leaving the click to be discovered.

   Deliberately unbordered: it is a statement of fact about the current session,
   not a button competing with the header's other controls. The avatar and the
   separator before "Log out" give it enough shape without an outline, and a
   pill drawn around it read as a second wordmark beside the real one. Hover
   still tints, so the log-out affordance is discoverable. */

.nitrusa-whoami {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	padding: var(--sp-1) var(--sp-2);
	border: 0;
	border-radius: var(--r-full);
	background-color: transparent;
	color: var(--c-text);
	text-decoration: none;
	max-width: 240px;
	transition: background-color var(--transition);
}
.nitrusa-whoami:hover {
	background-color: var(--c-surface-hover);
}
.nitrusa-whoami__avatar { display: inline-flex; flex: 0 0 auto; }
.nitrusa-whoami__avatar img {
	width: 28px;
	height: 28px;
	border-radius: var(--r-full);
	display: block;
}
.nitrusa-whoami__body { min-width: 0; display: flex; flex-direction: column; line-height: var(--lh-tight); }
.nitrusa-whoami__name {
	font-size: var(--fs-sm);
	font-weight: var(--fw-semibold);
	color: var(--c-text-strong);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.nitrusa-whoami__roles {
	font-size: var(--fs-xs);
	color: var(--c-accent);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.nitrusa-whoami__action {
	flex: 0 0 auto;
	font-size: var(--fs-xs);
	color: var(--c-text-muted);
	padding-inline-start: var(--sp-2);
	border-inline-start: 1px solid var(--c-border);
}
@media (max-width: 560px) {
	.nitrusa-whoami { max-width: 150px; }
	.nitrusa-whoami__action { display: none; }   /* the aria-label still says it */
}

/* ---- The privileges control (ADM-2) --------------------------------------
   A vertical-dots control on the member card, opening a set of checkboxes.
   Built on <details>, so it opens and closes without JavaScript and cannot be
   left stuck open by a script that failed to load. */

.nitrusa-ecard { position: relative; }

.nitrusa-ecard__actions {
	position: absolute;
	inset-block-start: var(--sp-2);
	inset-inline-end: var(--sp-2);
	z-index: 2;                       /* above the card's stretched link */
}

/* The control floats over the card, so the cell beneath it has to stop before
   it starts. Without this the right-hand cell -- the year and the branch, which
   are right-justified -- ran under the dots and the two read as one crowded
   lump. Only on cards that actually carry the control: a card without one has
   no reason to leave a gap. */
.nitrusa-ecard:has(.nitrusa-ecard__actions) .nitrusa-ecard__aside {
	padding-inline-end: var(--sp-6);
}
.nitrusa-ecards.grid .nitrusa-ecard:has(.nitrusa-ecard__actions) .nitrusa-ecard__aside {
	padding-inline-end: 0;            /* the grid cell stacks; nothing is beside it */
}
/* In a grid cell the name is the thing that reaches the top corner instead. */
.nitrusa-ecards.grid .nitrusa-ecard:has(.nitrusa-ecard__actions) .nitrusa-ecard__title {
	padding-inline: var(--sp-6);
}

/* Positioning this container creates a stacking context, so the open panel's
   own z-index is measured *inside* it -- the whole subtree competes at 2, and
   the sticky members bar (45) painted straight over the checkboxes. Raised only
   while the control is open: kept high, the dots would float above the bar as
   the card scrolls under it. Above the members bar, below the site header (50),
   so nothing escapes the page's chrome. */
.nitrusa-ecard__actions:has(.nitrusa-actions[open]) {
	z-index: 46;
}

.nitrusa-actions { position: relative; }
.nitrusa-actions__toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	border-radius: var(--r-full);
	color: var(--c-text-muted);
	font-size: var(--fs-lg);
	line-height: 1;
	cursor: pointer;
	list-style: none;                 /* no disclosure triangle */
	transition: background-color var(--transition), color var(--transition);
}
.nitrusa-actions__toggle::-webkit-details-marker { display: none; }
.nitrusa-actions__toggle:hover { background-color: var(--c-surface-hover); color: var(--c-text); }
.nitrusa-actions[open] .nitrusa-actions__toggle { background-color: var(--c-surface-hover); color: var(--c-accent); }

.nitrusa-actions__panel {
	position: absolute;
	inset-inline-end: 0;
	top: calc(100% + var(--sp-1));
	z-index: 30;
	min-width: 15rem;
	padding: var(--sp-3);
	background-color: var(--c-bg-elevated);
	border: var(--border);
	border-radius: var(--r-md);
	box-shadow: var(--shadow-lg);
	text-align: start;
}
.nitrusa-actions__panel fieldset { border: 0; margin: 0 0 var(--sp-3); padding: 0; }
.nitrusa-actions__panel legend {
	padding: 0;
	margin-block-end: var(--sp-2);
	font-size: var(--fs-xs);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	color: var(--c-text-muted);
}
/* A tick-list inside an action panel: the offices a member holds (ADM-2), the
   albums a photograph is in (MED-9). One rule, two names — the question is the
   same shape and so is the control. */
.nitrusa-privileges__option,
.nitrusa-albumpick__option {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 32px;
	margin: 0;
	color: var(--c-text);
	font-size: var(--fs-sm);
	font-weight: var(--fw-regular);
	cursor: pointer;
}
.nitrusa-privileges__option input,
.nitrusa-albumpick__option input { width: 16px; height: 16px; accent-color: var(--c-accent); }

/* A long list of albums scrolls inside the panel rather than growing it past
   the bottom of the screen (DSN-31). */
.nitrusa-albumpick__form fieldset {
	max-height: 15rem;
	overflow-y: auto;
}

/* ---- Action items, in the menu and on the bar (EVT-13, DSN-30) -----------
   One treatment for an action wherever it appears: a row in the card's menu,
   a control on a detail page's bar. Links and submit buttons look identical,
   because to the member they are the same thing -- the difference is only
   whether the action changes something. */

.nitrusa-actions__item {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	width: 100%;
	min-height: 44px;
	padding: var(--sp-2) var(--sp-3);
	border: 0;
	border-radius: var(--r-sm);
	background: none;
	color: var(--c-text);
	font: inherit;
	font-size: var(--fs-sm);
	text-align: start;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--transition), color var(--transition);
}
.nitrusa-actions__item:hover,
.nitrusa-actions__item:focus-visible { background-color: var(--c-surface-hover); color: var(--c-text-strong); }
.nitrusa-actions__item--danger { color: var(--c-error); }
.nitrusa-actions__item--danger:hover,
.nitrusa-actions__item--danger:focus-visible { color: var(--c-error); background-color: color-mix(in srgb, var(--c-error) 12%, transparent); }
.nitrusa-actions__form { margin: 0; }

/* The one case where an unavailable action is present rather than absent: the
   member came to find out whether they can register (EVT-13). */
.nitrusa-actions__note {
	margin: 0;
	padding: var(--sp-2) var(--sp-3);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}

/* ---- The detail page's action bar (EVT-14) -------------------------------
   **The same bar as the members area's** (IA-9). It carries different items —
   an event's actions rather than the members area's sections — but a member
   moving between them must not meet two different bars, so the treatment is
   one: borderless items, icon left of label, and the current one marked by the
   highlight underline rather than by a fill.

   Outlined buttons were the first attempt and were wrong: five bordered pills
   read as five things you must do, when most of them are places to go. */
.nitrusa-actionbar {
	display: flex;
	align-items: stretch;
	gap: var(--sp-1);
	margin-bottom: var(--sp-5);
	border-block-end: 1px solid var(--c-border);
	/* Wraps, never scrolls — the same rule as the members bar, for the same
	   reason (DSN-33). Cancel and Delete are the items that fall off the end of
	   this one, which is the worst possible pair to hide. */
	flex-wrap: wrap;
}

.nitrusa-actionbar .nitrusa-actions__item {
	width: auto;
	min-height: 48px;
	padding: 0 var(--sp-3);
	border: 0;
	border-radius: 0;
	border-block-end: 2px solid transparent;
	color: var(--c-text-muted);
	font-weight: var(--fw-medium);
	white-space: nowrap;
}
.nitrusa-actionbar .nitrusa-actions__item:hover,
.nitrusa-actionbar .nitrusa-actions__item:focus-visible {
	color: var(--c-text);
	background-color: var(--c-surface-hover);
}
.nitrusa-actionbar .nitrusa-icon { color: var(--c-icon); flex: 0 0 auto; }

/* Where you are now, marked exactly as the members bar marks it. */
.nitrusa-actionbar .nitrusa-actions__item.is-current {
	color: var(--c-text-strong);
	border-block-end-color: var(--c-highlight);
}

/* A destructive action keeps its colour but not a border. */
.nitrusa-actionbar .nitrusa-actions__item--danger { color: var(--c-error); }

.nitrusa-actionbar .nitrusa-actions__note {
	/* A statement sits with the controls without pretending to be one. */
	align-self: center;
	white-space: nowrap;
}

/* ---- Pending registrations, shown where the approver already is ---------- */

.nitrusa-pending {
	padding: var(--sp-4);
	border: var(--border);
	border-inline-start: 3px solid var(--c-warning);
	border-radius: var(--r-lg);
	background-color: var(--c-surface);
	margin-block-end: var(--sp-5);
}
/* Collapsed by default, so the queue announces itself in one line rather than
   pushing the directory off the screen (ADM-1). The summary *is* the banner. */
.nitrusa-pending__summary {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	min-height: 44px;
	cursor: pointer;
	list-style: none;
}
.nitrusa-pending__summary::-webkit-details-marker { display: none; }
.nitrusa-pending__summary:focus-visible {
	outline: var(--focus-ring);
	outline-offset: var(--focus-offset);
}

/* The number carries the weight, so the count is legible before the sentence
   is read. */
.nitrusa-pending__count {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2rem;
	height: 2rem;
	padding-inline: var(--sp-2);
	border-radius: var(--r-full);
	background-color: var(--c-warning);
	color: var(--c-bg);
	font-weight: var(--fw-bold);
	font-variant-numeric: tabular-nums;
	flex: 0 0 auto;
}

.nitrusa-pending__title {
	margin: 0;
	font-size: var(--fs-lg);
	color: var(--c-text-strong);
}

/* The disclosure arrow, in the same idiom as the listing groups. */
.nitrusa-pending__summary::after {
	content: "";
	width: 0.5em;
	height: 0.5em;
	margin-inline-start: auto;
	border-inline-end: 2px solid var(--c-icon);
	border-block-end: 2px solid var(--c-icon);
	transform: rotate(45deg) translate(-0.1em, -0.1em);
	transition: transform var(--transition);
	flex: 0 0 auto;
}
.nitrusa-pending[open] > .nitrusa-pending__summary::after {
	transform: rotate(225deg) translate(-0.1em, -0.1em);
}
/* Open, the banner needs a gap before the queue it revealed. */
.nitrusa-pending[open] > .nitrusa-pending__summary { margin-block-end: var(--sp-4); }

/* ---- Photos and videos (MED-4) -------------------------------------------
   Three formats. The metadata goes somewhere different in each, so each has
   its own rules — but the card format has none of its own at all: it is the
   site's entity card, unchanged. */

/* The album's search, sort, view switch and count are the shared listing
   toolbar (DSN-26) -- there are deliberately no rules for them here. */

/* ---- Grid: metadata beneath the thumbnail ------------------------------- */

.nitrusa-media-grid {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: var(--sp-4);
}
.nitrusa-media-grid__item {
	background-color: var(--c-surface);
	border: var(--border);
	border-radius: var(--r-lg);
	overflow: hidden;
}
.nitrusa-media__image {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	background-color: var(--c-bg);
}
.nitrusa-media__image--missing { display: block; }
.nitrusa-media__meta { padding: var(--sp-3); }

/* The album control sits at the top right of the metadata block, where the
   entity card puts the same control (MED-9, DSN-30). Floated rather than
   absolutely placed, so the heading wraps beside it instead of running under
   it on a narrow cell. */
.nitrusa-media__meta .nitrusa-actions--albums {
	float: inline-end;
	margin-inline-start: var(--sp-2);
}
/* The grid cell clips to its corner radius, which would take the open panel
   with it -- and the neighbouring cells would paint over what survived. Both
   are lifted only while the menu is open, so the rounding is unaffected the
   rest of the time. */
.nitrusa-media-grid__item:has(.nitrusa-actions[open]) {
	position: relative;
	z-index: 46;
	overflow: visible;
}
.nitrusa-media__event {
	margin: 0 0 var(--sp-1);
	font-size: var(--fs-base);
	color: var(--c-text-strong);
	line-height: var(--lh-snug);
}
.nitrusa-media__description {
	margin: 0 0 var(--sp-2);
	color: var(--c-text);
	font-size: var(--fs-sm);
}
.nitrusa-media__meta .nitrusa-ecard__facts { margin-top: var(--sp-2); }

/* Card format: the entity card, with a picture where the avatar goes. */
.nitrusa-ecard--media .nitrusa-ecard__figure {
	width: 96px;
	height: 72px;
	border-radius: var(--r-md);
}
.nitrusa-ecard--media .nitrusa-ecard__figure img { border-radius: var(--r-md); }

/* ---- Carousel: one at a time, metadata in the bar beneath --------------- */

/* The wrapper clips on the x axis, and that is not belt-and-braces: the track
   inside it is a scroll container, but the page still reported the width of all
   three slides and scrolled sideways by 355px at 360px wide. `clip` rather than
   `hidden` so the y axis stays visible — `hidden` on one axis forces the other
   to scroll, which would trap the dots' focus ring in a scroll box (DSN-31). */
.nitrusa-carousel {
	position: relative;
	overflow-x: clip;
}
.nitrusa-carousel__track {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	gap: var(--sp-4);
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	-webkit-overflow-scrolling: touch;
}
.nitrusa-carousel__slide {
	flex: 0 0 100%;
	scroll-snap-align: center;
	background-color: var(--c-surface);
	border: var(--border);
	border-radius: var(--r-lg);
	overflow: hidden;
}
.nitrusa-carousel__slide:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.nitrusa-carousel__stage { background-color: var(--c-bg); }
.nitrusa-carousel__stage .nitrusa-media__image { aspect-ratio: 16 / 9; }
.nitrusa-media__embed { position: relative; aspect-ratio: 16 / 9; }
.nitrusa-media__embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* The metadata card in the navigation bar beneath the image. */
.nitrusa-carousel__bar {
	padding: var(--sp-3) var(--sp-4);
	border-block-start: var(--border);
	background-color: var(--c-surface);
}

.nitrusa-carousel__dots {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2);
	justify-content: center;
	margin: var(--sp-3) 0 0;
	padding: 0;
}
.nitrusa-carousel__dots a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px;
	min-height: 32px;
	border-radius: var(--r-full);
	border: var(--border);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	text-decoration: none;
}
.nitrusa-carousel__dots a:hover { background-color: var(--c-surface-hover); color: var(--c-text); }

/* ---- Upload ------------------------------------------------------------- */

.nitrusa-upload { margin-block-end: var(--sp-5); }
.nitrusa-upload > summary { display: inline-flex; align-items: center; cursor: pointer; list-style: none; }
.nitrusa-upload > summary::-webkit-details-marker { display: none; }
.nitrusa-upload__form {
	margin-block-start: var(--sp-4);
	padding: var(--sp-4);
	border: var(--border);
	border-radius: var(--r-lg);
	background-color: var(--c-surface);
}
/* A file input is the one control the browser sizes for us, and it sizes it to
   its own button plus a filename: 312px, with `max-width: none`, whatever it is
   put in. At 320px that is wider than the form holding it, and because nothing
   clipped it the whole page scrolled sideways (DSN-31). Site-wide rather than
   scoped to the upload form, because every file input has this problem and the
   member import screen has one too. */
input[type="file"] {
	display: block;
	width: 100%;
	max-width: 100%;
}

.nitrusa-upload__file { margin-block-end: var(--sp-4); }
.nitrusa-upload__file label { display: block; margin-block-end: var(--sp-2); color: var(--c-text); font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
.nitrusa-upload__note { color: var(--c-text-muted); font-size: var(--fs-sm); max-width: 46ch; }

@media (max-width: 600px) {
	.nitrusa-toolbar__views { margin-inline-start: 0; }
}

/* ---- A member's profile (MEM-9) -----------------------------------------
   The card, then Professional, then Personal. No cover image and no second
   navigation: the site header and the members bar already say where you are,
   and the platform's versions of both were chrome we do not need. */

.nitrusa-profile__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-3);
	margin-block: var(--sp-4) 0;
}

.nitrusa-profile__section-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-3);
	margin-block-end: var(--sp-3);
}
.nitrusa-profile__section-head h2 { margin-block-end: 0; }
.nitrusa-profile__edit { min-height: 34px; padding-inline: var(--sp-3); font-size: var(--fs-sm); }

.nitrusa-profile__section h2 {
	font-size: var(--fs-sm);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	color: var(--c-heading-section);
	margin-block-end: var(--sp-3);
}

.nitrusa-profile__fields { margin: 0; }
.nitrusa-profile__row {
	display: grid;
	grid-template-columns: minmax(9rem, 14rem) 1fr;
	gap: var(--sp-4);
	padding-block: var(--sp-3);
	border-block-end: 1px solid var(--c-border);
}
.nitrusa-profile__row:last-child { border-block-end: 0; }
.nitrusa-profile__row dt {
	margin: 0;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}
.nitrusa-profile__row dd {
	margin: 0;
	color: var(--c-text);
	min-width: 0;
	overflow-wrap: break-word;
}
.nitrusa-profile__row dd a { color: var(--c-accent); }
.nitrusa-profile__contact { overflow-wrap: anywhere; }   /* a long address wraps, never widens the page (DSN-31) */

@media (max-width: 560px) {
	.nitrusa-profile__row { grid-template-columns: 1fr; gap: var(--sp-1); }
}

/* The platform's own screens -- editing, the photograph, settings -- inside
   our shell. Their forms are handled by the field component (DSN-23). */
.nitrusa-member-screen { margin-block-start: var(--sp-4); }
/* The list inside the <nav> is what actually holds the items, so the row has
   to be declared on it as well -- flexing the wrapper alone left a <nav> in a
   row containing a stacked <ul>, which is what put the sub-tabs in a column. */
.nitrusa-member-screen .bp-navs,
.nitrusa-member-screen #subnav,
.nitrusa-member-screen .bp-subnavs,
.nitrusa-member-screen .bp-navs > ul,
.nitrusa-member-screen .bp-subnavs > ul {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2);
	list-style: none;
	margin: 0 0 var(--sp-4);
	padding: 0;
	border-block-end: 1px solid var(--c-border);
}
.nitrusa-member-screen .bp-navs li,
.nitrusa-member-screen .bp-subnavs li { list-style: none; }
.nitrusa-member-screen .bp-navs a,
.nitrusa-member-screen .bp-subnavs a {
	display: inline-flex;
	align-items: center;
	min-height: 40px;
	padding: 0 var(--sp-3);
	color: var(--c-text-muted);
	text-decoration: none;
	border-block-end: 2px solid transparent;
}
.nitrusa-member-screen .bp-navs .current a,
.nitrusa-member-screen .bp-navs .selected a,
.nitrusa-member-screen .bp-subnavs .current a,
.nitrusa-member-screen .bp-subnavs .selected a {
	color: var(--c-text-strong);
	border-block-end-color: var(--c-highlight);
}

/* ---- Editing a profile group (MEM-6) -------------------------------------
   The plugin renders this screen: a row of group tabs, then one fieldset per
   field carrying its description *above* the control and its visibility
   setting after it. Three things are corrected without touching the markup --
   the tabs arrive as a bare list, the description belongs below the box
   (DSN-23), and the visibility line is a caption about the field rather than
   an action competing with Save. */

#buddypress .profile.edit .button-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2);
	list-style: none;
	margin: 0 0 var(--sp-5);
	padding: 0;
	border-block-end: 1px solid var(--c-border);
}
#buddypress .profile.edit .button-tabs li { list-style: none; margin: 0; }
#buddypress .profile.edit .button-tabs a {
	display: inline-flex;
	align-items: center;
	min-height: 40px;
	padding: 0 var(--sp-3);
	color: var(--c-text-muted);
	text-decoration: none;
	border-block-end: 2px solid transparent;
	transition: color var(--transition), border-color var(--transition);
}
#buddypress .profile.edit .button-tabs a:hover { color: var(--c-text); }
#buddypress .profile.edit .button-tabs .current a {
	color: var(--c-text-strong);
	border-block-end-color: var(--c-highlight);
}

/* One block per field, its parts in the order DSN-23 specifies rather than the
   order the plugin emits them. Reordered visually rather than by moving nodes,
   so `aria-describedby` still points at a description that follows its control
   in the accessibility tree. */
#buddypress .editfield { margin-block-end: var(--sp-5); }
#buddypress .editfield > fieldset {
	display: flex;
	flex-direction: column;
	gap: var(--sp-2);
	margin: 0;
	padding: 0;
	border: 0;
}
#buddypress .editfield .nitrusa-field { order: 1; margin-block-end: 0; }
#buddypress .editfield > fieldset > .description { order: 2; }
#buddypress .editfield .field-visibility-settings-header { order: 3; }
#buddypress .editfield .field-visibility-settings { order: 4; }

#buddypress .editfield .description {
	margin: 0;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}

/* Who may see this field. With the members area gated (NFR-SEC-8) the default
   -- visible to the whole membership -- is what every field is unless its
   owner says otherwise, and a line under every box announcing it was noise
   that also read as a promise the site does not make: nothing here is public.
   So the default says nothing, and only a restricted field speaks up. The
   control to change it stays on every field either way. */
#buddypress .editfield.visibility-loggedin .current-visibility-level,
#buddypress .editfield.visibility-public .current-visibility-level { display: none; }

#buddypress .field-visibility-settings-header {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	margin: 0;
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
}
#buddypress .field-visibility-settings-header .current-visibility-level { color: var(--c-text-muted); }
#buddypress .visibility-toggle-link,
#buddypress .field-visibility-settings-close {
	min-height: 32px;
	padding: 0 var(--sp-2) !important;
	background: transparent !important;
	border: 0 !important;
	color: var(--c-accent) !important;
	font-size: var(--fs-sm) !important;
	font-weight: var(--fw-regular) !important;
	text-decoration: underline;
	cursor: pointer;
}
#buddypress .field-visibility-settings {
	margin: 0;
	padding: var(--sp-3);
	background-color: var(--c-surface);
	border: var(--border);
	border-radius: var(--r-md);
}
#buddypress .field-visibility-settings fieldset { margin: 0; padding: 0; border: 0; }
#buddypress .field-visibility-settings legend {
	padding: 0;
	margin-block-end: var(--sp-2);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}
#buddypress .field-visibility-settings .bp-radio-wrap {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 32px;
}
#buddypress .field-visibility-settings label {
	margin: 0;
	color: var(--c-text);
	font-size: var(--fs-sm);
	font-weight: var(--fw-regular);
}
#buddypress .field-visibility-settings input[type="radio"] { min-height: 0; margin: 0; }
#buddypress .bp-hide { display: none; }

/* ---- Member settings (MEM-8) --------------------------------------------
   A topic per row, a channel per column. On a phone the table becomes a stack
   of topics, each checkbox labelled by the column it came from, because a
   two-column grid of unlabelled boxes is unreadable once the header scrolls
   away (DSN-7). */

.nitrusa-settings__table {
	width: 100%;
	border-collapse: collapse;
	margin-block: var(--sp-4);
}
.nitrusa-settings__table th,
.nitrusa-settings__table td {
	padding: var(--sp-3);
	border-block-end: 1px solid var(--c-border);
	text-align: start;
	vertical-align: top;
}
.nitrusa-settings__table thead th {
	color: var(--c-text-muted);
	font-size: var(--fs-xs);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	white-space: nowrap;
}
.nitrusa-settings__table tbody th { font-weight: var(--fw-regular); }
.nitrusa-settings__table td { text-align: center; width: 8rem; }
.nitrusa-settings__table input[type="checkbox"] {
	width: 20px;
	height: 20px;
	accent-color: var(--c-accent);
	cursor: pointer;
}

.nitrusa-settings__label { display: block; color: var(--c-text-strong); font-weight: var(--fw-semibold); }
.nitrusa-settings__hint  { display: block; color: var(--c-text-muted); font-size: var(--fs-sm); margin-block-start: 2px; }

.nitrusa-settings__note {
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	max-width: 46ch;
	margin-block-end: var(--sp-4);
}

@media (max-width: 600px) {
	.nitrusa-settings__table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
	.nitrusa-settings__table tr { display: block; padding-block: var(--sp-3); border-block-end: 1px solid var(--c-border); }
	.nitrusa-settings__table th,
	.nitrusa-settings__table td { display: block; border: 0; padding: var(--sp-1) 0; width: auto; text-align: start; }
	.nitrusa-settings__table td { display: flex; align-items: center; gap: var(--sp-2); }
	.nitrusa-settings__table td::before {
		content: attr(data-label);
		color: var(--c-text-muted);
		font-size: var(--fs-sm);
		order: 2;
	}
}

/* ---- The activity log (ADM-3) ------------------------------------------- */

.nitrusa-log { list-style: none; margin: var(--sp-4) 0 0; padding: 0; }
.nitrusa-log__entry {
	display: grid;
	grid-template-columns: 12rem 1fr;
	gap: var(--sp-4);
	padding: var(--sp-3) 0;
	border-block-end: 1px solid var(--c-border);
	align-items: baseline;
}
.nitrusa-log__when { color: var(--c-text-muted); font-size: var(--fs-sm); white-space: nowrap; }
.nitrusa-log__what { color: var(--c-text); }

@media (max-width: 560px) {
	.nitrusa-log__entry { grid-template-columns: 1fr; gap: var(--sp-1); }
}

/* ---- Approvals queue (ADM-1) -------------------------------------------- */

.nitrusa-approval-actions {
	list-style: none;
	margin: calc(var(--sp-3) * -1) 0 0;
	padding: 0 var(--sp-5) var(--sp-4);
}
.nitrusa-approval-form { display: flex; gap: var(--sp-2); }

.nitrusa-btn {
	min-height: 40px;
	padding: 0 var(--sp-4);
	border-radius: var(--r-md);
	border: var(--border);
	font-weight: var(--fw-semibold);
	font-size: var(--fs-sm);
	cursor: pointer;
	background: transparent;
	color: var(--c-text);
	transition: background-color var(--transition), border-color var(--transition);
}
.nitrusa-btn--primary {
	background-color: var(--c-accent);
	border-color: transparent;
	color: var(--c-text-on-accent);
}
.nitrusa-btn--primary:hover { background-color: var(--c-accent-hover); }
.nitrusa-btn--quiet { color: var(--c-text-muted); }
.nitrusa-btn--quiet:hover { color: var(--c-text); border-color: var(--c-border-strong); }

/* ---- The field component (DSN-23) ----------------------------------------
   Site-wide: a text-entry control carries its label inside the box. The label
   rests on the value's line while the field is empty and rises to a caption
   once it is focused or filled, so a part-completed form still says what each
   field is — which a placeholder does not, because it vanishes on the first
   keystroke.

   The label element itself is kept and stays associated with its control; only
   its position changes. Built by assets/js/forms.js, which reshapes our own
   markup and the plugin's into this one component. */

.nitrusa-field {
	position: relative;
	display: block;
	margin-block-end: var(--sp-4);
}

/* The #buddypress copies of each selector are not decoration. Our own
   normalisation of the plugin's controls is written at `#buddypress
   input[type="text"]` weight so that it can outrank the plugin's, and that
   silently beat this component on every plugin screen -- the profile editor
   drew a 44px box with 8px padding and the raised label landed on top of the
   value. The component is the site-wide authority (DSN-23), so it is stated at
   a weight that wins there too, on the same rule rather than a second copy. */
.nitrusa-field > input,
.nitrusa-field > select,
.nitrusa-field > textarea,
#buddypress .nitrusa-field > input,
#buddypress .nitrusa-field > select,
#buddypress .nitrusa-field > textarea {
	width: 100%;
	min-height: 56px;                          /* room for the raised label */
	padding: 22px var(--sp-3) 6px;
	background-color: var(--c-bg);
	border: var(--border);
	border-radius: var(--r-md);
	color: var(--c-text);
	font: inherit;
}
.nitrusa-field--area > textarea,
#buddypress .nitrusa-field--area > textarea { min-height: 8rem; padding-block-end: var(--sp-3); }

.nitrusa-field__label {
	position: absolute;
	inset-inline-start: calc(var(--sp-3) + 1px);
	top: 50%;
	transform: translateY(-50%);
	display: block;
	margin: 0;
	max-width: calc(100% - var(--sp-6));
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--c-text-subtle);
	font-size: var(--fs-base);
	font-weight: var(--fw-regular);
	line-height: 1;
	pointer-events: none;                      /* clicks reach the control */
	transition: top var(--transition), font-size var(--transition), color var(--transition), transform var(--transition);
}

/* Raised: focused, holding a value, or a control that always has one. */
.nitrusa-field > input:focus ~ .nitrusa-field__label,
.nitrusa-field > textarea:focus ~ .nitrusa-field__label,
.nitrusa-field > select:focus ~ .nitrusa-field__label,
.nitrusa-field > input:not(:placeholder-shown) ~ .nitrusa-field__label,
.nitrusa-field > textarea:not(:placeholder-shown) ~ .nitrusa-field__label,
.nitrusa-field--select .nitrusa-field__label,
.nitrusa-field--filled .nitrusa-field__label {
	top: 9px;
	transform: none;
	font-size: var(--fs-xs);
	color: var(--c-text-muted);
}
.nitrusa-field > input:focus ~ .nitrusa-field__label,
.nitrusa-field > textarea:focus ~ .nitrusa-field__label,
.nitrusa-field > select:focus ~ .nitrusa-field__label { color: var(--c-accent); }

/* The required marker (DSN-27): one character after the label, never the word.
   "Last Name (required)" spends a third of the label's width restating on
   every field what a single mark says once, and inside a floating label that
   shrinks to caption size it is the part that gets truncated first.

   Colour rather than shape carries no meaning here -- the control's own
   `required` attribute is what assistive technology reads, and the mark is
   `aria-hidden` -- so it is tinted to be noticed, not to be relied on. */
.nitrusa-field__required {
	margin-inline-start: 2px;
	color: var(--c-highlight);
	font-weight: var(--fw-semibold);
}

/* A textarea's label sits at the top of the box rather than centred in it. */
.nitrusa-field--area .nitrusa-field__label { top: 9px; transform: none; }

/* Select keeps room for its own arrow. */
.nitrusa-field--select > select,
#buddypress .nitrusa-field--select > select {
	appearance: none;
	padding-inline-end: var(--sp-6);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right var(--sp-3) center;
	background-size: 18px 18px;
}

/* A format example lives in the placeholder, so it appears exactly when the
   label lifts out of the way and is never on screen beside it. */
.nitrusa-field > input::placeholder,
.nitrusa-field > textarea::placeholder {
	color: transparent;
	transition: color var(--transition);
}
.nitrusa-field > input:focus::placeholder,
.nitrusa-field > textarea:focus::placeholder {
	color: var(--c-text-subtle);
}

/* No show/hide eye on the password. It is a control most people never use,
   sitting on top of the one box where an onlooker reading the screen matters,
   and it crowded the field once the label moved inside it. */
.bb-toggle-password { display: none !important; }
.bb-password-wrap { position: relative; display: block; width: 100%; }

/* A field description belongs under the box, not inside it. */
.nitrusa-field + .description,
.nitrusa-field + .nitrusa-form__hint {
	display: block;
	margin: calc(var(--sp-3) * -1) 0 var(--sp-4);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}

/* ---- The agreement (LEG-2) -----------------------------------------------
   Checkbox to the left of the sentence it governs, directly above the button
   it enables. */

.nitrusa-consent {
	display: grid;
	grid-template-columns: auto 1fr;
	align-items: start;
	gap: var(--sp-3);
	margin-block: var(--sp-5) var(--sp-4);
	max-width: 34rem;
}
.nitrusa-consent input[type="checkbox"] {
	width: 20px;
	height: 20px;
	margin: 2px 0 0;
	accent-color: var(--c-accent);
	flex: 0 0 auto;
	cursor: pointer;
}
.nitrusa-consent label {
	margin: 0;
	color: var(--c-text);
	font-size: var(--fs-sm);
	font-weight: var(--fw-regular);
	line-height: var(--lh-snug);
	cursor: pointer;
}
.nitrusa-consent a { color: var(--c-accent); }

.nitrusa-consent--error input[type="checkbox"] { outline: 2px solid var(--c-error); outline-offset: 2px; }
.nitrusa-consent__error {
	grid-column: 2;
	margin: var(--sp-1) 0 0;
	color: var(--c-error);
	font-size: var(--fs-sm);
}

/* A button that cannot yet be used must look like one. */
.nitrusa-form [type="submit"]:disabled,
#signup-form [type="submit"]:disabled {
	opacity: 0.45;
	cursor: not-allowed;
	background-color: var(--c-surface-hover) !important;
	color: var(--c-text-muted) !important;
}

/* ---- Legal links --------------------------------------------------------
   Reachable from the register page, the login page and the footer (LEG-1). */

.nitrusa-legal {
	margin-block-start: var(--sp-4);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}
.nitrusa-legal a { color: var(--c-accent); }

/* ---- Notices ------------------------------------------------------------
   One treatment for "we need to tell you something", used by the login and
   register screens and by BuddyBoss's own template notices. */

.nitrusa-notice,
.bp-feedback,
.bp-template-notice {
	padding: var(--sp-3) var(--sp-4);
	border: var(--border);
	border-inline-start-width: 3px;
	border-radius: var(--r-md);
	background-color: var(--c-surface);
	color: var(--c-text);
	font-size: var(--fs-sm);
	margin-block-end: var(--sp-4);
	max-width: 34rem;
}
.nitrusa-notice--error,
.bp-feedback.error { border-inline-start-color: var(--c-error); }
.nitrusa-notice--info,
.bp-feedback.info { border-inline-start-color: var(--c-info); }
.nitrusa-notice--success,
.bp-feedback.success { border-inline-start-color: var(--c-success); }

/* A narrow section: forms and other single-column content read badly at full
   page width. */
.nitrusa-section--narrow { max-width: 34rem; }

/* ---- The page shell (DSN-17) --------------------------------------------
   One place that defines how a page sits on the site. Templates supply content
   and never set their own background, width or vertical spacing. */

.nitrusa-page {
	background-color: var(--c-bg);
	/* The single source of the gap under the header -- see DSN-16 above. */
	padding-block: var(--sp-3) var(--sp-7);
}
.nitrusa-section { padding-block: var(--sp-5); }
.nitrusa-section:first-child { padding-block-start: 0; }
.nitrusa-section:last-child  { padding-block-end: 0; }

.nitrusa-lead {
	font-size: var(--fs-xl);
	color: var(--c-text-muted);
	max-width: 55ch;
	margin: 0;
}
.nitrusa-empty {
	color: var(--c-text-muted);
	padding: var(--sp-6) 0;
}

/* ---- Listing groups (EVT-8) ----------------------------------------------
   A listing that is divided into named runs -- the events page, which groups by
   Current, Upcoming and Past. Built on <details> so a group folds away without
   JavaScript and cannot be left stuck shut by a script that failed to load.

   Nothing here restyles the cards inside: a grouped listing is the same listing
   with headings in it (DSN-12). */

.nitrusa-group + .nitrusa-group { margin-block-start: var(--sp-6); }

.nitrusa-group__summary {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	/* A heading that folds a section is a control, so it takes a control's
	   target size (DSN-7). */
	min-height: 44px;
	padding-block: var(--sp-2);
	border-block-end: var(--border);
	cursor: pointer;
	list-style: none;
}
.nitrusa-group__summary::-webkit-details-marker { display: none; }

.nitrusa-group__heading {
	margin: 0;
	font-size: var(--fs-lg);
	line-height: var(--lh-tight);
}

.nitrusa-group__count {
	margin-inline-start: auto;
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
}

/* Our own disclosure caret: the native marker cannot be positioned, and a flex
   summary drops it in some browsers -- so a group would fold with nothing on
   screen saying it could. */
.nitrusa-group__summary::after {
	content: "";
	flex: 0 0 auto;
	width: 0.5em;
	height: 0.5em;
	margin-inline-start: var(--sp-2);
	border-inline-end: 2px solid var(--c-icon);
	border-block-end: 2px solid var(--c-icon);
	transform: rotate(45deg) translate(-0.1em, -0.1em);
	transition: transform var(--transition);
}
.nitrusa-group[open] > .nitrusa-group__summary::after {
	transform: rotate(225deg) translate(-0.1em, -0.1em);
}

.nitrusa-group__summary:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: 2px;
}

/* ---- An event's own facts, on its page (EVT-9, EVT-14) -------------------
   A definition list, because that is what it is: labelled facts. Two columns
   where there is room, one where there is not -- a label and its value must
   never end up on separate lines from each other. */

/* ---- The event banner (EVT-14) -------------------------------------------
   Where the member stands with this event, across the top, in one sentence.
   A link where there is somewhere to go and a statement where there is not —
   and it looks like a link in the first case, because a banner that is
   clickable without looking it is a banner nobody clicks. */

.nitrusa-eventbanner {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	margin: 0 0 var(--sp-5);
	padding: var(--sp-4) var(--sp-5);
	min-height: 44px;
	border: var(--border);
	border-inline-start: 3px solid var(--c-info);
	border-radius: var(--r-md);
	background-color: var(--c-surface);
	color: var(--c-text);
	font-size: var(--fs-lg);
	text-decoration: none;
	transition: background-color var(--transition), border-color var(--transition);
}
a.nitrusa-eventbanner:hover,
a.nitrusa-eventbanner:focus-visible { background-color: var(--c-surface-hover); }

.nitrusa-eventbanner .nitrusa-icon { flex: 0 0 auto; color: var(--c-icon); }

.nitrusa-eventbanner--success { border-inline-start-color: var(--c-success); }
.nitrusa-eventbanner--success .nitrusa-icon { color: var(--c-success); }
.nitrusa-eventbanner--info    { border-inline-start-color: var(--c-info); }
.nitrusa-eventbanner--error   { border-inline-start-color: var(--c-error); }
.nitrusa-eventbanner--error .nitrusa-icon { color: var(--c-error); }

/* A labelled section on an event's page — Description, and anything after it. */
.nitrusa-eventsection { margin-block: var(--sp-6); }
.nitrusa-eventsection__heading {
	margin: 0 0 var(--sp-3);
	font-size: var(--fs-lg);
	line-height: var(--lh-tight);
}

.nitrusa-eventmeta {
	margin: 0 0 var(--sp-6);
	padding: var(--sp-5);
	border: var(--border);
	border-radius: var(--r-lg);
	background-color: var(--c-surface);
	display: grid;
	gap: var(--sp-3) var(--sp-6);
	grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}
.nitrusa-eventmeta__row { display: grid; gap: var(--sp-1); }

.nitrusa-eventmeta dt {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	margin: 0;
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
}
.nitrusa-eventmeta dd {
	margin: 0;
	color: var(--c-text);
	/* A long venue wraps rather than pushing the panel wide (DSN-7). */
	overflow-wrap: break-word;
}
.nitrusa-article__meta {
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	margin-bottom: var(--sp-4);
}

/* ---- The contact form (CNT-12) -------------------------------------------
   The form itself is nothing but the site's field component in a column; the
   only thing here that is its own is the honeypot. */

.nitrusa-contact {
	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
	align-items: flex-start;
}
.nitrusa-contact .nitrusa-field { width: 100%; }

/* The honeypot is taken out of the page without being taken out of the DOM.
   `display: none` is the obvious way and the wrong one: it is the first thing
   a form-filling script checks for, and skips. Positioned off-screen the field
   is invisible to a person, unreachable by keyboard, hidden from assistive
   technology, and still present to anything reading the markup. */
.nitrusa-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.nitrusa-field__error {
	margin: var(--sp-1) 0 0;
	color: var(--c-error);
	font-size: var(--fs-sm);
}
.nitrusa-field--invalid input,
.nitrusa-field--invalid textarea { border-color: var(--c-error); }

/* A notice that warns rather than reports a failure -- an unreviewed legal
   draft (LEG-3), not an error the reader has made. */
.nitrusa-notice--warning { border-inline-start-color: var(--c-warning); }

/* ---- [+ Add New] in the toolbar (DSN-29) ---------------------------------
   Right-justified at the end of the bar, and the one filled control on it —
   it is the single action a listing offers, so it is the single thing that
   looks like an action. It wraps to its own full-width row on a narrow screen
   rather than crushing the search field. */

.nitrusa-toolbar__add {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 44px;
	margin-inline-start: var(--sp-3);
	padding-inline: var(--sp-4);
	white-space: nowrap;
	text-decoration: none;
}
.nitrusa-toolbar__addmark { font-size: var(--fs-lg); line-height: 1; }

/* ---- The bar's own menu (DSN-30, MED-11) ---------------------------------
   The site's action menu, at the end of the bar. It never grows: whatever it
   holds opens in a panel, so a screen with somewhere else to go costs the bar
   one 32px control rather than another row. */
.nitrusa-toolbar__menu { flex: 0 0 auto; }
/* Same reason as the entity card's: positioning creates a stacking context, so
   the open panel is measured inside it and the sticky members bar would paint
   over it. Raised only while open. */
.nitrusa-toolbar__menu:has(.nitrusa-actions[open]) {
	position: relative;
	z-index: 46;
}

@media (max-width: 700px) {
	.nitrusa-toolbar__add {
		order: 3;
		flex: 1 0 100%;
		margin-inline-start: 0;
		justify-content: center;
	}
}

/* ---- The Program (EVT-12) ------------------------------------------------
   An event's schedule, grouped by day. A time column and what happens in it,
   which is how a printed programme reads and how somebody scans one: down the
   times first, then across to the thing they care about.

   The two columns collapse to one on a narrow screen. A 5.5rem time column
   beside a session called "Welcome reception and registration desk" leaves the
   name three words wide, and a schedule you have to unwrap word by word is
   worse than one that simply stacks. */

.nitrusa-program__day {
	margin: var(--sp-5) 0 var(--sp-2);
	font-size: var(--fs-base);
	color: var(--c-text-subtle);
}
.nitrusa-group--program .nitrusa-program__day:first-of-type { margin-block-start: var(--sp-3); }

.nitrusa-program {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: var(--sp-1);
}

.nitrusa-program__item {
	display: grid;
	grid-template-columns: minmax(5.5rem, max-content) 1fr;
	align-items: baseline;
	gap: var(--sp-1) var(--sp-4);
	padding: var(--sp-3) var(--sp-4);
	border: var(--border);
	border-radius: var(--r-md);
	background-color: var(--c-surface);
}

.nitrusa-program__time {
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
	font-variant-numeric: tabular-nums;
}
.nitrusa-program__what { font-weight: 500; }

/* Where it happens, when that is not where the event happens. Its own line
   under the name rather than a third column: a venue is a sentence, and a
   column sized for one would starve the two beside it. */
.nitrusa-program__where {
	grid-column: 2;
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
}
.nitrusa-program__where .nitrusa-icon { flex: 0 0 auto; color: var(--c-icon); }

.nitrusa-program__item .nitrusa-chips { grid-column: 2; }

@media (max-width: 30rem) {
	.nitrusa-program__item { grid-template-columns: 1fr; }
	.nitrusa-program__where,
	.nitrusa-program__item .nitrusa-chips { grid-column: 1; }
}

/* ---- Forms on the front end (EVT-15, EVT-16, CNT-11) ---------------------
   The field component supplies the fields; this is only the column they sit
   in and the space between them. */

.nitrusa-form { display: grid; gap: var(--sp-4); }
.nitrusa-form .nitrusa-btn { justify-self: start; }

.nitrusa-field__hint {
	margin: var(--sp-1) 0 0;
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
}

/* A checkbox is a statement you agree with, not a labelled box, so it keeps
   its label beside it (DSN-23's one exception). */
.nitrusa-check label {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 44px;
	cursor: pointer;
}
.nitrusa-check input { width: 18px; height: 18px; accent-color: var(--c-accent); }

/* A quiet button: real, but not the thing you came to press. Cancelling your
   own registration should not look like the primary action on the page. */
.nitrusa-btn--quiet {
	background: none;
	border: var(--border);
	color: var(--c-text-muted);
}
.nitrusa-btn--quiet:hover,
.nitrusa-btn--quiet:focus-visible { color: var(--c-error); border-color: var(--c-error); }

/* A group of fields that belong to one question — the programme's rows
   (EVT-12), the committee's appointments (EVT-11), which sessions somebody is
   coming to (EVT-17). A real <fieldset> and <legend>, because that is what
   tells a screen reader that eight checkboxes are one question. */
.nitrusa-fieldset {
	margin: 0;
	padding: var(--sp-4);
	border: var(--border);
	border-radius: var(--r-lg);
	background-color: var(--c-surface);
	display: grid;
	gap: var(--sp-4);
	/* A fieldset is min-width:auto by default and refuses to shrink below its
	   content, which is how a long session name becomes a horizontally
	   scrolling page (DSN-7). */
	min-width: 0;
}
.nitrusa-fieldset__legend {
	padding: 0 var(--sp-2);
	font-size: var(--fs-base);
	font-weight: 600;
}
.nitrusa-fieldset > .nitrusa-field__hint { margin: 0; }

/* One row of a repeating block. Bordered so it reads as a unit: without it,
   four fields for one session look like four unrelated fields. */
.nitrusa-subevent,
.nitrusa-appointment {
	display: grid;
	gap: var(--sp-3);
	padding: var(--sp-4);
	border: var(--border);
	border-radius: var(--r-md);
	background-color: var(--c-bg);
	min-width: 0;
}
.nitrusa-subevent--invalid { border-color: var(--c-error); }

/* Two across where there is room. The name and the time are the pair somebody
   fills in together, and one field per line makes a six-session programme a
   very long scroll. The checkboxes take the full width, because a statement you
   agree with reads badly in half a row.

   An appointment stays one column: with the single event role G1 leaves us it
   has one control, and a two-column grid would sit it beside an empty cell. */
@media (min-width: 40rem) {
	.nitrusa-subevent { grid-template-columns: 1fr 1fr; }
	.nitrusa-subevent > .nitrusa-check { grid-column: 1 / -1; }
}

/* Announcing an event to the membership (EVT-21). The audience and its size
   are read *before* the button, so the button sits under them rather than
   beside them — a confirmation you can press without having read it is not a
   confirmation.

   Deliberately not `.nitrusa-notice`: a notice reports what has happened, and
   this asks for a decision that reaches every member of the Association. */
.nitrusa-announce {
	display: grid;
	gap: var(--sp-3);
	max-width: 34rem;
	margin-block-end: var(--sp-5);
	padding: var(--sp-4);
	border: var(--border);
	border-inline-start: 3px solid var(--c-accent);
	border-radius: var(--r-md);
	background-color: var(--c-surface);
	font-size: var(--fs-sm);
}
.nitrusa-announce p { margin: 0; }
.nitrusa-announce form { margin: 0; }

/* Once it has gone: a fact about the event, recorded for the officers. Quiet,
   because it asks for nothing. */
.nitrusa-announced {
	margin: 0 0 var(--sp-5);
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
}

/* The payment menu hangs off a registration card and holds a small form. */
.nitrusa-actions--payment .nitrusa-actions__panel { min-width: 15rem; }

/* ---- The registrations summary (EVT-18) ----------------------------------
   At the bottom because it is a conclusion, and sticky because a treasurer
   reading down a long list needs the totals still there when they reach the
   end. It sticks to the *bottom* of the viewport, which is the one edge a
   footer summary can usefully hold. */

.nitrusa-regsummary {
	position: sticky;
	bottom: 0;
	z-index: 40;
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-4) var(--sp-6);
	margin-top: var(--sp-5);
	padding: var(--sp-4) var(--sp-5);
	border: var(--border);
	border-radius: var(--r-lg);
	background-color: var(--c-bg-elevated);
	box-shadow: var(--shadow-md);
}
.nitrusa-regsummary__item {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
}
.nitrusa-regsummary__label {
	color: var(--c-text-subtle);
	font-size: var(--fs-sm);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
}
.nitrusa-regsummary__value {
	color: var(--c-text-strong);
	font-weight: var(--fw-semibold);
}
.nitrusa-regsummary .nitrusa-icon { color: var(--c-icon); flex: 0 0 auto; }

/* Which event the page is scoped to, above the bar. */
.nitrusa-eventscope {
	margin: 0 0 var(--sp-3);
	color: var(--c-text-muted);
}

/* ---- The phone's chrome: one band, not three (DSN-34) --------------------
   Wrapping the members bar (DSN-33) put every section on screen and cost three
   rows of sticky chrome to do it; with the toolbar's four rows beneath, a
   320px screen had more chrome than page. So on a phone both fold into the
   header's hamburger row: the toolbar behind a magnifier, the sections into the
   one you are in.

   Above the breakpoint neither control exists and the full bars are unchanged
   — this is a phone layout, not a new design. */

.nitrusa-header-actions__tools {
	display: none;                       /* phone only; shown in the query below */
	align-items: center;
	gap: var(--sp-2);
	margin-inline-start: auto;           /* right-justified on the hamburger row */
}

/* Both controls are the same shape: a 44px target carrying a glyph. */
.nitrusa-sectionmenu__summary,
.nitrusa-toolbarmenu__summary {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 44px;
	padding: 0 var(--sp-3);
	border: var(--border);
	border-radius: var(--r-full);
	background-color: var(--c-surface);
	color: var(--c-text);
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	cursor: pointer;
	list-style: none;                    /* no disclosure triangle */
	white-space: nowrap;
}
.nitrusa-sectionmenu__summary::-webkit-details-marker,
.nitrusa-toolbarmenu__summary::-webkit-details-marker { display: none; }

.nitrusa-toolbarmenu__summary { min-width: 44px; justify-content: center; }

.nitrusa-sectionmenu__summary .nitrusa-icon,
.nitrusa-toolbarmenu__summary .nitrusa-icon { color: var(--c-icon); flex: 0 0 auto; }

.nitrusa-sectionmenu__summary:focus-visible,
.nitrusa-toolbarmenu__summary:focus-visible {
	outline: var(--focus-ring);
	outline-offset: var(--focus-offset);
}

/* The open control reads as pressed, so it is obvious which one is showing. */
.nitrusa-sectionmenu[open] > .nitrusa-sectionmenu__summary,
.nitrusa-toolbarmenu[open] > .nitrusa-toolbarmenu__summary {
	border-color: var(--c-border-strong);
	background-color: var(--c-surface-hover);
	color: var(--c-text-strong);
}

/* The section it shows must not push the hamburger row wide: the label gives
   way before the row does. */
.nitrusa-sectionmenu__label {
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 8rem;
}

/* The panel: every section, one per row, anchored under the control. */
.nitrusa-sectionmenu { position: relative; }
.nitrusa-sectionmenu__panel {
	position: absolute;
	inset-block-start: calc(100% + var(--sp-2));
	inset-inline-end: 0;
	z-index: 60;                         /* above the header itself */
	min-width: 13rem;
	max-width: min(20rem, calc(100vw - var(--sp-5) * 2));
	padding: var(--sp-2);
	border: var(--border);
	border-radius: var(--r-lg);
	background-color: var(--c-bg-elevated);
	box-shadow: 0 12px 32px rgb(0 0 0 / 45%);
}
.nitrusa-sectionmenu__panel ul { list-style: none; margin: 0; padding: 0; }
.nitrusa-sectionmenu__panel a,
.nitrusa-sectionmenu__panel span[aria-disabled] {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	min-height: 44px;
	padding: 0 var(--sp-3);
	border-radius: var(--r-md);
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	text-decoration: none;
}
.nitrusa-sectionmenu__panel a:hover,
.nitrusa-sectionmenu__panel a:focus-visible {
	background-color: var(--c-surface-hover);
	color: var(--c-text);
}
.nitrusa-sectionmenu__panel .is-current > a {
	color: var(--c-text-strong);
	background-color: var(--c-surface);
}
.nitrusa-sectionmenu__panel .nitrusa-icon { color: var(--c-icon); flex: 0 0 auto; }
.nitrusa-sectionmenu__panel span[aria-disabled] { color: var(--c-text-subtle); cursor: default; }

@media (max-width: 560px) {
	.nitrusa-header-actions__tools { display: flex; }

	/* The full-width bars stand down. `display: none` rather than hidden with
	   opacity: they leave the accessibility tree too, so the sections are
	   announced once — from the menu — rather than twice. */
	.nitrusa-members-bar { display: none; }

	/* The toolbar is folded away and opens from the header's magnifier. It sits
	   as an ordinary block when open rather than sticking: a panel the member
	   just opened is already in view, and a sticky one would take back the
	   height this whole section exists to give the page. */
	body:has(.nitrusa-toolbarmenu) .nitrusa-toolbar { display: none; }
	body:has(.nitrusa-toolbarmenu[open]) .nitrusa-toolbar {
		display: flex;
		position: static;
	}

	/* Nothing to open: no control. The header cannot know whether the page has
	   a toolbar — it is drawn first — so the page tells it, backwards. */
	body:not(:has(.nitrusa-toolbar)) .nitrusa-toolbarmenu { display: none; }

	/* With the members bar gone, the page's own top spacing comes back — it was
	   suppressed because the bar was providing it.

	   Only on members pages. A listing that merely has a toolbar keeps its zero:
	   the toolbar is folded away, so the page starts with its content, and the
	   16px added here on top of the shell's own margin put a 60px dead band
	   under the header (DSN-17's budget is 48). */
	body:has(.nitrusa-members-bar) main.nitrusa-page {
		padding-block-start: var(--sp-4);
	}
}

/* ==========================================================================
   Tooltip (DSN-36)

   One bubble, shared by every button and action on the site, placed by
   assets/js/tooltips.js. The same recipe as the action menu's panel — the
   elevated surface, the one border, the soft shadow — so it reads as part of
   the same product rather than as the browser's own grey box.
   ========================================================================== */
.nitrusa-tooltip {
	position: fixed;          /* viewport coordinates: the same inside a modal dialog as outside */
	z-index: var(--z-tooltip);
	max-width: min(var(--tooltip-max), calc(100vw - 2 * var(--sp-2)));
	padding: var(--sp-1) var(--sp-2);
	background-color: var(--c-bg-elevated);
	color: var(--c-text-strong);
	border: var(--border);
	border-radius: var(--r-sm);
	box-shadow: var(--shadow-md);
	font-family: var(--font-sans);
	font-size: var(--fs-xs);
	font-weight: var(--fw-medium);
	line-height: var(--lh-snug);
	text-align: start;
	text-transform: none;
	letter-spacing: normal;
	white-space: normal;
	overflow-wrap: anywhere;
	pointer-events: auto;     /* the pointer may rest on it (WCAG 1.4.13) */
}
.nitrusa-tooltip[hidden] { display: none; }

/* ==========================================================================
   Help with this page (HLP-4)

   A "?" immediately after the page caption, members only. It opens a modal
   dialog (help.js) that a button grows to the full page and shrinks back.
   The panel's look is the same in every state — the elevated surface, the one
   border — and only its size and place change.

   With no script, the <details> opens the same panel in place, dropped from
   under the header; that is the last block below.
   ========================================================================== */
.nitrusa-help { position: static; }

.nitrusa-help__toggle,
.nitrusa-help__size,
.nitrusa-help__close {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: var(--touch-target);
	min-height: var(--touch-target);
	padding: 0;
	border: 0;
	border-radius: var(--r-full);
	background: none;
	color: var(--c-icon);
	cursor: pointer;
	transition: background-color var(--transition), color var(--transition);
}
.nitrusa-help__toggle { list-style: none; }   /* no disclosure triangle */
.nitrusa-help__toggle::-webkit-details-marker { display: none; }
.nitrusa-help__toggle:hover,
.nitrusa-help__size:hover,
.nitrusa-help__close:hover { background-color: var(--c-surface-hover); color: var(--c-icon-hover); }
.nitrusa-help__toggle:focus-visible,
.nitrusa-help__size:focus-visible,
.nitrusa-help__close:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.nitrusa-help__toggle[aria-expanded="true"],
.nitrusa-help[open] .nitrusa-help__toggle { background-color: var(--c-surface-hover); color: var(--c-accent); }
.nitrusa-help__size[hidden],
.nitrusa-help__close[hidden] { display: none; }

/* The size control shows the glyph for where it will take you. */
.nitrusa-help__size-dialog { display: none; }
.nitrusa-help__panel--full .nitrusa-help__size-full { display: none; }
.nitrusa-help__panel--full .nitrusa-help__size-dialog { display: inline-flex; }

/* ---- The panel, whatever its size ----------------------------------------- */
.nitrusa-help__panel {
	box-sizing: border-box;
	padding: 0;
	background-color: var(--c-bg-elevated);
	color: var(--c-text);
	border: var(--border);
	border-radius: var(--r-lg);
	box-shadow: var(--shadow-lg);
	font-size: var(--fs-sm);
	line-height: var(--lh-snug);
	text-align: start;
}

/* Title and window controls stay put; the help scrolls beneath them. */
.nitrusa-help__bar {
	display: flex;
	align-items: center;
	gap: var(--sp-1);
	padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-5);
	border-block-end: var(--border);
}
.nitrusa-help__title {
	flex: 1 1 auto;
	min-width: 0;
	margin: 0;
	color: var(--c-heading);
	font-size: var(--fs-lg);
	line-height: var(--lh-tight);
}
.nitrusa-help__content {
	padding: var(--sp-4) var(--sp-5) var(--sp-5);
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* ---- As a dialog ----------------------------------------------------------- */
.nitrusa-help__panel.is-dialog[open] {
	display: flex;
	flex-direction: column;
	position: fixed;
	inset: 0;
	margin: auto;
	width: min(var(--help-width), calc(100vw - 2 * var(--sp-4)));
	max-width: none;
	height: auto;
	max-height: calc(100dvh - 2 * var(--sp-6));
}
.nitrusa-help__panel.is-dialog .nitrusa-help__content { flex: 1 1 auto; min-height: 0; }
.nitrusa-help__panel.is-dialog::backdrop { background-color: var(--c-scrim); }

/* ---- As the full page ------------------------------------------------------ */
.nitrusa-help__panel.is-dialog.nitrusa-help__panel--full[open] {
	width: 100vw;
	height: 100dvh;
	max-height: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
}
/* Full page reads like a page: the same measure as the site's content. */
.nitrusa-help__panel--full .nitrusa-help__bar,
.nitrusa-help__panel--full .nitrusa-help__content {
	padding-inline: max(var(--sp-5), calc((100vw - var(--help-width)) / 2));
}

/* The page behind does not scroll while help is open over it. */
html:has(.nitrusa-help__panel.is-dialog[open]) { overflow: hidden; }

/* ---- With no script: the <details> opens it in place ----------------------- */
.nitrusa-help[open] > .nitrusa-help__panel:not(.is-dialog) {
	display: block;
	position: fixed;
	inset-block-start: calc(var(--header-height, 6rem) + var(--sp-2));
	inset-inline-start: var(--sp-4);
	z-index: 60;                      /* the section menu's layer: above the bars */
	margin: 0;
	width: min(var(--help-width), calc(100vw - 2 * var(--sp-4)));
	max-height: calc(100dvh - var(--header-height, 6rem) - 2 * var(--sp-4));
	overflow-y: auto;
}

/* ---- The help's own text --------------------------------------------------- */
.nitrusa-help__part + .nitrusa-help__part { margin-block-start: var(--sp-4); }
.nitrusa-help__part h3 {
	margin: 0 0 var(--sp-2);
	color: var(--c-highlight);
	font-size: var(--fs-xs);
	font-variant-caps: var(--caps-variant);
	letter-spacing: var(--caps-tracking);
	font-weight: var(--fw-semibold);
}
.nitrusa-help__part p { margin: 0; }
.nitrusa-help__part ul,
.nitrusa-help__part ol { margin: 0; padding-inline-start: var(--sp-5); }
.nitrusa-help__part li + li { margin-block-start: var(--sp-1); }
.nitrusa-help__task + .nitrusa-help__task { margin-block-start: var(--sp-3); }
.nitrusa-help__task h4 {
	margin: 0 0 var(--sp-1);
	color: var(--c-text-strong);
	font-size: var(--fs-sm);
	font-weight: var(--fw-semibold);
}

@media (max-width: 560px) {
	.nitrusa-help__panel.is-dialog[open] {
		width: calc(100vw - 2 * var(--sp-2));
		max-height: calc(100dvh - 2 * var(--sp-4));
	}
	.nitrusa-help[open] > .nitrusa-help__panel:not(.is-dialog) {
		inset-inline-start: var(--sp-2);
		width: calc(100vw - 2 * var(--sp-2));
	}
	.nitrusa-help__bar { padding-inline-start: var(--sp-4); }
	.nitrusa-help__content { padding: var(--sp-3) var(--sp-4) var(--sp-4); }
}
