/* "Basic" is loaded via <link> tags in each page's <head> instead of
   @import here — see the comment above those links for why. */
.basic-regular {
  font-family: "Basic", sans-serif;
  font-weight: 400;
  font-style: normal;
}

/* Belt-and-suspenders against horizontal scroll: sub-pixel rounding
   in mobile viewport metrics (the same class of issue .header's
   left/right: 0 above already works around) can occasionally still
   leave 1-2px of horizontal overflow on some devices even when no
   single element is visibly too wide. Nothing on the site relies on
   horizontal scroll/overflow, so this is a safe guarantee rather than
   a workaround for a specific element. */
html {
    overflow-x: hidden;
}

body {
    margin: 0;
    overflow-x: hidden;
    background-color: #F5F1E8;
    color: #2C2C2A;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    /* On mobile browsers, 100vh is measured against the viewport with
       the address/toolbar hidden — its largest possible size. When the
       toolbar is showing (e.g. after the page settles at the very
       bottom of a scroll), the actual visible area is shorter than
       that, leaving a gap below the footer. 100dvh tracks the toolbar
       and always matches the real visible height; browsers that don't
       support it just keep using the 100vh above. */
    min-height: 100dvh;
    /* Applies "Basic" to all text on the site via inheritance —
       see .basic-regular above for the same properties as a
       standalone utility class. */
    font-family: "Basic", sans-serif;
    font-weight: 400;
    font-style: normal;
}

/* Pushes the footer to the bottom of the viewport on pages whose
   content is shorter than the screen, without affecting pages
   where the content already exceeds the viewport height. */
#footer-placeholder {
    margin-top: auto;
}

/* Applies to every <p> except the one in the header (the "Glenn R
   Miller" site name/logo link, which is navigation, not body copy) —
   buttons and nav menus don't use <p> tags at all, so no exclusion
   is needed for those. */
p {
    line-height: 1.5;
}

.header p {
    line-height: normal;
}

.header {
    /* left: 0; right: 0 instead of width: 100% — on some mobile
       viewports window.innerWidth (what a fixed element's width: 100%
       resolves against) doesn't match document.documentElement.clientWidth
       (what actually determines horizontal scroll), so width: 100% can
       render the header wider than the visible viewport and cause
       horizontal scroll on the whole page. left/right: 0 pins both
       edges directly, which isn't subject to that mismatch. */
    left: 0;
    right: 0;
    display: flex;
    /* Keeps "Glenn R Miller" and the nav row vertically centered
       together. The Books dropdown's padding-bottom growth (below)
       adds space after this content box, so it doesn't affect this
       alignment. */
    align-items: center;
    position: fixed;
    top: 0;
    z-index: 1000;
    padding-bottom: 0;
    transition: background-color 0.2s, padding-bottom 0.3s ease, transform 0.3s ease;
    /* Forces the header onto its own GPU compositing layer. Without
       this, mobile browsers can desync a "position: fixed" element from
       the viewport during elastic/rubber-band overscroll (e.g. the
       bounce from pulling down past the top of the page), leaving it
       stranded at the wrong spot — or scrolled out of view entirely —
       until the next scroll or repaint puts it back. */
    will-change: transform;
}

/* Soft dark scrim behind the logo/nav on pages where the header still
   has no background of its own (i.e. before scrolling on the homepage
   hero) — keeps the white nav text readable against bright hero
   imagery without giving the header a visible background yet. Sits
   behind the header's own content (negative z-index) but above the
   header's background-color, so it's faded out via .has-bg once that
   background-color is applied instead of stacking on top of it. */
.header::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 140px;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0));
    pointer-events: none;
    z-index: -1;
    opacity: 1;
    transition: opacity 0.2s;
}

.header.has-bg::before {
    opacity: 0;
}

/* Grows the header itself downward while "Books" is hovered, so the
   green bar is the thing animating — the dropdown just becomes
   visible within the extra space this opens up beneath it. */
.header:has(.dropdown:hover) {
    padding-bottom: 80px;
}

.header a,
.header .standard_menu_item {
    color: #F7F3EC;
    /* Keeps the white nav text legible over bright/busy hero imagery
       before the header has its own background (see .header::before
       above). Removed once .has-bg is applied (below), since the
       solid background-color already gives the text enough contrast
       on its own. */
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
    transition: text-shadow 0.2s;
}

.header.has-bg a,
.header.has-bg .standard_menu_item {
    text-shadow: none;
}

.header_menu {
    display: flex;
    flex-direction: row;
    align-items: center;
    /* position: fixed; */
}

/* Hidden on desktop; only shown in the mobile media query below */
.hamburger_menu_button {
    display: none;
}

.mobile_menu_item_row {
    display: contents;
}

.dropdown_toggle {
    display: none;
}

.footer {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    justify-content: center;
    background-color: #0F6E56;
    color: #F7F3EC;
}

.footer a,
.footer .standard_menu_item {
    color: #F7F3EC;
}

.footer_menu ul {
    display: flex;
    flex-direction: row;
    margin-top: 10px;
}

/* Puts the icons to the right of "Glenn R Miller" on the same line
   (see components/footer.html), vertically centered against it.
   margin-bottom (moved off the h2 itself, below) keeps the same gap
   to the nav links beneath — kept here instead so the h2 has no
   margin of its own left to throw off the centering. margin-top is
   this row's own spacing above it. */
.footer_title {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    margin-bottom: 4px;
}

.social_media {
    display: flex;
    flex-direction: row;
    gap: 12px;
}

/* Both icon files are solid black artwork (LinkedIn's is a filled
   badge with the logo cut out; Instagram's is a black outline) —
   low contrast directly on the footer's dark green, so each link
   gets its own small off-white chip behind the icon instead of
   trying to recolor the icons themselves. */
.social_media a {
    display: flex;
    align-items: center;
    justify-content: center;
    /* 15% less than the original 30px */
    width: 25.5px;
    height: 25.5px;
    background-color: #F7F3EC;
    border-radius: 6px;
    transition: transform 0.2s, opacity 0.2s;
}

.social_media img {
    /* 15% less than the original 18px */
    width: 15.3px;
    height: 15.3px;
    display: block;
}

.social_media a:hover {
    opacity: 0.85;
    transform: translateY(-2px);
}

.footer_title h2 {
    font-size: 1.1rem;
    margin: 0;
}

/* Removing the bottom margin collapses the gap between this line and the menu */
.footer_title h3 {
    font-size: 0.85rem;
    font-weight: normal;
    margin-top: 0;
    margin-bottom: 0;
}

.name_logo {
    font-size: 28px;
    margin: 0px 30px;
}

ul {
    list-style-type: none;
    margin-left: auto;
    margin-right:30px;
    /* going to need to differentiate between header & footer to have header right and footer center? */
}

li {
    padding: 10px;
}

.name_logo {
    padding: 10px;
}

.content {
    margin: 0;
}

.hero {
    height: 90vh;
    display: flex;
    padding-left: 60px;
    padding-right: 60px;
    padding-top: 80px;
}

/* position: relative + z-index: 0 gives .hero_bg_img's own z-index: -1
   (below) a local stacking context to sit within, instead of slipping
   behind the whole page. */
.hero_img_background {
    position: relative;
    z-index: 0;
}

/* A real <img> (see index.html) instead of a CSS background-image —
   background-images are only discovered once the CSSOM is built,
   after the browser's early preload scan of the raw HTML, which was
   delaying the start of this download relative to everything else on
   the page. object-fit/object-position replicate the old
   background-size: cover/background-position: center. */
.hero_bg_img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    z-index: -1;
}

.hero_book_cover {
    display: flex;
    flex-direction: row;
    align-items: center;
    /* need to fix the vertical position of the image here  */
    margin-left: 15%;
    margin-right: 5%;
}

/* The <a> wrapping the cover (links to rough-cuts.html) needs to be
   a flex box too, or the img inside it has nothing to size itself
   against — same reasoning as .additional_work_book_cover a.
   align-items centers the img (a fixed 28em tall) vertically within
   this box, which is stretched by .hero's own layout to the full
   height of .hero — without it, the img sits flush against the top
   instead of centered in that space. */
.hero_book_cover a {
    display: flex;
    align-items: center;
    height: 100%;
}

.hero_book_cover img {
    /* max-height: 80%; */
    /* height: 60%; */
    height: 28em;
    /* Now that width/height attributes are set in the HTML (to
       prevent layout shift while the image loads), this flex item
       needs an explicit "width: auto" — without it, some browsers
       size the box to the image's raw pixel width instead of
       scaling it to match the height above, distorting the cover. */
    width: auto;
    /* Cast only to the bottom-right, like light falling from the
       upper left — gives the flat cover a slight illusion of sitting
       above the page instead of being printed flat on it. Deepens
       on hover (below) to reinforce the lift alongside the scale. */
    box-shadow: 4px 6px 10px rgba(0, 0, 0, 0.25);
    /* Subtle scale effect on hover to signal the cover is clickable —
       same treatment as .additional_work_book_cover and
       .buy-book-cover-link. */
    transition: transform 0.2s, box-shadow 0.2s;
    /* padding: 10px; */

}

.hero_book_cover a:hover img {
    transform: scale(1.03);
    box-shadow: 6px 10px 16px rgba(0, 0, 0, 0.32);
}

.hero_text {
    padding-top: 60px;
    /* transform moves it purely visually — unlike margin, it doesn't
       change the space this flex item occupies, so .hero_book_cover
       (and everything else in the row) stays exactly where it was.
       Net +50px right of center (-30, +60, +15, +5) and +10px down. */
    transform: translate(50px, 10px);
}

.additional_work_container {
    padding: 0px 60px;
    margin-bottom: 40px;

    /* Need to standardize the size of the book covers (probably)
    or at least adjust to make the differences less stark */
}

.section_header {
    padding-top: 27px;
    font-size: 40px;
}

.additional_work {
    /* padding-top: 60px; */
    height: 60%;
    display: flex;
    position: relative;
}

/* Background image lives on its own layer behind the text/cover
   (real DOM children), so its opacity can be adjusted independently
   of them — opacity on .additional_work itself would fade everything
   inside it too. Bled out past .additional_work's own box on all
   sides (rather than inset: 0) so the image reaches the viewport's
   left/right edges and the footer's top edge, without moving
   .additional_work or its content at all — this pseudo-element is
   the only thing being resized. Left/right cancel out exactly
   .additional_work_container's 60px side padding (its own edges
   already sit flush with the viewport, since nothing constrains its
   width); bottom cancels out the 40px gap (the container's
   margin-bottom) between .additional_work and the footer below it. */
.additional_work::before {
    content: "";
    position: absolute;
    /* No "top" — height instead comes from aspect-ratio (matching the
       source image, 1867x1333) at the full bled-out width below, and
       "bottom" anchors that box so it grows upward from the footer's
       top edge rather than being capped at .additional_work's own
       height. That's what lets the full image show uncropped left-to-
       right while still starting exactly at the bottom of the div —
       constraining top: 0 like the other sides previously clipped
       whatever didn't fit in .additional_work's own (shorter) height. */
    left: -60px;
    right: -60px;
    bottom: -40px;
    aspect-ratio: 1867 / 1333;
    background-image: url(media/glenn-r-miller-ny-skyline.png);
    background-repeat: no-repeat;
    background-size: 100% 100%;
    opacity: 0.1;
    z-index: -1;
}

.additional_work_book_cover {
    display: flex;
    flex-direction: row;
    align-items: center;
    margin-left: 15%;
    margin-right: 5%;
    height: 28em;

    
}

.additional_work_text {
    width: 70%;
}

/* The <a> wrapping the cover (added so it links to the book page)
   needs to be a height:100% flex box too, or the "height: 100%" on
   the image below has nothing to resolve against and the image
   renders at its native pixel size instead. */
.additional_work_book_cover a {
    display: flex;
    height: 100%;
}

.additional_work_book_cover img {
    height: 100%;
    /* See the matching comment on .hero_book_cover img — needed so
       this flex item scales to match the height above instead of
       rendering at the image's raw pixel width. */
    width: auto;
    /* Cast only to the bottom-right, like light falling from the
       upper left — gives the flat cover a slight illusion of sitting
       above the page instead of being printed flat on it. Deepens
       on hover (below) to reinforce the lift alongside the scale. */
    box-shadow: 4px 6px 10px rgba(0, 0, 0, 0.25);
    /* Subtle scale effect on hover to signal the cover is clickable —
       same treatment as .buy-book-cover-link on buy.html. */
    transition: transform 0.2s, box-shadow 0.2s;
}

.additional_work_book_cover a:hover img {
    transform: scale(1.03);
    box-shadow: 6px 10px 16px rgba(0, 0, 0, 0.32);
}

.awards {
    width: 100%;
    margin: 10px 0px 30px 0px;
}

.awards_container {
    width: 100%;
    display: flex;
    justify-content: space-evenly;
}

.single_award_container {
    border: 2px solid #0F6E56;
    display: flex;
    width: 20%;
    justify-content: center;
    align-items: center;
    aspect-ratio: 1;
    /* Required so the ::before pseudo-element is positioned relative to this box */
    position: relative;
    cursor: pointer;
}

.award_copy {
    width: 80%;
    text-align: center;
    font-weight: bold;
    /* Hidden by default; fades in on hover */
    opacity: 0;
    transition: opacity 0.3s;
    /* z-index ensures the text sits above the ::before background layer */
    position: relative;
    z-index: 1;
}

.single_award_container:hover .award_copy {
    opacity: 1;
}

/* ::before is a pseudo-element — an invisible layer automatically inserted
   before the box's content. We use it to hold the background image so we
   can control its opacity independently from the text sitting on top of it. */
.single_award_container::before {
    content: '';
    position: absolute;
    inset: 0; /* shorthand for top/right/bottom/left all = 0, filling the box */
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    opacity: 1;
    transition: opacity 0.3s;
}

.single_award_container:hover::before {
    opacity: 0.25;
}

/* Each award box gets its own background image on the ::before layer */
#award_dragonfly::before {
    background-image: url('media/royal-dragonfly.png');
}

#award_bookfest::before {
    background-image: url('media/best-bookfest.jpg');
}

/* Top padding clears the 111px fixed header plus a 60px gap; bottom
   padding is that same 60px gap on its own (nothing fixed to clear
   down there), so the whitespace above and below the content matches. */
.bio_content_container {
    display: flex;
    justify-content: center;
    padding: 171px 60px 60px 60px;
}

.bio_text_container {
    padding: 1% 4% 1% 0;
}

/* Zeroes the browser's default h2 top margin, which would otherwise
   stack on top of .bio_content_container's own padding-top and throw
   off the top/bottom balance that padding is meant to create. */
.bio_text_container h2 {
    margin-top: 0;
}

.bio_photo_container img {
    border: 1px solid #2C2C2A;
    /* height:fit-content; */
}

.bio_photo_container img {
    height: 28em;
    width: auto;
}

/* Book/publisher names are italicized everywhere they appear in
   static page text — this class is already used throughout the
   site's HTML to mark them, it just had no styling of its own yet. */
.title {
    font-style: italic;
}

/* The 4 book-title headings (hero "Rough Cuts", "Other Work"
   "Doorman Wanted" on index.html, and the page <h1> titles on
   rough-cuts.html/doorman-wanted.html) — bold, and the same color as
   the CTA buttons (.buttons a / .buy-button) so they visually tie
   together. */
.title.basic-regular {
    font-weight: bold;
    font-size: 48px;
    font-style: normal;
    color: #6B2D5C;
}

a {
    text-decoration: none;
    color: #2C2C2A;
}

/* Reads as plain text until interacted with — explicitly matches
   the surrounding paragraph's own color (rather than relying on the
   "a" rule above happening to use the same value) so it stays right
   even inside a box with its own text color, with the link only
   revealing itself on hover, focus, or while being clicked. */
.publisher-link {
    color: inherit;
    transition: color 0.2s;
}

.publisher-link:hover,
.publisher-link:focus,
.publisher-link:active {
    color: #555;
    text-decoration: underline;
}

.standard_menu_item {
    transition: color 0.2s;
}

.standard_menu_item:hover {
    color: white;
    text-decoration: underline;
}

.buttons a,
.buttons button {
    background-color: #6B2D5C;
    padding: 4px 10px;
    border: 1px solid #4C1F41;
    color: white;
    display: inline-block;
    transition: background-color 0.2s, transform 0.2s;
}

/* Resets browser default <button> chrome (font, cursor) so it reads
   identically to the .buttons a links used everywhere else on the site. */
.buttons button {
    font: inherit;
    cursor: pointer;
}

.buttons a:hover,
.buttons button:hover {
    background-color: #55234A;
    transform: translateY(-2px);
}

/* Space between the Doorman Wanted blurb and the "Learn More" button
   beneath it, in the "Other Work" section on the homepage. */
.additional_work_text .buttons {
    margin-top: 20px;
}

/* --- Buy Page --- */

/* Adds top padding so content clears the fixed header */
.buy-page {
    padding: 60px;
}

/* Stacks the two book rows vertically. margin-top is tuned so the
   gap above the first cover (.buy-page's padding-top + this margin +
   this padding-top, minus the header's height) matches the same gap
   on the individual book pages (.book-page's padding-top + .book-
   page-content's margin-top). */
.buy-books-container {
    display: flex;
    flex-direction: column;
    gap: 60px;
    padding: 40px 0;
    margin-top: 60px;
}

/* Each book row: cover on the left, details on the right */
.buy-book {
    display: flex;
    flex-direction: row;
    gap: 40px;
    align-items: flex-start;
}

.buy-book-cover-link {
    display: block;
    flex-shrink: 0; /* Prevents the cover from squishing when the text is long */
}

.buy-book-cover-link img {
    height: 22em;
    width: auto;
    /* Cast only to the bottom-right, like light falling from the
       upper left — gives the flat cover a slight illusion of sitting
       above the page instead of being printed flat on it. Deepens
       on hover (below) to reinforce the lift alongside the scale. */
    box-shadow: 4px 6px 10px rgba(0, 0, 0, 0.25);
    /* Subtle scale effect on hover to signal the cover is clickable */
    transition: transform 0.2s, box-shadow 0.2s;
}

.buy-book-cover-link:hover img {
    transform: scale(1.03);
    box-shadow: 6px 10px 16px rgba(0, 0, 0, 0.32);
}

/* Text block to the right of the book cover */
.buy-book-details {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

/* "Coming Fall 2026" label beneath the Rough Cuts title */
.buy-book-status {
    margin: 0 0 12px 0;
    font-style: italic;
    color: #555;
}

/* Three purchase buttons displayed in a horizontal row */
.buy-buttons {
    display: flex;
    flex-direction: row;
    gap: 12px;
    margin-top: 16px;
}

/* Pulls the buttons closer to "Preorder Now" on the Rough Cuts page
   than the default margin-top above — scoped to this heading only
   so buy.html's own button rows are unaffected. */
.preorder-heading {
    margin-bottom: 4px;
}

.preorder-heading + .buy-buttons {
    margin-top: 8px;
}

/* Individual purchase button — matches the existing .buttons a style */
.buy-button {
    background-color: #6B2D5C;
    padding: 6px 14px;
    border: 1px solid #4C1F41;
    text-decoration: none;
    color: white;
    display: inline-block;
    transition: background-color 0.2s, transform 0.2s;
}

.buy-button:hover {
    background-color: #55234A;
    transform: translateY(-2px);
}

/* --- Book Detail Pages (doorman-wanted.html, rough-cuts.html) --- */

/* Adds top padding so content clears the fixed header.
   The header is fixed (overlays the page), so pages need
   explicit top padding to push their content below it. */
.book-page {
    padding: 120px 60px 60px 60px;
}

/* Cover image on the left, text details on the right */
.book-page-content {
    display: flex;
    flex-direction: row;
    gap: 40px;
    align-items: flex-start;
    margin-top: 40px;
}

.book-page-content img {
    height: 26em;
    width: auto;
    /* Cast only to the bottom-right, like light falling from the
       upper left — gives the flat cover a slight illusion of sitting
       above the page instead of being printed flat on it. */
    box-shadow: 4px 6px 10px rgba(0, 0, 0, 0.25);
    flex-shrink: 0; /* Prevents the cover from squishing when the text is long */
}

/* Text block to the right of the cover */
.book-page-details {
    display: flex;
    flex-direction: column;
}

/* "Praise for..." section beneath the cover/details row. Hidden
   entirely by renderBlurbs() (blurbs.js) when the book has no blurbs
   in book-blurbs.js, rather than showing an empty heading. */
.blurbs-section {
    margin-top: 40px;
}

.blurb-container {
    display: flex;
    flex-direction: column;
    gap: 20px;
    margin-top: 20px;
}

/* Rendered as a <div> when the blurb has no link, or an <a> when it
   does (see renderBlurbCard in blurbs.js) — same box either way, so
   the styling lives on the shared .blurb-card class regardless. */
.blurb-card {
    display: block;
    padding: 16px 20px;
    color: inherit;
    text-decoration: none;
    box-shadow: 0 4px 6px -2px rgba(0, 0, 0, 0.15);
    transition: transform 0.2s, box-shadow 0.2s;
}

/* Only linked blurbs get the hover lift — an unlinked card isn't
   clickable, so hinting otherwise would be misleading. The drop
   shadow itself is always on (above); hover just deepens it slightly
   to reinforce the lift. */
a.blurb-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 10px -2px rgba(0, 0, 0, 0.2);
}

/* The "Doorman Wanted" blurb, specifically (not the "Rough Cuts" one
   in the hero, and not blurbs elsewhere on the site) — sits directly
   on the .additional_work skyline background, where the drop shadow
   looked out of place, so it's turned off just for this instance. */
#doorman-blurb-container .blurb-card,
#doorman-blurb-container a.blurb-card:hover {
    box-shadow: none;
}

.blurb-text {
    margin: 0;
}

/* Right-aligned beneath the blurb, matching the source's usual
   placement in other quote treatments across the site. Only the
   source itself is italicized (see .blurb-source-text) — when an
   author is also shown, it stays upright ("Author, Source"). */
.blurb-source {
    margin: 10px 0 0 0;
    text-align: right;
}

.blurb-source-text {
    font-style: italic;
}

/* --- Events --- */

/* Adds top padding so content clears the fixed header */
.events-page {
    padding: 120px 60px 60px 60px;
}

/* Sticks the "Events" heading just below the fixed site header
   (108px tall) so it stays in view while the event list scrolls
   underneath it. The background matches the page so scrolling
   cards don't show through. */
.events-header {
    position: sticky;
    top: 108px;
    z-index: 500;
    background-color: #F5F1E8;
    transition: box-shadow 0.2s, padding-bottom 0.2s;
    /* Cancels .events-page's own side padding so this bleeds edge-to-edge,
       then re-adds it as padding so "Events" doesn't shift position. */
    margin-left: -60px;
    margin-right: -60px;
    padding-left: 60px;
    padding-right: 60px;
    /* Replaces the h1's default bottom margin with padding (same 27px
       amount) so the space below "Events" is part of this sticky box. */
    margin-top: 0;
    margin-bottom: 0;
    padding-bottom: 27px;
}

/* Added once the user starts scrolling, so the stuck heading
   reads as its own layer above the event cards passing beneath it. */
.events-header.scrolled {
    box-shadow: 0 4px 6px -2px rgba(0, 0, 0, 0.15);
    /* 15% more breathing room below "Events" while scrolled */
    padding-bottom: 31px;
}

.events-container {
    display: flex;
    flex-direction: column;
    gap: 20px;
    margin-top: 20px;
}

/* Desktop: 2 cards per row on the full Events list page (not the
   homepage preview column, which stays single-column). Reverted to
   one column on mobile, see the media query. */
.events-page .events-container {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
}

.event-card {
    border: 1px solid #0F6E56;
    padding: 16px 20px;
    background-color: #F7F3EC;
    /* Same lift-on-hover feedback used by the site's buttons (.buttons a, .buy-button) */
    transition: transform 0.2s, border-width 0.2s, box-shadow 0.2s;
}

/* Desktop: 1px thicker border (2px total) and the same drop shadow
   used by the sticky "Events"/"News" heading once scrolled — only on
   hover, and only on desktop (see the media query, which neutralizes
   this for touch devices that can linger on :hover after a tap). */
.event-card:hover {
    transform: translateY(-2px);
    border-width: 2px;
    box-shadow: 0 4px 6px -2px rgba(0, 0, 0, 0.15);
}

/* Right-facing arrow, vertically centered — only on the full Events
   list page (events.html), not the homepage preview cards. Reserves
   the space at all times (rather than only on hover) so the arrow
   fading in doesn't shift the card's text.
.events-page .event-card {
    position: relative;
    padding-right: 90px;
}

.events-page .event-card::after {
    content: '\2192';
    position: absolute;
    top: 50%;
    right: 30px;
    transform: translateY(-50%);
    font-size: 60px;
    color: #0F6E56;
    opacity: 0;
    transition: opacity 0.2s ease;
    pointer-events: none;
}

.events-page .event-card:hover::after {
    opacity: 1;
}
*/

.event-date {
    margin: 0 0 6px 0;
    font-weight: bold;
    color: #555;
    /* Guarantees a single line, regardless of how long the
       formatted date/time turns out to be. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Fixed to exactly two lines (line-height x 2) regardless of the
   actual title length, so every card's summary is the same height
   and .event-location always sits in the same spot beneath it. */
.event-title {
    margin: 0 0 6px 0;
    font-size: 18px;
    line-height: 24px;
    height: 48px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* Always the last line of the visible summary now (the description
   moved below it, see .event-description), so no trailing margin —
   the gap down to the card's bottom border is just the 16px padding,
   matching the 16px gap at the top. */
.event-location {
    margin: 0;
    font-style: italic;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Reserves a full line even when an event has no location, so
       every card is the same height whether or not this is blank —
       an empty <p> would otherwise collapse to 0. */
    min-height: 24px;
}

/* Collapsed to zero height by default; expands into view on hover,
   growing to fit however much description text there is (no fixed
   or guessed height) rather than floating over the content below —
   the grid-template-rows 0fr->1fr animates smoothly to "auto" size,
   which plain height/max-height can't do. Because this is normal
   in-flow content (not positioned), every card below this one gets
   pushed down as it opens. The 10px gap above the description lives
   here as padding-top (added only on hover, alongside the row
   growing) rather than as the description's own margin — a margin
   would still count toward the row's minimum size even while
   collapsed, leaving a few px of unwanted height on every card. */
.event-description-wrap {
    display: grid;
    grid-template-rows: 0fr;
    padding-top: 0;
    transition: grid-template-rows 0.25s ease, padding-top 0.25s ease;
}

.event-card:hover .event-description-wrap {
    grid-template-rows: 1fr;
    padding-top: 10px;
}

.event-description {
    margin: 0;
    overflow: hidden;
    min-height: 0;
}

.no-events-message {
    color: #555;
    font-style: italic;
}

/* Homepage preview section — Upcoming Events and Latest News sit
   side by side in two equal columns on desktop (stacked on mobile,
   see the media query below). This wrapper owns the page's usual
   60px side padding; the two columns underneath no longer need it. */
.home-preview-container {
    display: flex;
    flex-direction: row;
    gap: 60px;
    padding: 0px 60px 40px 60px;
}

/* Each column is a flex column so its card list (flex-grow: 1 below)
   can stretch to fill any leftover height — .home-preview-container's
   default stretch already makes both columns the same overall height,
   so this is what keeps the two "See All..." buttons level with each
   other even if one column ends up with fewer/shorter cards. */
.events-preview-container,
.news-preview-container {
    flex: 1;
    min-width: 0; /* Lets long card text wrap instead of overflowing the column */
    display: flex;
    flex-direction: column;
}

.events-preview-container .events-container,
.news-preview-container .news-container {
    flex-grow: 1;
    min-height: 0;
}

/* Added by script.js (via index.html) when there are no upcoming
   events — drops the Events column entirely, rather than showing an
   empty state, so News is left as the only flex item and stretches
   (flex: 1, above) to fill the full row on its own. */
.home-preview-container.no-upcoming-events .events-preview-container {
    display: none;
}

/* Space between the last Event/News card and its "See All..." button
   — a minimum, not a fixed gap: flex-grow above adds more than this
   whenever the two columns' card lists aren't naturally the same height. */
.events-preview-container .buttons,
.news-preview-container .buttons {
    margin-top: 40px;
}

/* --- News --- */
/* Mirrors the Events page pattern above exactly — same sticky
   heading, same card styling — just for articles instead. */

/* Adds top padding so content clears the fixed header */
.news-page {
    padding: 120px 60px 60px 60px;
}

/* Sticks the "News" heading just below the fixed site header
   (108px tall) so it stays in view while the article list scrolls
   underneath it. The background matches the page so scrolling
   cards don't show through. */
.news-header {
    position: sticky;
    top: 108px;
    z-index: 500;
    background-color: #F5F1E8;
    transition: box-shadow 0.2s, padding-bottom 0.2s;
    /* Cancels .news-page's own side padding so this bleeds edge-to-edge,
       then re-adds it as padding so "News" doesn't shift position. */
    margin-left: -60px;
    margin-right: -60px;
    padding-left: 60px;
    padding-right: 60px;
    /* Replaces the h1's default bottom margin with padding (same 27px
       amount) so the space below "News" is part of this sticky box. */
    margin-top: 0;
    margin-bottom: 0;
    padding-bottom: 27px;
}

/* Added once the user starts scrolling, so the stuck heading
   reads as its own layer above the news cards passing beneath it. */
.news-header.scrolled {
    box-shadow: 0 4px 6px -2px rgba(0, 0, 0, 0.15);
    /* 15% more breathing room below "News" while scrolled */
    padding-bottom: 31px;
}

.news-container {
    display: flex;
    flex-direction: column;
    gap: 20px;
    margin-top: 20px;
}

/* Desktop: 2 cards per row on the full News list page (not the
   homepage preview column, which stays single-column). Reverted to
   one column on mobile, see the media query. */
.news-page .news-container {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
}

/* Rendered as an <a> when the article has a url (see renderNewsCard
   in news.js), so the whole card — not just the title — is
   clickable; the anchor reset (display/color/text-decoration) below
   keeps it looking identical to a plain box either way. */
.news-card {
    display: block;
    border: 1px solid #0F6E56;
    padding: 16px 20px;
    background-color: #F7F3EC;
    color: inherit;
    text-decoration: none;
    /* Same lift-on-hover feedback used by the site's buttons (.buttons a, .buy-button) */
    transition: transform 0.2s, border-width 0.2s, box-shadow 0.2s;
}

/* Desktop: 1px thicker border (2px total) and the same drop shadow
   used by the sticky "Events"/"News" heading once scrolled — only on
   hover, and only on desktop (see the media query, which neutralizes
   this for touch devices that can linger on :hover after a tap). Only
   the linked (<a>) form of the card gets this — an article without a
   url isn't clickable, so hinting otherwise would be misleading. */
a.news-card:hover {
    transform: translateY(-2px);
    border-width: 2px;
    box-shadow: 0 4px 6px -2px rgba(0, 0, 0, 0.15);
}

/* Right-facing arrow, vertically centered — only on the full News
   list page (news.html), not the homepage preview cards. Reserves
   the space at all times (rather than only on hover) so the arrow
   fading in doesn't shift the card's text.
.news-page .news-card {
    position: relative;
    padding-right: 90px;
}

.news-page .news-card::after {
    content: '\2192';
    position: absolute;
    top: 50%;
    right: 30px;
    transform: translateY(-50%);
    font-size: 60px;
    color: #0F6E56;
    opacity: 0;
    transition: opacity 0.2s ease;
    pointer-events: none;
}

.news-page .news-card:hover::after {
    opacity: 1;
}
*/

.news-date {
    margin: 0 0 6px 0;
    font-weight: bold;
    color: #555;
    /* Guarantees a single line, regardless of how long the
       formatted date turns out to be. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Fixed to exactly two lines (line-height x 2) regardless of the
   actual title length, so every card's summary is the same height
   and .news-source always sits in the same spot beneath it. */
.news-title {
    margin: 0 0 6px 0;
    font-size: 18px;
    line-height: 24px;
    height: 48px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* Always the last line of the visible summary now (the description
   moved below it, see .news-description), so no trailing margin —
   the gap down to the card's bottom border is just the 16px padding,
   matching the 16px gap at the top. */
.news-source {
    margin: 0;
    font-style: italic;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Reserves a full line even when an article has no source, so
       every card is the same height whether or not this is blank —
       an empty <p> would otherwise collapse to 0. */
    min-height: 24px;
}

/* Collapsed to zero height by default; expands into view on hover,
   growing to fit however much description text there is (no fixed
   or guessed height) rather than floating over the content below —
   the grid-template-rows 0fr->1fr animates smoothly to "auto" size,
   which plain height/max-height can't do. Because this is normal
   in-flow content (not positioned), every card below this one gets
   pushed down as it opens. The 10px gap above the description lives
   here as padding-top (added only on hover, alongside the row
   growing) rather than as the description's own margin — a margin
   would still count toward the row's minimum size even while
   collapsed, leaving a few px of unwanted height on every card. */
.news-description-wrap {
    display: grid;
    grid-template-rows: 0fr;
    padding-top: 0;
    transition: grid-template-rows 0.25s ease, padding-top 0.25s ease;
}

.news-card:hover .news-description-wrap {
    grid-template-rows: 1fr;
    padding-top: 10px;
}

.news-description {
    margin: 0;
    overflow: hidden;
    min-height: 0;
}

.no-news-message {
    color: #555;
    font-style: italic;
}

/* --- Dropdown Overlay --- */

/* Dims the rest of the page while a header dropdown (Books, About) is
   open, so attention stays on the menu. The .25s delay on transition
   only applies going IN — it's what makes the overlay wait until the
   dropdown has been open for a moment before appearing at all. Fading
   out (mouse leaves before or after that) happens immediately, with
   no delay, via the base rule below. */
.page-dim-overlay {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.1);
    opacity: 0;
    pointer-events: none;
    /* Above ordinary page content, below the header (z-index: 1000)
       and its dropdown so both stay fully visible and usable. */
    z-index: 900;
    transition: opacity 0.2s ease;
}

body:has(.dropdown:hover) .page-dim-overlay {
    opacity: 1;
    transition-delay: 0.05s;
}

/* --- Books Dropdown Menu --- */

/* Makes "Books" the anchor point for the absolutely-positioned dropdown */
.dropdown {
    position: relative;
    cursor: default;
}

/* The dropdown list itself no longer carries the "reveal" animation —
   .header's own padding-bottom (above) grows to do that. This just
   fades in quickly once the header has made room for it, anchored
   directly below "Books" without affecting that li's own width. */
.dropdown-menu {
    display: block;
    position: absolute;
    top: 100%;
    left: 0;
    margin: 0;
    padding: 0;
    padding-left: 10px;
    min-width: 160px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
}

/* Each link in the dropdown */
.dropdown-menu li {
    padding: 0;
}

.dropdown-menu a {
    display: block;
    padding: 10px 14px;
    color: #F7F3EC;
    white-space: nowrap; /* Prevents the link text from wrapping to a second line */
}

.dropdown-menu a:hover {
    text-decoration: underline;
    color: white;
}

/* Show the dropdown when the user hovers over the "Books" item */
.dropdown:hover .dropdown-menu {
    opacity: 1;
    pointer-events: auto;
}

/* Single column at every screen size — intro text on top, form below
   — rather than .bio_content_container's side-by-side row, so the
   form (and its width:100% fields below) always gets the full
   content width instead of sharing the row with the text block.
   Same 171px top clearance for the fixed header and 60px padding on
   the remaining sides as .bio_content_container. */
.contact_page {
    display: flex;
    flex-direction: column;
    padding: 171px 60px 60px 60px;
}

.contact_page_text {
    padding: 1% 4% 1% 0;
}

/* Zeroes the browser's default h1 top margin — same reasoning as
   .bio_text_container h2 above. */
.contact_page_text .section_header {
    margin-top: 0;
}

/* Shown in place of the form once it's submitted (see the inline
   script in contact.html). Reuses the footer's .social_media icon
   chips so the Instagram/LinkedIn links match the rest of the site
   instead of introducing a new icon treatment. */
.contact_thank_you h2 {
    margin-top: 0;
}

.contact_thank_you .social_media {
    margin-top: 20px;
}

/* The hidden attribute's built-in [hidden] { display: none } is
   lower-specificity than the class selector below and would
   otherwise lose to it, leaving the form visible after submission. */
.contact_page_form form[hidden] {
    display: none;
}

.contact_error {
    color: #B3261E;
    font-weight: bold;
}

.contact_page_form form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Stretches every field to the form's own width — without this the
   textarea's cols="100" attribute would render at its intrinsic
   character width, which is wider than the available column on both
   desktop and mobile and causes horizontal scroll. box-sizing keeps
   the border inside that 100% instead of adding to it. */
.contact_page_form input[type="text"],
.contact_page_form input[type="email"],
.contact_page_form textarea,
.contact_page_form fieldset {
    width: 100%;
    box-sizing: border-box;
    font-family: inherit;
}

/* Caps Name/Email at 500px on wide screens. width: 100% (above) still
   applies underneath this, so on any screen narrower than 500px plus
   .contact_page's own side padding, the field shrinks to fit its
   container instead of overflowing it — no extra media query needed. */
.contact_page_form input[type="text"],
.contact_page_form input[type="email"] {
    max-width: 500px;
}

/* Same treatment for the additional-details textarea, capped wider
   (750px) since it's meant to hold more text than a name/email field. */
.contact_page_form textarea {
    max-width: 750px;
}

/* Pulls each field 4px closer to its own label, bringing that gap
   down from the form's 12px inter-field gap to 8px — matching the
   legend-to-.contact_checkbox_option spacing. Scoped to just these
   three fields (by id) so the 12px gap between separate label/input
   sets — e.g. the Name input down to the Email label — is untouched. */
#name,
#email,
#additional_details {
    margin-top: -4px;
}

/* Checkboxes keep their natural (small) width — the width: 100% rule
   above is only for text-like fields. Each checkbox/label pair stays
   inline (the default flow), one pair per line via the <br> tags
   already in the markup — a flex container here would turn every
   child, including each label, into its own stacked row. */
.contact_checkbox_option input[type="checkbox"] {
    margin-right: 8px;
    vertical-align: middle;
}

.contact_checkbox_option label {
    display: inline-block;
    margin-bottom: 8px;
}

/* Strips the browser default fieldset border/padding so the legend
   lines up flush left with the Name/Email/Additional details labels
   above and below it, instead of being inset inside a boxed border. */
.contact_page_form fieldset {
    border: none;
    margin: 0;
    padding: 0;
}

.contact_page_form legend {
    padding: 0;
    margin-bottom: 8px;
}

/* Marks the Name/Email labels as required, plus the key at the top
   of the form explaining what the asterisk means. No existing
   site-standard "error/required" color, so this introduces a single
   new accent (a conventional required-field red) rather than reusing
   the brand plum, which is reserved for actions/links. */
.required_indicator {
    color: #B3261E;
    margin-left: 2px;
}

.form_required_note {
    font-size: 13px;
    color: #5A5A57;
    margin: 0 0 4px 0;
}

/* Small circular "?" badge that reveals a custom tooltip on hover/
   focus — a native title="" attribute can't be restyled with the
   site's font/colors, so this is a lightweight custom component
   built from the same brand palette as the rest of the form
   (.buttons a's plum background, the site's "Basic" font). */
.field_tooltip_trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    margin-left: 6px;
    border-radius: 50%;
    background-color: #6B2D5C;
    color: white;
    cursor: help;
    vertical-align: middle;
}

/* Isolated from the surrounding whitespace/nested tooltip markup so
   it's the only thing the flexbox centering above has to center. Its
   own nested flex centering (rather than relying on font line-height,
   which sits the glyph off-center within its line box) is what
   actually lines the "?" up in the middle of the circle. The
   translate is a small manual correction on top of that: flexbox
   only centers the font's line box, and the "Basic" font's "?"
   glyph sits low and slightly right within its own line box (visible
   ink doesn't fill it symmetrically), so a pure flex/box-based
   centering still looks off — confirmed by comparing against the
   rendered result, not just computed box metrics. */
.field_tooltip_icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-family: "Basic", sans-serif;
    font-size: 11px;
    line-height: 1;
    transform: translate(-0.5px, -1.8px);
}

/* Anchors the tooltip to the whole label/legend (not just the small
   trigger badge) so it can be centered over the text it belongs to,
   rather than off to one side under the badge. */
.contact_page_form label,
.contact_page_form legend {
    position: relative;
}

.field_tooltip {
    position: absolute;
    bottom: 130%;
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    background-color: #2C2C2A;
    color: #F5F1E8;
    font-family: "Basic", sans-serif;
    font-size: 13px;
    font-weight: 400;
    white-space: normal;
    width: max-content;
    max-width: 220px;
    box-sizing: border-box;
    padding: 6px 10px;
    border-radius: 4px;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s, transform 0.2s;
    pointer-events: none;
    z-index: 10;
}

.field_tooltip_trigger:hover .field_tooltip,
.field_tooltip_trigger:focus .field_tooltip {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}

/* Re-adds the fieldset's old 12px left padding here instead, so the
   checkboxes/labels stay exactly where they were — only the legend
   moves flush left. */
.contact_page_form .contact_checkbox_option {
    padding-left: 12px;
}

/* -------------------------------------------------------
   Responsive layout — applies to screens 768px and under
   (phones and portrait tablets).

   How media queries work: the styles inside this block
   override the rules above ONLY when the screen is narrow.
   The desktop styles above remain unchanged.
------------------------------------------------------- */
@media (max-width: 768px) {

    /* Back to a single column on mobile — the 2-per-row grid is
       desktop-only. */
    .events-page .events-container,
    .news-page .news-container {
        grid-template-columns: 1fr;
    }

    /* Keep the name on the left and the hamburger button on the right,
       on a single row, instead of the desktop row-of-links layout */
    .header {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        padding-right: 20px;
        box-sizing: border-box;
    }

    /* Remove the auto left margin that pushes the menu to the right on desktop */
    ul {
        margin-left: 0;
    }

    /* The three-bar icon that opens the full-screen menu. Positioned
       and raised above the menu overlay so it stays visible (now as an
       "X") and clickable to close the menu once it's open. */
    .hamburger_menu_button {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        gap: 6px;
        width: 44px;
        height: 44px;
        flex-shrink: 0;
        position: relative;
        z-index: 1001;
        background: none;
        border: none;
        cursor: pointer;
        padding: 0;
    }

    .hamburger_bar {
        display: block;
        width: 26px;
        height: 3px;
        background-color: #F7F3EC;
        transition: transform 0.2s, opacity 0.2s;
    }

    /* Turns the three bars into an "X" once the menu is open
       (the "mobile-menu-open" class is added by script.js) */
    .header.mobile-menu-open .hamburger_bar:nth-child(1) {
        transform: translateY(9px) rotate(45deg);
    }

    .header.mobile-menu-open .hamburger_bar:nth-child(2) {
        opacity: 0;
    }

    .header.mobile-menu-open .hamburger_bar:nth-child(3) {
        transform: translateY(-9px) rotate(-45deg);
    }

    /* The nav menu itself is hidden until the hamburger opens it, at
       which point it expands to fill the whole screen */
    .header_menu {
        display: none;
        position: fixed;
        inset: 0;
        /* inset: 0's bottom: 0 resolves against .header's own (short,
           content-sized) box instead of the viewport — .header has
           will-change: transform (for GPU-compositing during
           rubber-band overscroll, see its own comment), which makes it
           the containing block for fixed descendants, the same way an
           actual transform would. vh/dvh units sidestep that entirely
           since they're always relative to the true viewport,
           regardless of containing block — explicit height here
           overrides the broken bottom: 0-derived height. 100dvh (with
           100vh fallback) matches the same mobile-toolbar-aware
           pattern used on body. */
        height: 100vh;
        height: 100dvh;
        /* Without this, the 110px/30px padding below adds on top of
           the 100dvh height instead of being carved out of it,
           overshooting the real viewport height by exactly that much. */
        box-sizing: border-box;
        margin: 0;
        padding: 110px 30px 30px 30px;
        background-color: #0F6E56;
        flex-direction: column;
        align-items: flex-start;
        gap: 6px;
        overflow-y: auto;
    }

    .header.mobile-menu-open .header_menu {
        display: flex;
    }

    .header_menu li {
        width: 100%;
        padding: 10px 0;
    }

    .header_menu .standard_menu_item {
        font-size: 1.5rem;
    }

    /* Puts "Books" and its caret button on the same row, at opposite ends */
    .mobile_menu_item_row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        width: 100%;
        cursor: pointer;
    }

    /* The caret button that expands/collapses the Books submenu.
       Hover doesn't work on touch devices, so mobile gets its own
       tap target instead of relying on :hover like desktop does. */
    .dropdown_toggle {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        background: none;
        border: none;
        cursor: pointer;
        padding: 0;
    }

    .dropdown_caret {
        display: block;
        width: 10px;
        height: 10px;
        border-right: 2px solid #F7F3EC;
        border-bottom: 2px solid #F7F3EC;
        transform: rotate(45deg);
        transition: transform 0.2s;
    }

    /* Points the caret up once its submenu is open
       ("mobile-dropdown-open" is added by script.js) */
    .dropdown.mobile-dropdown-open .dropdown_caret {
        transform: rotate(-135deg);
    }

    /* On mobile the submenu is toggled by tapping the caret, not by
       hovering, so it needs to sit in normal document flow (not the
       absolutely-positioned floating panel desktop uses) and default
       to hidden until "mobile-dropdown-open" is added. */
    .dropdown-menu {
        display: none;
        position: static;
        background-color: transparent;
        padding-left: 20px;
        margin-top: 6px;
        /* Undo the desktop fade animation — mobile still toggles with
           plain display: none/block via the caret button. */
        opacity: 1;
        pointer-events: auto;
        transition: none;
    }

    .dropdown.mobile-dropdown-open .dropdown-menu {
        display: block;
    }

    .dropdown-menu a {
        font-size: 1.2rem;
        padding: 10px 0;
        color: white;
    }

    /* Disables the desktop hover reveal so a tap-and-hold on a touch
       screen can't pop the submenu open outside of the caret toggle */
    .dropdown:hover .dropdown-menu {
        display: none;
    }

    /* Some touch browsers keep :hover active after a tap, which would
       otherwise grow the header on mobile too. Mobile only expands via
       the "mobile-menu-open" class instead. */
    .header:has(.dropdown:hover) {
        padding-bottom: 0;
    }

    /* Same reasoning — don't let a lingering touch :hover state dim
       the page on mobile, where the full-screen menu already covers it. */
    body:has(.dropdown:hover) .page-dim-overlay {
        opacity: 0;
    }

    .dropdown.mobile-dropdown-open:hover .dropdown-menu {
        display: block;
    }

    /* Stack hero text and book cover vertically; let height grow with content */
    .hero {
        flex-direction: column;
        height: auto;
        padding: 100px 20px 40px 20px;
    }

    /* Remove the large left margin used to position the cover on desktop.
       margin-top matches the gap .blurb-container already puts above
       itself (20px), so the space above/below the blurb is even now
       that the cover sits directly beneath it in the stacked layout. */
    .hero_book_cover {
        margin-left: 0;
        margin-right: 0;
        margin-top: 20px;
        justify-content: center;
    }

    /* Remove extra left padding from hero text so it doesn't feel cramped.
       Desktop's transform (shifts text right/down to visually balance
       against the book cover sitting beside it) doesn't apply once the
       two are stacked instead of side by side — left uncancelled, it
       pushed the title/text/blurb past the right edge of the viewport
       (causing horizontal scroll) and down far enough to overlap the
       book cover below. padding-top is also cut, since most of the gap
       above "Rough Cuts" comes from here, on top of .hero's own
       padding-top above. */
    .hero_text {
        padding-left: 0;
        padding-top: 20px;
        transform: none;
    }

    /* Tighten side padding for the "Other Work" section */
    .additional_work_container {
        padding: 0 20px;
    }

    /* The empty (&nbsp;) heading above "Doorman Wanted" exists only to
       reserve the same spacing "Other Work" used to take up (see the
       comment in index.html) — worth keeping on desktop, but on mobile
       that reserved gap just pushes "Doorman Wanted" down for no
       reason, so the heading (and its padding-top/line-height) is
       dropped entirely here instead of just zeroing the padding. Only
       targets this specific empty spacer, not the real "Upcoming
       Events"/"Latest News" headings or other pages' .section_header
       titles, whose mobile spacing is unaffected. */
    .additional_work_container > .section_header {
        display: none;
    }

    /* Skyline background is desktop-only — hidden on mobile rather
       than just repositioned, since the much taller stacked layout
       here would tile it repeatedly behind the text. */
    .additional_work::before {
        display: none;
    }

    /* Stack the book description and cover vertically; let height grow
       naturally. gap adds space between "Learn More" and the cover
       below it, now that they're stacked instead of side by side. */
    .additional_work {
        flex-direction: column;
        height: auto;
        padding-left: 0;
        margin-bottom: 40px;
        gap: 40px;
    }

    /* Let the text take full width instead of the fixed 70% used on desktop */
    .additional_work_text {
        width: 100%;
    }

    /* Centers the "Learn More" button in the middle of the screen —
       .buttons a is inline-block, so centering its text-align parent
       is enough, without affecting the buttons on desktop or the
       Events/News "See All..." buttons elsewhere on the page. */
    .additional_work_text .buttons {
        text-align: center;
    }

    /* Remove desktop margins and center the book cover */
    .additional_work_book_cover {
        margin-left: 0;
        margin-right: 0;
        height: auto;
        justify-content: center;
    }

    /* Scale book cover images to a readable size on small screens */
    .additional_work_book_cover img {
        height: 22em;
        width: auto;
    }

    /* Stack award boxes vertically instead of side by side, centered
       as a column, with even space between the two. */
    .awards_container {
        flex-direction: column;
        align-items: center;
        gap: 20px;
    }

    /* Widen each award box so it's readable on a narrow screen */
    .single_award_container {
        width: 70%;
    }

    /* Stack the bio photo and text vertically. Top padding clears the
       111px fixed header plus a 40px gap (matching the Events/News
       mobile heading gap); bottom padding is that same 40px on its
       own, so the whitespace above and below the content matches. */
    .bio_content_container {
        flex-direction: column;
        padding: 151px 20px 40px 20px;
    }

    /* Already a single column at every width (see .contact_page above)
       — only the top padding changes here, using the same 124px
       formula as .events-page/.news-page (111px fixed header + 40px
       gap - 27px already baked into .section_header's padding-top)
       since the "Contact Glenn" heading uses .section_header too. */
    .contact_page {
        padding: 124px 20px 40px 20px;
    }

    /* Desktop sizes the photo by a fixed height (28em), which on a
       narrow mobile viewport renders wider than .bio_content_container
       and bleeds past its right padding — sizing by width instead
       keeps it exactly as wide as the container, so the left/right
       margins (both the container's 20px side padding) end up even. */
    .bio_photo_container img {
        width: 100%;
        height: auto;
        /* Without this, the 1px border is added on top of the 100%
           width instead of inside it, making the image 2px wider than
           its container and off-center by those 2px. */
        box-sizing: border-box;
    }

    /* Tighten side padding for the Events page and homepage preview.
       Top padding is raised to 200px (not 100px) because the fixed
       header is much taller here than on desktop — the site name and
       nav links stack into two rows instead of sitting side by side. */
    /* 124px = 111px fixed header + 40px gap - 27px already baked into
       .section_header's padding-top, so "Events" sits 40px below the
       header. */
    .events-page {
        padding: 124px 20px 40px 20px;
    }

    /* Matches the page's narrower mobile side padding so the sticky
       heading still bleeds edge-to-edge without shifting "Events". */
    .events-header {
        margin-left: -20px;
        margin-right: -20px;
        padding-left: 20px;
        padding-right: 20px;
    }

    /* Stack News above Events on mobile instead of side by side.
       column-reverse flips the visual order to News-then-Events
       while leaving the underlying markup (Events, then News) alone. */
    .home-preview-container {
        flex-direction: column-reverse;
        gap: 40px;
        padding: 0 20px 40px 20px;
    }

    /* Less top padding than the other mobile pages — the fixed
       header here is a single ~111px row (no two-row wrap), so the
       shared 200px value was leaving a large empty gap above the
       cover image. */
    .book-page {
        padding: 130px 20px 40px 20px;
    }

    /* Stack the cover above the details instead of side by side —
       the row layout doesn't fit a mobile-width viewport and was
       forcing a horizontal scrollbar. */
    .book-page-content {
        flex-direction: column;
        /* Overrides the desktop-only "align-items: flex-start" —
           in a column layout that shrinks each child to its content's
           natural width instead of the available 335px, which is what
           was pushing the title/subtitle/paragraph text wide enough
           to cause the horizontal scroll. */
        align-items: stretch;
        /* Halves the ~59px gap between the header and the cover image
           (desktop's 40px margin-top was making it larger than needed
           once .book-page's own top padding already clears the header). */
        margin-top: 10px;
    }

    /* Scale the cover down and center it, matching the same
       treatment used for book covers elsewhere on mobile. */
    .book-page-content img {
        height: 22em;
        width: auto;
        align-self: center;
    }

    /* Stack the buy buttons instead of a horizontal row — several
       buttons side by side don't fit a mobile-width viewport. Used on
       the book pages and the Buy page alike. Same 12px gap as the row
       layout (flex gap works the same in either direction), so the
       spacing is unchanged. */
    .buy-buttons {
        flex-direction: column;
        align-items: stretch;
    }

    /* Less top padding than the shared 200px value — the fixed header
       here is a single ~111px row (no two-row wrap), matching the
       same fix already applied to the book pages. */
    .buy-page {
        padding: 130px 20px 40px 20px;
    }

    /* Cuts the gap above the first cover down to match the book
       pages' mobile gap (130px header clearance above + 10px here =
       the same total as .book-page-content's 10px margin-top). The
       desktop margin-top/padding-top here add up to far more than
       that once .buy-page's own top padding grew to clear the mobile
       header. */
    .buy-books-container {
        margin-top: 0;
        padding-top: 10px;
    }

    /* Stack each book's cover above its details instead of side by
       side — the row layout doesn't fit a mobile-width viewport and
       was forcing a horizontal scrollbar. */
    .buy-book {
        flex-direction: column;
        /* Overrides the desktop-only "align-items: flex-start" — in a
           column layout that shrinks each child to its content's
           natural width instead of the full available width, which is
           what was pushing the title/description/buttons wide enough
           to cause the horizontal scroll. */
        align-items: stretch;
    }

    /* Center the (already mobile-sized, 22em) cover above the text. */
    .buy-book-cover-link {
        align-self: center;
    }

    /* Matches the full-stretched width of the buy-buttons below it —
       "Learn More" is a plain inline-block link, not a flex item, so
       it doesn't stretch to fill .buy-book-details on its own. Left-
       aligned with the same padding as .buy-button, rather than
       centered, so the text lines up the same way in both. */
    .buy-book-details .buttons a {
        display: block;
        box-sizing: border-box;
        width: 100%;
        text-align: left;
        padding: 6px 14px;
    }

    /* 124px = 111px fixed header + 40px gap - 27px already baked into
       .section_header's padding-top, so "News" sits 40px below the
       header. */
    .news-page {
        padding: 124px 20px 40px 20px;
    }

    /* Matches the page's narrower mobile side padding so the sticky
       heading still bleeds edge-to-edge without shifting "News". */
    .news-header {
        margin-left: -20px;
        margin-right: -20px;
        padding-left: 20px;
        padding-right: 20px;
    }

    /* No hover-in arrow on mobile — touch devices don't have a true
       hover state to animate, so it's removed along with the extra
       padding reserved for it, reverting to the base card padding.
    .events-page .event-card,
    .news-page .news-card {
        padding-right: 20px;
    }

    .events-page .event-card::after,
    .news-page .news-card::after {
        content: none;
    }
    */

    /* The thicker border and drop shadow are desktop-only — also
       covers :hover, in case a touch device lingers on :hover after
       a tap instead of never triggering it at all. */
    .event-card,
    .news-card,
    .event-card:hover,
    .news-card:hover,
    a.news-card:hover {
        border-width: 1px;
        box-shadow: none;
    }

    /* Without this, the nowrap text below gives .event-card/.news-card
       an intrinsic min-width wider than .events-container/.news-container
       (a flex column), pushing the card past the viewport edge and
       causing horizontal scroll — min-width: 0 lets the card shrink
       back down to the container's width. */
    .event-card,
    .news-card {
        min-width: 0;
    }

    /* Wrap the date/location/source instead of truncating them to a
       single ellipsized line — at mobile widths the desktop nowrap
       treatment cuts off text that would otherwise fit on two lines. */
    .event-date,
    .event-location,
    .news-date,
    .news-source {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }
}
