/**
 * The review box and the message a block says back.
 *
 * ⚠️ THE PLATFORM SHIPS THIS, THE WAY IT SHIPS votes.css. A control the platform
 * renders needs enough presentation to be usable wherever it lands, or a site
 * that has not styled it gets an unstyled textarea and a message with no shape.
 * Everything here is a floor: the site's own stylesheet wins on specificity.
 *
 * ⚠️ AND IT NAMES NO DATASET AND NO SITE. `ov-engage-*` is the platform's own,
 * the way `oview-card` is (D45). The drawn block's classes are the site's and
 * are left alone.
 */

/*
 * THE SKELETON BOTH BOXES WEAR (D224). `engine:reviews` and `engine:thread`
 * rendered a bare form each: no title, so neither said what it was, and the
 * thread's button was a sibling of the drawn panel with `align-self: flex-end`,
 * which does nothing unless the panel happens to be a flex column. On site four
 * it sat at the left, touching the field, while the review's sat at the right.
 * The platform owns the shape now: title, body, then a foot whose primary
 * button is at the end and whose secondary link is at the start.
 */
.oview-engage {
	display: flex;
	flex-direction: column;
	gap: var(--space-s);
}

/* Title and state together, tighter than the box's own rhythm. */
.oview-engage__head {
	display: flex;
	flex-direction: column;
	gap: var(--space-2xs);
}

.oview-engage__title {
	margin: 0;
	font-size: var(--h4);
	line-height: 1.2;
}

.oview-engage__foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: var(--space-s);
	margin-top: var(--space-xs);
}

/*
 * The primary button is last and ends the row; a secondary link before it
 * holds the start. `margin-inline-end: auto` rather than `space-between`,
 * because in a narrow panel the two wrap, and a wrapped button on its own
 * line under `space-between` goes back to the left.
 */
.oview-engage__foot > :first-child:not(:last-child) {
	margin-inline-end: auto;
}

/* The secondary link is a tap target, not a line of text (D224). */
.oview-engage__all {
	display: inline-flex;
	align-items: center;
	min-block-size: var(--tap-min);
	font-size: var(--text-s);
}

.ov-engage-box {
	display: block;
	width: 100%;
	min-height: 7rem;
	padding: 0.75rem;
	border: 1px solid var(--color-border-strong, rgba( 0, 0, 0, 0.15 ));
	border-radius: var(--radius-l-2);
	background: var(--color-surface-sunk, rgba( 0, 0, 0, 0.02 ));
	font: inherit;
	line-height: 1.5;
	resize: vertical;
}

/*
 * The button that submits it. A floor, so a site with no design for this block
 * still has a control a person can press; `oview/reviews/classes` is how a site
 * puts its own button here instead.
 */
/*
 * The row the button sits in. A floor: a site with its own footer class maps
 * `foot` through `oview/reviews/classes` and this never applies.
 */
.ov-engage-foot {
	display: flex;
	justify-content: flex-end;
	margin-top: var(--space-m, 1rem);
}

.ov-engage-post {
	padding: 0.5rem 1rem;
	border: 1px solid var(--color-border, rgba( 0, 0, 0, 0.15 ));
	border-radius: var(--radius-l-2);
	background: var(--color-accent, #2b6cb0);
	color: var(--color-on-accent, #fff);
	font: inherit;
	cursor: pointer;
}

.ov-engage-box:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 1px;
}

/*
 * ⚠️ A FLOOR EXPRESSED AS A TOKEN CANNOT CONSTRAIN A SIZE COMPUTED FROM A PARENT.
 *
 * `tokens.css` clamps this site's three smallest type steps to 12px, because
 * WCAG puts body text at 4.5:1 and this project puts it at 12px. Every rule in
 * the SITE's stylesheets goes through those steps. Every rule in THIS one asked
 * for a fraction of whatever it happened to sit inside, so the floor never
 * applied: `0.875em` of a 13px parent is 11.4px and `0.75em` is 9.8px, and
 * `check-mobile.js` reported all three.
 *
 * ⚠️ AND THE FALLBACK IS 12px, NOT THE FRACTION IT REPLACED. This file ships in
 * the platform and has to render on a site that defines no tokens at all - so
 * falling back to `0.875em` would keep the bug for exactly the installs that
 * have nothing else holding the line. A rem fallback would not work either:
 * this site sets a 62.5% root, so `1.2rem` is 12px here and 19.2px anywhere
 * else. The floor is an absolute, which is what makes it a floor.
 */
.ov-engage-note {
	margin: 0.5rem 0 0;
	font-size: var(--note-size, 13px);
	color: var(--note-color, inherit);
}

/*
 * ⚠️ THE STATE LINE HAD NO STYLE AT ALL. `[oview_thread_box]` prints
 * `<p class="ov-meta">No conversation yet.</p>` and only site one styled that
 * class, so on every other site it came out as body copy in the middle of a
 * panel (D224). It is a note, like the rest.
 */
.ov-meta {
	margin: 0;
	font-size: var(--note-size, 13px);
	color: var(--note-color, inherit);
}

/*
 * ⚠️ AND A STATE LINE A SHORTCODE PRINTS IS NOT IN THE BOX'S FLEX FLOW. The
 * thread's shortcode prints its note and its box together inside one Bricks
 * element, so the gap the review box gets from its container's `gap` never
 * reaches it and the words sat directly on the field (D224). A note followed by
 * something inside one shortcode pays for its own space.
 *
 * And `{ovp_forum_last}` prints nothing when there is no last post, which left
 * an empty paragraph holding a line of height under the visible one.
 */
.brxe-shortcode > .ov-meta:not(:last-child) {
	margin-block-end: var(--space-xs);
}

.ov-meta:empty {
	display: none;
}

/* ⚠️ Not colour alone. A refusal that reads as ordinary text to somebody who
   cannot see the red is a refusal they will not notice. */
.ov-engage-note[data-tone="warn"]::before {
	content: "⚠ ";
}

.ov-engage-note[data-tone="ok"]::before {
	content: "✓ ";
}

/* ⚠️ A token with a fallback, and the fallbacks are ones the site already uses.
   Two new hex values would be two more colours nobody can restyle, which is what
   check-css-tokens.py exists to stop - it caught these on the first run. */
.ov-engage-note[data-tone="warn"] {
	color: var(--color-error, #b3261e);
}

.ov-engage-note[data-tone="ok"] {
	color: var(--color-success-ink, #0a6b2f);
}

/*
 * ⚠️ QUIET IS A COLOUR, NEVER OPACITY (D224). Dimming text to 0.7 multiplies
 * its contrast by the same amount and nothing in the CSS says so: this note
 * read 9.5:1 by its colour and 4.17:1 as rendered, and only the mobile gate
 * could see it.
 */
.ov-engage-note[data-tone="info"] {
	color: var(--note-color, inherit);
}

/*
 * The way in, inside a note that offers one.
 *
 * ⚠️ UNDERLINED, BECAUSE COLOUR ALONE IS NOT A LINK. The anchor inherits a
 * darker ink than the note around it and nothing else, so "Sign in to write a
 * review." read as a sentence with two shades in it rather than as something
 * to click. That is exactly the complaint it was added to answer - somebody
 * looked for a way to sign in and found none - and it is also WCAG 1.4.1:
 * colour cannot be the only thing carrying meaning.
 */
.ov-engage-note__link {
	text-decoration: underline;
	text-underline-offset: 0.2rem;
}

/**
 * The poll. A question, its options, and how they are running.
 *
 * ⚠️ THE BAR IS A CUSTOM PROPERTY, so the browser can move it after an answer
 * without touching a stylesheet, and a site can restyle the whole thing by
 * overriding these rules rather than by needing different markup.
 */
.ov-poll__q {
	margin: 0 0 0.75rem;
	font-weight: 600;
}

.ov-poll__opt {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 0.25rem 0.75rem;
	align-items: center;
	width: 100%;
	margin: 0 0 0.5rem;
	padding: 0.5rem 0.75rem;
	border: 1px solid var(--color-border, rgba( 0, 0, 0, 0.15 ));
	border-radius: var(--radius-m-2);
	background: none;
	font: inherit;
	text-align: left;
}

button.ov-poll__opt:hover:not(:disabled) {
	border-color: currentColor;
	cursor: pointer;
}

.ov-poll__opt.is-mine {
	border-color: currentColor;
	font-weight: 600;
}

/* The bar spans both columns, under the label and the percentage. */
.ov-poll__bar {
	grid-column: 1 / -1;
	height: 0.35rem;
	border-radius: var(--radius-s);
	background: var(--color-border, rgba( 0, 0, 0, 0.12 ));
	position: relative;
	overflow: hidden;
}

.ov-poll__bar::before {
	content: "";
	position: absolute;
	inset: 0 auto 0 0;
	width: var(--share, 0%);
	background: var(--color-accent, currentColor);
	/* ⚠️ A transition, because the bar moves when an answer lands and a jump
	   reads as the page reloading. */
	transition: width 0.3s ease;
}

/* The flexible column. It carries no look of its own, but a class we emit and
   never style renders as an unstyled div and looks like a design decision -
   which is what check-authored-classes.js exists to catch. */
.ov-poll__label {
	min-width: 0;
}

.ov-poll__pct {
	font-variant-numeric: tabular-nums;
	color: var(--note-color, inherit);
}

.ov-poll__foot {
	margin: 0.5rem 0 0;
	font-size: var(--note-size, 13px);
	color: var(--note-color, inherit);
}

/**
 * The kicker row and the radio mark.
 *
 * ⚠️ A FLOOR, NOT THE DESIGN. A site that names its own classes through
 * `oview/poll/classes` never sees these; they are what a site with no poll
 * design of its own gets, so the badge and the radio are legible rather than
 * absent.
 */
.ov-poll__kicker {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	margin: 0 0 0.5rem;
}

.ov-poll__badge {
	padding: 0.15em 0.5em;
	border-radius: var(--radius-s);
	background: var(--color-accent, currentColor);
	color: var(--color-accent-ink, #fff);
	font-size: var(--text-xs, 12px);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.ov-poll__badge--closed {
	background: var(--color-border, rgba( 0, 0, 0, 0.15 ));
	color: inherit;
}

.ov-poll__when {
	font-size: var(--note-size, 13px);
	color: var(--note-color, inherit);
}

/* ⚠️ A circle, and only a circle. Whether it is filled is the answer, so it
   must not depend on colour alone: `is-mine` also thickens the border. */
.ov-poll__radio {
	width: 1em;
	height: 1em;
	flex: 0 0 auto;
	border: 1px solid var(--color-border-strong, currentColor);
	border-radius: var(--radius-full);
}

.ov-poll__opt.is-mine .ov-poll__radio {
	border-width: 0.32em;
	border-color: var(--color-accent, currentColor);
}

/**
 * The side panel and the two-step answer, as a floor.
 *
 * ⚠️ `is-chosen` IS NOT `is-mine`. Chosen is what you have selected and not yet
 * submitted; mine is what is recorded. They have to look different or the
 * button asking you to submit makes no sense.
 */
.ov-poll__side {
	margin-top: 1rem;
}

.ov-poll__submit,
.ov-poll__retract {
	display: block;
	width: 100%;
	padding: 0.6em 1em;
	border: 1px solid var(--color-accent, currentColor);
	border-radius: var(--radius-m-2);
	background: var(--color-accent, transparent);
	color: var(--color-accent-ink, inherit);
	font: inherit;
	font-weight: 600;
	cursor: pointer;
}

.ov-poll__retract {
	background: none;
	color: inherit;
	font-weight: 400;
}

.ov-poll__submit[disabled] {
	opacity: 0.45;
	cursor: not-allowed;
}

.ov-poll__opt.is-chosen {
	border-color: var(--color-accent, currentColor);
}

.ov-poll__opt.is-chosen .ov-poll__radio {
	border-width: 0.32em;
	border-color: var(--color-accent, currentColor);
}

/* Label and percentage on one line, the radio inside the label beside the words. */
.ov-poll__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
}

.ov-poll__label {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	min-width: 0;
}

.ov-poll__total-value {
	margin: 0;
	font-size: var(--text-2xl, 1.75em);
	font-weight: 700;
	line-height: 1.1;
}

.ov-poll__meta {
	margin: 0.75rem 0 0.25rem;
	font-size: var(--note-size, 13px);
	color: var(--note-color, inherit);
}

.ov-poll__share-link {
	padding: 0;
	border: 0;
	background: none;
	color: var(--color-accent, currentColor);
	font: inherit;
	cursor: pointer;
}

/* The platform's floor for the share row: a mark, then the words. */
.ov-poll__share-link {
	display: flex;
	align-items: center;
	gap: 0.5rem;
}

.ov-poll__share-mark {
	width: 1.1em;
	height: 1.1em;
	flex: 0 0 auto;
	border-radius: var(--radius-s);
	background: var(--color-accent, currentColor);
}

/**
 * The review section. A floor, so a site with no design for it is readable.
 *
 * ⚠️ ITS OWN SECTION AND ITS OWN CARD. This lived inside the "Leave a review"
 * block, which is one half of a two-column row: the form and every review
 * anybody had written were sharing a column narrower than a paragraph.
 */
.ov-reviews {
	margin-top: var(--space-l, 2rem);
	padding: var(--space-m, 1.5rem);
	border: 1px solid var(--color-border, rgba( 0, 0, 0, 0.1 ));
	border-radius: var(--radius-l-2);
	background: var(--color-surface, #fff);
}

.ov-reviews__head {
	margin-bottom: var(--space-m, 1.25rem);
}

.ov-reviews__title {
	margin: 0;
	font-size: var(--text-l, 1.25rem);
	font-weight: 700;
	line-height: 1.2;
}

.ov-reviews__count {
	margin: 0.25rem 0 0;
	font-size: var(--text-xs, 0.875em);
	color: var(--color-text-muted, #6a6a74);
}

.ov-reviews__list {
	display: grid;
	gap: 0.75rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * ⚠️ EACH REVIEW IS ITS OWN CARD, not a row separated by a rule. A review is
 * several lines of somebody's prose with a name and a score attached, and a
 * horizontal line between two of those does not say where one ends.
 */
.ov-review {
	padding: var(--space-s, 1rem);
	border: 1px solid var(--color-border, rgba( 0, 0, 0, 0.1 ));
	border-radius: var(--radius-l-2);
}

/* Your own, so it is findable in a long list. */
.ov-review--yours {
	border-color: var(--color-accent, rgba( 0, 0, 0, 0.35 ));
}

.ov-review__row {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	margin-bottom: 0.6rem;
}

/*
 * ⚠️ AN INITIAL OVER A GENERATED HUE, NOT A GRAVATAR. The hue arrives as
 * `--ov-hue` from the account id, so one person is the same colour everywhere
 * and no request leaves this site carrying a hash of their email address.
 */
/*
 * ⚠️ AN INDEX INTO A PALETTE, NOT A GENERATED COLOUR. The first version built
 * an `hsl()` from the account id, which is 360 shades this site never chose and
 * cannot restyle. The site already ships five avatar colours and already picks
 * between them by index for the poll options, so the platform emits the index
 * and the site says what each one is - the same bargain everywhere else here.
 */
.ov-review__avatar {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: var(--control-h-s, 2.6rem);
	height: var(--control-h-s, 2.6rem);
	border-radius: var(--radius-full);
	color: var(--color-text, inherit);
	font-weight: 700;
	line-height: 1;
}

/*
 * ⚠️ THE NEUTRAL IS A FLOOR, SO IT HAS ZERO SPECIFICITY.
 *
 * It was a plain declaration inside the rule above, which is (0,1,0) - the same
 * as the site's `[data-ov-avatar="4"]`. A tie is decided by source order, so
 * whether a member's avatar was blue or grey depended on which stylesheet the
 * enqueue happened to put last. The review circles went grey the moment the
 * site stopped qualifying its palette with a class name.
 *
 * `:where()` scores nothing, which is what a default should score: present when
 * a site says nothing, and beaten by anything a site does say.
 */
:where(.ov-review__avatar, .oview-avatar, .oview-account__avatar) {
	background: var(--color-surface-sunk, rgba( 0, 0, 0, 0.06 ));
}


.ov-review__who {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
}

.ov-review__author {
	font-weight: 700;
}

.ov-review__meta {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	font-size: var(--text-xs, 0.8125em);
	color: var(--color-text-muted, #6a6a74);
}

.ov-review__edited::before {
	content: "\00b7";
	margin-right: 0.4rem;
}

/*
 * ⚠️ THE SCORE PUSHES RIGHT AND WRAPS LAST. On a narrow screen the name and
 * the stars end up on one line together, and `margin-left:auto` on a flex item
 * is what keeps them apart without a third wrapper.
 */
.ov-review__score {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin-left: auto;
	white-space: nowrap;
}

.ov-review__stars {
	letter-spacing: 0.05em;
	color: var(--color-text-muted, #6a6a74);
}

.ov-review__star[data-ov-on] {
	/*
	 * ⚠️ THE SAME TOKEN THE VOTE CARD'S OWN STARS USE. `votes.css` fills
	 * `.oview-vote__star[data-fill="on"]` with `--color-accent-ink`, and a
	 * review's stars are the same fact drawn smaller. The first version
	 * invented `--color-star`, which this site does not define, so it always
	 * fell through to a hard-coded yellow that no palette could reach.
	 */
	color: var(--color-accent-ink, #7a5c00);
}

.ov-review__value {
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.ov-review__body {
	line-height: 1.55;
}

/*
 * A review is plain text, so its line breaks are shown as typed, and the edit
 * box reads them back from the text rather than losing them to markup.
 */
:where([data-ov-review-text]) {
	white-space: pre-line;
}

.ov-review__body p:last-child {
	margin-bottom: 0;
}

.ov-review__body .ov-engage-box {
	width: 100%;
	min-height: 6rem;
}

.ov-review__actions {
	display: flex;
	gap: 0.5rem;
	margin-top: 0.75rem;
}

.ov-review__action {
	padding: 0.3rem 0.75rem;
	border: 1px solid var(--color-border, rgba( 0, 0, 0, 0.15 ));
	border-radius: var(--radius-full);
	background: none;
	color: inherit;
	font: inherit;
	font-size: var(--text-xs, 12px);
	cursor: pointer;
}

.ov-review__action:hover {
	border-color: var(--color-accent, currentColor);
}

.ov-reviews__more {
	margin: 0.75rem 0 0;
	font-size: var(--note-size, 13px);
	color: var(--note-color, inherit);
}

/* ==========================================================================
 * THE FORUM'S OWN PAGES. Asgaros draws its markup with its own sizes and greys,
 * and every site that turns the forum on inherits them: `<small>` at 9 to 11px,
 * #888 on white at 3.54:1, a 16px search field, and two h1s on the overview.
 *
 * ⚠️ THESE LIVED IN SITE ONE'S STYLESHEETS, so the first other site to turn
 * its forum on (D221) failed four accessibility checks on /forum/. They are
 * the platform's now, in the platform's default tokens; a site restyles the
 * forum on top. Scoped to `#af-wrapper`, the plugin's own root. The reasoning
 * for each (two ids, one !important) is in site one's pages.css history.
 * ======================================================================== */

#af-wrapper small,
#af-wrapper .forum-description,
#af-wrapper .forum-stats,
#af-wrapper .no-topics,
#af-wrapper #forum-header span,
#af-wrapper #forum-breadcrumbs span,
#af-wrapper #forum-breadcrumbs a {
	font-size: var(--text-xs);
	color: var(--color-text-muted);
}

#af-wrapper input {
	block-size: auto;
	min-block-size: var(--tap-min);
}

#af-wrapper #forum-search input[type="search"],
#af-wrapper input[type="search"],
#af-wrapper input[type="text"],
#af-wrapper input[type="submit"] {
	min-block-size: var(--tap-min);
	padding-block: var(--space-2xs);
}

#af-wrapper a.forum-title {
	display: inline-flex;
	align-items: center;
	min-block-size: var(--tap-min);
}

#af-wrapper .notice {
	border-color: var(--color-border);
	background: var(--color-surface-sunk);
	color: var(--color-text);
}

/* Asgaros marks its own link colour !important, so only !important meets it. */
#af-wrapper .notice a[href] {
	color: var(--color-warning-ink) !important;
}

#af-wrapper .title-element-dark {
	background-color: var(--color-text-muted);
}

/* One h1 per view: the page title on the overview, Asgaros's own elsewhere. */
#af-wrapper h1.main-title-overview {
	display: none;
}

body.asgaros-forum:not(.asgaros-forum-overview) #brx-content > h1 {
	display: none;
}

/*
 * The forum on a site that switches light and dark (D222).
 *
 * Asgaros paints its panels and text with its own fixed colours, #fff and
 * #444 from its appearance settings, and the rules above flip the small text
 * to the platform's muted role. In dark mode that put light-grey text on a
 * white panel at 2.5:1. On a switching site its panels and ink take the
 * platform's roles, which flip together; everywhere else Asgaros keeps its
 * own look.
 */
:root[data-ov-scheme] #af-wrapper,
:root[data-ov-scheme] #af-wrapper #forum-search,
:root[data-ov-scheme] #af-wrapper #statistics,
:root[data-ov-scheme] #af-wrapper .content-container {
	background-color: var(--color-surface);
	color: var(--color-text-body);
}
:root[data-ov-scheme] #af-wrapper .content-element,
:root[data-ov-scheme] #af-wrapper #statistics-online-users {
	background-color: var(--color-surface-sunk);
	border-color: var(--color-border);
	color: var(--color-text-body);
}
:root[data-ov-scheme] #af-wrapper .content-container,
:root[data-ov-scheme] #af-wrapper #forum-search input {
	border-color: var(--color-border);
}
/* Its links are its own blue, and its admin names its own red, fixed too. */
:root[data-ov-scheme] #af-wrapper a {
	color: var(--color-accent-ink);
}
:root[data-ov-scheme] #af-wrapper a.profile-link {
	color: var(--color-accent-ink) !important;
}
:root[data-ov-scheme] #af-wrapper :is(#forum-header, .title-element) a {
	color: inherit;
}
:root[data-ov-scheme] #af-wrapper .title-element-dark {
	background-color: var(--color-text-muted);
	color: var(--color-surface);
}
