/* Site footer */

.site-footer {
	background: #fee937;
	margin-top: 4rem;
}

/* On the gallery entry page the footer follows straight on from a
   solid yellow photo wall — that top margin left a stripe of the
   site's plain gray background awkwardly sandwiched between two
   different yellows. The page's own padding already gives enough
   breathing room, so no extra margin is needed there. */
.gallery-single-page + .site-footer {
	margin-top: 0;
}

/* Same idea on the front page: #gallery (see grid.css) already drops
   its own trailing space and .page-grid's bottom padding since it's
   the last section, ending in a full-bleed photo — drop the footer's
   usual top margin too so it actually sits flush after that. */
.page-grid + .site-footer {
	margin-top: 0;
}

.site-footer__inner {
	max-width: 1600px;
	margin: 0 auto;
	padding: 4rem var(--gutter);
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 0.5rem;
	font-size: 0.85rem;
	color: var(--color-ink);
}

.site-footer__copyright,
.site-footer__credit {
	margin: 0;
}

/* Same hand-drawn brush-stroke system as .prose/.publications/
   .elsewhere__list links (see the .underline-v* rules below) — this
   was still on the old single repeating squiggle, which is why it
   looked different from every other link on the site. */
.site-footer__credit-link {
	color: var(--color-ink);
	font-weight: 600;
}

/* Nav */

.site-mark {
	display: flex;
	align-items: center;
	gap: 0.6em;
	font-weight: 700;
	font-size: 1.1rem;
	color: var(--color-ink);
	text-decoration: none;
	margin-bottom: 2rem;
}

.site-mark__icon {
	width: 28px;
	height: auto;
	flex-shrink: 0;
}

.site-nav__list {
	list-style: none;
	margin: 0 0 2rem;
	padding: 0;
}

.site-nav__list li + li {
	margin-top: 0.225em;
}

.site-nav__list a {
	color: var(--color-ink);
	text-decoration: none;
	font-weight: 500;
	font-size: 0.65em;
	line-height: 0.4;
}

.site-nav__list a[data-nav-link].is-active {
	color: #292735;
	font-weight: 700;
}

.section__heading {
	color: var(--color-primary);
	font-style: italic;
	font-weight: 500;
}

/* About: the body copy itself sits on ruled notebook-paper lines —
   yellow rules directly behind each line of text, page background
   stays the site's own gray. The ruled grid is on .prose itself, ONE
   continuous pattern from its top edge, rather than restarted on each
   <p> — restarting per paragraph kept each paragraph internally
   aligned but let the grid drift between paragraphs, since a plain
   1em paragraph margin isn't a whole multiple of the row height.
   Paragraph spacing is instead a whole line-row so a paragraph break
   just skips one rule rather than breaking the grid.

   The row height is --line-px (a whole-pixel value measured and set
   by assets/js/line-height.js), not 1.6em directly: the fluid,
   viewport-based font-size almost never lands on a whole pixel, so
   1.6em resolves to a fractional height like 32.0985px. The gradient
   math handles that fraction exactly, but the browser's real text
   line boxes get rounded to whole pixels for crisp rendering — and
   different browsers round that per-line vs. cumulatively. Over
   enough lines those two slightly different roundings drift apart
   (most visible in Safari, worst by the last paragraph), so the rule
   ends up further and further from the text it's supposed to sit
   under. Driving both the gradient AND the paragraph spacing off the
   same already-rounded --line-px keeps them locked together exactly,
   regardless of how any given browser rounds text layout. */
.prose {
	--ruled-line-color: #fcd700;
	/* The rules bleed 10px past the text on each side. A background
	   only ever paints within its own element's box, so the box itself
	   has to be 10px wider than the text on each side — grown with a
	   negative margin, then padded back in by the same amount so the
	   text itself doesn't actually move. */
	margin-left: -10px;
	margin-right: -10px;
	padding-left: 10px;
	padding-right: 10px;
	box-sizing: border-box;
	background-image: repeating-linear-gradient(
		to bottom,
		transparent 0,
		transparent calc(var(--line-px, 1.6em) - 1px),
		var(--ruled-line-color) calc(var(--line-px, 1.6em) - 1px),
		var(--ruled-line-color) var(--line-px, 1.6em)
	);
}

.prose p {
	/* Text line boxes, not just the margin/background math, have to
	   resolve to the exact same --line-px value — otherwise this only
	   fixes the paragraph-to-paragraph gap and the drift just moves
	   inside each paragraph instead (still visible, just less of it). */
	line-height: var(--line-px, 1.6);
	margin: 0 0 var(--line-px, 1.6em);
}

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

/* About: date note ruled the same way — page background stays the
   site's own gray, rules are the brand yellow. Line-height is kept
   close to the text's natural height (not the much taller spacing
   used earlier) so the text sits flush on its rule instead of
   floating in the middle of an oversized line box; min-height then
   adds a few more blank ruled rows below it (a real ruled-paper
   block, not just one line under the date). */
.about-date-note {
	margin-top: 1.5rem;
	font-size: 0.6em;
	font-weight: 700;
	opacity: 0.4;
}

/* Hand-drawn brush-stroke underline for every link on the site (About
   prose, Publications citation links, Elsewhere links, the footer
   credit, nav links, EN|한국어) — a plain browser underline, or one
   repeating squiggle, was showing in various of these spots before.
   Each link gets --underline set inline (see
   seungholee_random_underline_style() in inc/bilingual.php) to one of
   18 precomputed shape x color variants — a random shape per link,
   sharing one random color for the whole page load. It's a plain
   background-image, not a mask on a separate ::after layer (an
   earlier version did that, to recolor a single shared shape via
   mask-image + background-color) — box-decoration-break:clone here
   needs a real background to clone, and doing it this way is what
   makes the stroke re-draw correctly under EVERY wrapped line of a
   link's text, not just the first/last fragment; a ::after only ever
   generates one box for the whole element regardless of how many
   lines it wraps to. */
.prose a,
.publications a,
.elsewhere__list a,
.site-footer__credit-link {
	text-decoration: none;
	padding-bottom: 3px;
	background-image: var(--underline, none);
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 100% 0.5em;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}

/* Nav links and lang-switch buttons carry the same --underline (set
   inline per element, same as every other link) but only the
   active/selected one should actually show it — not every item at
   once. */
.site-nav__list a,
.lang-switch button {
	text-decoration: none;
	padding-bottom: 3px;
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 100% 0.5em;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
	background-image: none;
}

.site-nav__list a.is-active {
	background-image: var(--underline, none);
}

html[data-lang="en"] .lang-switch button[data-lang-switch="en"],
html[data-lang="ko"] .lang-switch button[data-lang-switch="ko"] {
	background-image: var(--underline, none);
}

/* Publications */

.publications {
	font-size: 0.8em;
}

.publications__year {
	margin-bottom: 2rem;
}

/* Matches the current page load's brush-stroke underline color (set
   on <body>, cycled in inc/setup.php) instead of the fixed brand
   purple, so the year headings visually tie back to the underlines. */
.publications__year h3 {
	color: var(--stroke-color-current, var(--color-primary));
}

.publications__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.publications__list li {
	margin-bottom: 1em;
}

/* Elsewhere */

.elsewhere__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.elsewhere__list li {
	margin-bottom: 0.75em;
	font-size: 1.1rem;
}

.elsewhere__list a {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
}

.elsewhere__icon {
	flex-shrink: 0;
}

/* Photo gallery — one full-width clickable parallax banner per entry,
   its bilingual title overlaid in white. No separate thumbnail grid. */

.gallery-heroes {
	display: flex;
	flex-direction: column;
	gap: 0;
}

.gallery-hero {
	/* Full-bleed breakout: edge-to-edge of the browser viewport, ignoring
	   the content column's own width (a deliberate exception — nothing
	   else on the page does this).
	   The classic width:100vw + left:50%/margin-left:-50vw trick
	   assumes its containing block is horizontally centered on the
	   viewport — true only if the column it's nested in has equal
	   space on both sides. Here it doesn't: the content grid has a
	   margin-col track on the left and an independently-sized (usually
	   wider) nav-col track on the right, so that assumption was always
	   false by some margin, before Safari's scrollbar-width quirk even
	   comes into it. --hero-left/--hero-right are the container's
	   actual measured distance to the real viewport edges (assets/js/
	   viewport-width.js), so the negative margins below cancel out
	   whatever that gap actually is, symmetric or not. */
	position: relative;
	left: auto;
	right: auto;
	margin-left: calc(-1 * var(--hero-left, 0px));
	margin-right: calc(-1 * var(--hero-right, 0px));
	width: auto;
	display: flex;
	align-items: center;
	justify-content: center;
	height: 30vh;
	background-color: var(--color-ink);
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	background-attachment: fixed;
	overflow: hidden;
	cursor: pointer;
}

/* background-attachment:fixed doesn't work reliably on iOS Safari;
   it just falls back to scrolling normally there, which is fine. */

/* Hover/focus feedback: a flat yellow tint over the whole banner,
   confirming it's clickable. z-index 0 keeps it under the title
   (z-index 1) rather than washing the text out. */
.gallery-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	background-color: var(--color-yellow);
	opacity: 0;
	transition: opacity 0.2s ease;
	pointer-events: none;
}

.gallery-hero:hover::after,
.gallery-hero:focus-visible::after {
	opacity: 0.3;
}

.gallery-hero__title {
	position: relative;
	z-index: 1;
	color: #fff;
	font-size: 1.6rem;
	padding: 1.5rem;
	text-align: center;
}

/* Gallery entry page — full-screen photo wall on a yellow backdrop,
   its own page rather than a modal (a modal's close button turned out
   to be unreliable to find/click). Photos keep their real aspect ratio
   (never cropped): each row is pinned to a fixed height and each
   image's width follows naturally from that, wrapping into rows;
   flex-grow lets a row's photos stretch slightly to fill leftover
   width. Order follows upload order (not reshuffled) so an entry
   "brick-stacks" the same way every time. */

.gallery-single-page {
	background: #fcd700;
	min-height: 100vh;
}

.gallery-single {
	/* 30% wider than the site's usual 1600px content cap — this page is
	   mostly full-bleed photos, not reading text, so it benefits from
	   using more of a large monitor's width (the text column below
	   stays capped separately at a comfortable reading measure). */
	max-width: 2080px;
	margin: 0 auto;
	padding: 40px;
	/* Back button: top 20px + 56px tall = bottom edge at 76px. Leaves a
	   plain ~19px gap to the first photo (was ~4px). */
	padding-top: 95px;
	box-sizing: border-box;
}

/* Always fixed top-left — never moves, never hides, unlike the old
   modal close button. Icon-only (no label): a big round tap target so
   it's easy to hit without needing text to justify its size. */
.gallery-single__back {
	position: fixed;
	top: 20px;
	left: 20px;
	z-index: 50;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 112px;
	height: 56px;
	color: var(--color-ink);
	font-size: 1.5rem;
	line-height: 1;
	text-decoration: none;
	background: rgba(255, 255, 255, 0.6);
	border-radius: 999px;
}

/* Photos stay full-bleed/full-screen, but the text underneath reads
   at the same size, format and column width as the About copy, just
   swapped to the gray page color instead of yellow since this page's
   own background already is yellow.
   The ruled grid is ONE continuous background on the .gallery-single__text
   wrapper (not restarted on title/description/comment separately) —
   same fix, and same reasoning, as .prose above: every gap between
   blocks is a whole --line-px row (not an arbitrary rem value, and
   not raw 1.6em — see the long comment on .prose for why a rounded
   pixel value is needed instead) so title, description and comment
   all land on the same grid instead of each restarting its own. */
.gallery-single__text {
	max-width: 780px;
	margin-top: 1.5rem;
	margin-left: auto;
	margin-right: auto;
	background-image: repeating-linear-gradient(
		to bottom,
		transparent 0,
		transparent calc(var(--line-px, 1.6em) - 1px),
		#f0eefc calc(var(--line-px, 1.6em) - 1px),
		#f0eefc var(--line-px, 1.6em)
	);
}

/* The wrapper above already draws the grid; .prose's own copy of it
   would just double up (and drift, since it restarts at .prose's own
   top instead of the wrapper's) — switch it off here specifically. */
.gallery-single__text .prose {
	background-image: none;
}

.gallery-single__title {
	font-size: 1em;
	font-weight: 400;
	line-height: var(--line-px, 1.6em);
	margin: 0;
	color: var(--color-ink);
}

.gallery-single__description,
.gallery-single__comment {
	color: rgba(23, 21, 58, 0.65);
}

/* No skipped line between the title and the description — directly
   below it, on the very next rule — but the description-to-comment
   break still skips one (matches how paragraph breaks work in
   .prose). */
.gallery-single__comment {
	margin-top: var(--line-px, 1.6em);
}

/* Justified layout (Flickr/Google-Photos-style row packing — see
   assets/js/justified-gallery.js): JS computes each photo's exact
   pixel width/height so every row fills the container edge-to-edge
   with no leftover gap, mixing landscape and portrait photos in the
   same row. The figure/img just need to accept whatever size JS
   assigns; flex here only controls gap and row-wrapping, not sizing. */
.gallery-single__photos {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: 6.667px;
}

.gallery-single__photo {
	margin: 0;
}

.gallery-single__photo img {
	display: block;
	width: 100%;
	height: auto;
}

.gallery-single__caption {
	margin-top: 0.5em;
	font-size: 0.75em;
	font-style: italic;
	color: rgba(23, 21, 58, 0.65);
}

