/**
 * Poll text alignment and readability, on the front end.
 *
 * WHY THIS LIVES IN THE NEWS EDITOR PLUGIN AND NOT IN CORE.
 *
 * The centring comes from `.poll-header-content { text-align: center }` in the
 * core true-polls plugin, which belongs to the development agency. Editing it
 * there works until their next deploy overwrites the file, and then the fix is
 * gone with no sign of why. Our own plugin survives that, so the override
 * lives here.
 *
 * WHY CENTRED BODY TEXT READS AS SLOPPY.
 *
 * A centred paragraph has a ragged edge on BOTH sides, so the eye has no fixed
 * point to return to at the end of a line. It is fine for a headline of three
 * words and steadily worse the longer the text runs — and a drafted news
 * summary runs to several hundred. The heading stays centred because it is
 * short; the long text is aligned below.
 */

/*
 * FULL JUSTIFICATION — owner's instruction, 2026-08-29.
 *
 * Justified text sets a straight edge on both sides by stretching the spaces
 * between words. On a wide column that reads as typeset. In a narrow one the
 * same stretching opens "rivers" of white space, because there are too few
 * words on a line to absorb the slack — which is why an earlier version of this
 * file deliberately stopped at `left`.
 *
 * `hyphens: auto` lets the browser break a long word across lines instead of
 * pushing it whole to the next line and stretching what is left behind to fill
 * the gap. It needs to know the page language to apply the right breaking
 * rules; WordPress prints one on <html> via `language_attributes()`, so this
 * works with no theme change. Safari still requires the -webkit- prefix.
 *
 * IT IS NOT A RESCUE FOR PHONES, THOUGH IT WAS ADDED BELIEVING IT WOULD BE.
 * Checked on a real Android, 2026-08-29: the gaps are still there. Hyphenation
 * helps at the margin and earns its place from tablet width up; it cannot
 * manufacture the words a 32-character line has no room for. The phone case is
 * settled by the media query further down instead.
 *
 * `overflow-wrap: break-word` is the backstop for a token with no legal
 * hyphenation point at all — a bare URL pasted into a hand-written description
 * would otherwise force a line wider than the column and defeat the alignment
 * entirely.
 *
 * The last line of a justified block is NOT stretched. That is correct CSS
 * behaviour and it is what stops a two-word final line being spread across the
 * full width. `text-align-last` would force it; do not add it.
 *
 * THE QUESTION IS RENDERED BY TWO DIFFERENT TEMPLATES, WITH DIFFERENT MARKUP.
 * The page a member votes on (`poll-form.php`) and its preview both write the
 * question as a bare `<h4>` inside `.poll-question`; the details page
 * (`poll-details-single.php`) writes `<h3 class="question-text">`. Styling only
 * one of them leaves the other unjustified, and the two pages look near
 * identical, so the miss is easy to walk past. Both are listed below.
 *
 * NO SPECIFICITY BATTLE HERE. Core sets text-align on the PARENT
 * (.poll-header-content) and lets it inherit, and sets none at all on either
 * question element — so there is no competing rule to outrank, and an inherited
 * value always loses to a direct one whatever the specificity. The WIDTH cap
 * further down is the opposite case and does need two classes.
 */
.poll-description,
.poll-question h4,
.question-text {
	text-align: justify;
	-webkit-hyphens: auto;
	hyphens: auto;
	overflow-wrap: break-word;
}

/*
 * PHONES FALL BACK TO LEFT-ALIGNED. Owner's decision, 2026-08-29, after seeing
 * it on his own Android and after the alternatives were measured and rejected.
 *
 * Justification distributes a line's leftover space across the gaps between its
 * words, so it needs enough words on a line for that slack to disappear into —
 * roughly 45 characters and up. A 375px phone gives this column 285px once the
 * theme's padding is taken, which is about 32 characters at core's 18px. One
 * long word ("denuclearize", "inappropriate") then eats half the line and the
 * remainder is stretched across two or three gaps.
 *
 * MEASURED ON POLL 162 AT 375px, gaps as a multiple of a normal space —
 * median 2.07x, worst 8.4x, 10 lines of 49 above 3x. For contrast the same text
 * at 768px runs 1.3x median with NO line above 2x. The column width is the whole
 * story.
 *
 * EVERYTHING ELSE WAS TRIED FIRST AND DID NOT WORK. Each was confirmed applied
 * by reading the computed style back, so these are null results, not typos:
 *
 *     text-wrap: pretty              2.08x median / 8.4x worst  (no change)
 *     hyphenate-limit-chars: 5 2 2   2.07x median / 8.4x worst  (no change)
 *     font-size 16px                 1.81x median / 8.2x worst
 *     font-size 14px                 1.99x median / 5.9x worst  (and too small)
 *     soft hyphens injected by us    2.06x median / 8.2x worst
 *
 * `hyphens: auto` does not rescue it either, on a real Android or anywhere else.
 * Hyphenation helps at the margin; it cannot manufacture the words a
 * 32-character line has no room for. It is left switched on above because it
 * costs nothing and genuinely helps at tablet width and up.
 *
 * 560px is where the column reaches roughly 50 characters. Below that, left.
 * Note this only overrides text-align — `hyphens` and `overflow-wrap` stay in
 * force, because both still help ragged-right text and `overflow-wrap` is what
 * stops a pasted URL blowing out the column at any alignment.
 */
@media ( max-width: 560px ) {

	.poll-description,
	.poll-question h4,
	.question-text {
		text-align: left;
	}
}

/*
 * THE LINE-LENGTH CAP NEEDS TWO CLASSES — AND A MEDIA QUERY.
 *
 * Core already caps the width, with `.poll-header-section .poll-description`
 * at 60% and an `:has(.poll-featured-image)` variant at 80%. Those are two
 * classes; a bare `.poll-description` is one, so the first attempt here lost
 * the cascade silently — the alignment applied, the width did not, and the
 * computed style read `max-width: 100%` as though nothing had been written.
 *
 * Matching core's own selectors settles it on specificity rather than on load
 * order, which is the part that would otherwise break the next time either
 * plugin changed when it enqueues.
 *
 * min() keeps BOTH limits: core's percentage still governs middling screens,
 * and the character measure takes over on a wide monitor, where 80% of 2560px
 * is about 1600px of text and the eye loses its place returning to the next
 * line. Roughly 65-75 characters is the comfortable range.
 *
 * THE MEDIA QUERY IS NOT OPTIONAL — IT REPAIRS A REGRESSION. Core releases the
 * cap on small screens:
 *
 *     @media (max-width: 980px) {
 *         .poll-header-section .poll-description { max-width: 100% }
 *     }
 *
 * A media query adds NO specificity. Core's mobile rule and the rule below are
 * both 0-2-0, so the winner is whichever stylesheet loads last — and ours does.
 * Written without a query of its own, the 60% cap therefore reached the phone
 * too and squeezed the description into a 171px ribbon of about NINETEEN
 * characters a line. Measured live on 2026-08-29 at a 375px viewport: 90 lines
 * for a description that takes 20 on a desktop.
 *
 * That was live before the text was justified and nobody had spotted it,
 * because ragged-right text degrades quietly at any width. Justification is
 * what exposed it: a 19-character line usually holds a single word, a line with
 * one word has no spaces to stretch, so justification silently does nothing and
 * the column comes out visibly ragged and broken instead.
 *
 * Scoping to (min-width: 981px) — the exact complement of core's breakpoint —
 * leaves their mobile rule to win by default rather than by load order. The
 * general lesson: when overriding another plugin by matching its selector,
 * check the whole cascade for that selector, not the one declaration in view.
 * Their media query was invisible from the base rule.
 */
@media ( min-width: 981px ) {

	.poll-header-section .poll-description {
		max-width: min( 68ch, 60% );
		margin-left: auto;
		margin-right: auto;
	}

	.poll-header-section:has( .poll-featured-image ) .poll-description {
		max-width: min( 68ch, 80% );
		margin-left: auto;
		margin-right: auto;
	}
}

/*
 * Paragraph spacing, for when the description contains real paragraphs.
 *
 * Feed descriptions arrive as one run of text, so today this mostly does
 * nothing. It matters the moment somebody writes a description by hand in the
 * poll editor, and costs nothing until then.
 *
 * `text-align: inherit` carries the justification down. `hyphens` and
 * `overflow-wrap` are inherited properties, so they need no repeating here.
 */
.poll-description p {
	margin: 0 0 0.9em;
	text-align: inherit;
}

.poll-description p:last-child {
	margin-bottom: 0;
}

/*
 * ANSWER OPTIONS ARE DELIBERATELY NOT JUSTIFIED.
 *
 * `.option-text` is a control label — "Strongly approve", "No opinion" — not
 * text anybody reads in sequence. A label that wraps to two lines under
 * justification gets its FIRST line stretched to the full width of the option
 * row, which reads as a rendering fault rather than as typesetting. Same
 * reasoning for badges, dates and buttons: justification is for prose.
 */
