/*
Theme Name: PV Theme
Theme URI: https://github.com/aleteia-italia-srl/visite-du-pape-2026
Description: Full Site Editing theme for the «Visite du pape en France» app (25-28 September 2026), built on the Atelier Argo graphic charter.
Author: Magnificat
Version: 0.38.0
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 8.2
Template: twentytwentyfive
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: pv
Tags: full-site-editing, block-patterns
*/

/*
 * Hand-written CSS, no framework. Colours, typography and spacing live in
 * theme.json; this file carries what theme.json cannot express — the components.
 *
 * Mobile-first throughout: the app shows this site at phone width, so the phone
 * is the design, not a breakpoint to degrade to. The few media queries below add
 * to it rather than undo it.
 *
 * Palette (Atelier Argo, leonXIV_charte_6juillet2026.pdf):
 *   bleu foncé #0F2D85 · rouge #F71021 · bleu cyan #1ACCFF
 *   vert #00B5B0 · jaune #FFA107
 */

:root {
	--pv-font-display: var( --wp--preset--font-family--jost );
	/*
	 * The reading face, used by the day's texts from Magnificat and nowhere
	 * else. Faces the phone already has: the printed Magnificat is set in a
	 * licensed serif we cannot ship, and a webfont for one page is bytes spent
	 * on the worst network of the year. Every name here is a serif with a large
	 * x-height and real italics, which is what the text needs; the differences
	 * between them matter far less than the difference from the sans.
	 */
	--pv-font-serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
	--pv-bleu: var( --wp--preset--color--bleu );
	--pv-cyan: var( --wp--preset--color--cyan );
	--pv-vert: var( --wp--preset--color--vert );
	--pv-jaune: var( --wp--preset--color--jaune );
	--pv-rouge: var( --wp--preset--color--rouge );
	--pv-surface: var( --wp--preset--color--surface );
	--pv-gris: var( --wp--preset--color--gris );
	/*
	 * The alias was missing while the hover on the directions button already
	 * referred to it: an undefined custom property makes the whole declaration
	 * invalid, so that hover left white text on no background at all.
	 */
	--pv-encre: var( --wp--preset--color--encre );
	--pv-radius: 2px;
	--pv-touch: 44px;
}

/* Used while walking, one-handed, sometimes in gloves. 44px is the floor. */
.wp-block-navigation a,
.pv-card,
.pv-next__link,
.wp-element-button {
	min-height: var( --pv-touch );
}

/* -------------------------------------------------------------------------
 * Alert banner
 *
 * Empty in the HTML and filled from pv-now.json, because this page is cached on
 * Cloudflare: anything rendered server-side here would be frozen for the length
 * of the TTL, and this is the one element that must never be stale.
 * ---------------------------------------------------------------------- */

.pv-alert {
	display: none;
}

/*
 * As slim as it can be while staying legible: one compact line on a phone, the
 * navy of the reference site behind it, and the severity carried by a coloured
 * bar down the left rather than by a coloured box.
 *
 * The height matters more than it looks. This sits above the header on every
 * page, so every pixel here is a pixel of programme pushed below the fold on a
 * phone — and the phone is the product.
 */
.pv-alert[data-level] {
	display: block;
	padding: 0.45rem var( --wp--preset--spacing--30 );
	border-left: 4px solid var( --pv-cyan );
	background: var( --wp--preset--color--navy );
	color: #fff;
	font-size: 0.8125rem;
	line-height: 1.35;
}

.pv-alert[data-level="warning"] {
	border-left-color: var( --pv-jaune );
}

/*
 * Urgent keeps the red field, not just a red edge. It is the one state that has
 * to interrupt someone walking, and it is the only red on the site.
 */
.pv-alert[data-level="urgent"] {
	border-left-color: var( --pv-rouge );
	background: var( --pv-rouge );
}

/* -------------------------------------------------------------------------
 * Offline notice
 *
 * Under the alert, and quieter than it on purpose. An alert is something to
 * act on; this is a caveat about the page underneath it — «what you are
 * reading was received at half past two». On the four days both can be true at
 * once, and the one that must be read first has to look different from the one
 * that must merely be understood.
 *
 * Grey on the surface colour rather than a colour of its own: the palette has
 * three severities already and being offline is not a fourth.
 * ---------------------------------------------------------------------- */

.pv-stale {
	padding: 0.4rem var( --wp--preset--spacing--30 );
	background: var( --pv-surface );
	color: var( --pv-gris );
	font-size: 0.8125rem;
	line-height: 1.35;
}

/* Title and message run together on one line; they only wrap when they must. */
.pv-alert__title {
	font-weight: 700;
}

.pv-alert__title::after {
	content: " — ";
	font-weight: 400;
	opacity: 0.7;
}

.pv-alert__message {
	display: inline;
	margin: 0;
}

.pv-alert a {
	color: #fff;
	margin-left: 0.4rem;
	white-space: nowrap;
}

/* -------------------------------------------------------------------------
 * Header
 * ---------------------------------------------------------------------- */

.pv-header {
	border-bottom: 1px solid rgba( 15, 45, 133, 0.12 );
}

.pv-header__bar {
	/*
	 * Width and centring live here, not in the block's layout. A constrained
	 * layout gives every child max-width and margin-inline:auto, which turns
	 * this flex row into a stack — the burger lands under the logo.
	 */
	max-width: 64rem;
	margin-inline: auto;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var( --wp--preset--spacing--30 );
	padding: 0.75rem var( --wp--preset--spacing--30 );
	/*
	 * The bar follows the alert element, so WordPress gives it the block gap as
	 * a top margin. With symmetric padding that leaves more space above the logo
	 * than below it, and the header reads as sitting too low.
	 */
	margin-block-start: 0;
}

/*
 * WordPress gives every child after the first a block-gap top margin, and in a
 * centred flex row a top margin displaces the item by half of it. That is the
 * whole story of the burger sitting twelve pixels below the logo: 24px of gap,
 * 12px of drift. Measured, not guessed.
 */
.pv-header__bar > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/*
 * The burger also sits inside a template-part wrapper and a nav, both plain
 * blocks that neither stretch nor centre.
 */
.pv-header__bar .wp-block-template-part,
.pv-header__bar .pv-nav,
.pv-header__bar .wp-block-navigation,
.pv-header__bar .wp-block-navigation__responsive-container-open {
	display: flex;
	align-items: center;
}

.pv-logo img,
.pv-logo svg {
	display: block;
	width: auto;
	/*
	 * Sized so LÉON XIV reads, not so the date line does.
	 *
	 * Measured from the artwork: of the four lines in the lock-up, the wordmark
	 * occupies 430 of 1394px and "25-28 SEPTEMBRE" only 115. At a header height
	 * that fits a phone, that last line renders around 6px — and reaching 10px
	 * would need a 121px logo, which is most of the screen above the fold.
	 *
	 * So it is treated as decorative here. The dates are content, and they are
	 * on the home page and in the footer where they can be read. At 72px the
	 * wordmark is 22px, which is the thing that has to be legible.
	 *
	 * Still fits at 320px: 155px of logo, 16 of gap, 44 of burger, inside 288.
	 */
	height: clamp( 72px, 19vw, 96px );
}

/* -------------------------------------------------------------------------
 * Off-canvas navigation
 *
 * The panel is the core Navigation block's overlay. Everything below formats it;
 * none of it changes how it works, so the block keeps behaving the way the
 * editorial team expects in the Site Editor.
 * ---------------------------------------------------------------------- */

/*
 * Three lines, drawn here rather than taken from the block.
 *
 * The core icon is a single glyph whose weight is not adjustable, and it reads
 * thin next to a logo this size. These are three real bars, sized against the
 * charter's blue and the 44px target.
 */
.pv-nav .wp-block-navigation__responsive-container-open svg {
	display: none;
}

.pv-nav .wp-block-navigation__responsive-container-open::before {
	content: "";
	width: 26px;
	height: 2px;
	border-radius: 1px;
	background: currentColor;
	box-shadow: 0 -8px 0 currentColor, 0 8px 0 currentColor;
}

/* The hamburger has to be a real target, not an icon floating in a small box. */
.pv-nav .wp-block-navigation__responsive-container-open,
.pv-nav .wp-block-navigation__responsive-container-close {
	min-width: var( --pv-touch );
	min-height: var( --pv-touch );
	display: flex;
	align-items: center;
	justify-content: center;
}

.pv-nav .wp-block-navigation__responsive-container-open {
	color: var( --pv-bleu );
}

/*
 * White, not the blue used for the hamburger: this one sits on the bleu foncé
 * panel, and inheriting that colour makes the only way out of the menu
 * invisible.
 */
.pv-nav .wp-block-navigation__responsive-container-close {
	color: #fff;
	margin: 0.5rem 0.25rem 0 0;
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open {
	padding: 0;
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-close {
	max-width: none;
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
	display: block;
	padding: var( --wp--preset--spacing--30 ) var( --wp--preset--spacing--40 ) var( --wp--preset--spacing--50 );
}

/*
 * The logo at the top of the panel.
 *
 * Drawn here rather than added as a block: the Navigation block accepts only a
 * fixed set of inner blocks, and a custom one would render on the front end
 * while breaking the menu editor. The white lock-up, because the panel is
 * bleu foncé — the charter requires the monochrome version on a solid colour.
 *
 * The URL is relative to this stylesheet, so it needs no PHP to resolve.
 */
.pv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content::before {
	content: "";
	display: block;
	width: 190px;
	height: 56px;
	margin: 0 0 var( --wp--preset--spacing--50 );
	background: url( "assets/img/logo-blanc.svg" ) left center / contain no-repeat;
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container {
	display: block;
	gap: 0;
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item {
	display: block;
	border-bottom: 1px solid rgba( 255, 255, 255, 0.18 );
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	display: flex;
	align-items: center;
	min-height: 3.25rem;
	font-size: 1.25rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	text-decoration: none;
}

/*
 * Social links sit after the menu, visually separate from it.
 *
 * Matched at the same depth as the panel's own rules: WordPress emits layout
 * margins for the block, and a bare .pv-nav__social loses to them — the icons
 * end up flush against the last menu item and read as another row of it.
 */
.pv-nav .wp-block-navigation__responsive-container.is-menu-open .pv-nav__social {
	margin-top: var( --wp--preset--spacing--50 );
	padding-top: var( --wp--preset--spacing--30 );
}

.pv-nav .wp-block-navigation__responsive-container.is-menu-open .pv-nav__social .wp-block-social-link {
	margin: 0 0.75rem 0 0;
}

/*
 * Footer menu, in the right-hand column.
 *
 * `auto-fill` rather than a fixed count and a breakpoint: the menu sits in a
 * column whose width changes with the viewport, so what it should ask is "how
 * many of these fit", not "how wide is the window". It answers two at every
 * size the footer actually takes, and would answer one without being told if
 * the column ever narrowed.
 *
 * 8rem is the floor because the longest label, "Intentions de prière", measures
 * 110px at this size. A column narrower than that wraps a menu item onto two
 * lines, which looks like a mistake.
 *
 * Two columns rather than a single file of nine is also what keeps the footer
 * short: five rows against the credits and the icons beside them, instead of a
 * menu twice the height of everything it sits next to.
 *
 * The links are underlined and stay underlined. On a navy ground, white text
 * that only underlines on hover is indistinguishable from the paragraph beside
 * it — and hover does not exist on the device most of this audience is holding.
 */
.pv-footer__menu {
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( 8rem, 1fr ) );
	gap: 0 1.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * The legal line.
 *
 * Smaller and quieter than the menu, because nobody comes to a site for it —
 * but underlined and at full contrast, because somebody looking for it is
 * usually looking for it in a hurry.
 */
.pv-footer__legal {
	margin: 1.5rem 0 0;
	font-size: var( --wp--preset--font-size--small );
}

.pv-footer__legal a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.pv-footer__menu a {
	display: block;
	/*
	 * 0.35rem against the small font size is a 40px row: still a target a thumb
	 * can hit outdoors, without the footer becoming a second page.
	 */
	padding: 0.35rem 0;
	color: inherit;
	font-size: var( --wp--preset--font-size--small );
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/*
 * The two columns.
 *
 * The gap is set on the block, so this only handles the stacked case: without
 * it the menu sits directly under the social icons with no separation, and the
 * two read as one list.
 */
.pv-footer__cols {
	align-items: flex-start;
}

/* Footer social icons: white on the navy, and a real touch target. */
.pv-footer__social {
	margin-top: var( --wp--preset--spacing--30 );
	margin-bottom: 0;
}

.pv-footer__social .wp-block-social-link {
	margin: 0 0.75rem 0 0;
}

/* -------------------------------------------------------------------------
 * Live badge
 * ---------------------------------------------------------------------- */

.pv-live-badge {
	display: none;
	align-items: center;
	gap: 0.4rem;
	padding: 0.25rem 0.6rem;
	border-radius: 999px;
	background: var( --pv-rouge );
	color: #fff;
	font-size: 0.8125rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	text-decoration: none;
}

.pv-live-badge[data-active="1"] {
	display: inline-flex;
}

.pv-live-badge::before {
	content: "";
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: #fff;
	animation: pv-pulse 2s ease-in-out infinite;
}

@keyframes pv-pulse {
	50% {
		opacity: 0.3;
	}
}

@media ( prefers-reduced-motion: reduce ) {
	.pv-live-badge::before {
		animation: none;
	}
}

/* -------------------------------------------------------------------------
 * One column, one left edge
 *
 * Every template's main sits at 64rem. Prose is capped for readability, but
 * capped by max-width and pinned to the start — not centred. A constrained
 * layout centres anything narrower than the column, which is why a 40rem title
 * above 64rem cards never lined up with them.
 *
 * The measure applies to running text only. Headings, listings and anything
 * carrying an alignment keep the full column, so the left edge is shared all
 * the way down the page.
 * ---------------------------------------------------------------------- */

.entry-content > :where( p, ul, ol, blockquote, figure, .wp-block-quote ),
main > :where( p, ul, ol, blockquote ) {
	max-width: 44rem;
	margin-inline-start: 0;
}

/*
 * Nothing here for bands on purpose.
 *
 * Their paragraphs are not direct children of main, so the measure above never
 * reached them anyway — and an override that unset max-width also unset the one
 * the constrained layout uses to centre them, which left the text flush against
 * the screen edge while the heading stayed centred.
 */

/* -------------------------------------------------------------------------
 * Full-width bands
 *
 * The home page alternates backgrounds so the sections are told apart before
 * they are read. Everything here is about making that survive the defaults.
 * ---------------------------------------------------------------------- */

.pv-band {
	/*
	 * Horizontal padding lives on the band, not on main: main has none, so the
	 * colour reaches the edge of the screen while the text still keeps its
	 * margin from it.
	 */
	padding-inline: var( --wp--preset--spacing--30 );
}

/*
 * On a coloured band the text colour is set by the block, but headings and
 * links carry their own blue from theme.json and would disappear into it.
 */
.pv-band--dark :is( h1, h2, h3, h4 ),
.pv-band--dark a {
	color: inherit;
}

/*
 * Matched with the [data-ready] attribute too. The countdown's own rule sets
 * the charter blue at equal specificity and appears later in the file, so a
 * plainer selector loses and the text disappears into the blue band.
 */
.pv-band--dark .pv-countdown[data-ready] {
	color: inherit;
}

.pv-band--dark a {
	text-decoration-thickness: 0.1em;
	text-underline-offset: 0.2em;
}

/*
 * The first band sits directly under the header. Its own padding is enough;
 * the block gap on top would only push the fold further down.
 */
.pv-band:first-child {
	margin-block-start: 0;
}

/* Cards need a white ground to lift off the pale band. */
.pv-band .pv-card {
	background: #fff;
}

/* -------------------------------------------------------------------------
 * Cards and programme listings
 * ---------------------------------------------------------------------- */

.pv-list {
	display: grid;
	gap: 0.75rem;
	margin: var( --wp--preset--spacing--40 ) 0;
	padding: 0;
	list-style: none;
	/*
	 * One column on a phone, as many as fit once there is room. auto-fill with a
	 * min() floor rather than a breakpoint: the same rule holds at 40rem and at
	 * the wide width, so widening a template needs no CSS change.
	 */
	grid-template-columns: repeat( auto-fill, minmax( min( 100%, 20rem ), 1fr ) );
}

/*
 * Cards are colour-coded by stage. It gives the programme a second, faster way
 * to be read: someone following one city can find their days without reading a
 * word. The accent defaults to the charter blue so a card without a stage still
 * looks deliberate.
 */
.pv-card {
	--pv-accent: var( --pv-bleu );
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	padding: var( --wp--preset--spacing--30 );
	border: 1px solid rgba( 15, 45, 133, 0.14 );
	border-top: 4px solid var( --pv-accent );
	border-radius: var( --pv-radius );
	text-decoration: none;
	color: inherit;
	background: #fff;
	transition: border-color 0.15s, transform 0.15s;
}

.pv-card--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-card--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-card--vert  { --pv-accent: var( --pv-vert ); }
.pv-card--jaune { --pv-accent: var( --pv-jaune ); }

.pv-card:hover,
.pv-card:focus-visible {
	border-color: var( --pv-accent );
	transform: translateY( -1px );
}

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

	.pv-card:hover,
	.pv-card:focus-visible {
		transform: none;
	}
}

.pv-card__head {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	margin-bottom: 0.15rem;
}

/* The charter ships pictograms for Paris, Lourdes and Metz. Elsewhere there is
   simply none, and the row closes up rather than showing a placeholder. */
.pv-card__picto {
	width: 2.25rem;
	height: 2.25rem;
	flex: none;
}

.pv-card__time {
	font-weight: 700;
	font-size: 1.125rem;
	color: var( --pv-bleu );
	font-variant-numeric: tabular-nums;
}

/* The one place red is spent outside the alert: arriving at a cancelled
   celebration is worse than any consistency argument. */
.pv-card__flag {
	margin-left: auto;
	padding: 0.1rem 0.5rem;
	border-radius: 999px;
	background: var( --pv-rouge );
	color: #fff;
	font-size: 0.75rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.03em;
}

.pv-card__title {
	display: block;
	font-size: var( --wp--preset--font-size--large );
	font-weight: 700;
	line-height: 1.2;
	color: var( --pv-bleu );
}

.pv-card__meta {
	display: block;
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
}

.pv-card__type {
	align-self: flex-start;
	margin-top: 0.4rem;
	padding: 0.15rem 0.55rem;
	border-radius: 999px;
	background: color-mix( in srgb, var( --pv-accent ) 12%, #fff );
	color: var( --pv-accent );
	font-size: 0.75rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

/* -------------------------------------------------------------------------
 * Sequence header
 * ---------------------------------------------------------------------- */

.pv-hero {
	--pv-accent: var( --pv-bleu );
	display: flex;
	align-items: center;
	gap: var( --wp--preset--spacing--30 );
	/*
	 * The band runs edge to edge but its content lines up with the column below
	 * it: the inline padding grows to whatever is left over once 64rem is taken,
	 * never less than the page gutter. Without it the pictogram sits against the
	 * screen edge while the text beneath starts a third of the way in.
	 */
	padding-block: var( --wp--preset--spacing--40 );
	padding-inline: max( var( --wp--preset--spacing--30 ), calc( ( 100% - 64rem ) / 2 ) );
	background: var( --pv-accent );
	color: #fff;
}

.pv-hero--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-hero--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-hero--vert  { --pv-accent: var( --pv-vert ); }
.pv-hero--jaune { --pv-accent: var( --pv-jaune ); }

/*
 * Cyan and yellow are light. White on them fails contrast, so those two flip to
 * the charter blue rather than being nudged darker — the palette is the client's
 * and is not ours to bend.
 */
.pv-hero--cyan,
.pv-hero--jaune {
	color: var( --pv-bleu );
}

.pv-hero__text {
	max-width: 44rem;
}

/* The charter pictogram, in the monochrome-on-colour treatment it asks for. */
.pv-hero__picto {
	width: clamp( 3rem, 12vw, 4.5rem );
	height: auto;
	flex: none;
	filter: brightness( 0 ) invert( 1 );
}

.pv-hero--cyan .pv-hero__picto,
.pv-hero--jaune .pv-hero__picto {
	filter: none;
}

.pv-hero__eyebrow {
	margin: 0;
	font-size: var( --wp--preset--font-size--small );
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	opacity: 0.85;
}

.pv-hero__title {
	margin: 0.15rem 0 0;
	color: inherit;
	font-size: var( --wp--preset--font-size--x-large );
	line-height: 1.1;
	text-transform: uppercase;
}

.pv-hero__facts {
	margin: 0.35rem 0 0;
	font-weight: 500;
}

/* -------------------------------------------------------------------------
 * Directions button
 *
 * Arguably the most useful control on the site during the four days: it is the
 * one that answers "how do I get there from here". Sized and weighted to be
 * found without looking for it.
 * ---------------------------------------------------------------------- */

.pv-directions {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	min-height: var( --pv-touch );
	padding: 0.6rem 1.1rem;
	border-radius: 999px;
	background: var( --pv-bleu );
	color: #fff;
	font-weight: 700;
	text-decoration: none;
	line-height: 1.2;
}

.pv-directions:hover,
.pv-directions:focus-visible {
	background: var( --pv-encre );
	color: #fff;
}

/*
 * On a coloured header the filled blue button disappears into the ground, so it
 * inverts: white field, the band's colour for the text.
 */
.pv-hero .pv-directions {
	margin-top: 0.75rem;
	background: #fff;
	color: var( --pv-accent );
}

.pv-hero .pv-directions:hover,
.pv-hero .pv-directions:focus-visible {
	background: var( --pv-surface );
	color: var( --pv-accent );
}

/* -------------------------------------------------------------------------
 * Timeline
 *
 * A spine with the steps down it. On a phone the spine sits at the left and
 * every step runs down one side — alternating needs room the phone does not
 * have, and the phone is the product. The two-sided treatment starts at 48rem
 * and is an enhancement, not the design.
 * ---------------------------------------------------------------------- */

.pv-timeline__heading {
	margin-top: var( --wp--preset--spacing--50 );
}

.pv-timeline {
	--pv-spine: 1.25rem;
	position: relative;
	margin: var( --wp--preset--spacing--40 ) 0 0;
	padding: 0;
	list-style: none;
}

.pv-timeline::before {
	content: "";
	position: absolute;
	top: 0.5rem;
	bottom: 0.5rem;
	left: var( --pv-spine );
	width: 2px;
	background: rgba( 15, 45, 133, 0.16 );
}

.pv-step {
	--pv-accent: var( --pv-bleu );
	position: relative;
	/*
	 * Without this, width:50% measures the content box and the 3rem of padding
	 * pushes the step 48px past the spine — which is exactly how far the markers
	 * on that side were sitting off it.
	 */
	box-sizing: border-box;
	padding: 0 0 var( --wp--preset--spacing--40 ) calc( var( --pv-spine ) + 2rem );
}

.pv-step--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-step--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-step--vert  { --pv-accent: var( --pv-vert ); }
.pv-step--jaune { --pv-accent: var( --pv-jaune ); }
.pv-step--gris  { --pv-accent: var( --pv-gris ); }

.pv-step__marker {
	position: absolute;
	top: 0;
	left: 0;
	width: 2.5rem;
	height: 2.5rem;
	transform: translateX( calc( var( --pv-spine ) - 1.25rem ) );
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var( --pv-accent );
	color: #fff;
	font-weight: 700;
}

/* Same contrast problem as the hero, same answer. */
.pv-step--cyan .pv-step__marker,
.pv-step--jaune .pv-step__marker {
	color: var( --pv-bleu );
}

.pv-step__type {
	display: block;
	font-size: 0.75rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var( --pv-accent );
}

.pv-step__title {
	margin: 0.1rem 0 0;
	font-size: var( --wp--preset--font-size--large );
}

.pv-step__text {
	margin: 0.3rem 0 0;
	max-width: 40rem;
}

.pv-step__duration {
	display: inline-block;
	margin-top: 0.35rem;
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
	font-variant-numeric: tabular-nums;
}

@media ( min-width: 48rem ) {
	.pv-timeline {
		--pv-spine: 50%;
	}

	.pv-step {
		width: 50%;
		padding-left: 0;
		padding-right: 3rem;
		text-align: right;
	}

	.pv-step__marker {
		left: auto;
		right: 0;
		transform: translateX( 1.25rem );
	}

	.pv-step:nth-child( even ) {
		margin-left: 50%;
		padding-left: 3rem;
		padding-right: 0;
		text-align: left;
	}

	.pv-step:nth-child( even ) .pv-step__marker {
		right: auto;
		left: 0;
		transform: translateX( -1.25rem );
	}

	.pv-step__text {
		max-width: none;
	}
}

/* -------------------------------------------------------------------------
 * Tiles — prayers and places
 *
 * The icon box is a fixed square rather than sized to its contents, so a row
 * lines up whether the artwork is a wide facade or a narrow steeple. That was
 * the whole reason the places page looked ragged.
 * ---------------------------------------------------------------------- */

.pv-tiles {
	display: grid;
	gap: 0.75rem;
	margin: var( --wp--preset--spacing--40 ) 0;
	padding: 0;
	list-style: none;
	grid-template-columns: repeat( auto-fill, minmax( min( 100%, 17rem ), 1fr ) );
}

.pv-tile {
	--pv-accent: var( --pv-bleu );
	display: flex;
	align-items: flex-start;
	gap: 0.85rem;
	height: 100%;
	padding: var( --wp--preset--spacing--30 );
	border: 1px solid rgba( 15, 45, 133, 0.14 );
	border-left: 4px solid var( --pv-accent );
	border-radius: var( --pv-radius );
	background: #fff;
	color: inherit;
	text-decoration: none;
	box-sizing: border-box;
}

.pv-tile--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-tile--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-tile--vert  { --pv-accent: var( --pv-vert ); }
.pv-tile--jaune { --pv-accent: var( --pv-jaune ); }

.pv-tile:hover,
.pv-tile:focus-visible {
	border-color: var( --pv-accent );
}

/* Fixed square: the alignment depends on it, not on what is inside. */
.pv-tile__icon {
	flex: none;
	width: 2.5rem;
	height: 2.5rem;
	display: grid;
	place-items: center;
	color: var( --pv-accent );
}

.pv-tile__icon img,
.pv-tile__icon svg {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
}

.pv-tile__body {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
}

.pv-tile__title {
	font-weight: 700;
	line-height: 1.2;
	color: var( --pv-bleu );
}

.pv-tile__excerpt,
.pv-tile__meta {
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
}

/* -------------------------------------------------------------------------
 * News cards
 * ---------------------------------------------------------------------- */

.pv-newslist {
	display: grid;
	gap: var( --wp--preset--spacing--30 );
	margin: var( --wp--preset--spacing--40 ) 0;
	padding: 0;
	list-style: none;
	grid-template-columns: repeat( auto-fill, minmax( min( 100%, 19rem ), 1fr ) );
}

.pv-news {
	--pv-accent: var( --pv-bleu );
	display: flex;
	flex-direction: column;
	height: 100%;
	border: 1px solid rgba( 15, 45, 133, 0.14 );
	border-radius: var( --pv-radius );
	overflow: hidden;
	background: #fff;
	color: inherit;
	text-decoration: none;
}

.pv-news--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-news--vert  { --pv-accent: var( --pv-vert ); }
.pv-news--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-news--jaune { --pv-accent: var( --pv-jaune ); }

.pv-news:hover,
.pv-news:focus-visible {
	border-color: var( --pv-accent );
}

/*
 * The media band holds its shape with or without a photograph. Nothing seeded
 * has one, and a grey placeholder would read as a broken image — a field of
 * charter colour reads as a decision. The palette cycles so a list of them still
 * looks like a set.
 */
.pv-news__media {
	display: block;
	aspect-ratio: 16 / 9;
	background: var( --pv-accent );
}

/*
 * No image, no slab.
 *
 * An article without a featured image was giving a 16/9 rectangle of flat
 * colour, and three of them stacked on the home page's band pushed everything
 * under them off the screen. The accent still marks the card — as a bar, which
 * is what it was doing anyway.
 */
.pv-news__media:empty {
	aspect-ratio: auto;
	height: 6px;
}

.pv-news__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.pv-news__body {
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
	padding: var( --wp--preset--spacing--30 );
}

.pv-news__date {
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
}

.pv-news__title {
	font-size: var( --wp--preset--font-size--large );
	font-weight: 700;
	line-height: 1.2;
	color: var( --pv-bleu );
}

.pv-news__excerpt {
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
}

/* -------------------------------------------------------------------------
 * Intentions and the guest book
 *
 * The one place on this site where a stranger's words appear, and the one place
 * a pilgrim writes rather than reads. Both halves are filled on the client, so
 * everything here has to look deliberate while empty.
 * ---------------------------------------------------------------------- */

.pv-ugc__form-area {
	padding: var( --wp--preset--spacing--40 );
	border-radius: var( --pv-radius );
	background: var( --pv-surface );
}

.pv-ugc__intro {
	margin-top: 0;
	max-width: 40rem;
}

.pv-ugc__form label {
	display: block;
	margin-bottom: 0.25rem;
	font-weight: 700;
	color: var( --pv-bleu );
}

.pv-ugc__form textarea,
.pv-ugc__form input[type="text"] {
	/*
	 * border-box, and it is not optional.
	 *
	 * WordPress does not set it globally and this file does not either, so
	 * width:100% meant 100% *plus* 1.6rem of padding and 2px of border: the
	 * fields ran 28px past the panel they sit in, which on a phone is the whole
	 * right-hand edge of the form hanging over the page. Measured at 414px.
	 */
	box-sizing: border-box;
	width: 100%;
	max-width: 34rem;
	padding: 0.7rem 0.8rem;
	border: 1px solid rgba( 15, 45, 133, 0.3 );
	border-radius: var( --pv-radius );
	background: #fff;
	font: inherit;
	/* 16px minimum, or iOS zooms the page on focus and the layout jumps. */
	font-size: max( 1rem, 16px );
}

.pv-ugc__form textarea:focus-visible,
.pv-ugc__form input:focus-visible {
	border-color: var( --pv-bleu );
}

.pv-ugc__status {
	min-height: 1.4em;
	margin-bottom: 0;
	font-weight: 500;
	color: var( --pv-bleu );
}

.pv-ugc__heading {
	margin-top: var( --wp--preset--spacing--50 );
}

.pv-ugc__count {
	color: var( --pv-gris );
	font-variant-numeric: tabular-nums;
}

.pv-ugc__list {
	display: grid;
	gap: 0.75rem;
	margin: var( --wp--preset--spacing--30 ) 0 0;
	padding: 0;
	list-style: none;
	grid-template-columns: repeat( auto-fill, minmax( min( 100%, 20rem ), 1fr ) );
}

/*
 * An entry is a card, and the same card the rest of the site uses.
 *
 * The rule the site follows everywhere else — white ground, hairline border, a
 * 4px accent along the top, the accent cycling through the four charter colours
 * by position — is what the prayers and the places already look like. Following
 * it here costs nothing and stops this page reading as a different site.
 *
 * The accent is on the top rather than the left because that is where the rest
 * of the site puts it, and because in a grid of cards a left edge sets up a
 * vertical rhythm that fights the columns.
 *
 * No hover lift, unlike .pv-card. These are not links, and a card that rises
 * under the cursor promises somewhere to go.
 */
.pv-ugc__entry {
	--pv-accent: var( --pv-bleu );
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	height: 100%;
	padding: var( --wp--preset--spacing--30 );
	border: 1px solid rgba( 15, 45, 133, 0.14 );
	border-top: 4px solid var( --pv-accent );
	border-radius: var( --pv-radius );
	background: #fff;
	box-sizing: border-box;
}

.pv-ugc__entry--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-ugc__entry--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-ugc__entry--vert  { --pv-accent: var( --pv-vert ); }
.pv-ugc__entry--jaune { --pv-accent: var( --pv-jaune ); }

/*
 * Emblem and words, side by side.
 *
 * margin-bottom:auto sits here rather than on the text, and nowhere else.
 *
 * Cards in a row are as tall as the tallest, so the shorter ones have space to
 * spend. One auto margin here gives all of it to this row, which sends the
 * signature and the report link to the foot as a block. Putting an auto margin
 * on each of those two instead would split the space between them and leave the
 * name floating in the middle of the card — flexbox shares free space equally
 * among auto margins rather than giving it to the first.
 */
.pv-ugc__head {
	display: flex;
	gap: 0.6rem;
	margin-bottom: auto;
}

/*
 * The emblem takes the card's accent, so it turns over with the stripe above it
 * — except on the guest book, where the book is gold because that is the name
 * of the thing.
 *
 * flex-shrink:0 because an SVG in a flex row is compressible, and a long word
 * in someone's message would otherwise squeeze the hands into an oval.
 */
.pv-ugc__icon {
	flex: 0 0 auto;
	display: flex;
	/*
	 * Optical, not mathematical. The drawings are 28px in a 24-unit box with air
	 * at the top, so aligning the boxes puts the emblem visibly above the first
	 * line of text; this drops it back onto it.
	 */
	padding-top: 0.15rem;
	color: var( --pv-accent );
}

.pv-ugc--livre-or .pv-ugc__icon {
	color: var( --pv-jaune );
}

.pv-ugc__text {
	margin: 0;
	/* Someone else's words, so they are given room rather than truncated. */
	white-space: pre-line;
	overflow-wrap: anywhere;
	line-height: 1.5;
}

/* The first name reads as a signature. */
.pv-ugc__author {
	padding-top: 0.5rem;
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
}

.pv-ugc__author::before {
	content: "— ";
}

/*
 * The honeypot. Off-screen rather than display:none, which is the first thing a
 * form-filler checks for.
 */
.pv-ugc__trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/*
 * Quiet on purpose. It has to be findable by someone who needs it and invisible
 * to everyone else — a prominent button next to a stranger's prayer invites
 * idle clicking, and every idle click removes something real.
 */
.pv-ugc__report {
	align-self: flex-start;
	margin-top: 0.35rem;
	padding: 0;
	border: 0;
	background: none;
	color: var( --pv-gris );
	font: inherit;
	font-size: 0.75rem;
	text-decoration: underline;
	cursor: pointer;
}

.pv-ugc__report:hover,
.pv-ugc__report:focus-visible {
	color: var( --pv-rouge );
}

.pv-ugc__report[disabled] {
	color: var( --pv-gris );
	text-decoration: none;
	cursor: default;
}

/* Withdrawn on sight, before the request has even answered. */
.pv-ugc__entry.is-reported {
	opacity: 0.45;
}

.pv-ugc__entry.is-reported .pv-ugc__text {
	text-decoration: line-through;
}

.pv-ugc__notice {
	margin: 0;
	color: var( --pv-gris );
}

/* -------------------------------------------------------------------------
 * Metadata list, used on sequence and place pages
 * ---------------------------------------------------------------------- */

.pv-meta {
	margin: var( --wp--preset--spacing--40 ) 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid rgba( 15, 45, 133, 0.14 );
}

.pv-meta li {
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem 1rem;
	padding: 0.7rem 0;
	border-bottom: 1px solid rgba( 15, 45, 133, 0.14 );
}

.pv-meta__label {
	flex: 0 0 8.5rem;
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.pv-meta__value {
	flex: 1 1 12rem;
	font-weight: 500;
}

/* -------------------------------------------------------------------------
 * Registration row inside that list
 *
 * The sentence and the two links stack, because « Gérer mon inscription » next
 * to « S'inscrire » on a narrow screen is two targets a thumb cannot tell
 * apart. Tap targets are 44px on the short side for the same reason.
 * ---------------------------------------------------------------------- */

.pv-inscription {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.pv-inscription__note {
	font-weight: 400;
	color: var( --pv-gris );
}

.pv-inscription__links {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.pv-inscription__link {
	display: inline-flex;
	align-items: center;
	min-height: var( --pv-touch );
	padding: 0.6rem 1.1rem;
	border-radius: 999px;
	background: var( --pv-bleu );
	color: #fff;
	font-weight: 700;
	line-height: 1.2;
	text-decoration: none;
}

.pv-inscription__link:hover,
.pv-inscription__link:focus-visible {
	background: var( --pv-encre );
	color: #fff;
}

/*
 * The second link is for somebody who has already registered, which is the
 * rarer errand: outlined, so it is plainly there and plainly not the first
 * thing to do.
 */
.pv-inscription__link--secondary {
	background: transparent;
	color: var( --pv-bleu );
	box-shadow: inset 0 0 0 1px rgba( 15, 45, 133, 0.35 );
}

.pv-inscription__link--secondary:hover,
.pv-inscription__link--secondary:focus-visible {
	background: var( --pv-surface );
	color: var( --pv-encre );
}

/* -------------------------------------------------------------------------
 * Ordered modules of a sequence
 *
 * The order is the order it is prayed in, so it is numbered and cannot be
 * reflowed into a grid.
 * ---------------------------------------------------------------------- */

.pv-modules {
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: pv-module;
}

.pv-modules li {
	position: relative;
	padding: 0.85rem 0 0.85rem 2.5rem;
	border-bottom: 1px solid rgba( 15, 45, 133, 0.14 );
	counter-increment: pv-module;
}

.pv-modules li::before {
	content: counter( pv-module );
	position: absolute;
	left: 0;
	top: 0.9rem;
	width: 1.75rem;
	height: 1.75rem;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var( --pv-surface );
	color: var( --pv-bleu );
	font-size: 0.8125rem;
	font-weight: 700;
}

.pv-modules__title {
	font-weight: 700;
}

.pv-modules__duration {
	color: var( --pv-gris );
	font-size: var( --wp--preset--font-size--small );
}

/* -------------------------------------------------------------------------
 * The home page's two live bands: today's texts, and the next celebration
 *
 * The four coloured buttons that used to open the home page are gone — the
 * bottom bar carries Programme and Prier, and «Les lieux» and «Infos pratiques»
 * have the band at the foot of the page. What is here instead is the day.
 * ---------------------------------------------------------------------- */

.pv-today__day {
	margin: 0;
	font-family: var( --pv-font-display );
	font-size: 1.375rem;
	font-weight: 700;
	color: var( --pv-bleu );
}

.pv-today__saint {
	margin: 0.15rem 0 var( --wp--preset--spacing--30 );
	color: var( --pv-gris );
}

.pv-today__saint strong {
	color: var( --pv-encre );
}

/*
 * What is waiting on /aujourd-hui/, by name. A row of quiet chips rather than a
 * bulleted list: it is an index of three things, not a text to read.
 */
.pv-today__list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0 0 var( --wp--preset--spacing--30 );
	padding: 0;
	list-style: none;
}

/*
 * Each chip is a link to its own section, so it is sized like one thing a thumb
 * aims at rather than like a label that happens to be round.
 */
.pv-today__list a {
	display: flex;
	align-items: center;
	min-height: var( --pv-touch );
	padding: 0.35rem 0.9rem;
	border: 1px solid rgba( 15, 45, 133, 0.16 );
	border-radius: 999px;
	background: var( --wp--preset--color--base );
	color: var( --pv-bleu );
	font-size: 0.9375rem;
	text-decoration: none;
}

.pv-today__list a:hover,
.pv-today__list a:focus-visible {
	border-color: var( --pv-bleu );
	text-decoration: underline;
}

.pv-today__empty,
.pv-next__empty {
	margin: 0;
	color: var( --pv-gris );
}

.pv-next__list {
	margin: 0 0 var( --wp--preset--spacing--30 );
	padding: 0;
	list-style: none;
}

/*
 * One item, and only one: the next.
 *
 * pv-now.js hides every celebration that has already begun, and this leaves the
 * first of those still standing — «the first item not hidden», expressed as
 * «every item not hidden that follows another». It holds with no JavaScript
 * too, where nothing is hidden and the first entry of the programme shows: true,
 * merely early, which is the right way for this to fail.
 */
.pv-next__item:not( [hidden] ) ~ .pv-next__item:not( [hidden] ) {
	display: none;
}

.pv-next__link {
	display: block;
	padding: var( --wp--preset--spacing--30 );
	border-left: 4px solid var( --pv-cyan );
	border-radius: var( --pv-radius );
	background: var( --pv-surface );
	color: inherit;
	text-decoration: none;
}

.pv-band--dark .pv-next__link,
.pv-band.has-surface-background-color .pv-next__link {
	background: var( --wp--preset--color--base );
}

.pv-next__when {
	display: block;
	font-weight: 700;
	color: var( --pv-bleu );
}

.pv-next__title {
	display: block;
	margin-top: 0.15rem;
	font-family: var( --pv-font-display );
	font-size: 1.375rem;
	font-weight: 700;
	line-height: 1.2;
}

.pv-next__place {
	display: block;
	margin-top: 0.15rem;
	color: var( --pv-gris );
}

.pv-next__all {
	margin: 0;
}

/* -------------------------------------------------------------------------
 * Day tabs
 *
 * Four tabs, each carrying the day and where it happens — the city is what a
 * pilgrim navigates by. A grid rather than a scrolling row of pills: on a phone
 * a horizontal scroller hides half its options and gives no hint that it moves,
 * which is exactly the failure it looked like.
 * ---------------------------------------------------------------------- */

.pv-days {
	margin: 0 0 var( --wp--preset--spacing--40 );
	border-bottom: 1px solid rgba( 15, 45, 133, 0.14 );
}

.pv-days ul {
	display: grid;
	/*
	 * Two columns on a phone, four once there is room.
	 *
	 * Four across a 375px screen leaves 94px a tab, and a day spanning two
	 * cities — "Paris · Saint-Denis" — wraps to four lines in that. Two columns
	 * is the honest answer at that width, and it is still every option visible
	 * at once, which the scrolling pills never were.
	 */
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	margin: 0;
	padding: 0;
	list-style: none;
}

@media ( min-width: 30rem ) {
	.pv-days ul {
		/* Left-aligned and bounded, not stretched across the wide width. */
		grid-template-columns: repeat( 4, minmax( 6rem, 11rem ) );
		justify-content: start;
	}
}

.pv-days__tab {
	--pv-accent: var( --pv-bleu );
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 0.1rem;
	min-height: var( --pv-touch );
	padding: 0.6rem 0.35rem;
	border-bottom: 3px solid transparent;
	text-decoration: none;
	text-align: center;
}

.pv-days__tab--bleu  { --pv-accent: var( --pv-bleu ); }
.pv-days__tab--cyan  { --pv-accent: var( --pv-cyan ); }
.pv-days__tab--vert  { --pv-accent: var( --pv-vert ); }
.pv-days__tab--jaune { --pv-accent: var( --pv-jaune ); }

.pv-days__when {
	font-size: 0.8125rem;
	color: var( --pv-gris );
}

.pv-days__where {
	font-weight: 700;
	line-height: 1.15;
	color: var( --pv-bleu );
	overflow-wrap: anywhere;
}

.pv-days__tab[aria-current="page"] {
	border-bottom-color: var( --pv-accent );
}

.pv-days__tab[aria-current="page"] .pv-days__when {
	color: var( --pv-bleu );
}

@media ( min-width: 30rem ) {
	.pv-days__where {
		font-size: 1.0625rem;
	}

	.pv-days__tab {
		text-align: left;
		padding-inline: 0.25rem 1.25rem;
	}
}

/* -------------------------------------------------------------------------
 * Pictograms — Paris, Lourdes, Metz
 * ---------------------------------------------------------------------- */

.pv-picto {
	display: block;
	width: 3rem;
	height: auto;
	margin-bottom: 0.5rem;
}

/* -------------------------------------------------------------------------
 * Countdown, filled on the client for the same reason as the alert
 * ---------------------------------------------------------------------- */

.pv-countdown {
	display: none;
}

.pv-countdown[data-ready] {
	display: block;
	font-weight: 700;
	color: var( --pv-bleu );
	font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------
 * Prayer text: the one thing that must stay readable in bright sunlight,
 * offline, at arm's length.
 * ---------------------------------------------------------------------- */

.pv-prayer .entry-content {
	font-size: 1.1875rem;
	line-height: 1.75;
}

/*
 * A prayer is read slowly and often at arm's length, so its measure is tighter
 * than the rest — pinned to the start like everything else, so the text still
 * begins where the title does.
 */
.pv-prayer .entry-content > :where( p, ul, ol, blockquote ) {
	max-width: 34rem;
	margin-inline-start: 0;
}

/* -------------------------------------------------------------------------
 * Accessibility
 * ---------------------------------------------------------------------- */

:where( a, button, input, summary ):focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 3px;
	border-radius: 2px;
}

/*
 * Kept, not removed.
 *
 * :focus-visible already means a mouse click never draws a ring — the one that
 * appears when the menu opens is WordPress moving focus into the panel, which is
 * correct and is what lets a keyboard reach the menu at all. Deleting it would
 * be a WCAG 2.4.7 failure and would strand anyone using a keyboard, a switch
 * device or voice control.
 *
 * So it is made quiet instead: it takes the colour of the text it surrounds,
 * which inside the blue panel means white and outside it means the charter blue.
 * Yellow on blue was reading as an error state.
 */
.pv-nav .wp-block-navigation__responsive-container.is-menu-open :focus-visible {
	outline: none;
	background: rgba( 255, 255, 255, 0.14 );
	box-shadow: inset 4px 0 0 #fff;
}

/* The close button is not a full-width row, so it keeps a ring. */
.pv-nav .wp-block-navigation__responsive-container-close:focus-visible {
	outline: 2px solid #fff;
	background: none;
	box-shadow: none;
}

.pv-skip-link {
	position: absolute;
	left: -9999px;
}

.pv-skip-link:focus {
	left: var( --wp--preset--spacing--30 );
	top: 0.5rem;
	z-index: 10;
	padding: 0.6rem 1rem;
	background: var( --pv-bleu );
	color: #fff;
}

/* -------------------------------------------------------------------------
 * Print: a pilgrim without a charged phone still needs the programme.
 * ---------------------------------------------------------------------- */

@media print {
	.pv-header,
	.pv-live-badge,
	.wp-block-navigation {
		display: none;
	}

	.pv-card {
		break-inside: avoid;
	}
}

/* -----------------------------------------------------------------------------
 * Notification channels — /notifications/
 *
 * Read one-handed, outdoors, often by someone who is not sure what they are
 * agreeing to. So: one row per channel, the whole row is the target, and the
 * explanation sits under the label rather than behind an icon.
 * -------------------------------------------------------------------------- */

.pv-push__intro {
	margin-top: 0;
	max-width: 40rem;
}

.pv-push__list {
	margin: var( --wp--preset--spacing--30 ) 0 0;
	padding: 0;
	list-style: none;
}

.pv-push__row + .pv-push__row {
	margin-top: 0.75rem;
}

.pv-push__switch {
	display: flex;
	gap: 0.9rem;
	align-items: flex-start;
	box-sizing: border-box;
	/* The same floor the rest of the site gives anything you have to hit. */
	min-height: var( --pv-touch );
	padding: var( --wp--preset--spacing--30 );
	border-radius: var( --pv-radius );
	background: var( --pv-surface );
	cursor: pointer;
}

/*
 * The whole row is the hit area, not just the box. A 16px checkbox is a hard
 * target for anyone standing up, and this is a screen people use once.
 */
.pv-push__switch input[type="checkbox"] {
	flex: 0 0 auto;
	width: 1.5rem;
	height: 1.5rem;
	margin: 0;
	accent-color: var( --pv-bleu );
	cursor: pointer;
}

.pv-push__switch input[type="checkbox"]:focus-visible {
	outline: 2px solid var( --pv-bleu );
	outline-offset: 2px;
}

/*
 * Disabled until the script has read the real state off the device. Without
 * this a pilgrim can tick a box in the half-second before the answer arrives
 * and watch it tick itself back.
 */
.pv-push__switch input[type="checkbox"][disabled] {
	opacity: 0.45;
	cursor: default;
}

.pv-push__text {
	display: block;
}

.pv-push__label {
	display: block;
	font-weight: 700;
	color: var( --pv-bleu );
}

.pv-push__description {
	display: block;
	margin-top: 0.15rem;
	font-size: 0.9rem;
	color: var( --pv-gris );
}

.pv-push__permission {
	margin: var( --wp--preset--spacing--30 ) 0;
}

.pv-push__status {
	min-height: 1.4em;
	margin-top: var( --wp--preset--spacing--30 );
	font-size: 0.9rem;
	color: var( --pv-gris );
}

.pv-push__notice {
	padding: var( --wp--preset--spacing--30 );
	border-radius: var( --pv-radius );
	background: var( --pv-surface );
	color: var( --pv-gris );
}

/* -----------------------------------------------------------------------------
 * Bottom bar
 *
 * The only navigation within thumb reach. Today the burger is the sole way
 * between sections: two taps and a full-screen overlay for a move a pilgrim
 * makes constantly, one-handed, walking.
 *
 * Shown below 48rem and hidden above it — never chosen by looking at the device.
 * The same HTML is cached at the edge for everyone, so a server-side decision
 * here would mean a `Vary` on User-Agent and one cached copy per phone. The
 * media query costs a desktop a few hundred bytes and keeps one copy of
 * everything.
 * -------------------------------------------------------------------------- */

.pv-tabbar {
	position: fixed;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 20;
	background: var( --wp--preset--color--base );
	border-top: 1px solid rgba( 15, 45, 133, 0.12 );
	/*
	 * The bar sits exactly where the iOS home indicator is. Nothing else on the
	 * site styles an inset yet — the shell compensates with
	 * `ios.contentInset: always`, which makes this resolve to 0 today. It is
	 * here so the bar stays correct on the day that setting moves to `never`,
	 * and it costs nothing meanwhile.
	 */
	padding-bottom: env( safe-area-inset-bottom, 0 );
}

.pv-tabbar__list {
	display: flex;
	margin: 0;
	padding: 0;
	list-style: none;
}

.pv-tabbar__item {
	flex: 1 1 0;
	/* Five equal columns whatever the labels say, so the icons line up. */
	min-width: 0;
}

.pv-tabbar__link {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.15rem;
	min-height: var( --pv-touch );
	/*
	 * 0.125rem at the sides, not 0.25rem: with five columns a 375px screen
	 * gives each one 75px, and every 2px of padding is 2px the longest label
	 * does not have. The column is the tap target, not this box, so narrowing
	 * the padding costs nothing to a thumb.
	 */
	padding: 0.4rem 0.125rem 0.5rem;
	color: var( --pv-gris );
	text-decoration: none;
	text-align: center;
}

.pv-tabbar__label {
	/*
	 * 11px rather than 12px, because five labels have to fit where three did.
	 * Measured in Jost, which is narrower than it looks: «Aujourd’hui», the
	 * longest of the five, is 60.5px bold — the weight the current tab is
	 * drawn at, and so the width that actually has to fit — against the 71px
	 * a 375px screen leaves. At 12px it was 66px against 67px, which is one
	 * pixel of margin and a truncated label on the first phone that disagrees.
	 */
	font-size: 0.6875rem;
	line-height: 1.2;
	/* One line. A wrapped label makes the five columns different heights. */
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 100%;
}

/*
 * 320px — an iPhone SE of the first generation, and not a hypothetical one in
 * this audience. Five columns of 64px leave 60px of text box, and 60.5px of
 * bold «Aujourd’hui» does not fit in it. 10px does, with room to spare for the
 * fallback face shown while Jost is still loading.
 */
@media ( max-width: 22.5rem ) {
	.pv-tabbar__label {
		font-size: 0.625rem;
	}
}

/*
 * The current section, in the charter blue. Colour alone would not be enough on
 * its own, which is why the weight changes too.
 */
.pv-tabbar__link.is-current {
	color: var( --pv-bleu );
}

.pv-tabbar__link.is-current .pv-tabbar__label {
	font-weight: 700;
}

.pv-tabbar__link:focus-visible {
	outline: 2px solid var( --pv-bleu );
	outline-offset: -2px;
}

/*
 * Room at the foot of every page for the bar to sit over.
 *
 * Without this the last line of the footer is under the bar on every single
 * page — and the footer is where the legal links live.
 *
 * 3.75rem and not the 3.5rem it said: the bar measures 59.4px — the 44px touch
 * target, which is what governs since the icon and its label come to less, plus
 * the link's 6.4px and 8px of padding, plus the 1px border — and 56px of room
 * left the last 3.4px of the footer under it. Nothing to do with the five
 * items: the height does not depend on the labels at all, which is why it was
 * measured rather than assumed.
 */
@media ( max-width: 47.999rem ) {
	body {
		padding-bottom: calc( 3.75rem + env( safe-area-inset-bottom, 0px ) );
	}
}

@media ( min-width: 48rem ) {
	.pv-tabbar {
		display: none;
	}
}

@media print {
	.pv-tabbar {
		display: none;
	}
}

/* -----------------------------------------------------------------------------
 * Aujourd'hui — the day's content from Magnificat
 *
 * Long-form devotional text, read on a phone, often outdoors and often at an
 * hour when the light is bad. So: a narrow measure, generous line height, and
 * nothing competing with the words.
 * -------------------------------------------------------------------------- */

.pv-prayer__day {
	margin: 0;
	font-family: var( --pv-font-display );
	font-size: 1.375rem;
	font-weight: 700;
	color: var( --pv-bleu );
}

.pv-prayer__saint {
	margin: 0.15rem 0 var( --wp--preset--spacing--40 );
	color: var( --pv-gris );
}

.pv-prayer__saint strong {
	color: var( --pv-encre, var( --wp--preset--color--encre ) );
}

.pv-prayer__section {
	margin-top: var( --wp--preset--spacing--50 );
}

.pv-prayer__heading,
.pv-prayer__summary {
	font-family: var( --pv-font-display );
	font-size: 1.125rem;
	font-weight: 700;
	color: var( --pv-bleu );
	text-transform: uppercase;
	letter-spacing: 0.02em;
}

.pv-prayer__heading {
	margin: 0 0 var( --wp--preset--spacing--20 );
	padding-bottom: 0.4rem;
	border-bottom: 2px solid var( --pv-cyan );
}

/*
 * The folded sections. A <details> because it needs no JavaScript and works
 * with a keyboard and a screen reader for free — and because the day's prayers
 * run to eleven thousand characters, which printed open buries the credit line
 * a minute of scrolling below the fold.
 */
.pv-prayer__section--folded {
	padding: var( --wp--preset--spacing--30 );
	border-radius: var( --pv-radius );
	background: var( --pv-surface );
}

.pv-prayer__summary {
	min-height: var( --pv-touch );
	display: flex;
	align-items: center;
	cursor: pointer;
}

.pv-prayer__section--folded[open] .pv-prayer__summary {
	margin-bottom: var( --wp--preset--spacing--20 );
	border-bottom: 2px solid var( --pv-cyan );
}

.pv-prayer__body {
	/*
	 * Measured off page 80 of the September 2026 issue: the ink is warmer than
	 * the site's #111827, and the rubrics are a crimson of their own that is
	 * not the charter red — which on this site means an alert, and must go on
	 * meaning only that. Both stay inside the day's texts.
	 *
	 * The rubric red gives 6:1 on white and 5.4:1 on the folded sections'
	 * surface, so it carries body text under AA with little to spare. It is
	 * never the only mark of a rubric: weight and capitals carry it too, for
	 * September sun and for anyone who does not separate the two colours.
	 */
	--pv-prayer-encre: #231f20;
	--pv-prayer-rubrique: #c50750;
	--pv-prayer-filet: rgba( 197, 7, 80, 0.4 );

	font-family: var( --pv-font-serif );
	color: var( --pv-prayer-encre );
	line-height: 1.7;
	/*
	 * Not justified and never hyphenated, unlike the page this is modelled on.
	 * That page is 291pt wide; a phone is 360px, where justification opens
	 * rivers and hyphenation breaks words mid-prayer.
	 */
	text-align: left;
	hyphens: manual;
}

.pv-prayer__body p {
	margin: 0 0 0.9em;
	/*
	 * A block formatting context, so that the initial floated inside a strophe
	 * is contained by it instead of hanging into the one below. Cheaper and far
	 * better supported than :has() on the few paragraphs that carry one.
	 */
	display: flow-root;
}

.pv-prayer__credit {
	margin-top: var( --wp--preset--spacing--50 );
	padding-top: var( --wp--preset--spacing--30 );
	border-top: 1px solid rgba( 15, 45, 133, 0.12 );
	font-size: 0.9rem;
	color: var( --pv-gris );
}

.pv-prayer__notice {
	padding: var( --wp--preset--spacing--30 );
	border-radius: var( --pv-radius );
	background: var( --pv-surface );
	color: var( --pv-gris );
}

/* -----------------------------------------------------------------------------
 * Aleteia's own classes, arriving inside the feed body
 *
 * The markup is meaningless without them — they are what distinguishes a
 * liturgical rubric from the text of a prayer — so the sanitiser keeps `class`
 * and they are styled here. Deliberately NOT by importing Aleteia's stylesheet:
 * that would be a third-party request on the worst network of the year, and it
 * would bring hundreds of rules for a page that needs five.
 *
 * WHAT THESE RULES ARE AIMING AT
 *
 * The same texts, in the printed Magnificat: section titles in spaced capitals
 * between two rules, rubrics in red, an initial opening each psalm, antiphons
 * and responses in italic, references set small. The classes below are the
 * print's own editorial vocabulary — `sotiaf-psalm`, `sotiaf-initial`,
 * `sotiaf-repons`, `sotiaf-blessing` — so this is a stylesheet job and not a
 * markup one: the hooks already arrive, they were simply falling through as
 * paragraphs. Read off the live feed on 9 September 2026:
 *
 *   dom → the day's head: the saint, a sentence to carry, «Bonne fête !»
 *   prayer, hymn, psalm, wog, canticle, intercession, ma → one office section
 *     each, most of them opening with an <h2>
 *   text → a strophe, its lines separated by <br>
 *   initial → the initial the print sets large at the head of a psalm
 *   intro, repons, antienne, refrain, invitatory → what is said rather than read
 *   intention, day-point + liturgy → rubrics: the instruction, not the words
 *   ref, source, author, notice → attribution
 *
 * `sotiaf-prayer` is on two different things — the <div> wrapping the whole
 * «Prière du matin», and the <p> holding the concluding prayer — so the rules
 * below name the element as well as the class. `sotiaf-antienne` and
 * `sotiaf-refrain` were not in that day's payload but are kept: the list above
 * is one day of a feed we do not control.
 * -------------------------------------------------------------------------- */

/* One office to the next. */
.pv-prayer__body > div + div {
	margin-top: var( --wp--preset--spacing--40 );
}

/*
 * Section titles: «Hymne», «Psaume 85 : …», «Antienne mariale».
 *
 * Without this they inherit the global heading style and arrive at 1.75rem in
 * charter blue — a website's heading in the middle of a psalter. The capitals
 * come from CSS and not from the content, so a screen reader still receives a
 * sentence.
 */
.pv-prayer__body h2 {
	margin: 0 0 0.9em;
	padding: 0.35em 0;
	border-top: 1px solid var( --pv-prayer-filet );
	border-bottom: 1px solid var( --pv-prayer-filet );
	font-family: inherit;
	font-size: 0.9375rem;
	font-weight: 700;
	line-height: 1.35;
	letter-spacing: 0.1em;
	text-align: center;
	text-transform: uppercase;
	color: var( --pv-prayer-rubrique );
}

/*
 * The meditation's own title is a title and not a rubric — «Heureux», the words
 * the author chose — so it keeps the register of the text under it.
 */
.pv-prayer__body .sotiaf-meditation h2 {
	margin: 0 0 0.8em;
	padding: 0;
	border: 0;
	font-size: 1.1875rem;
	font-weight: 400;
	font-style: italic;
	letter-spacing: 0;
	text-transform: none;
	color: var( --pv-prayer-encre );
}

/*
 * The day's head, set off from the offices that follow it — by space alone,
 * because the first office opens with a title that already carries a rule and
 * two of them a line apart read as a mistake.
 */
.pv-prayer__body .sotiaf-dom {
	margin-bottom: var( --wp--preset--spacing--40 );
}

/* The sentence to carry through the day, and who said it. */
.pv-prayer__body .sotiaf-day-point {
	font-style: italic;
}

/* A rubric: the instruction, not the words to say. */
.pv-prayer__body .sotiaf-day-point.sotiaf-liturgy,
.pv-prayer__body .sotiaf-intention {
	margin-top: 1.3em;
	font-size: 0.9375rem;
	font-style: normal;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var( --pv-prayer-rubrique );
}

.pv-prayer__body .sotiaf-celebration {
	margin-top: 0.6em;
	font-size: 0.9375rem;
	color: var( --pv-gris );
}

/* Antiphons and responses, which are said rather than read. */
.pv-prayer__body .sotiaf-intro,
.pv-prayer__body .sotiaf-repons,
.pv-prayer__body .sotiaf-antienne,
.pv-prayer__body .sotiaf-refrain {
	padding-left: 0.9rem;
	border-left: 2px solid var( --pv-prayer-filet );
	font-style: italic;
}

/* The prayer that closes an office. A <p>, unlike the <div> of the same name. */
.pv-prayer__body p.sotiaf-prayer {
	margin-top: 1.3em;
	padding-left: 0.9rem;
	border-left: 2px solid var( --pv-prayer-rubrique );
}

/* The doxology, which the print sets apart from the intercessions above it. */
.pv-prayer__body .sotiaf-blessing {
	margin: 1.3em 0;
	font-style: italic;
	text-align: center;
}

/*
 * The initial that opens a psalm, a reading, a canticle.
 *
 * It floats, so it is read in place by a screen reader — «Ecoute» stays one
 * word — and the strophe carrying it contains it, see the flow-root above.
 */
.pv-prayer__body .sotiaf-initial {
	float: left;
	margin: 0.05em 0.1em 0 0;
	font-size: 2.6em;
	font-weight: 400;
	line-height: 0.82;
	color: var( --pv-prayer-rubrique );
}

/*
 * A reference: the psalm's subtitle, the chapter and verse, who is being
 * quoted. Inline — it arrives as a <span> inside a heading or a sentence, and
 * `display: block` was breaking «Psaume 85 :» away from its own subtitle.
 */
.pv-prayer__body .sotiaf-ref {
	font-style: italic;
	color: var( --pv-gris );
}

.pv-prayer__body h2 .sotiaf-ref {
	font-size: 0.9375em;
	letter-spacing: 0.04em;
	text-transform: none;
	color: inherit;
}

/*
 * The gospel, which arrives with no classes of its own.
 *
 * Two hooks are added at render time — see pv_prayer_mark_gospel() — and they
 * are the whole difference between this section and the offices below it. The
 * reference becomes the section title the printed page gives it; the
 * acclamation is set apart like the responses in the offices.
 */
.pv-prayer__body .pv-prayer__ref {
	margin: 0 0 0.9em;
	padding: 0.35em 0;
	border-top: 1px solid var( --pv-prayer-filet );
	border-bottom: 1px solid var( --pv-prayer-filet );
	font-size: 0.9375rem;
	line-height: 1.35;
	letter-spacing: 0.1em;
	text-align: center;
	text-transform: uppercase;
	color: var( --pv-prayer-rubrique );
}

/* The <strong> the feed sends is the whole line, so it carries no weight of
   its own here: capitals and the rubric red already say what it is. */
.pv-prayer__body .pv-prayer__ref strong {
	font-weight: 700;
}

/*
 * The initial, on the paragraph that follows the reference.
 *
 * ::first-letter and not a span, because there is no span to have: the feed
 * sends the gospel as plain paragraphs. Conditioned on the reference having
 * been recognised — no reference, no initial, rather than a large letter in the
 * middle of a body whose shape we did not understand.
 */
.pv-prayer__body .pv-prayer__ref + p::first-letter {
	float: left;
	margin: 0.05em 0.1em 0 0;
	font-size: 2.6em;
	line-height: 0.82;
	color: var( --pv-prayer-rubrique );
}

/* «– Acclamons la Parole de Dieu.» — said, not read, like the responses. */
.pv-prayer__body .pv-prayer__response {
	margin-top: 1.3em;
	padding-left: 0.9rem;
	border-left: 2px solid var( --pv-prayer-filet );
	font-style: italic;
}

/* Who wrote the meditation. */
.pv-prayer__body .sotiaf-author {
	margin-top: 1em;
	font-size: 0.9375rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.pv-prayer__body .sotiaf-source,
.pv-prayer__body .sotiaf-notice {
	display: block;
	margin-top: 0.5em;
	font-size: 0.875rem;
	color: var( --pv-gris );
}

/* -----------------------------------------------------------------------------
 * The contact address, on /notifications/
 *
 * The only personal data this project asks a pilgrim for, so it is set apart
 * from the switches above it rather than tacked on as one more row.
 * -------------------------------------------------------------------------- */

.pv-push__email {
	margin-top: var( --wp--preset--spacing--50 );
	padding-top: var( --wp--preset--spacing--40 );
	border-top: 1px solid rgba( 15, 45, 133, 0.12 );
}

.pv-push__email-heading {
	margin-top: 0;
	font-size: 1.125rem;
}

.pv-push__email-intro,
.pv-push__email-current {
	max-width: 40rem;
}

.pv-push__email-form input[type="email"] {
	/* border-box, for the same reason the UGC form needs it: width:100% plus
	   padding ran the field past its container on a phone. */
	box-sizing: border-box;
	width: 100%;
	max-width: 24rem;
	min-height: var( --pv-touch );
	padding: 0.6rem 0.8rem;
	border: 1px solid var( --pv-gris );
	border-radius: var( --pv-radius );
	font: inherit;
}

.pv-push__email-form label {
	display: block;
	margin-bottom: 0.25rem;
	font-weight: 700;
	color: var( --pv-bleu );
}

/*
 * The consent line. Its label is not bold and not blue: it is a sentence to
 * read, not a field name, and styling it like a heading is how people stop
 * reading consent text.
 */
.pv-push__consent label {
	display: flex;
	gap: 0.6rem;
	align-items: flex-start;
	margin: 0;
	font-weight: 400;
	color: inherit;
	cursor: pointer;
}

.pv-push__consent input[type="checkbox"] {
	flex: 0 0 auto;
	width: 1.25rem;
	height: 1.25rem;
	margin: 0.1rem 0 0;
	accent-color: var( --pv-bleu );
}

.pv-push__consent span {
	font-size: 0.9rem;
	line-height: 1.45;
}

/*
 * Leaving must be as easy as arriving, so this is a real button and not a
 * footnote — but it is not the primary action on the screen either.
 */
.pv-push__email-remove {
	min-height: var( --pv-touch );
	padding: 0.5rem 1rem;
	border: 1px solid var( --pv-gris );
	border-radius: var( --pv-radius );
	background: transparent;
	color: var( --pv-bleu );
	font: inherit;
	cursor: pointer;
}

.pv-push__email-remove:hover,
.pv-push__email-remove:focus-visible {
	border-color: var( --pv-bleu );
}

.pv-push__email-status {
	min-height: 1.4em;
	font-size: 0.9rem;
	color: var( --pv-gris );
}

/* -----------------------------------------------------------------------------
 * The welcome dialog, at the first launch of the app
 *
 * A native <dialog>: focus is trapped, Escape closes it and the page behind it
 * is inert, all of which had to be right and none of which is worth writing by
 * hand. It ships closed in every cached page and is opened by pv-push.js.
 *
 * The rules below are what a phone needs and the UA does not give: a width, a
 * ceiling with its own scroll — the two offers and their consent do not fit on
 * a small screen in landscape — and controls that stay 44px under a thumb.
 * -------------------------------------------------------------------------- */

.pv-welcome {
	box-sizing: border-box;
	width: calc( 100% - 2rem );
	max-width: 28rem;
	/*
	 * dvh, not vh: the address bar and the notch are exactly the difference
	 * between «tall enough» and a «Plus tard» nobody can reach.
	 */
	max-height: 85dvh;
	padding: 0;
	border: 0;
	border-radius: var( --pv-radius );
	background: var( --wp--preset--color--base );
	color: var( --wp--preset--color--encre );
	overflow: auto;
	/* Safari centres a dialog only from these; without them it sits at the top. */
	margin: auto;
}

.pv-welcome::backdrop {
	background: rgba( 9, 29, 90, 0.55 );
}

.pv-welcome__inner {
	padding: var( --wp--preset--spacing--40 );
}

/*
 * Every control here sits in its own paragraph, and the browser's 1em above and
 * below each of them adds up to a dialog that does not fit a small screen in
 * landscape. Tightened once, rather than fought rule by rule.
 */
.pv-welcome__inner p {
	margin: 0 0 0.9rem;
}

.pv-welcome__title {
	margin: 0 0 0.4em;
	font-size: 1.375rem;
}

.pv-welcome__intro {
	margin: 0 0 var( --wp--preset--spacing--30 );
}

/*
 * The two buttons that do something are the theme's own; only the way out is
 * quieter. It is still a 44px target and still says what it does — skipping has
 * to be as easy as accepting, or the dialog is a trap on the first screen a
 * pilgrim ever sees.
 */
.pv-welcome__later {
	min-height: var( --pv-touch );
	padding: 0.5rem 1rem;
	border: 1px solid var( --pv-gris );
	border-radius: var( --pv-radius );
	background: transparent;
	color: var( --pv-bleu );
	font: inherit;
	cursor: pointer;
}

.pv-welcome__later:hover,
.pv-welcome__later:focus-visible {
	border-color: var( --pv-bleu );
}

/*
 * Reserved space, so a status line arriving does not push the button the
 * pilgrim is reaching for. Its own margins are tightened: the default ones plus
 * the reserved line left a hole under every button.
 */
.pv-welcome__status,
.pv-welcome__email-status {
	margin: 0.4rem 0 0;
	min-height: 1.4em;
	font-size: 0.9rem;
	color: var( --pv-gris );
}

.pv-welcome__email {
	margin-top: var( --wp--preset--spacing--40 );
	padding-top: var( --wp--preset--spacing--30 );
	border-top: 1px solid rgba( 15, 45, 133, 0.12 );
}

.pv-welcome__email-heading {
	margin: 0 0 0.4em;
	font-size: 1.0625rem;
}

.pv-welcome__email-intro {
	margin: 0 0 var( --wp--preset--spacing--30 );
	font-size: 0.9375rem;
}

.pv-welcome__email-form input[type="email"] {
	box-sizing: border-box;
	width: 100%;
	min-height: var( --pv-touch );
	padding: 0.6rem 0.8rem;
	border: 1px solid var( --pv-gris );
	border-radius: var( --pv-radius );
	font: inherit;
}

.pv-welcome__email-form label {
	display: block;
	margin-bottom: 0.25rem;
	font-weight: 700;
	color: var( --pv-bleu );
}

/* Not bold and not blue: a sentence to read, not a field name. See the same
   rule on /notifications/, which is where this consent is worded. */
.pv-welcome__consent label {
	display: flex;
	gap: 0.6rem;
	align-items: flex-start;
	margin: 0;
	font-weight: 400;
	color: inherit;
	cursor: pointer;
}

.pv-welcome__consent input[type="checkbox"] {
	flex: 0 0 auto;
	width: 1.25rem;
	height: 1.25rem;
	margin: 0.1rem 0 0;
	accent-color: var( --pv-bleu );
}

.pv-welcome__consent span {
	font-size: 0.9rem;
	line-height: 1.45;
}

.pv-welcome__after {
	margin: var( --wp--preset--spacing--30 ) 0 0;
	font-size: 0.875rem;
	color: var( --pv-gris );
}

/*
 * Stuck to the bottom of the dialog, which is what scrolls once the text is
 * large enough not to fit. Somebody who wants out has to be able to get out
 * without discovering that the button is three swipes further down.
 *
 * Opaque and edge to edge, with a rule along its top: on a phone the content
 * passes underneath, and on a device this read as a bug — «M'inscrire» sliced
 * in half by a white box, a channel row cut through the middle. It was the bar
 * doing its job with nothing to say so. The line is what says so.
 *
 * The negative side margins undo the inner's padding so the rule spans the
 * whole dialog; the padding is put back inside it, so the button does not move.
 */
.pv-welcome__out {
	position: sticky;
	bottom: calc( var( --wp--preset--spacing--40 ) * -1 );
	margin: var( --wp--preset--spacing--30 ) calc( var( --wp--preset--spacing--40 ) * -1 ) 0;
	padding: var( --wp--preset--spacing--30 ) var( --wp--preset--spacing--40 ) var( --wp--preset--spacing--40 );
	border-top: 1px solid rgba( 15, 45, 133, 0.14 );
	background: var( --wp--preset--color--base );
}

/*
 * The channels, inside the welcome dialog.
 *
 * They arrive after the permission is granted, in the place the button leaves —
 * so the dialog gets taller at the moment somebody has just tapped it. The
 * heading is what tells them why, and the switches are the same rows, with the
 * same behaviour, as the ones on /notifications/.
 */
.pv-welcome__channels {
	margin-top: var( --wp--preset--spacing--30 );
}

.pv-welcome__channels-heading {
	margin: 0 0 0.4em;
	font-size: 1.0625rem;
}

.pv-welcome__channels .pv-push__list {
	margin: 0;
}

.pv-welcome__channels-more {
	margin: var( --wp--preset--spacing--20 ) 0 0;
	font-size: 0.9375rem;
}
