/*!*******************************************************************************************************************************************************************************************************************************************!*\
  !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/scss/main.scss ***!
  \*******************************************************************************************************************************************************************************************************************************************/
/* Opts every same-origin navigation on the site into the native (Chromium
   for now — Safari/Firefox just navigate normally, no error, no transition)
   cross-document View Transition: a smooth crossfade between the old and
   new page, instead of the usual instant cut. Elements sharing a matching
   view-transition-name across the two pages (see js/mirmoc-menu.js:
   bindViewTransitionNames, and mirmoc_post_thumbnail() in
   inc/template-tags.php) morph into each other instead of just
   cross-fading independently. No JS framework, no DOM-swapping — every
   page still does a completely normal load, so nothing else in this file
   needs to change to support it. */
@view-transition {
	navigation: auto;
}

/* Browser default for the crossfade is 0.25s ease — same duration as
   MIR_EASE_DURATION (js/mirmoc-menu.js) but a plain "ease" curve, not the
   power2.inOut this site uses everywhere else. Trimmed a little quicker
   and switched to that same curve (its cubic-bezier approximation) so the
   page-to-page cut feels consistent with every other transition on the
   site, not just quicker. */
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
	animation-duration: 0.18s;
	animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
}

/*
  1. Use a more-intuitive box-sizing model.
*/


@font-face {
   font-family: 'GT-Maru-Bold';
    src: url('../fonts/GT-Maru-Bold.woff2') format('woff2'), url('../fonts/GT-Maru-Bold.woff') format('woff'), url('../fonts/GT-Maru-Bold.otf') format('opentype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}


@font-face {
    font-family: 'GT-Planar-Regular';
    src: url('../fonts/GT-Planar-Regular.woff2') format('woff2'), url('../fonts/GT-Planar-Regular.woff') format('woff');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}


*,
*::before,
*::after {
  box-sizing: border-box;
}
/*
    2. Remove default margin
  */
* {
  margin: 0;
}
/*
    Typographic tweaks!
    3. Add accessible line-height
    4. Improve text rendering
  */
body {
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
/*
    5. Improve media defaults
  */
img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}
/*
    6. Remove built-in form typography styles
  */
input,
button,
textarea,
select {
  font: inherit;
}
/*
    7. Avoid text overflows
  */
p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}



/* Global styles */
:root {

  /* Aliased to the theme.json palette (--wp--preset--color--*) so these
     stay in sync with the block editor's color picker and the .has-black-*
     / .has-white-* utility classes WP generates from it. */
  --mir-color-black: var(--wp--preset--color--black, #141419);
  --mir-color-white: var(--wp--preset--color--white, #FEFBF9);



  /* Aliased to the theme.json palette, same pattern as black/white/grey. */
  --mir-color-green-1: var(--wp--preset--color--green-1, #52a469);
  --mir-color-green-2: var(--wp--preset--color--green-2, #8eab92);
  --mir-color-green-3: var(--wp--preset--color--green-3, #cad1ca);

--mir-color-brown-1: var(--wp--preset--color--brown-1, #91562E);
--mir-color-brown-2: var(--wp--preset--color--brown-2, #B4774D);
--mir-color-brown-3: var(--wp--preset--color--brown-3, #D7B39A);
  
  /* Aliased to the theme.json palette (--wp--preset--color--*), same as
     black/white above — kept in sync with the block editor's color picker
     and the .has-grey-*-color / .has-grey-*-background-color classes it generates. */
  --mir-color-grey-1: var(--wp--preset--color--grey-1, #5D5A66);
  --mir-color-grey-2: var(--wp--preset--color--grey-2, #9F9DA6);
  --mir-color-grey-3: var(--wp--preset--color--grey-3, #E2E0E6);

  

  /* Aliased to the theme.json palette, same pattern as black/white/grey. */
  --mir-color-blue-1: var(--wp--preset--color--blue-1, #413DB6);
  --mir-color-blue-2: var(--wp--preset--color--blue-2, #7F7FE4);
  --mir-color-blue-3: var(--wp--preset--color--blue-3, #D4D4F6);


  /* Aliased to the theme.json spacing presets (--wp--preset--spacing--*),
     same pattern as the color palette/font families above — kept in sync
     with the block editor's padding/margin controls (GenerateBlocks'
     Container included, since it uses the same standard spacing UI) and
     these hand-written styles. */
  --mir-spacing-1: var(--wp--preset--spacing--1, 6px);
  --mir-spacing-2: var(--wp--preset--spacing--2, 10px);
  --mir-spacing-3: var(--wp--preset--spacing--3, 16px);
  --mir-spacing-4: var(--wp--preset--spacing--4, 26px);
  --mir-spacing-5: var(--wp--preset--spacing--5, 42px);
  --mir-spacing-6: var(--wp--preset--spacing--6, 68px);
  --mir-spacing-7: var(--wp--preset--spacing--7, 111px);
  --mir-spacing-8: var(--wp--preset--spacing--8, 181px);
  --mir-spacing-9: var(--wp--preset--spacing--9, 294px);

  /* Padding-specific scale — same 9 steps/values as spacing above, just
     its own token namespace. Spacing is also used for margin/gap all over
     this file (e.g. .mirmoc-menu-cards' gap, .mirmoc-project__desc's
     gap); aliasing padding separately means a viewport override (see
     .mirmoc-footer below) can retarget padding specifically without
     touching every margin/gap that happens to share the same numeric
     step. */
  --mir-padding-1: var(--mir-spacing-1);
  --mir-padding-2: var(--mir-spacing-2);
  --mir-padding-3: var(--mir-spacing-3);
  --mir-padding-4: var(--mir-spacing-4);
  --mir-padding-5: var(--mir-spacing-5);
  --mir-padding-6: var(--mir-spacing-6);
  --mir-padding-7: var(--mir-spacing-7);
  --mir-padding-8: var(--mir-spacing-8);
  --mir-padding-9: var(--mir-spacing-9);

--mir-font-planar: 'GT-Planar-Regular';
--mir-font-gtmaru: 'GT-Maru-Bold';

/* Semantic role token, aliased to the theme.json presets (--wp--preset--font-family--*)
   so the block editor's font picker and these hand-written styles stay in sync.
   Switch the active heading font here, or scope with .mir-font-alt on any
   ancestor to flip a section only. */
--mir-font-heading: var(--wp--preset--font-family--gtplanar, var(--mir-font-planar));
--mir-font-heading-alt: var(--wp--preset--font-family--gtmaru, var(--mir-font-gtmaru));

  --mir-font-family-sans-serif: "-apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, Adwaita Sans, Cantarell, Ubuntu, roboto, noto, helvetica, arial, sans-serif";
  --mir-font-family-serif: "Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol";
  --mir-font-family-mono: "Menlo, Consolas, Monaco, Adwaita Mono, Liberation Mono, Lucida Console, monospace";

  --mir-font-size-1: 10px;
  --mir-font-size-2: 16px;
  --mir-font-size-3: 26px;
  --mir-font-size-4: 42px;
  --mir-font-size-5: 68px;
  --mir-font-size-6: 111px;
  --mir-font-size-7: 181px;
  --mir-font-size-8: 294px;

   /* Line-height scale — matches font-size steps 1–8, shared by both
     fonts (GT Planar and GT Maru). font-size-2 (p, body copy) stays
     anchored at 1.25, untouched. Every other step now moves by a flat,
     slightly larger 0.08 per step (was a mix of 0.1 and 0.05) — h1
     (step 7) lands smaller (0.85) than before (0.95) as a result. */
  --mir-line-height-1: 1.33;
  --mir-line-height-2: 1.25;
  --mir-line-height-3: 1.17;
  --mir-line-height-4: 1.09;
  --mir-line-height-5: 1.01;
  --mir-line-height-6: 0.93;
  --mir-line-height-7: 0.85;
  --mir-line-height-8: 0.77;

  /* Letter-spacing (tracking) scale — GT Planar's own. font-size-2 (the
     body copy) is the anchor, nudged down to 0.0125em (was 0.025em).
     Same 0.0125em step from there. .mir-font-gtmaru below re-declares
     all eight for GT-Maru's own, subtler scale — the two fonts need
     different tracking, not one scale shared between them. */
  --mir-letter-spacing-1: 0.025em;
  --mir-letter-spacing-2: 0.0125em;
  --mir-letter-spacing-3: 0em;
  --mir-letter-spacing-4: -0.0125em;
  --mir-letter-spacing-5: -0.025em;
  --mir-letter-spacing-6: -0.0375em;
  --mir-letter-spacing-7: -0.05em;
  --mir-letter-spacing-8: -0.0625em;

  /* Font weights — named explicitly so nothing falls back to the
     browser's default bold heading weight and triggers faux bold
     on single-weight fonts like GT Planar. */
  --mir-font-weight-regular: 400;
  --mir-font-weight-medium: 500;
  --mir-font-weight-bold: 700;

  /* Aliased to theme.json's settings.custom.border.radius (--wp--custom--
     border-radius--*), same pattern as the color/spacing/font tokens
     above — keeps these in sync with whatever the block editor actually
     resolves var(--mir-border-radius-*) to, since border-radius has no
     preset-picker UI of its own to alias against directly. */
  --mir-border-radius-1: var(--wp--custom--border-radius--1, 8px);
  --mir-border-radius-2: var(--wp--custom--border-radius--2, 16px);
  --mir-border-radius-full: var(--wp--custom--border-radius--full, 999px);

  /* CSS-transition scale, for simple states like button hovers. Bigger
     components (the Projects overlay, further animations) use GSAP instead
     — see js/mirmoc-menu.js — since GSAP can't reach ::after pseudo-elements
     anyway, and CSS transitions are simpler/cheaper for a plain hover fade. */
  --mir-transition: 0.15s ease-in-out;

}



p {
    font-size: var(--mir-font-size-2);
    line-height: var(--mir-line-height-2);
    letter-spacing: var(--mir-letter-spacing-2);
    font-family: var(--mir-font-heading);
}

/* WordPress image captions — .wp-caption-text is the classic
   caption-shortcode output, figcaption is the block editor's Image block.
   Pinned to GT Planar specifically (not --mir-font-heading), same idea as
   .mir-font-eskapade/.mir-font-gtmaru: a caption shouldn't silently follow
   .mir-font-alt/.mir-font-gtmaru if either ever wraps it. */
.wp-caption-text,
figcaption {
    font-family: var(--mir-font-planar);
}

/* WordPress's font-size preset picker (theme.json settings.typography.
   fontSizes) only carries the size itself — .has-*-font-size is the
   utility class it generates, and it only ever sets font-size (with
   !important). Matching line-height/letter-spacing here is what makes a
   size picked in the block editor actually match this site's type scale
   instead of just the raw px value floating with the browser/theme
   default line-height. Mapped 1:1 to the same steps used for the
   font-size values themselves in theme.json. */
.has-small-font-size {
    line-height: var(--mir-line-height-1);
    letter-spacing: var(--mir-letter-spacing-1);
}

.has-medium-font-size {
    line-height: var(--mir-line-height-2);
    letter-spacing: var(--mir-letter-spacing-2);
}

.has-large-font-size {
    line-height: var(--mir-line-height-3);
    letter-spacing: var(--mir-letter-spacing-3);
}

.has-x-large-font-size {
    line-height: var(--mir-line-height-4);
    letter-spacing: var(--mir-letter-spacing-4);
}

.has-xx-large-font-size {
    line-height: var(--mir-line-height-5);
    letter-spacing: var(--mir-letter-spacing-5);
}

h1, h2, h3, h4, h5 {
    font-family: var(--mir-font-heading);
    font-weight: var(--mir-font-weight-regular);
    margin: 0;
}

h1,
.mirmoc-slogan-mask__slide {
    font-size: var(--mir-font-size-7);
    line-height: var(--mir-line-height-7);
    letter-spacing: var(--mir-letter-spacing-7);
}

h2 {
    font-size: var(--mir-font-size-6);
    line-height: var(--mir-line-height-6);
    letter-spacing: var(--mir-letter-spacing-6);
}

h3 {
    font-size: var(--mir-font-size-5);
    line-height: var(--mir-line-height-5);
    letter-spacing: var(--mir-letter-spacing-5);
}

h4 {
    font-size: var(--mir-font-size-4);
    line-height: var(--mir-line-height-4);
    letter-spacing: var(--mir-letter-spacing-4);
}

h5 {
    font-size: var(--mir-font-size-3);
    line-height: var(--mir-line-height-3);
    letter-spacing: var(--mir-letter-spacing-3);
}

/* Apply to any ancestor to flip that subtree's headings to the alt font
   (they still follow --mir-font-heading, just reassigned locally). */
.mir-font-alt {
    --mir-font-heading: var(--mir-font-heading-alt);
}

/* Pin an element to one specific font regardless of --mir-font-heading,
   e.g. a logotype that must never follow the global heading swap. */
.mir-font-planar {
    font-family: var(--mir-font-planar);
}

.mir-font-gtmaru {
    font-family: var(--mir-font-gtmaru);
    /* GT-Maru's own tracking scale, subtler than GT Planar's (see :root) —
       re-declaring these custom properties, not letter-spacing itself,
       means this still works whether applied directly to a heading or to
       an ancestor wrapping one (h1-h5's own rule only ever reads
       var(--mir-letter-spacing-N), it never sets it, so there's no
       "direct rule beats inherited value" conflict to worry about here). */
    --mir-letter-spacing-1: -0.01em;
    --mir-letter-spacing-2: -0.03em;
    --mir-letter-spacing-3: -0.035em;
    --mir-letter-spacing-4: -0.04em;
    --mir-letter-spacing-5: -0.05em;
    --mir-letter-spacing-6: -0.06em;
    --mir-letter-spacing-7: -0.07em;
    --mir-letter-spacing-8: -0.08em;
}

/* Reusable "glass" modifier: blurs whatever renders behind the element.
   Blur only — no background-color baked in, since callers need different
   tints (e.g. a dark page scrim vs. white caption pills); add your own
   background-color alongside this class, not the `opacity` property (that
   would fade the element's own children too, not just what's behind it). */
.mir-backdrop-blur {
    backdrop-filter: blur(50px);
    -webkit-backdrop-filter: blur(50px);
}

/*
    8. Create a root stacking context
  */
#root,
#__next {
  isolation: isolate;
}
html {
  /* overflow-x:hidden on body alone doesn't reliably clip position:fixed
     descendants (they're positioned against the viewport/initial
     containing block, not body) — and this theme has several: the
     navbar, the intro, all three overlays, the cursor label, the pinned
     description/excerpt pills. If any one of those is even slightly
     wider than a narrow mobile viewport, the page can still rubber-band
     sideways on a scroll gesture without this on the root element too. */
  overflow-x: hidden;
}
body {
  overflow-x: hidden;
  background-color: var(--mir-color-white);
}
p {
  margin-bottom: 0;
}
li {
  line-height: 1.5;
}
img {
  width: auto;
  height: 100%;
}

:where(body .is-layout-constrained) > * {
  margin-block-start: 1.2rem;
  margin-block-end: 0;
}
.wp-element-caption {
  text-align: right;
  margin-bottom: 0;
  line-height: 1.2;
}
a {
  color: var(--wp--preset--color--blue-normal);
  text-decoration: none;
}
a:hover {
  color: var(--wp--preset--color--blue-dark);
}

/*
 * mirmoc — structural CSS additions
 * Append this to style.css (or @import it). These are only the layout
 * rules needed to make the overlay/lightbox/hero behave as spec'd —
 * colors, type, hover states and the approach-section reveal are left
 * for later.
 */

/* --- Nav bar ---
 * Fixed + high z-index so it stays visible above both overlays. Adjust
 * --mirmoc-header-height to match your actual rendered header height,
 * and give .site-content matching top padding so page content doesn't
 * sit underneath it.
 */
:root {
	--mirmoc-header-height: 80px;
}

.mirmoc-navbar {
	position: fixed;
    /* Grid, not flex justify-content:space-between — with 3 unevenly-sized
       children (the buttons cluster, the site title, the tagline), space-
       between just distributes equal *gaps*, not equal columns, so the
       middle item (.mirmoc-site-title) lands off the navbar's true visual
       center whenever the two side items differ in width — visible as a
       mismatch against separately-centered content further down the page
       (e.g. the hero project sections). 1fr auto 1fr gives the two side
       columns equal, adjustable width no matter their content, which pins
       the middle column's midpoint to the real center every time. */
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    top: 0;
    left: 0;
    width: 100%;
    padding: var(--mir-spacing-2);
    z-index: 1001;
    /* .mirmoc-navbar itself has no visible background and its buttons/
       tagline only take up as much width as their own content, but the
       <nav> element's own box still spans the full width — without this,
       the empty grid-cell space silently intercepts hover/click for
       anything sitting underneath it. .mirmoc-site-title (a direct child)
       opts back in with its own pointer-events:auto below. */
    pointer-events: none;
}

.mirmoc-actions {
    justify-self: start;
    pointer-events: auto;
}

.mirmoc-tagline {
    justify-self: end;
}

.mirmoc-nav-btn {
  margin-right: var(--mir-spacing-1);
}


/* --- Information overlay ---
 * Same backdrop + GSAP-fade pattern as the Projects overlay and the "Do
 * Something" lightbox (js/mirmoc-menu.js: bindInfoMenu) — a plain wrapper
 * that doesn't itself animate, a blurred/dimmed __backdrop (behind, closes
 * on click), and __inner (in front) fading via GSAP. Full width/height and
 * a lower z-index than .mirmoc-navbar, so the nav bar stays visible and
 * clickable while this is open.
 */
.mirmoc-info-menu {
	position: fixed;
	inset: 0;
	z-index: 998;
	pointer-events: none;
	/* Centers .mirmoc-info-menu__inner as a content-sized card instead of
	   letting it stretch to the full viewport — same pattern as
	   .mirmoc-lightbox. */
	display: flex;
	align-items: center;
	justify-content: center;
}

.mirmoc-info-menu.is-open {
	pointer-events: auto;
}

.mirmoc-info-menu__backdrop {
	position: absolute;
	inset: 0;
	background-color: color-mix(in srgb, var(--mir-color-black) 50%, transparent);
	opacity: 0; /* pre-JS fallback; GSAP animates this */
	cursor: pointer;
}

.mirmoc-info-menu__inner {
	/* position:relative + no inset — height comes from its own content
	   (the bio copy) instead of stretching to fill .mirmoc-info-menu
	   (which is the full viewport). max-height/overflow-y are just a
	   safety net for short viewports, not the normal case. */
	position: relative;
	max-height: 90vh;
	overflow-y: auto;
	width: 90%;
	max-width: 720px; /* text column — bio copy + contact, not image cards */
	padding: var(--mir-spacing-6);
	/* Same border-radius token as .mirmoc-lightbox__inner (the "Do
	   Something" popup). */
	border-radius: var(--mir-border-radius-2);
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
	opacity: 0; /* pre-JS fallback; GSAP animates this */
}

.mirmoc-info-menu__contact {
	margin-top: 1rem;
  text-align: center;
}

.mirmoc-info-menu__contact a:hover {
  color: var(--mir-color-blue-1);
}

.mirmoc-info-menu__contact-title {
	/* Regular, not bold — this renders in GT Planar (the h1-h5 base rule
	   targets h2 directly, which beats the parent .mir-font-gtmaru wrapper
	   for inheritance purposes), a single-weight font file. Forcing bold
	   on it triggers the browser's synthetic faux-bold instead of an
	   actual bold glyph, which is both why this looked thicker and why it
	   didn't match every other GT Planar usage on the site (all regular). */
	font-weight: var(--mir-font-weight-regular);
	margin-bottom: var(--mir-spacing-1);
}

.mirmoc-info-menu__inner p {
  margin-block-start: 0;
  margin: 0;
}

/* --- Projects overlay menu ---
 * .mirmoc-projects-menu is a plain full-screen wrapper — it does not itself
 * animate. Its two children key off its .is-open class and animate
 * independently:
 *   - __backdrop: full width, behind (first in DOM), fades via opacity.
 *   - __inner: the 50%-width panel, in front (last in DOM), slides via
 *     translateX. This is what used to move together with the backdrop
 *     when both were driven by one transform on the wrapper.
 */
.mirmoc-projects-menu {
	position: fixed;
	inset: 0;
	overflow: hidden;
	z-index: 999;
	/* Closed by default so clicks pass through to the page underneath (e.g.
	   the "Do Something" button). display:none would do that too, but it'd
	   also cut the close animation short — the backdrop/inner are still
	   fading/sliding out via GSAP for a moment after .is-open is removed,
	   and display:none unmounts them from rendering instantly. */
	pointer-events: none;
}

.mirmoc-projects-menu.is-open {
	pointer-events: auto;
}

/* js/mirmoc-menu.js adds this to <body> whenever the Projects overlay opens
   (toggle button or backdrop click) and removes it on close. Locks the page
   scroll; .mirmoc-projects-menu__inner keeps its own overflow-y: auto, so
   the panel itself still scrolls independently. */
body.mirmoc-menu-open {
	overflow: hidden;
}

/* js/mirmoc-menu.js (bindIntroTransition) adds this on load and removes it
   on the second scroll/wheel/touch/key intent — the page genuinely can't
   move (not just visually held in place) during the intro→projects
   handoff. position:fixed, not just overflow:hidden, since scrollY is
   always 0 at this point (page just loaded), so there's no offset to
   preserve/restore on release. */
body.mirmoc-scroll-locked {
	position: fixed;
	inset: 0;
	width: 100%;
	overflow: hidden;
}

.mirmoc-projects-menu__backdrop {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	/* Tint lives here (not in .mir-backdrop-blur — that's blur-only and
	   reused below on the title/desc pills, which need a different tint). */
	background-color: color-mix(in srgb, var(--mir-color-black) 50%, transparent);
	/* Pre-JS fallback state only — js/mirmoc-menu.js animates opacity via
	   GSAP (smooth ease-in-out curve) rather than a CSS transition. */
	opacity: 0;
	pointer-events: none;
	cursor: pointer;
}

.mirmoc-projects-menu.is-open .mirmoc-projects-menu__backdrop {
	pointer-events: auto;
}

.mirmoc-projects-menu__inner {
	position: absolute;
	top: 0;
	left: 0;
	width: 50%;
	height: 100%;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	padding: var(--mir-spacing-7);
	/* .75 alpha at rest, fully opaque on hover — no backdrop-filter of its
	   own (turned out not to be the reveal-stutter cause after all; kept
	   plain regardless, per the visual design). */
	background-color: color-mix(in srgb, var(--mir-color-blue-1) 75%, transparent);
	transition: background-color var(--mir-transition);
	/* Pre-JS fallback state only — js/mirmoc-menu.js animates this via GSAP
	   xPercent (smooth ease-in-out curve) rather than a CSS transition. */
	transform: translateX(-100%);
	/* Scroll still works — just no visible scrollbar track/thumb. */
	scrollbar-width: none; /* Firefox */
	-ms-overflow-style: none; /* legacy Edge */
}

.mirmoc-projects-menu__inner:hover {
	background-color: var(--mir-color-blue-1);
}

.mirmoc-projects-menu__inner::-webkit-scrollbar {
	display: none; /* Chrome, Safari, Edge (Chromium) */
}

.mirmoc-menu-cards {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--mir-spacing-7);
	/* Anchors the list to the bottom when it's shorter than the panel,
	   without justify-content:flex-end on the parent — that combination
	   with overflow:auto is a known flexbox bug where content overflowing
	   toward the start becomes unreachable by scrolling. */
}

.mirmoc-menu-card__link {
	display: block;
	text-decoration: none;
	color: inherit;
}

.mirmoc-menu-card__image-wrap {
	position: relative;
	border-radius: var(--mir-border-radius-1);
	overflow: hidden; /* clips the scaled-up .mirmoc-menu-card__image-frame */
	/* No permanent will-change here — unlike .mirmoc-project__hero (a
	   normal page section, one layer, native window scroll), every card in
	   this list lives inside one scrollable container
	   (.mirmoc-projects-menu__inner). A blanket will-change:clip-path on
	   the class would promote every card's image-wrap to its own GPU layer
	   simultaneously, all stacked inside that one scroller — too many
	   concurrent layers in a scrolling container is a known trigger for
	   browsers to fall back to slow, main-thread scrolling instead of
	   compositor-only scrolling. js/mirmoc-menu.js (buildCardReveal) adds
	   this only to the one card actually animating, and removes it once
	   that reveal completes. */
}

/* Scaled by the reveal animation (js/mirmoc-menu.js) instead of the <img>
   itself, so .mirmoc-menu-card__caption — a sibling, not a child of this —
   is never affected by the transform. No sizing of its own: it just wraps
   the image tightly, since sizing/cropping stays on the <img> below. */
.mirmoc-menu-card__image-frame {
	display: block;
}

.mirmoc-menu-card__image {
	display: block;
	width: 100%;
	height: auto;
	max-height: 500px;
	object-fit: cover;
}

.mirmoc-menu-card__caption {
	position: absolute;
	left: var(--mir-spacing-3);
	bottom: var(--mir-spacing-3);
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--mir-spacing-1);
	max-width: calc(100% - 2 * var(--mir-spacing-3));
}

.mirmoc-menu-card__title {
	margin: 0;
	padding: var(--mir-spacing-1) var(--mir-spacing-3);
	border-radius: var(--mir-border-radius-1);
	background-color: color-mix(in srgb, var(--mir-color-white) 50%, transparent);
	color: var(--mir-color-black);
	font-size: var(--mir-font-size-4);
	line-height: var(--mir-line-height-4);
	/* Simple hover state, not GSAP — see .mirmoc-menu-card:hover below. */
	transition: background-color var(--mir-transition);
}

.mirmoc-menu-card:hover .mirmoc-menu-card__title {
	background-color: var(--mir-color-white);
}

/* --- "Do Something" lightbox ---
 * Same pattern as the Projects overlay: a full-screen wrapper that never
 * itself animates, holding a blurred/dimmed __backdrop (behind, closes on
 * click) and the actual __inner content box (in front). Both fade in/out
 * via GSAP (js/mirmoc-menu.js) rather than CSS transitions.
 */
.mirmoc-lightbox {
	position: fixed;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 1000;
	pointer-events: none;
}

.mirmoc-lightbox.is-open {
	pointer-events: auto;
}

.mirmoc-lightbox__backdrop {
	position: absolute;
	inset: 0;
	background-color: color-mix(in srgb, var(--mir-color-black) 50%, transparent);
	opacity: 0; /* pre-JS fallback; GSAP animates this */
	cursor: pointer;
}

.mirmoc-lightbox__inner {
	position: relative;
	width: 90%;
	max-width: 700px;
	padding: var(--mir-padding-3);
	border-radius: var(--mir-border-radius-2);
	color: var(--mir-color-black);
	opacity: 0; /* pre-JS fallback; GSAP animates this */
}

/* assets/icons/close.svg's own fill is baked-in (#5D5A66, grey-1) and
   fixed, so it can't be recolored on hover as an <img>/background-image —
   used as a mask instead: background-color is what's actually visible
   (shaped by the SVG), so it's just a normal color property to animate. */
.mirmoc-lightbox__close {
	position: absolute;
	top: var(--mir-spacing-3);
	right: var(--mir-spacing-3);
	/* Same visual size as the arrow in .mirmoc-projects-toggle::after — that
	   icon sits in a 24px box at background-size:50%, i.e. a 12px glyph. */
	width: 12px;
	height: 12px;
	border: 0;
	padding: 0;
	cursor: pointer;
	background-color: var(--mir-color-grey-2);
	-webkit-mask-image: url("../assets/icons/close.svg");
	mask-image: url("../assets/icons/close.svg");
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-size: contain;
	mask-size: contain;
	transition: background-color var(--mir-transition);
}

.mirmoc-lightbox__close:hover {
	background-color: var(--mir-color-black);
}

/* --- Cursor label ("CLOSE" on overlay backdrops, "VIEW" on project cards) ---
 * Shown alongside the normal hand/pointer cursor (not replacing it) while
 * hovering the relevant element — positioned via JS (js/mirmoc-menu.js)
 * following the mouse, offset lower-right. One reusable class; each use
 * site creates its own instance with its own label text.
 */
/* Styled like .mirmoc-menu-card__title/__desc — .mir-backdrop-blur is added
   in JS (js/mirmoc-menu.js) alongside this class for the blur; the tint
   here is its own background-color (not baked into .mir-backdrop-blur,
   which is blur-only precisely so callers can each pick their own tint). */
.mir-cursor-label {
	position: fixed;
	top: 0;
	left: 0;
	font-family: var(--mir-font-gtmaru);
	font-size: var(--mir-font-size-3);
	color: var(--mir-color-white);
	padding: var(--mir-spacing-1) var(--mir-spacing-3);
	border-radius: var(--mir-border-radius-1);
	background-color: color-mix(in srgb, var(--mir-color-green-1) 50%, transparent);
	pointer-events: none;
	z-index: 1100;
	white-space: nowrap;
	opacity: 0;
	transition: opacity var(--mir-transition);
	will-change: transform;
}

.mir-cursor-label.is-visible {
	opacity: 1;
}

/* has-grey-3-color (header.php) is a WP block-utility class and carries its
   own !important, so overriding it — in either mode — needs !important too;
   the body-ancestor selector (matching the .mirmoc-nav-on-dark pattern used
   for the nav buttons) keeps specificity deterministic regardless of
   stylesheet load order, rather than relying on source-order to break the
   !important-vs-!important tie against a bare single-class selector. */
body .mirmoc-tagline {
	color: var(--mir-color-grey-1) !important;
}

body.mirmoc-nav-on-dark .mirmoc-tagline {
	color: var(--mir-color-grey-3) !important;
}

/* .mirmoc-footer (blue-1) — toggled in js/mirmoc-menu.js (bindFooterReveal)
   independently of .mirmoc-nav-on-dark, since this needs white, not
   grey-3, for legible contrast against blue-1 rather than black. */
body.mirmoc-nav-on-footer .mirmoc-tagline {
	color: var(--mir-color-white) !important;
}

/* --- Intro section --- */
.mirmoc-intro {
    /* Fixed in place from the start — never moves. js/mirmoc-menu.js
       (bindIntroTransition) fades it out on the first scroll. No spacer:
       the Projects section starts at the very top of the document too, so
       it sits directly behind the intro from the start (not pushed down
       by a reserved gap) — once intro fades, whatever's already there
       underneath is revealed immediately. */
    position: fixed;
    inset: 0;
    z-index: 500; /* above ordinary page content, below .mirmoc-navbar (1001) and the overlays (998-1000) */
    /* Grid, not a single centered flex column: row 1 and row 3 are equal
       (1fr each), so row 2 — .mirmoc-intro__body — sits exactly centered,
       same as before. .mirmoc-site-title-spacer lives in row 1, so its own
       vertical centering (align-self below) is scoped to precisely the
       real leftover space between the viewport top and wherever
       .mirmoc-intro__body (and the slogan mask inside it) actually starts
       — not a guessed/hardcoded height. */
    display: grid;
    grid-template-rows: 1fr auto 1fr;
    justify-items: center;
    height: 100vh; /* fallback for browsers without dvh support */
    height: 100dvh;
    /* Plain rule, not the has-black-background-color utility (!important) —
       js/mirmoc-menu.js (bindIntroTransition) fades this element's own
       background-color (not opacity) to transparent, and !important would
       beat GSAP's inline style regardless of specificity. */
    background-color: var(--mir-color-black);
}

/* Layout-only stand-in for .mirmoc-site-title (now in .mirmoc-navbar,
   header.php) — same grid cell/centering the title itself used to occupy,
   kept only so js/mirmoc-menu.js can measure where the title should
   visually start. visibility:hidden (not display:none/opacity:0): still
   takes up layout space and is measurable via getBoundingClientRect, but
   invisible and out of both hit-testing and the accessibility tree. */
.mirmoc-site-title-spacer {
    grid-row: 1;
    align-self: center;
    visibility: hidden;
}

.mirmoc-site-title {
    /* Centers this grid item within its own column — which, since
       .mirmoc-navbar's side columns are equal 1fr each, is the navbar's
       true visual center regardless of how .mirmoc-actions/.mirmoc-tagline
       compare in width. */
    justify-self: center;
    /* <a> is inline by default — its hit area (and hover/click target)
       would otherwise hug just the text's own baseline box. inline-block
       makes padding actually expand the clickable/hoverable surface
       instead of just adding visual space around a still text-sized
       target. */
    display: inline-block;
    /* pinHoverSwapWidth (js/mirmoc-menu.js) pins this box's width to fit
       its longer text ("Mircea Mocanu" vs "Home"), so whichever one is
       currently shorter needs to be centered in that fixed width rather
       than sitting left-aligned against it. */
    text-align: center;
    /* Same padding tokens as .mirmoc-nav-btn (main.css ~line 974). */
    padding: var(--mir-spacing-1) var(--mir-spacing-2);
    border-radius: var(--mir-border-radius-1);
    box-shadow: 0 0 0 1px rgba(56, 53, 53, 0.1);
    /* A direct child of .mirmoc-navbar, which is pointer-events:none (see
       above) — without this override the title would inherit that and
       never receive hover/click at all. */
    pointer-events: auto;
}

/* Every page but the front page: js/mirmoc-menu.js (bindIntroTransition)
   never runs here (no .mirmoc-intro to animate away from), so this is a
   static stand-in for the front page's post-intro "pinned" look — same
   size/color the site title settles into there (--mir-font-size-3, black),
   just without anything to animate from. Position needs no override: with
   no JS ever applying an x/y transform here, it already sits at its plain,
   untransformed navbar position — exactly the front page's pinned end
   state.
   .home, not .front-page — WordPress's get_body_class() only ever adds
   .home for is_front_page() (see wp-includes/post-template.php); .front-page
   isn't a real body class, so :not(.front-page) matched everywhere,
   including the front page itself, and — since this targets the <h4>
   directly rather than relying on inheritance — silently beat the
   has-grey-3-color !important on its parent <a> (a direct rule always wins
   over an inherited value, regardless of the inherited value's own
   !important). That's what was making the site title render black at the
   top of the landing page instead of grey-3. */
body:not(.home) .mirmoc-site-title h4 {
    font-size: var(--mir-font-size-3);
    color: var(--mir-color-black);
    transition: color var(--mir-transition);
}

/* Grouped with .mirmoc-tagline/.mirmoc-info-toggle/.mirmoc-do-something
   under the same .mirmoc-nav-on-footer class (js/mirmoc-menu.js:
   bindFooterReveal) rather than its own separate tween — placed after the
   rule above since both match at once here (same specificity — body+class
   either way — so source order is what decides the tie). Front-page-only:
   the intro's own GSAP color tween (bindIntroTransition) sets this as an
   inline style, which would silently beat any CSS rule regardless of
   specificity, so that case stays JS-driven instead (see bindFooterReveal's
   `if (intro && siteTitleText)` branch). */
body.mirmoc-nav-on-footer .mirmoc-site-title h4 {
    color: var(--mir-color-white);
}

.mirmoc-intro__body {
    grid-row: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.mirmoc-slogan {
    text-align: center;
    text-transform: uppercase;
}

/* Extra <br class="mirmoc-slogan__mobile-break"> between "Views"/"Are"
   and "Our"/"Own" (front-page.php) — off by default (desktop's normal
   two-row split uses a plain, always-on <br> between "Are" and "Our"
   instead), switched back on in the mobile media query below. */
.mirmoc-slogan__mobile-break {
    display: none;
}

/* --- Project sections --- */
.mirmoc-project {
	width: 100%;
	min-height: 100vh;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
    padding: var(--mir-spacing-7) 0;
}

/* Tablet and below (same 782px breakpoint as the footer/admin-bar rules):
   100vh-tall sections were mostly empty space around the content on a
   shorter, narrower viewport, with a full spacing-7 (111px) gap on top of
   that between each one. min-height:auto lets each section size to its
   own content instead of stretching to fill the screen; the reduced
   padding is what actually separates consecutive sections now, not
   leftover viewport height. */
@media screen and (max-width: 782px) {
    .mirmoc-project {
        min-height: auto;
        padding: var(--mir-padding-4) 0;
    }
}

.mirmoc-project__desc {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--mir-spacing-1);
}

.mirmoc-project__desc-item {
	padding: var(--mir-spacing-1);
	border-radius: var(--mir-border-radius-1);
	/* Simple hover state, not GSAP — see .mirmoc-project__hero:hover below. */
	transition: background-color var(--mir-transition);
}

.mirmoc-project__hero {
	position: relative;
	width: 100%;
	max-width: 1000px;
    margin-top: var(--mir-spacing-5);
    border-radius: var(--mir-border-radius-1);
	aspect-ratio: 4 / 3;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden; /* mask — stays fixed size; clips the scaled-up frame */
	text-decoration: none; /* now an <a>, links to the post */
	will-change: clip-path; /* see .mirmoc-menu-card__image-wrap */
}

/* Scaled by the reveal animation (js/mirmoc-menu.js) instead of the <img>
   itself. Fills .mirmoc-project__hero exactly, same as the <img> used to,
   so nothing shifts when this was inserted between them. */
.mirmoc-project__hero-frame {
	display: block;
	width: 100%;
	height: 100%;
}

.mirmoc-project__hero-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Excerpt pills pinned inside the hero image itself, bottom-left — the
   caption treatment the Projects overlay cards used to have
   (.mirmoc-menu-card__caption, now removed), moved here instead. Tighter
   spacing-1 inset, not that card's -3: this hero is its own full section,
   not a small card in a list. .mirmoc-project__hero is position:relative
   with overflow:hidden (its own reveal mask), so this sits clipped to the
   same rounded corners and reveals along with the image. */
.mirmoc-project__desc--caption {
	position: absolute;
	left: var(--mir-spacing-1);
	bottom: var(--mir-spacing-1);
}

.mirmoc-project__desc--caption .mirmoc-project__desc-item {
	background-color: color-mix(in srgb, var(--mir-color-white) 50%, transparent);
}

/* Same idea as .mirmoc-menu-card:hover — a plain CSS hover, not GSAP, since
   the caption's spans are plain descendants of this same link. */
.mirmoc-project__hero:hover .mirmoc-project__desc-item {
	background-color: var(--mir-color-white);
}

/* --- Slogan mask ---
 * .mirmoc-slogan-mask__slide duplicates the slogan text (aria-hidden) with a
 * post thumbnail as its own background, clipped to the letters via
 * background-clip: text. Stacked on top of the real, accessible .mirmoc-
 * slogan h1 — which is also what's visible in the gaps between images.
 *
 * No longer a CSS animation loop — js/mirmoc-menu.js (bindIntroTransition)
 * swaps the active slide via GSAP in response to actual mouse movement
 * (cumulative travel distance, not autoplay), so :first-child starting at
 * opacity:1 here is this component's entire pre-JS/no-JS state: whichever
 * slide is first just stays put.
 */
.mirmoc-slogan-mask {
	position: relative;
}

.mirmoc-slogan {
	position: relative;
	/* Kept in the flow (sizes .mirmoc-slogan-mask so the slides line up)
	   and kept in the accessibility tree — just not painted. opacity, unlike
	   visibility:hidden/display:none, does both. */
	opacity: 0;
   margin-bottom: var(--mir-spacing-5);
}

.mirmoc-slogan-mask__images {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.mirmoc-slogan-mask__slide {
	position: absolute;
	inset: 0;
	margin: 0;
	text-align: center;
	text-transform: uppercase;
	background-repeat: no-repeat;
	background-size: cover;
	background-position: center;
	background-clip: text;
	-webkit-background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
	opacity: 0;
}

.mirmoc-slogan-mask__slide:first-child {
	opacity: 1;
}

/* --- Approach section ---
 * Pinned + scroll-scrubbed by js/mirmoc-menu.js (bindApproachScroll): as you
 * scroll through it, each item's title lifts up (translateY + grey-2 to
 * white) and its paragraph fades in; then, in sync with the *next* title's
 * entrance, the current paragraph fades out. Titles stay in normal flow so
 * they keep stacking; .mirmoc-approach__text is positioned absolutely
 * beneath its own title so hiding/showing it never disturbs that stack —
 * that's what makes the next title "lift up" into a stable, tight position
 * rather than jumping around as paragraphs come and go.
 */
.mirmoc-approach {
    position: relative;
    height: 100vh;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0 var(--mir-spacing-5);
}

.mirmoc-approach__item {
	position: relative;
}

.mirmoc-approach__text {
	position: absolute;
	top: 100%;
	left: 0;
	margin-top: var(--mir-spacing-2);
}

/* <h3> (front-page.php), so it'd otherwise inherit the plain h3 rule's
   font-size-5/line-height-5/letter-spacing-5 — stepped down to h4's whole
   scale instead. */
.mirmoc-approach__text {
	font-size: var(--mir-font-size-4);
	line-height: var(--mir-line-height-4);
	letter-spacing: var(--mir-letter-spacing-4);
}

/* Also an <h3>, but stepped up to h2's whole scale on desktop — the
   mobile-only override further down (main.css mobile block) steps it
   back down to h3's own scale instead, matching the plain tag. */
.mirmoc-approach__title {
	font-size: var(--mir-font-size-6);
	line-height: var(--mir-line-height-6);
	letter-spacing: var(--mir-letter-spacing-6);
}


/* Footer */
.mirmoc-footer {
    background-color: var(--mir-color-blue-1);
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    padding: var(--mir-padding-8) 0;
    position: relative;
    height: 100vh;
    height: 100dvh;
}

/* Same tablet-and-below breakpoint as the admin-bar override near the top
   of this file (782px is WP's own standard tablet cutoff) — spacing-8's
   181px vertical padding is disproportionate once the viewport (and the
   footer's own content) is this much narrower. */
@media screen and (max-width: 782px) {
    .mirmoc-footer {
        padding: var(--mir-padding-3) 0;
    }
}

.mirmoc-footer__title {
    font-family: var(--mir-font-heading);
    color: var(--mir-color-blue-3);
    text-align: center;
}

.mirmoc-footer__bottom {
    width: 100%;

    display: flex;
    justify-content: space-between;
    padding: var(--mir-spacing-2);
    position: absolute;
    bottom: 0;
}

.mirmoc-footer__links a:nth-child(2) {
  padding: 0 var(--mir-spacing-1);
}

.mirmoc-footer__bottom a:hover {
  color: var(--mir-color-brown-3);
}

/* --- Buttons --- */

.mirmoc-nav-btn {
  /* Flex centering, not line-height/vertical-align — guarantees the text
     node and the ::after icon sit dead-center regardless of font metrics. */
  display: inline-flex;
  align-items: center;
  /* <button> carries browser-default padding/border that our reset never
     zeroes (it only resets `font` on form elements) — left unset, that
     default padding is often asymmetric top/bottom, which reads as content
     sitting a few px too high. Set explicitly so nothing is left to the UA. */
  padding: var(--mir-spacing-1) var(--mir-spacing-3);
  border: 0;
  cursor: pointer;
  border-radius: 100px;
  background-color: var(--mir-color-grey-3);
  font-family: var(--mir-font-gtmaru);
  transition: background-color var(--mir-transition);
}

.mirmoc-projects-toggle:hover {
  background-color: var(--mir-color-grey-2);
}

/* Dark mode (.mirmoc-intro/.mirmoc-approach/Projects overlay open — see
   js/mirmoc-menu.js: setNavDark) keeps the original white hover; only the
   default/white-bg case switches to grey-1. Higher specificity than the
   plain rule above via the body ancestor, so no :not(:hover) needed here —
   unlike .mirmoc-info-toggle/.mirmoc-do-something, this rule IS the hover
   state, not a resting-state override that has to dodge it. */
body.mirmoc-nav-on-dark .mirmoc-projects-toggle:hover {
  background-color: var(--mir-color-white);
}

.mirmoc-info-toggle {
    background-color: initial;
    border: 1px var(--mir-color-grey-2) solid;
    color: var(--mir-color-blue-2);
    transition: background-color var(--mir-transition);
}

.mirmoc-info-toggle:hover, .mirmoc-do-something:hover {
  background-color: var(--mir-color-brown-1);
  border: 1px color-mix(in srgb, var(--mir-color-grey-3) 0%, transparent) solid;
  /* On the black-bg (.mirmoc-nav-on-dark) resting color, this is already
     blue-3 — same value, so hovering doesn't visibly change it. On the
     default/white-bg resting color (blue-2), this is a real change. One
     rule serves both since it just targets the same fixed value either way. */
  color: var(--mir-color-blue-3);
}

.mirmoc-projects-toggle::after {
  content: "";
  display: inline-block; /* still needed so width/height apply */
  width: 24px;
  height: 24px;
  margin-left: var(--mir-spacing-1);
  background-color: var(--mir-color-blue-2);
  background-image: url("../assets/icons/arrow.svg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 50%;
  border-radius: var(--mir-border-radius-full);
  transition: background-color var(--mir-transition);
}

.mirmoc-projects-toggle:hover::after {
  background-color: var(--mir-color-blue-1);
}

.mirmoc-do-something {
    border: 1px var(--mir-color-brown-1) solid;
    border-radius: var(--mir-border-radius-1);
    background-color: initial;
    font-family: var(--mir-font-gtmaru);
    color: var(--mir-color-blue-2);
    transition: background-color var(--mir-transition);
    margin-top: var(--mir-spacing-3);
    cursor: pointer;
}

/* .mirmoc-navbar is fixed, so it sits on top of whichever section is
   currently at the top of the viewport — on the front page that's a black
   background twice over (.mirmoc-intro, then later .mirmoc-approach; see
   js/mirmoc-menu.js: setNavDark). :not(:hover) keeps this from ever
   out-specificity-ing the hover rule above regardless of selector order. */
body.mirmoc-nav-on-dark .mirmoc-info-toggle:not(:hover) {
    color: var(--mir-color-blue-3);
    border-color: var(--mir-color-grey-3);
}


body.mirmoc-nav-on-dark .mirmoc-do-something:not(:hover) {
    color: var(--mir-color-blue-3);
    border-color: var(--mir-color-brown-1);
}

/* .mirmoc-footer (blue-1) — see .mirmoc-nav-on-footer on .mirmoc-tagline
   above; same reasoning, white instead of blue-3/grey-3. */
body.mirmoc-nav-on-footer .mirmoc-info-toggle:not(:hover),
body.mirmoc-nav-on-footer .mirmoc-do-something:not(:hover) {
    color: var(--mir-color-white);
    border-color: var(--mir-color-white);
}

/* --- Single post (template-parts/content.php) --- */

/* .site-main:not(.mirmoc-landing) — every other template (single.php,
   page.php, archive.php, index.php) shares the plain .site-main class;
   front-page.php is the only one that also adds .mirmoc-landing, so this
   excludes it, leaving its own full-bleed sections (.mirmoc-intro,
   .mirmoc-approach, etc.) untouched. Left/right matches .mirmoc-navbar's
   own padding — that's --mir-spacing-2 (10px), not spacing-1 (6px). */
.site-main:not(.mirmoc-landing) {
    padding: var(--mir-spacing-5) var(--mir-spacing-2);
}

/* Even rhythm down the whole article — scoped to body.single-post (the
   class WP adds specifically for single views of the "post" type, i.e.
   these project pages) rather than a bare article/.entry-content selector,
   since content-page.php and content-search.php reuse those same
   class names in other contexts. Two levels: between entry-header/
   .post-thumbnail/.entry-content themselves, and — separately — between
   each block the_content() actually produced inside .entry-content. The
   fixed-position description (.entry-content > p:first-child) is out of
   normal flow entirely, so it doesn't consume a gap slot here regardless. */
body.single-post article {
    display: flex;
    flex-direction: column;
    gap: var(--mir-spacing-5);
}

body.single-post .entry-content {
    display: flex;
    flex-direction: column;
    gap: var(--mir-spacing-5);
}

/* Mobile (600px — narrower than the 782px tablet breakpoint used
   elsewhere in this file). .entry-title has no rule of its own, so it
   inherits the plain h1 rule — font-size-7, sized for the giant landing-
   page slogan, badly oversized for a project's title at this width.
   Matched down to h3's whole scale (size/line-height/letter-spacing
   together), not just font-size alone. .mirmoc-footer__title is the same
   story — also a bare h1 — so it gets the same treatment here. */
@media screen and (max-width: 600px) {
    .entry-title,
    .mirmoc-footer__title {
        font-size: var(--mir-font-size-5);
        line-height: var(--mir-line-height-5);
        letter-spacing: var(--mir-letter-spacing-5);
    }

    /* .mirmoc-menu-card__title is an <h3> (nav-menu.php), but its own
       class rule already sets font-size-4/line-height-4 — h4's scale, not
       h3's — at every width. It never set its own letter-spacing though,
       so that alone was still falling through to the plain h3 rule's
       letter-spacing-5. Explicit letter-spacing-4 here on mobile closes
       that gap, so it's h4's scale throughout, not a mix of the two. */
    .mirmoc-menu-card__title {
        font-size: var(--mir-font-size-4);
        line-height: var(--mir-line-height-4);
        letter-spacing: var(--mir-letter-spacing-4);
    }

    /* Tighter inset at this width — spacing-3 (16px) was eating too much
       of the card. width:auto instead of a calc()'d max-width — it just
       shrink-wraps the title/desc pills' own content now (still an
       absolutely-positioned flex column with no `right` set, so that's
       its natural sizing anyway), rather than being capped against a
       fixed fraction of the card's width. */
    .mirmoc-menu-card__caption {
        left: var(--mir-spacing-1);
        bottom: var(--mir-spacing-1);
        width: auto;
    }

    /* .mirmoc-navbar's 3-column grid (actions / title / tagline, all one
       row — see its own rule) doesn't leave enough room for all three at
       this width. Tagline just hides; actions and the site title both go
       to their own independently fixed corners instead of sharing the
       navbar's grid at all — position:fixed removes them from grid flow
       entirely, so .mirmoc-navbar itself is left with nothing to lay out
       here (harmless: it has no visible background of its own anyway).
       Both use the same --mir-spacing-2 inset already used everywhere
       else on this page as "the standard distance" from an edge (e.g.
       .site-main:not(.mirmoc-landing)'s own left/right padding). */
    .mirmoc-tagline {
        display: none;
    }

    .mirmoc-actions {
        position: fixed;
        bottom: var(--mir-spacing-2);
        left: var(--mir-spacing-2);
    }

    .mirmoc-site-title {
        position: fixed;
        top: var(--mir-spacing-2);
        left: var(--mir-spacing-2);
    }

    /* h1's plain font-size-7 (181px) scale is sized for desktop's two-row
       "VIEWS ARE" / "OUR OWN" — stepped down to h2's whole scale instead,
       to go with the new one-word-per-row layout (see .mirmoc-slogan__
       mobile-break below) splitting it into four. Applied to both —
       .mirmoc-slogan-mask__slide has to keep matching the real h1 pixel-
       for-pixel, or the image-clipped overlay slides drift out of
       alignment with the text sitting underneath them. */
    .mirmoc-slogan,
    .mirmoc-slogan-mask__slide {
        font-size: var(--mir-font-size-6);
        line-height: var(--mir-line-height-6);
        letter-spacing: var(--mir-letter-spacing-6);
    }

    /* Extra word-splitting <br>s in front-page.php (mirmoc-slogan and each
       mirmoc-slogan-mask__slide) — hidden by default so desktop keeps its
       normal two-row "Views Are" / "Our Own", shown only here so mobile
       gets four rows, one word each, instead. display:block (not the
       default browser behavior for a hidden-then-shown <br>) is what
       actually forces the line break back on. */
    .mirmoc-slogan__mobile-break {
        display: block;
    }

    /* Left/right stays the same reduced inset as before. justify-content
       switches from the base rule's center to flex-start — pinned scroll-
       scrubbed content (bindApproachScroll) reads better starting a fixed
       distance from the top at this width than vertically centered in
       the full pinned height. */
    .mirmoc-approach {
        padding: var(--mir-spacing-6) var(--mir-padding-3) var(--mir-spacing-9);
        justify-content: flex-start;
    }

    /* Desktop's own rule steps this <h3> up to h2's scale — back down to
       its own plain h3 scale here instead. */
    .mirmoc-approach__title {
        font-size: var(--mir-font-size-4);
        line-height: var(--mir-line-height-4);
        letter-spacing: var(--mir-letter-spacing-4);
    }

    /* No rule of its own before this — just the plain p default
       (text-align: start). max-width forces it to wrap onto two lines on
       its own (no <br> needed, no DOM change); text-align: center keeps
       those two wrapped lines centered under the slogan above instead of
       sitting ragged-left. */
    .mirmoc-intro__sub {
        max-width: 65%;
        text-align: center;
    }

    /* Both the base rule and the tablet override (782px, above) leave
       left/right at 0 — fine once the hero image/title/desc had their own
       breathing room from a wide viewport around them, but at this width
       they're flush against the screen edges. Longhand, not the padding
       shorthand, so this only touches left/right and leaves whichever
       vertical value is already cascading in from the tablet rule alone. */
    .mirmoc-project {
        padding-left: var(--mir-padding-3);
        padding-right: var(--mir-padding-3);
    }

    /* .mirmoc-project is a flex column (title, then desc, then hero
       image, in that source order) — order:-1 moves the desc pills ahead
       of the title without touching the markup, so it's the first thing
       at the top of the section (right under the fixed site-title above
       it). align-self overrides the section's own align-items:center just
       for this one item (the box itself, left-edge aligned now instead of
       centered); justify-content overrides its own internal centering of
       the individual pills against each other. */
    .mirmoc-project__desc {
        order: -1;
        align-self: flex-start;
        justify-content: flex-start;
    }

    /* No rule of its own before this — just the plain h3 default, box
       position coming entirely from the section's own align-items:center.
       That centers the box itself (shrink-wrapped to its own text), but
       says nothing about a *wrapped* title's own lines, which default to
       left/start — invisible on a short, single-line title, but visibly
       ragged-left on a longer, wrapping one. align-self overrides the box
       position; text-align covers the wrapped-line case too, so every
       title is consistently left-aligned regardless of its length. */
    .mirmoc-project__title {
        align-self: flex-start;
        text-align: left;
    }

    .mirmoc-project__hero {
        margin-top: var(--mir-spacing-2);
    }

    .mirmoc-lightbox__inner {
        padding: var(--mir-padding-7) var(--mir-padding-3);
    }

    /* Mobile-only — 75% (base rule) left too narrow a column at this
       width. Full width of .entry-content itself, not the viewport:
       .site-main:not(.mirmoc-landing)'s own left/right padding is what
       keeps it off the edge of the page, not a cap here. */
    .post-thumbnail {
        max-width: 100%;
    }

    /* Rotated counter-clockwise around its own bottom-right corner
       (transform-origin) — that corner is what's actually anchored via
       bottom/right, so it stays pinned in place while the rest of the
       box swings up into a vertical column instead of a horizontal row. */
    .mirmoc-project__desc.mirmoc-project__desc--fixed {
        bottom: var(--mir-spacing-2);
        transform-origin: bottom right;
        transform: rotate(-90deg);
    }

    /* 50% of the viewport is too narrow to be usable at this width — full
       width instead. The backdrop behind it (.mirmoc-projects-menu__
       backdrop) needs no change: it's still there, just entirely covered
       by the now full-width panel in front of it, same as it's partially
       covered at 50% on desktop. */
    .mirmoc-projects-menu__inner {
        width: 100%;
        padding: var(--mir-padding-3);
    }

    /* .entry-content's own left/right padding (from .site-main:not(.mirmoc-
       landing), further up this file) stays untouched — this is 100% of
       what's already inside that, via box-sizing:border-box, not 100% of
       the viewport bleeding past it. */
    .entry-content .wp-block-paragraph {
        width: 100%;
    }

    /* spacing-6's 68px padding all around ate too much of the card at
       this width — padding-3 on every side now, with the vertical
       breathing room moved to a margin-top on the card itself instead. */
    .mirmoc-info-menu__inner {
        margin-top: var(--mir-spacing-6);
        padding: var(--mir-padding-3);
    }

    /* .mirmoc-footer__bottom's row + space-between (email flush left,
       links flush right) needs the full footer width to breathe; at this
       width the two were crowding each other. Stacked into a column,
       centered, instead. */
    .mirmoc-footer__bottom {
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: var(--mir-spacing-1);
    }

    /* .mirmoc-footer's own flex centering only ever centered .mirmoc-
       footer__title within the full height — .mirmoc-footer__bottom was
       never part of that (position:absolute, pinned flush to bottom:0
       instead, see its base rule). Grid instead: row 1 sizes to the
       title, row 2 is whatever's left over, and .mirmoc-footer__bottom
       (back in normal flow, no longer absolutely positioned) centers
       itself vertically within that leftover space specifically, rather
       than sitting flush against the very bottom edge. */
    .mirmoc-footer {
        display: grid;
        grid-template-rows: auto 1fr;
    }

    .mirmoc-footer__bottom {
        position: static;
        align-self: center;
    }
}

/* .post-thumbnail wraps the_post_thumbnail() on singular views (see
   mirmoc_post_thumbnail() in inc/template-tags.php). */
.post-thumbnail {
    max-width: 75%;
    margin-left: auto;
    margin-right: auto;
}

.post-thumbnail img {
    display: block;
    width: 100%;
    height: auto;
    /* Same radius as the landing page's own hero images
       (.mirmoc-project__hero). */
    border-radius: var(--mir-border-radius-1);
}

/* First paragraph of the_content() — the project description. Pinned to
   the viewport, bottom-left, over whatever's currently in view (the
   featured image, at first) instead of sitting inline in the content flow.
   js/mirmoc-menu.js (bindDescriptionFade) fades it out once the first real
   content section scrolls into view, and back in on scrolling back up past
   it. Same blur radius as .mir-backdrop-blur, not that class itself — this
   is auto-generated block-editor content, not markup we control the class
   list of — plus its own tint/padding/radius so it reads as an actual
   container over varying photo content behind it, not just a blur tight
   around the glyphs. */
.entry-content > p:first-child {
    position: fixed;
    bottom: var(--mir-spacing-2);
    left: var(--mir-spacing-2);
    max-width: 35%;
    text-align: left;
    margin: 0;
    z-index: 10;
    padding: var(--mir-spacing-2) var(--mir-spacing-3);
    border-radius: var(--mir-border-radius-1);
    background-color: color-mix(in srgb, var(--mir-color-white) 50%, transparent);
    backdrop-filter: blur(50px);
    -webkit-backdrop-filter: blur(50px);
}

/* This has to come after the base rule above, not inside the earlier
   mobile media query block (main.css ~line 1375) — a rule inside a media
   query gets no special cascade priority over one outside it; whichever
   rule is later in the file wins a tie, so placed earlier it was
   silently losing to the base rule's own max-width:35% on every viewport,
   mobile included. max-width:35% (sized for a wide desktop viewport) is
   far too narrow a column at this width. */
@media screen and (max-width: 600px) {
    .entry-content > p:first-child {
        /* Explicit width, not just left+right insets — this selector
           (0,2,1) is more specific than .entry-content .wp-block-paragraph
           (0,2,0)'s own width:100% (main.css, mobile block), but width is
           an all-or-nothing property: with both set on position:fixed,
           an explicit width wins outright and the browser stops
           calculating a width from left/right at all, which was making
           this ignore its right inset entirely and overflow the viewport.
           calc() here does what left+right together were supposed to. */
        width: calc(100% - 2 * var(--mir-spacing-2));
        max-width: none;
        /* .mirmoc-actions (the fixed Projects/Info buttons) sits at this
           same spacing-2 from the bottom now (main.css, mobile block) —
           this needs to clear its real height, not just guess a bigger
           bottom value, or the two will drift out of sync the moment
           either one's own sizing changes. See bindNavActionsHeightVar in
           js/mirmoc-menu.js for --mirmoc-actions-height. */
        bottom: calc(var(--mirmoc-actions-height) + 2 * var(--mir-spacing-2));
    }
}

/* Excerpt pills (template-parts/content.php) — same .mirmoc-project__desc/
   -item styling as the landing page's project cards, just pinned bottom-
   right instead of sitting inline, mirroring the description paragraph's
   own fixed bottom-left placement above (same spacing token for the
   offset). Kept as a separate modifier rather than changing
   .mirmoc-project__desc itself, since the landing page's own usage of
   that class needs to stay inline/centered. */
.mirmoc-project__desc--fixed {
    position: fixed;
    bottom: var(--mir-spacing-2);
    right: var(--mir-spacing-2);
    z-index: 10;
}

/* .mir-backdrop-blur (main.css) is blur-only by design, so it needs its
   own tint to actually read against whatever photo/content is behind it —
   same white/50% tint as the description paragraph's own fixed pill
   (.entry-content > p:first-child) above, for a matching pair of glass
   containers pinned to opposite bottom corners. Scoped to --fixed, not
   .mirmoc-project__desc-item itself, so the landing page's inline pills
   (already fine sitting over the plain page background) stay untinted. */
.mirmoc-project__desc--fixed .mirmoc-project__desc-item {
    background-color: color-mix(in srgb, var(--mir-color-white) 50%, transparent);
}