/*
Theme Name: Divi Child - Dunbar Free Library
Template: Divi
Description: Child theme for the Dunbar Free Library redesign. All custom CSS and template overrides live here so Divi core updates never wipe out site-specific work.
Version: 1.0.0
*/

/* ==========================================================================
   Design tokens — Direction B ("Community Table")
   Palette cleaned up from the live dunbarlibrary.org; fonts picked to give
   headings real contrast against body copy. See the "Dunbar Style
   Directions" reference for the reasoning behind these values.
   ========================================================================== */
:root {
	--dfl-accent: #B65741;      /* terracotta — links, buttons, small accents */
	--dfl-accent-ink: #8C4331;  /* darker terracotta — link text on light bg */
	/* --dfl-accent is only 2.09:1 against --dfl-ink (WCAG AA needs 4.5:1 for
	   text, 3:1 minimum for large text/UI indicators) — too low-contrast to
	   use as-is on dark ink. Lightening the same hue/saturation far enough
	   to pass 4.5:1 as text lands around #D9A295, which reads as washed-out
	   pink rather than terracotta, so this tint is calibrated for 3:1 instead
	   and meant for non-text indicators only (e.g. the header nav's
	   hover/current-item underline) — pair it with paper/white text, never
	   use it as text color itself on dark ink. */
	--dfl-accent-bright: #C87966;
	--dfl-ink: #36454F;         /* charcoal navy — footer, dark UI */
	--dfl-ink-nav: #2A363E;     /* ~22% darker than --dfl-ink - desktop header nav row only, see @media (min-width: 981px) below; still 11.6:1 for --dfl-paper text and 3.8:1 for --dfl-accent-bright, so existing header contrast work carries over unchanged */
	--dfl-paper: #FFFFFF;       /* pure white — main background (client request 2026-09-09, was warm off-white #FBF7EF) */
	--dfl-tan: #EFE2C6;         /* single alt-section tan (replaces 4 old near-duplicates) */
	--dfl-text: #2E2924;        /* body copy */
	--dfl-muted: #6E6459;       /* captions, secondary text */
	--dfl-rule: #DED2B8;        /* borders/dividers on paper or tan */

	--dfl-font-heading: 'Fraunces', Georgia, 'Times New Roman', serif;
	--dfl-font-body: 'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

	/* Spacing scale — every one-off margin/padding value on the site should
	   come from here (or from --dfl-gutter below, for rhythm between
	   sections) rather than a new hardcoded number, so the whole site draws
	   from one set of values instead of accumulating near-duplicates. Named
	   in ascending order rather than a round 4px/8px rhythm because these
	   values were pulled from spacing already in use across the site (some
	   of it fine-tuned against Divi's own hardcoded header CSS) — the goal
	   here is one source of truth per value, not new pixel values. */
	--dfl-space-xs: 14px;   /* logo-to-nav gap; footer bullet indent */
	--dfl-space-sm: 16px;   /* header logo/nav row gap; general block spacing */
	--dfl-space-md: 18px;   /* desktop header bottom padding */
	--dfl-space-lg: 22px;   /* desktop header top padding */
	--dfl-space-xl: 24px;   /* footer: space above a column's 2nd heading */

	/* Mobile sticky-header offset (see @media (max-width: 980px) below).
	   position: sticky's `top` is a hard floor on the element's distance
	   from the viewport top — set it any higher than the alert bar's real
	   rendered height and a gap opens up above the header even at rest, not
	   just while scrolling. Sized to the common case instead (1 line of
	   alert text: 2 * 14px vertical padding, --dfl-space-xs, + one 23.8px
	   line-height = ~52px, measured). A message long enough to wrap to 2
	   lines would make the header stick a few px too high, slightly
	   overlapping the alert bar's 2nd line — not a JS/layout bug, just a
	   soft ceiling on alert message length; bump this value (and accept the
	   opposite small gap on 1-line messages) if that becomes common. */
	--dfl-alert-bar-height: 52px;
	/* Rendered #main-header height at mobile widths (measured, same "not
	   token-driven, re-check if header padding/logo size changes" caveat as
	   the search-icon top offset elsewhere in this file) — used to park the
	   opened mobile menu panel right below the sticky header instead of
	   under Divi's own hardcoded top:53px guess for it (centered_header.css,
	   .et_header_style_centered .et_mobile_menu{top:53px}, which assumes a
	   shorter header than this site's actual wordmark+hamburger row). */
	--dfl-mobile-header-height: 72px;
}

/* ==========================================================================
   Grid rhythm — Carbon-inspired, adapted for Divi's builder
   Carbon's grid pairs a margin/gutter scale that widens with the viewport
   with a couple of fixed container widths, rather than a rigid column
   count. Divi's row/column tool already handles column math, so we borrow
   just that part: a consistent gutter for vertical spacing between
   sections, and two container-width tiers editors can opt into per-row
   with no code — add a CSS Class in the Divi builder (Row/Section
   Settings → Advanced → CSS ID & Classes): dfl-container-narrow or
   dfl-container-wide. Narrow (a ~65ch reading measure) is for text-heavy
   pages (About, policies, history); wide matches Divi's own 1080px
   default content width, confirmed via `wp option get et_divi` (no
   custom content_width/gutter_width set, so the site is on Divi's
   defaults) for pages that need the full row.
   ========================================================================== */
:root {
	--dfl-gutter: 16px;
	--dfl-container-narrow: 720px;
	--dfl-container-wide: 1080px;
}
@media (min-width: 768px) {
	:root { --dfl-gutter: 24px; }
}
@media (min-width: 992px) {
	:root { --dfl-gutter: 32px; }
}

/* Baseline vertical rhythm between stacked sections — two variants, since
   this site currently mixes two page-building systems:
   - .et_pb_section: true Divi Builder rows. Not in use anywhere on the site
     today (every page/post here is built with plain Gutenberg blocks, see
     .entry-content below), but kept in case a future page uses the
     Builder — per-row padding set in the builder (applied inline) still
     wins, this only fills in the default.
   - .entry-content > *: the actual page-building system in use. Every
     top-level block in the content area gets the same gutter as bottom
     margin, so new sections added in the block editor — a Group, an image,
     a paragraph, anything — get consistent spacing automatically instead
     of needing a one-off margin rule per component. The content container
     itself (#main-content .container, Divi core CSS — hardcoded to
     padding-top:58px/padding-bottom:0 there, unrelated to any token) gets
     the same gutter as top/bottom padding, so nav→first-section and
     last-section→footer match the gutter between sections instead of an
     arbitrary Divi default on one side and nothing on the other. The last
     child's own margin is cleared so it doesn't double up with the
     container's bottom padding. */
.et_pb_section {
	padding-top: var(--dfl-gutter);
	padding-bottom: var(--dfl-gutter);
}
/* !important: Divi core ships `body:not(.et-tb) #main-content .container
   { padding-top: 58px }`, whose extra :not()/body qualifiers out-specify a
   plain #main-content .container rule — so padding-top alone would keep
   losing to Divi's hardcoded value while padding-bottom (no such rule)
   applied fine. Matching that specificity instead of using !important
   would leave this fragile to Divi updating that selector again. */
#main-content .container {
	padding-top: var(--dfl-gutter) !important;
	padding-bottom: var(--dfl-gutter) !important;
}
.entry-content > * {
	margin-top: 0;
	margin-bottom: var(--dfl-gutter);
}
.entry-content > *:last-child {
	margin-bottom: 0;
}

/* Events page (post 23): the calendar grid benefits from more horizontal
   room than the site's standard 1080px content column gives it — narrow day
   cells wrap event titles awkwardly. Client asked (2026-09-10) for the
   calendar to use the full page width. #main-content itself is already
   edge-to-edge with no padding of its own (confirmed via computed styles),
   so this just drops .container's max-width/auto-centering on this page and
   replaces it with the standard gutter as side padding, instead of Divi's
   centered 1080px box. */
.page-id-23 #main-content .container {
	max-width: none !important;
	margin-left: 0 !important;
	margin-right: 0 !important;
	padding-left: var(--dfl-gutter) !important;
	padding-right: var(--dfl-gutter) !important;
}

.dfl-container-narrow,
.dfl-container-wide {
	float: none !important;
	margin-left: auto !important;
	margin-right: auto !important;
}
.dfl-container-narrow {
	max-width: var(--dfl-container-narrow) !important;
}
.dfl-container-wide {
	max-width: var(--dfl-container-wide) !important;
}

/* Homepage: Divi's default page template always renders the literal page
   title ("Homepage") as an <h1> above the content when the page isn't built
   with Divi's own builder (page.php has no per-page toggle for this) — the
   header wordmark already establishes where you are, so suppress it here
   without touching that title on other pages, where it's wanted. */
.page-id-13 .entry-title.main_title {
	display: none;
}

/* wp-content/themes/Divi/page.php hardcodes #main-content to white for every
   page using this (non-Builder) template — on every such page that breaks
   the warm-paper background the header and footer already share, dropping
   to a flat white slab in between. Match body instead. */
#main-content {
	background-color: var(--dfl-paper);
}

/* Homepage welcome band — wraps the welcome line + Quick Links row. Client
   asked (2026-09-09) to remove the tan boxed-in look; background now matches
   the page (--dfl-paper, currently white) so it reads as flush page content
   rather than a distinct section. Apply by wrapping those two blocks in a
   Group block with Additional CSS class "dfl-welcome-band" in the block
   editor — no code needed for future edits. Section-to-section spacing (this
   band to whatever follows it) comes from the universal .entry-content > *
   rule above, not a margin declared here. */
.dfl-welcome-band {
	background-color: var(--dfl-paper);
	padding: var(--dfl-space-lg) var(--dfl-gutter);
}
.dfl-welcome-band p {
	font-family: var(--dfl-font-heading);
	font-size: 1.15rem;
	color: var(--dfl-text);
	margin-top: 0;
	white-space: nowrap;
}
.dfl-welcome-band .dfl-quick-links {
	margin-top: var(--dfl-space-sm);
	margin-bottom: 0;
}
/* Welcome band photo — inset within the band's own padding (same as the
   text below it) rather than bled to the band's edges: Gutenberg's
   constrained-layout CSS forces `margin-left/right: auto !important` on
   block children, which fights a negative-margin bleed and resolves it
   asymmetrically (flush left, overflowing only on the right) instead of
   centering it. Matching the text's inset avoids the fight entirely. */
.dfl-welcome-photo {
	margin-top: 0;
	margin-bottom: var(--dfl-gutter);
}
.dfl-welcome-photo img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 8px;
}
/* Below 576px there isn't room for the welcome line on one line at any
   reasonable size — let it wrap there rather than overflowing or forcing
   the font down to the point of being hard to read. */
@media (max-width: 575px) {
	.dfl-welcome-band p {
		white-space: normal;
	}
}

/* Homepage News/Events columns — small terracotta accent under each column
   heading, and (768px+, where the columns sit side by side) a hairline
   divider between them so the two lists read as distinct, not just
   adjacent. Scoped to this section specifically (not every h2 in
   #content-area) so it doesn't also catch the centered Newsletter CTA
   heading below, whose accent needs centering instead. */
.dfl-news-events h2 {
	position: relative;
	padding-bottom: var(--dfl-space-xs);
	margin-bottom: var(--dfl-space-sm);
}
.dfl-news-events h2::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 48px;
	height: 3px;
	border-radius: 2px;
	background-color: var(--dfl-accent);
}
@media (min-width: 768px) {
	.dfl-news-events > .wp-block-column:last-child {
		border-left: 1px solid var(--dfl-rule);
		padding-left: var(--dfl-gutter);
	}
}

/* Homepage Newsletter CTA — a dark-ink band (rather than another tan one)
   so it reads as a distinct closing call-to-action and previews the dark
   footer just below it, echoing how the tan welcome band bridges the
   header into the page. Section-to-section spacing comes from the
   universal .entry-content > * rule above. */
.dfl-newsletter-cta {
	background-color: var(--dfl-ink);
	border-radius: 8px;
	padding: var(--dfl-space-lg) var(--dfl-gutter);
	text-align: center;
}
.dfl-newsletter-cta h2,
.dfl-newsletter-cta p {
	color: var(--dfl-paper);
}
.dfl-newsletter-cta h2 {
	position: relative;
	padding-bottom: var(--dfl-space-xs);
	margin-bottom: var(--dfl-space-sm);
}
.dfl-newsletter-cta h2::after {
	content: "";
	position: absolute;
	left: 50%;
	bottom: 0;
	transform: translateX(-50%);
	width: 48px;
	height: 3px;
	border-radius: 2px;
	background-color: var(--dfl-accent);
}
.dfl-newsletter-cta p {
	max-width: 60ch;
	margin-left: auto;
	margin-right: auto;
}
.dfl-newsletter-cta .wp-block-buttons {
	margin-top: var(--dfl-space-sm);
}

/* Staff page photo — same inset treatment as the homepage welcome photo
   (see .dfl-welcome-photo above for why: bleeding to the column edge fights
   Gutenberg's constrained-layout !important margin rule). */
.dfl-staff-photo img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 8px;
}

/* Friends of the DFL banner — same inset treatment as the homepage welcome
   photo and Staff page photo above; adds a bottom margin since this one
   leads the page instead of sitting beside/within other content. */
.dfl-friends-banner {
	margin-top: 0;
	margin-bottom: var(--dfl-gutter);
}
.dfl-friends-banner img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 8px;
}

/* Library Policies page (post 239): the loan-period reference table pulled
   in from the client's policies document. Applied directly to the <table>
   (display:block + overflow-x:auto scrolls the table itself on narrow
   screens, same reasoning as .dfl-staff-table elsewhere, just without a
   wrapper element since this table isn't inside one). !important needed for
   the same reason documented at .dfl-staff-table above — Divi/WooCommerce
   core ships higher-specificity table/tr/td border rules. */
.dfl-policy-table {
	display: block;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	width: 100%;
	border-collapse: collapse;
	border: none !important;
}
.dfl-policy-table th,
.dfl-policy-table td {
	text-align: left;
	padding: var(--dfl-space-xs) var(--dfl-space-sm) !important;
	border: none !important;
	border-bottom: 1px solid var(--dfl-rule) !important;
	vertical-align: top;
}
.dfl-policy-table th {
	border-bottom: 2px solid var(--dfl-text) !important;
}
.dfl-policy-table td p,
.dfl-policy-table th p {
	margin: 0;
}

/* Little Free Library page photo — same inset treatment as the other
   content photos above; capped narrower since this one isn't a full-width
   banner, just a supporting photo of the box itself. */
.dfl-lfl-photo {
	max-width: var(--dfl-container-narrow);
}
.dfl-lfl-photo img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 8px;
}

/* Staff directory — a real <table> (wp:table block), not a styled list:
   this is genuinely tabular data (name/role/email per person), and a table
   gives real, natively-aligned columns — each column's width is driven by
   its widest cell, consistently, across every row — instead of a flexbox
   row whose "columns" drift independently per row based on that row's own
   content width. white-space: nowrap on cells keeps long entries (e.g.
   "Sandy Stephan-Strombom") from wrapping instead of just wrapping in
   place. Hairline row dividers reuse --dfl-rule, the same token as the
   homepage's News/Events column divider. */
.dfl-staff-table {
	/* Below ~700px, three nowrap columns (name/role/email) don't fit —
	   scroll the table itself rather than letting it overflow the page or
	   forcing the columns to wrap after all. */
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}
/* !important: Divi/WooCommerce core ships `.entry-content table:not(.variations)
   { border: 1px solid #eee }`, whose :not() clause out-specifies a plain
   .dfl-staff-table table selector — same specificity trap as the
   #main-content .container padding rule above. */
.dfl-staff-table table {
	width: 100%;
	border-collapse: collapse;
	border: none !important;
}
/* !important: Divi core also ships `.entry-content tr td { border-top:
   1px solid #eee; padding: 6px 24px }` — the extra `tr` element pushes its
   specificity past a plain .dfl-staff-table td selector too (same trap as
   the table-border rule above), clobbering both our padding and border. */
.dfl-staff-table th,
.dfl-staff-table td {
	text-align: left;
	white-space: nowrap;
	padding: var(--dfl-space-sm) var(--dfl-space-sm) var(--dfl-space-sm) 0 !important;
	border: none !important;
	border-bottom: 1px solid var(--dfl-rule) !important;
}
/* Column headers stay in the markup (screen readers still get real <th>
   column headers) but aren't shown — visually the table starts straight
   into the data rows. */
.dfl-staff-table thead {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
}
.dfl-staff-table td:first-child {
	font-family: var(--dfl-font-heading);
	font-size: 1.05rem;
	font-weight: 600;
}
.dfl-staff-table td:nth-child(2) {
	color: var(--dfl-muted);
}
.dfl-staff-table td:last-child a {
	font-size: 0.9rem;
}
.dfl-staff-table tr:last-child td {
	border-bottom: none;
	padding-bottom: 0;
}

/* Upcoming Events (My Calendar plugin's default list markup) — dot-bullet
   rules shared with #footer-widgets li below, so the two dot-lists on the
   page read as one visual language instead of two one-off treatments. */
.mc-event-list.upcoming-events {
	margin: 0;
	padding: 0;
}
.mc-event-list.upcoming-events li {
	list-style: none !important;
	margin-bottom: var(--dfl-space-sm);
}

/* An event can optionally carry a plugin-side image (My Calendar's per-event
   "image" field) at whatever aspect ratio the file happens to be. Left
   unconstrained, My Calendar's own list_preset_4 card CSS (width:100%;
   height:auto) renders it at full native size, so a tall poster/flyer blows
   this compact sidebar widget out to several times the height of the
   plain-text events next to it. Cap it to a fixed-height thumbnail so every
   card reads at the same size regardless of what image, if any, a given
   event has. */
.mc-event-list.upcoming-events .mc-group-1 img {
	display: block;
	width: 100%;
	height: 140px;
	object-fit: cover;
	border-radius: 8px 8px 0 0;
}

/* Events page (My Calendar plugin, [my_calendar format="list"]) — the full
   calendar, as opposed to the homepage's lighter-weight upcoming-events
   widget above. Scoped to .mc-main (this shortcode's own wrapper) rather
   than a page ID, so it applies wherever the full calendar is embedded. */
.mc-main .heading.my-calendar-month {
	font-size: 1.4rem;
	margin-bottom: var(--dfl-space-sm);
}

/* Top/bottom toolbars (view/time switcher, month jump, Today/Next, and the
   category legend) all share one small-button look: quiet by default,
   accent border+text on hover, solid accent fill only for the currently
   active/pressed state — so "what view am I in" reads at a glance without
   the toolbar competing with real content for attention. */
.mc-main .my-calendar-navigation ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: var(--dfl-space-xs);
	align-items: center;
}
.mc-main .my-calendar-header,
.mc-main .mc_bottomnav {
	display: flex;
	flex-wrap: wrap;
	gap: var(--dfl-space-sm) var(--dfl-space-md);
	align-items: center;
	margin-bottom: var(--dfl-space-sm);
}
.mc-main .mc-navigation-button,
.mc-main .mc-date-switcher select,
.mc-main .mc-date-switcher input[type="submit"] {
	font-family: var(--dfl-font-body);
	font-size: 0.85rem;
	color: var(--dfl-text);
	background: transparent;
	border: 1px solid var(--dfl-rule);
	border-radius: 6px;
	padding: 0.4em 0.75em;
	cursor: pointer;
}
.mc-main .mc-navigation-button:hover,
.mc-main .mc-date-switcher input[type="submit"]:hover {
	border-color: var(--dfl-accent);
	color: var(--dfl-accent-ink);
}
.mc-main .mc-navigation-button.mc-active,
.mc-main .mc-navigation-button[aria-pressed="true"],
.mc-main .mc-navigation-button[aria-current="true"] {
	background: var(--dfl-accent);
	border-color: var(--dfl-accent);
	color: #fff;
}
.mc-main .my-calendar-date-switcher label {
	font-size: 0.85rem;
	color: var(--dfl-muted);
}

/* Date-grouped event list. */
.mc-main .mc-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.mc-main .mc-events {
	padding: var(--dfl-space-md) 0;
	border-bottom: 1px solid var(--dfl-rule);
}
.mc-main .mc-events:first-child {
	padding-top: 0;
}
.mc-main .mc-events:last-child {
	border-bottom: none;
	padding-bottom: 0;
}
.mc-main .event-date.mc-text-button {
	font-family: var(--dfl-font-heading);
	font-size: 1.1rem;
	font-weight: 600;
	color: var(--dfl-text);
	background: none;
	border: none;
	padding: 0 0 var(--dfl-space-sm);
	cursor: pointer;
	text-decoration: none;
}
.mc-main .event-date.mc-text-button:hover {
	color: var(--dfl-accent-ink);
}
/* Default focus ring here is a plain dark 1px outline (browser default) —
   swap in the brand accent so keyboard focus (e.g. returning to this
   button when the event-detail modal closes) still reads as "on this
   site" rather than a generic UA outline. */
.mc-main button:focus-visible,
.mc-main a:focus-visible {
	outline: 2px solid var(--dfl-accent);
	outline-offset: 2px;
}
.mc-main .list-event + .list-event {
	margin-top: var(--dfl-space-md);
	padding-top: var(--dfl-space-md);
	border-top: 1px solid var(--dfl-rule);
}
.mc-main .event-title {
	font-family: var(--dfl-font-heading);
	font-size: 1.05rem;
	font-weight: 600;
	color: var(--dfl-text);
	margin: 0 0 var(--dfl-space-xs);
}
.mc-main .time-block {
	display: flex;
	align-items: baseline;
	gap: var(--dfl-space-xs);
	color: var(--dfl-muted);
	font-size: 0.9rem;
	margin-bottom: var(--dfl-space-xs);
}
.mc-main .shortdesc.description {
	margin-bottom: var(--dfl-space-xs);
}
.mc-main .mc-image img {
	border-radius: 8px;
	margin-bottom: var(--dfl-space-xs);
}
.mc-main .mc-location {
	font-size: 0.9rem;
	color: var(--dfl-muted);
	margin-bottom: var(--dfl-space-xs);
}
.mc-main .sharing .mc-details {
	font-size: 0.9rem;
	margin: 0;
}

/* Category legend + print link, bottom toolbar. */
.mc-main .category-key h2 {
	font-family: var(--dfl-font-body);
	font-size: 0.75rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--dfl-muted);
	margin: 0 0 var(--dfl-space-xs);
	flex-basis: 100%;
}
.mc-main .category-color-sample {
	display: inline-block;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	margin-right: 0.4em;
}
.mc-main .all-categories .mc-active {
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--dfl-accent-ink);
	padding: 0.4em 0.75em;
}
.mc-main .mc-print a {
	font-size: 0.85rem;
	color: var(--dfl-muted);
}

/* Event-detail modal (native <dialog>, opened by clicking a date in the
   list) — default plugin styling is an unstyled gray header bar and a
   bright red "Close" button, both clashing hard with the rest of the site.
   Not scoped to .mc-main since the <dialog> is appended to the end of
   <body>, outside the shortcode's own wrapper. */
dialog.my-calendar-modal {
	max-width: min(90vw, var(--dfl-container-narrow));
	border: none;
	border-radius: 8px;
	padding: 0;
	box-shadow: 0 8px 32px rgba(46, 41, 36, 0.25);
}
dialog.my-calendar-modal::backdrop {
	background: rgba(46, 41, 36, 0.5);
}
.mc-modal-title-container {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--dfl-space-sm);
	padding: var(--dfl-space-sm) var(--dfl-space-md);
	background: var(--dfl-tan);
	border-bottom: 1px solid var(--dfl-rule);
}
.my-calendar-modal-title {
	font-family: var(--dfl-font-heading);
	font-size: 1.15rem;
	font-weight: 600;
	color: var(--dfl-text);
	margin: 0;
}
/* !important: My Calendar's own reset.css ships `button.my-calendar-modal-close
   { background: var(--close-button) }` (a red "danger" token) — the extra
   `button` element in its selector out-specifies a plain .mc-modal-close
   class, same trap as the other My Calendar/Divi overrides above. */
.mc-modal-close {
	display: flex;
	align-items: center;
	gap: 0.3em;
	font-family: var(--dfl-font-body);
	font-size: 0.85rem;
	color: var(--dfl-text) !important;
	background: transparent !important;
	border: 1px solid var(--dfl-rule) !important;
	border-radius: 6px;
	padding: 0.4em 0.75em;
	cursor: pointer;
	flex-shrink: 0;
}
.mc-modal-close:hover,
.mc-modal-close:focus,
.mc-modal-close:active {
	border-color: var(--dfl-accent) !important;
	color: var(--dfl-accent-ink) !important;
	background: transparent !important;
}
#mc-modal-content {
	padding: var(--dfl-space-md);
}

/* Quick Links labels never break mid-phrase ("Inter-Library" / "Loan") —
   forcing five equal-width buttons (an earlier attempt at this) squeezed
   the longer labels below their natural width and wrapped them instead. */
.dfl-quick-links .wp-block-button__link {
	white-space: nowrap;
}
/* One row, content-sized buttons. Below 992px the row keeps wrapping
   (Divi block default) since even content-sized, five buttons plus the
   longer labels don't reliably fit one line at narrower widths. */
@media (min-width: 992px) {
	.dfl-quick-links {
		flex-wrap: nowrap !important;
	}
}

/* Base */
body {
	background-color: var(--dfl-paper);
	color: var(--dfl-text);
	font-family: var(--dfl-font-body);
}

h1, h2, h3, h4, h5, h6,
.et_pb_module h1, .et_pb_module h2, .et_pb_module h3,
.et_pb_module h4, .et_pb_module h5, .et_pb_module h6 {
	font-family: var(--dfl-font-heading);
	font-weight: 600;
	color: var(--dfl-text);
}

p, li, .et_pb_text, .et_pb_module {
	font-family: var(--dfl-font-body);
}

a {
	color: var(--dfl-accent-ink);
}

/* Buttons (Divi button module + core block buttons) */
.et_pb_button,
.wp-block-button__link {
	background-color: var(--dfl-accent) !important;
	border: 2px solid var(--dfl-accent) !important;
	color: #fff !important;
	font-family: var(--dfl-font-body);
	font-weight: 600;
	border-radius: 6px;
}
.et_pb_button:hover,
.wp-block-button__link:hover {
	background-color: var(--dfl-accent-ink) !important;
	border-color: var(--dfl-accent-ink) !important;
	color: #fff !important;
}

/* Site-wide alert bar (dfl_site_alert_bar() in functions.php) — sits above
   the header, only rendered in PHP when staff have set a message via
   Appearance → Customize → Library Settings. --dfl-accent (not --dfl-ink,
   which the header itself now uses) so it reads as its own "something needs
   your attention" band distinct from the header directly below it, the way
   NYPL's yellow alert bar stands apart from its white nav. White text, not
   --dfl-paper — paper-on-accent is 4.44:1, just under the 4.5:1 AA text
   minimum; white clears it at 4.74:1 (same reasoning already applied to
   button text below, kept consistent here). No dismiss/close control by
   design — one Customizer field to blank out is the whole "how do I turn
   this off" story, no JS/localStorage needed. */
.dfl-site-alert {
	background-color: var(--dfl-accent);
	text-align: center;
	padding: var(--dfl-space-xs) var(--dfl-gutter);
}
/* Sticky on mobile only (see @media (max-width: 980px) below, next to the
   header's own sticky rule) — kept here since this selector already exists
   at every width and only needs a positioning change under 980px. */
.dfl-site-alert p {
	margin: 0;
	font-family: var(--dfl-font-body);
	font-size: 0.85rem;
	font-weight: 600;
	color: #fff;
}
.dfl-site-alert a {
	color: #fff;
	text-decoration: underline;
}

/* Primary nav — shared rules, apply at every width. Header gets the same
   dark --dfl-ink as the footer instead of matching the paper body — a
   deliberate dark-top/dark-bottom "bookend" around the warm paper body,
   plus a soft shadow for lift, so it reads as a distinct, persistent chrome
   bar rather than blending into whatever page content follows it. Every
   text/icon color below flips to light-on-dark, reusing the same pattern
   already proven on the footer and the homepage newsletter CTA rather than
   inventing a new one. (Tried a lighter --dfl-tan header first — see prior
   commit — but the user preferred this bolder dark version.) */
#top-header, #main-header, .et-fixed-header {
	background-color: var(--dfl-ink);
	font-family: var(--dfl-font-body);
	box-shadow: 0 2px 8px rgba(54, 69, 79, 0.12);
	position: relative;
	z-index: 1;
}
/* Divi always renders an <img> logo (falling back to its own placeholder
   when none is set) — we use real text instead. See dfl_text_wordmark_logo()
   in functions.php. The <img> stays in the DOM (hidden here) so Divi's
   header-sizing JS still has it to measure. */
#logo {
	display: none;
}
.dfl-site-title {
	display: inline-block;
	font-family: var(--dfl-font-heading);
	font-size: 1.15rem;
	font-weight: 600;
	color: var(--dfl-paper);
	text-decoration: none;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* Text stays --dfl-paper in every state (9.27:1 against --dfl-ink) — hover/
   current-item is marked with an underline instead of a color change, since
   neither --dfl-accent (2.09:1) nor --dfl-accent-ink (1.40:1, calibrated for
   light backgrounds) comes close to readable as text on dark ink. The base
   state reserves the same 2px transparent border so the underline appearing
   on hover/current doesn't shift the row by 2px. Divi's own default nav-link
   hover style applies opacity:0.7 — harmless for the text (paper dims to a
   still-safe 5.5:1) but drags the underline's already-tight 3.0:1 down to
   2.2:1, so it's neutralized here rather than left to quietly undo the
   contrast work above.
   Scoped with the `>` combinator (#top-menu > li, not #top-menu li) so this
   only ever touches the seven top-level bar items — Divi's own default rule
   for these two states is the unscoped `#top-menu li.current-menu-ancestor>a,
   #top-menu li.current-menu-item>a { color:#2ea3f2 }` (its stock blue,
   dynamic-assets/header.css), which — being unscoped — also matches
   current-menu-item on nested dropdown links. First pass here only added
   current-menu-item (fixing "Home" on the dark bar) and missed
   current-menu-ancestor (leaving "Borrow"'s stock-blue text/underline
   showing whenever a child page like ILL Overview is open) AND accidentally
   inherited Divi's own unscoped-selector mistake by matching dropdown items
   too (turning "Inter-Library Loan Overview" paper-on-paper — invisible —
   inside the white dropdown). See the dropdown-specific current-item rule
   further down for the light-background fix.
   !important on padding-bottom: Divi's centered-header CSS ships
   `.et_header_style_centered #top-menu>li>a{padding-bottom:2em}` (28px at
   this font-size) — one more class than our plain `#top-menu > li > a`, so
   it wins on specificity regardless of source order, leaving the intended
   2px gap silently inflated to 28px (a big gap between the link text and
   its hover/current underline, with no design intent behind it). */
#top-menu > li > a {
	color: var(--dfl-paper);
	border-bottom: 2px solid transparent;
	padding-bottom: 2px !important;
	opacity: 1;
}
#top-menu > li > a:hover,
#top-menu > li.current-menu-item > a,
#top-menu > li.current-menu-ancestor > a {
	color: var(--dfl-paper);
	border-bottom-color: var(--dfl-accent-bright);
	opacity: 1 !important;
}
/* Divi's search-icon glyph hardcodes a dark color of its own (unrelated to
   any nav-link rule above, so it didn't inherit the paper flip) — nearly
   invisible against dark ink until overridden explicitly. */
#et_search_icon:before {
	color: var(--dfl-paper);
}
/* Divi's default dropdown-panel top border is a stock bright blue
   (#2ea3f2, unrelated to any site token) that was easy to miss against the
   old paper-on-paper header but clashes hard now that the header itself has
   real color — swap it for the site's own accent, matching the mobile
   menu's border-top-color treatment below. */
#top-menu ul.sub-menu {
	border-top-color: var(--dfl-accent) !important;
}
#main-header .nav li ul,
#top-menu ul.sub-menu {
	background-color: var(--dfl-paper) !important;
}
#main-header .nav li ul a,
#top-menu ul.sub-menu a {
	color: rgba(0, 0, 0, 0.6) !important;
}

/* Divi bug, not ours: any dropdown with 5+ children auto-switches to a
   3-column "mega menu" layout (li.mega-menu-parent-3, width:33.33% per
   item — dynamic-assets/header.css) — but the `clear` rule that's supposed
   to start each new row is hardcoded for a 4-column grid that doesn't even
   exist as an option (only mega-menu-parent-2/-3 are defined):
   `li:nth-of-type(4n+1){clear:left}` / `li:nth-of-type(4n){clear:right}`.
   For a 3-wide row, that clear:left lands on item 5 — the 2nd item of what
   should be row 2 — forcing an unwanted line break there (row 2 ends up
   with just item 4 alone, row 3 gets items 5-7). Affects every dropdown
   with 5+ items (Borrow, Download & Stream, Events, Services, About Us).
   Each li is already exactly 33.33% wide, so plain float-wrap already
   produces the correct 3-3-1 grouping on its own once Divi's mismatched
   clear rule is neutralized — no clear rule of our own is needed. */
#top-menu li.mega-menu.mega-menu-parent-3 > ul > li {
	clear: none !important;
}
/* The dropdown panel is white/paper regardless of what color the collapsed
   bar above it is (see the top-of-file note by the header background rule),
   so its own current-page item needs a light-background-appropriate
   treatment, not the dark-bar one above — which is exactly the bug this
   fixes: Divi's ordinary dropdown links are rgba(0,0,0,.6) (its own
   default, never touched), so the current item is just bolded in the same
   --dfl-accent-ink already used for every other link-on-light-background on
   this site, rather than introducing a new color just for this one state. */
#top-menu ul.sub-menu li.current-menu-item > a {
	color: var(--dfl-accent-ink);
	font-weight: 600;
}

/* Mobile header — wordmark, hamburger, and search all stay on one row.
   The site's actual Divi header format is "Centered" (body carries
   et_header_style_centered), not "Left" — this block overrides that
   style's mobile layout (which stacks the logo above a 2-row nav) down
   to a single compact row instead. */
.container.et_menu_container {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--dfl-space-sm);
}
/* Divi's .clearfix:after (float-clearing, display:block) becomes an
   invisible third flex item once this container is flex — under
   space-between it steals the "flush right" slot, leaving the hamburger
   short of the true edge. It's a no-op in a flex context anyway, so drop it. */
.container.et_menu_container:after {
	display: none !important;
}
.logo_container {
	text-align: left;
	flex-shrink: 1;
	min-width: 0;
	overflow: hidden;
}
#et-top-navigation {
	float: none !important;
	display: flex !important;
	align-items: center;
	justify-content: flex-end;
	flex-shrink: 0;
	/* Divi's centered-header CSS hardcodes width:100% here, which — as a
	   flex-shrink:0 sibling of .logo_container — claims the entire row and
	   squashes the wordmark to 0 width. Let it hug its own (small, mobile-
	   toggle-only) content instead; restored at the 981px+ breakpoint below. */
	width: auto !important;
}

@media (max-width: 980px) {
	/* Divi's mobile "Select Page" label is a leftover from an old dropdown-
	   style menu. Its box is sized to the label text alone, while Divi
	   absolute-positions the hamburger relative to #et-top-navigation
	   (not to this text) — the two collide. Hiding the label removes the
	   collision and leaves a standard, cleaner hamburger-only toggle. */
	.select_page {
		display: none !important;
	}
	.mobile_nav {
		background-color: transparent !important;
		padding: 0 !important;
	}
	#et_mobile_nav_menu {
		margin-top: 0 !important;
	}
	/* Divi absolute-positions the hamburger at top:2px from #et-top-navigation,
	   a box whose own height is unrelated to the wordmark's — it's not
	   actually centered against the logo, just coincidentally close at some
	   widths. Put it back in normal flow so the outer row's flexbox
	   (align-items: center, justify-content: space-between) centers it
	   against the wordmark for real and pins it to the right edge. */
	.mobile_menu_bar {
		position: static !important;
		right: auto !important;
		top: auto !important;
	}
	/* !important: Divi's Customizer settings are cached to their own
	   stylesheet (et-divi-customizer.min.css) that WordPress enqueues after
	   every theme stylesheet on purpose, so a site owner's Customizer color
	   picks always beat theme CSS - it bundles this exact selector into a
	   dozen-selector rule setting rgba(0,0,0,0.6), same specificity as this
	   rule, later in source order, so it silently won without !important. */
	.mobile_menu_bar:before {
		color: var(--dfl-paper) !important;
	}
	/* Divi absolute-positions the open dropdown at width:100% of its nearest
	   positioned ancestor (#et_mobile_nav_menu) — which our compact,
	   content-hugging mobile toggle just shrank to hamburger-width. Anchor
	   to the viewport instead so the panel is reliably full-width regardless
	   of that ancestor's size. */
	.et_mobile_menu {
		position: fixed !important;
		left: 0 !important;
		right: 0 !important;
		/* Divi's default height is auto, sized to fit the whole (often long,
		   nested) menu — taller than most viewports. With no bottom offset
		   and no overflow constraint, the panel just hung off the bottom of
		   the screen: scrolling moved the page underneath a fixed element
		   that never moved, instead of scrolling the menu's own content.
		   Pinning bottom:0 makes the panel's height resolve to exactly
		   "viewport minus header," and overflow-y:auto scrolls the menu
		   itself within that space. */
		bottom: 0 !important;
		height: auto !important;
		overflow-y: auto !important;
		-webkit-overflow-scrolling: touch;
		width: auto !important;
		background-color: var(--dfl-paper) !important;
		border-top-color: var(--dfl-accent) !important;
	}
	.et_mobile_menu li a {
		font-family: var(--dfl-font-body);
		color: var(--dfl-text);
	}
	.et_mobile_menu li a:hover {
		color: var(--dfl-accent-ink);
	}
	/* Panel itself is paper (light) even though the collapsed header bar
	   above it is now dark ink — same "dark bar, light dropdown" split the
	   desktop hover menu already uses (see #top-menu ul.sub-menu), so this
	   chip only needs to stand out against paper, not against the header. */
	.et_mobile_menu .menu-item-has-children > a {
		background-color: var(--dfl-tan) !important;
	}

	/* Sticky header + alert bar, mobile only (user request). Deliberately
	   scoped to this breakpoint rather than sitewide, and deliberately
	   position: sticky rather than reviving Divi's own "Fixed Header"
	   feature — that was turned off globally earlier in this project
	   because its JS only recalculated #page-container's padding-top on
	   window.load, causing a visible content jump on first paint (see
	   Progress log, header/nav CSS section). Sticky sidesteps that whole bug
	   class: both elements keep their normal-flow space reserved, so no
	   padding compensation — JS-computed or otherwise — is needed at all. */
	.dfl-site-alert {
		position: sticky;
		top: 0;
		z-index: 21;
	}
	#top-header, #main-header, .et-fixed-header {
		position: sticky;
		top: 0;
		z-index: 20;
	}
	/* The alert bar renders above the header in normal document flow (see
	   wp_body_open() in functions.php — before #page-container opens) only
	   when its Customizer field is non-blank, so its presence in the DOM at
	   all is the signal to use here rather than a separate flag. */
	body:has(.dfl-site-alert) #top-header,
	body:has(.dfl-site-alert) #main-header,
	body:has(.dfl-site-alert) .et-fixed-header {
		top: var(--dfl-alert-bar-height);
	}
	/* Opened mobile menu panel: override Divi's hardcoded top:53px guess
	   (see --dfl-mobile-header-height above) so the panel starts flush
	   under the sticky header instead of under/behind it. */
	.et_mobile_menu {
		top: var(--dfl-mobile-header-height) !important;
	}
	body:has(.dfl-site-alert) .et_mobile_menu {
		top: calc(var(--dfl-alert-bar-height) + var(--dfl-mobile-header-height)) !important;
	}
}

/* Desktop header (981px+ — matches Divi's own breakpoint for switching from
   the mobile hamburger to the full nav, not our usual 576/768/992/1200
   scale, so the two never fall out of step with each other). Wordmark on
   its own centered row, nav centered on the row below. */
@media (min-width: 981px) {
	#main-header .container {
		padding-top: var(--dfl-space-lg);
		padding-bottom: var(--dfl-space-md);
	}
	.container.et_menu_container {
		display: block;
	}
	.logo_container {
		text-align: center;
		margin-bottom: var(--dfl-space-xs);
		flex-shrink: initial;
		overflow: visible;
	}
	.dfl-site-title {
		font-size: 1.5rem;
	}
	#et-top-navigation {
		justify-content: center;
		width: 100%;
		/* Own stacking context so the ::before band below paints against
		   #et-top-navigation's transparent background (behind the nav links,
		   in front of #main-header's ink) instead of getting swept into
		   #main-header's stacking context, where a negative z-index would
		   paint behind .logo_container as well and never be seen. */
		isolation: isolate;
	}
	/* Splits the header into two tones: logo row stays --dfl-ink, nav row
	   gets a subtly darker --dfl-ink-nav, so the eye reads "brand" vs
	   "navigation" as two bands instead of one undifferentiated slab. Full
	   viewport-width breakout (the left:50%/translateX trick) so the band
	   reads edge-to-edge like the rest of the header chrome, even though
	   #et-top-navigation itself only spans Divi's centered container -
	   deliberately not touching #et-top-navigation's own box, since Divi's
	   dropdown-positioning JS measures it. top/bottom extend past the
	   element's own tight (content-height-only) box by an equal
	   --dfl-space-md (18px) on both sides, so the band reads as evenly
	   padded around the nav links - not half the 14px logo-gap on top vs
	   the full padding-bottom below, which was the first pass and looked
	   bottom-heavy. Bottom is a hard constraint (has to land exactly on
	   #main-header .container's own padding-bottom to stay flush with the
	   header's outer edge, or a sliver of the old color shows below it);
	   matching top to that same value eats 4px into the tail end of
	   .logo_container's own (100px-tall, mostly-empty) box rather than
	   stopping at the gap - not visible, since the wordmark text sits
	   nowhere near that box's bottom edge. Desktop-only: on mobile
	   #et-top-navigation is just the 32px hamburger button, not a row
	   worth a second tone. */
	#et-top-navigation::before {
		content: "";
		position: absolute;
		left: 50%;
		width: 100vw;
		transform: translateX(-50%);
		top: calc(var(--dfl-space-md) * -1);
		bottom: calc(var(--dfl-space-md) * -1);
		background-color: var(--dfl-ink-nav);
		z-index: -1;
	}
	/* Divi's search-icon glyph offset (top:-13px, from centered_header.css)
	   is calibrated for Divi's own default header spacing. Our custom
	   container padding/logo margin above shifted the nav row down without
	   moving the icon's hardcoded offset, leaving it sitting off the nav
	   links' vertical center. Re-measured (a temporary real-element clone of
	   the ::before, since getBoundingClientRect can't target a pseudo-
	   element directly) after the nav-link padding-bottom fix above dropped
	   from 28px to 2px and shifted the row's own vertical center. */
	#et_search_icon:before {
		top: -10px !important;
	}
}

/* Footer */
#main-footer, .et-l--footer {
	background-color: var(--dfl-ink);
	color: var(--dfl-paper);
	font-family: var(--dfl-font-body);
}
#main-footer a, .et-l--footer a {
	color: var(--dfl-paper);
}
#footer-widgets li {
	list-style: none !important;
	position: relative;
	padding-left: var(--dfl-space-xs);
	display: block !important;
}
#footer-widgets li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.6em;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background-color: var(--dfl-accent);
	border: none !important;
}
#main-footer h1, #main-footer h2, #main-footer h3,
#main-footer h4, #main-footer h5, #main-footer h6,
#main-footer .wp-block-heading,
.et-l--footer h1, .et-l--footer h2, .et-l--footer h3,
.et-l--footer h4, .et-l--footer h5, .et-l--footer h6,
.et-l--footer .wp-block-heading {
	color: var(--dfl-paper) !important;
}
/* A footer column can carry two headings (e.g. Address / Mailing Address,
   Contact / Links) — give the second one room to breathe from the content
   above it, without adding space above the column's first heading. */
#footer-widgets .wp-block-heading:not(:first-child) {
	margin-top: var(--dfl-space-xl) !important;
}

/* Widget titles (sidebar) */
.et_pb_widget_area .widget-title,
.et_pb_widget h4.widget-title,
#main-footer .widget-title,
.et-l--footer .widget-title {
	font-family: var(--dfl-font-heading) !important;
	color: var(--dfl-text) !important;
}
#main-footer .widget-title,
.et-l--footer .widget-title {
	color: var(--dfl-paper) !important;
}

/* In-content images (e.g. Gutenberg alignright/alignleft with an inline
   width) squeeze body text into a narrow single-word-per-line column on
   phones. Stack full width by default; restore the side float on tablet+. */
.entry-content .wp-block-image.alignright,
.entry-content .wp-block-image.alignleft {
	float: none;
	width: 100% !important;
	max-width: 320px;
	margin-left: auto;
	margin-right: auto;
}

/* ILL Overview page (post 17): the delivery photo should lead the content
   on mobile (photo, then all body text) but float beside the steps list on
   tablet+, where it sits further down the content. Flexbox + order lets the
   same DOM position serve both layouts without duplicating the image. */
.page-id-17 .entry-content {
	display: flex;
	flex-direction: column;
}
.page-id-17 .entry-content .dfl-ill-photo {
	order: -1;
}

/* Medium devices (768px and up) */
@media (min-width: 768px) {
	.entry-content .wp-block-image.alignright {
		float: right;
		width: 320px !important;
		margin: 0 0 var(--dfl-space-md) var(--dfl-space-lg);
	}
	.entry-content .wp-block-image.alignleft {
		float: left;
		width: 320px !important;
		margin: 0 var(--dfl-space-lg) var(--dfl-space-md) 0;
	}
	.page-id-17 .entry-content {
		display: block;
	}
}

/* Seed Library page (post 20): "how it works" steps as photo cards — a
   background photo with the step name overlaid in a gradient at the
   bottom, mirroring the live production page's card treatment but in the
   redesign's own ink/paper palette instead of its flat black overlay.
   Built from plain Image + Heading blocks (not the Cover block) so staff
   can swap the photo or edit the caption with the standard block tools. */
.dfl-seed-steps.wp-block-columns {
	gap: var(--dfl-gutter);
}
.dfl-seed-step {
	position: relative;
	overflow: hidden;
	border-radius: 8px;
}
.dfl-seed-step__img {
	margin: 0;
	aspect-ratio: 4 / 3;
}
.dfl-seed-step__img img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.dfl-seed-step__label {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	margin: 0;
	padding: var(--dfl-space-md) var(--dfl-space-lg);
	background: linear-gradient(180deg, rgba(54, 69, 79, 0) 0%, rgba(54, 69, 79, 0.85) 75%);
	color: var(--dfl-paper) !important;
}

/* Site-wide: core Gutenberg "Details" blocks styled as closed-by-default
   drop-downs. Originated on Museum Passes (post 18) per the client's own
   spec ("Museum Passes: Use drop-downs to display text") and reused
   as-is on Trustees and Meetings (post 39, "Meeting Minutes (Click on
   the year to see all meetings for that year)" in the same spec doc) —
   kept unscoped by page ID so any future page can drop in the same
   block with no new CSS, matching how [dfl_catalog_url] gets reused
   rather than re-solved per page. */
.entry-content .wp-block-details {
	border-bottom: 1px solid var(--dfl-rule);
	/* No padding here — client asked (2026-09-09, Museum Passes) to tighten
	   the gap between closed entries to cut scrolling, without shrinking the
	   summary text or its own click-target padding below. Relying on just
	   summary's padding (--dfl-space-xs top+bottom) plus this border roughly
	   halves the old gap (was this padding stacked on top of summary's) while
	   still leaving a clear rule + breathing room between entries. */
	padding: 0;
}
.entry-content .wp-block-details:first-of-type {
	border-top: 1px solid var(--dfl-rule);
}
.entry-content .wp-block-details summary {
	font-family: var(--dfl-font-heading);
	font-size: 1.1rem;
	color: var(--dfl-text);
	cursor: pointer;
	padding: var(--dfl-space-xs) 0;
	list-style: none;
}
.entry-content .wp-block-details summary::-webkit-details-marker {
	display: none;
}
.entry-content .wp-block-details summary::before {
	content: "+";
	display: inline-block;
	width: 1em;
	margin-right: var(--dfl-space-xs);
	color: var(--dfl-accent);
	font-weight: 700;
}
.entry-content .wp-block-details[open] > summary::before {
	content: "\2212"; /* minus sign */
}
.entry-content .wp-block-details .wp-block-paragraph {
	margin: 0 0 var(--dfl-space-xs) 1.6em;
	color: var(--dfl-muted);
}
.entry-content .wp-block-details .wp-block-paragraph:last-child {
	margin-bottom: var(--dfl-space-xs);
}

/* Museum Passes: temporary photo placeholders (no museum photos on hand
   yet). Plain Group block so staff can just delete it and drop in a real
   Image block once photos are supplied — no code either way. */
.page-id-18 .dfl-photo-placeholder {
	aspect-ratio: 4 / 3;
	max-width: 280px;
	margin: var(--dfl-space-xs) 0 var(--dfl-space-sm) 1.6em;
	padding: var(--dfl-space-sm);
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	background: var(--dfl-tan);
	border: 1px dashed var(--dfl-rule);
	border-radius: 8px;
}
.page-id-18 .dfl-photo-placeholder p {
	margin: 0;
	font-size: 0.85rem;
	font-style: italic;
	color: var(--dfl-muted);
}

/* Directions page (post 120): free Google Maps embed (classic
   maps.google.com/maps?output=embed iframe - no API key/billing account
   needed, unlike the newer Maps Embed API, so it stays within the
   "no monthly-fee tools" constraint). aspect-ratio reserves the space
   up front so the iframe loading in doesn't cause a layout jump. */
.dfl-map-embed {
	aspect-ratio: 16 / 9;
	max-width: var(--dfl-container-narrow);
	border: 1px solid var(--dfl-rule);
	border-radius: 8px;
	overflow: hidden;
	margin: 0 auto var(--dfl-gutter);
}
.dfl-map-embed iframe {
	width: 100%;
	height: 100%;
	border: 0;
	display: block;
}

/* Suggest a Book (post 31): embedded Google Form — same free/no-monthly-fee
   reasoning as the Directions page's Maps embed above. No fixed aspect ratio
   here since Google Forms' own content height varies by form, so the iframe
   keeps its explicit height attribute rather than being ratio-locked. */
.dfl-google-form-embed {
	border: 1px solid var(--dfl-rule);
	border-radius: 8px;
	overflow: hidden;
	margin: 0 auto;
}
.dfl-google-form-embed iframe {
	width: 100%;
	border: 0;
	display: block;
}

/* Site Map (post 45): section headings are links to each area's own
   overview page (extending the one explicit hint in the client's spec -
   the T(w)een/Children/Getting Started nav items go straight to their
   page - to every section, since a site map's whole job is navigating).
   Divi's core heading styles force link color to match the heading text
   color, so on this page only, restore the normal link color/hover so
   they read as clickable. */
.page-id-45 h3.wp-block-heading a {
	color: var(--dfl-accent-ink);
}
.page-id-45 h3.wp-block-heading a:hover {
	text-decoration: underline;
}

/* Site-wide: small icon marking any link that leaves the site (catalog,
   streaming apps, database logins, etc.), so visitors can tell an internal
   page from a third-party site before clicking. The .dfl-external-link
   class is added automatically in functions.php (nav menu links and
   content links alike) by comparing each link's host against home_url() -
   no per-link markup to maintain. Drawn with a CSS mask instead of an
   <img> or icon font, so the glyph always matches the surrounding text
   color (nav vs. body copy, light vs. dark) and needs no extra request -
   keeps to the "minimal load time" priority. */
.dfl-external-link::after {
	content: "";
	display: inline-block;
	width: 0.7em;
	height: 0.7em;
	margin-left: 0.3em;
	vertical-align: -0.05em;
	background-color: currentColor;
	opacity: 0.7;
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E");
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
}

/* Reusable "card list" pattern: restyles a plain content list into a
   playful card grid, echoing the warmth of the old production site's
   illustrated cards without needing custom artwork - the emoji already
   typed at the front of each list item (plain text, so staff can add/
   edit/remove them same as any other word) stands in for an icon via the
   ::first-line size bump below. Reuses the site's existing tokens rather
   than inventing new ones. Originated on Children's Home Page (post 42),
   applied via the block's "Additional CSS Class" field (className
   "dfl-card-list") so any future kid/teen-style resource list can reuse
   it with no new CSS - same reuse pattern as .wp-block-details above. */

/* Divi resets <ol> to list-style-position:inside with zero padding via a
   same-specificity `.entry-content ol` rule inlined in <head> as
   #divi-style-parent-inline-inline-css (not an external stylesheet, so it's
   easy to miss when checking sources) — unlike <ul>, which it leaves at the
   browser default outside/indented. "Inside" puts the number in the text
   flow itself, so a wrapped second line falls back to the left margin under
   the number instead of hanging-indented under the first line's text —
   noticeable on any numbered list long enough to wrap (e.g. Library
   Policies' numbered procedures). !important needed even though this rule
   is later in the cascade: that inline block still wins on equal
   specificity, same class of issue as the other Divi overrides in this
   file. Site-wide since any future ordered list would hit the same Divi
   default. */
.entry-content ol {
	list-style-position: outside !important;
	padding-left: 1.4em !important;
}

/* Client asked (2026-09-10) for a left indent on list content, site-wide —
   separate from the padding-left above, which just makes room for the
   marker itself. This pushes the whole list (marker + text) in from the
   surrounding paragraph's left edge, the way an indented list commonly
   reads in a document. Starting value per client's own request — expect to
   tune. Excludes .dfl-card-list, which is a full-width card grid, not an
   indented list. */
.entry-content ul:not(.dfl-card-list),
.entry-content ol {
	margin-left: 20px;
}

.entry-content ul.wp-block-list.dfl-card-list {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--dfl-gutter);
	list-style: none;
	margin: 0;
	padding: 0;
}
.entry-content ul.wp-block-list.dfl-card-list li {
	background: #fff;
	border-top: 4px solid var(--dfl-accent);
	border-radius: 12px;
	padding: var(--dfl-space-md) var(--dfl-space-md) var(--dfl-space-lg);
	box-shadow: 0 1px 3px rgba(54, 69, 79, 0.08);
	transition: transform 0.15s ease, box-shadow 0.15s ease;
	list-style: none;
}
.entry-content ul.wp-block-list.dfl-card-list li:hover,
.entry-content ul.wp-block-list.dfl-card-list li:focus-within {
	transform: translateY(-3px);
	box-shadow: 0 6px 16px rgba(54, 69, 79, 0.14);
}
/* The leading emoji is a plain text node, which CSS :first-child ignores
   when matching element siblings - so this still targets the title link/
   strong even though the emoji visually comes first. */
.entry-content ul.wp-block-list.dfl-card-list li::first-line {
	font-size: 1.8rem;
}
.entry-content ul.wp-block-list.dfl-card-list li > a:first-child,
.entry-content ul.wp-block-list.dfl-card-list li > strong:first-child {
	display: block;
	font-family: var(--dfl-font-heading);
	font-size: 1.15rem;
	font-weight: 700;
	color: var(--dfl-accent-ink);
	margin-top: var(--dfl-space-xs);
	margin-bottom: var(--dfl-space-xs);
}

/* Library Policies page (post 239): the policy text is raw HTML pasted
   straight into .entry-content as plain <p> tags with no wrapping group
   blocks, so the site-wide ".entry-content > *" rule (margin-bottom:
   var(--dfl-gutter), meant for rhythm between page-level sections like
   headings/images/groups) applies to every single paragraph here — on top
   of Divi's own `p{padding-bottom:1em}`, doubling the gap between
   paragraphs. Client asked (2026-09-10) to drop the margin and keep just
   Divi's 14px padding for this page's paragraphs specifically. */
.page-id-239 .entry-content > p {
	margin-bottom: 0;
}

/* Accessibility audit fixes (2026-09-21) */

/* Divi's own inline Customizer CSS ships `.et-social-icon span{display:none}`
   for the footer Facebook/Instagram links — the icon glyph is the only
   visible content, but display:none also drops the span's "Facebook"/
   "Instagram" text from the accessibility tree, leaving the link with no
   name at all (axe: link-name). Swap to the standard visually-hidden
   pattern instead: the text stays out of view but is still announced. */
.et-social-icon span {
	display: inline-block !important;
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Divi's default #footer-info color (#666, tuned for a light background) is
   only 2.38:1 against this site's dark-ink footer — fails WCAG AA (needs
   4.5:1 for 14px text; axe: color-contrast). Match the light text color
   already used for everything else in the footer. */
#footer-info {
	color: var(--dfl-paper);
}

/* Divi's own inline Customizer CSS sets Contact Form fields (the real ILL
   Overview request form, and any future form built the same way) to a
   light #999 on a #eee fill — 2.46:1, fails WCAG AA color-contrast for
   both placeholder and typed text. --dfl-muted already clears 4.5:1 on
   this exact background and is the token this site already uses for
   secondary/muted text elsewhere. */
.et_pb_contact .et_pb_contact_field input,
.et_pb_contact .et_pb_contact_field textarea {
	color: var(--dfl-muted);
}

/* Links inline within body copy (Latest News list, Upcoming Events list,
   and any future "click here"-style content link) are only distinguished
   from surrounding text by color — the sitewide `a, a:hover
   {text-decoration:none}` base rule removes the one non-color cue WCAG
   1.4.1 requires (axe: link-in-text-block). Button/card-styled links keep
   their own shape/border affordance and are excluded so this doesn't
   double-underline the Quick Links row or the Children/Teens card grid. */
.entry-content p a,
.entry-content li a,
.entry-content td a,
.wp-block-latest-posts__post-title a {
	text-decoration: underline;
}
.entry-content .wp-block-button__link,
.entry-content .dfl-card-list a {
	text-decoration: none;
}

/* Medium devices (768px and up) */
@media (min-width: 768px) {
	.entry-content ul.wp-block-list.dfl-card-list {
		grid-template-columns: repeat(2, 1fr);
	}
}
/* Large devices (992px and up) */
@media (min-width: 992px) {
	.entry-content ul.wp-block-list.dfl-card-list {
		grid-template-columns: repeat(3, 1fr);
	}
}
