:root {
  --text: #17140f;
  --muted: #8c8175;
  --muted-hover: #3a352c;
  --bg: #f7f1e6;
  --bg-panel: #efe7d8;
  --rule: #17140f;
  --header-bg: #102a3f;
  --header-text: #f7f1e6;
  --header-muted: #a89e8d;
  --accent-red: #d6282d;
  --accent-green: #238c50;
  --accent-blue: #5080d7;
	--accent-yellow: #FFD300;
  --max-width: 720px;
  --pos-o-top: 50%;
  --pos-o-left: 48%;
  --pos-d-top: 50%;
  --pos-d-left: 50%;
  --pos-y-top: 36%;
  --pos-y-left: 46%;
  --pos-a-top: 46%;
  --pos-a-left: 46%;
  --name-glow: 0 0 8px rgba(255, 255, 255, 0.6), 0 0 20px rgba(255, 255, 255, 0.32);
  --name-lit-color: #ffffff;
  --serif-display: "SUSE", Georgia, "Iowan Old Style", "Palatino Linotype", serif;
  --serif-name: "SUSE", Georgia, "Iowan Old Style", "Palatino Linotype", serif;
  --serif: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
  --sans: -apple-system, BlinkMacSystemFont, "Inter", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1.05rem;
  line-height: 1.65;
}

.page {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 3rem 1.25rem 4rem;
}

.accent-bar {
  display: flex;
  width: 100%;
  height: 5px;
}

.accent-bar span {
  flex: 1 1 0;
}

.accent-bar .seg-red { background: var(--accent-red); }
.accent-bar .seg-green { background: var(--accent-green); }
.accent-bar .seg-blue { background: var(--accent-blue); }
.accent-bar .seg-yellow { background: var(--accent-yellow); }

header.site-header {
  position: relative;
  background: var(--header-bg);
  color: var(--header-text);
  padding: 2.25rem 2.5rem 2rem;
  text-align: center;
  overflow: hidden;
}

header.site-header.has-puzzle {
  padding-bottom: 1.75rem;
}

.header-artiform {
  position: absolute;
  top: 50%;
  height: 380px;
  width: auto;
  max-width: none;
  transform: translateY(-50%);
  opacity: 0.32;
  mix-blend-mode: screen;
  /* Contrast nudged up from the original 0.85 to compensate for the
     lower opacity above — keeps the linework legible instead of just
     uniformly dimming it along with the rest of the image. */
  filter: grayscale(1) brightness(1.35) contrast(0.95);
  pointer-events: none;
}

.header-artiform--left {
  /* header.site-header has 2.5rem (40px) horizontal padding, and this
     containing block (.header-hero) sits inside that padding rather than
     spanning the header's full box — so the offset is -20px (the
     originally intended bleed past the header edge) minus that 40px. */
  left: -60px;
  -webkit-mask-image: linear-gradient(to right, black 82%, transparent 100%),
                       linear-gradient(to bottom, transparent 0%, black 22%, black 78%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, black 82%, transparent 100%),
              linear-gradient(to bottom, transparent 0%, black 22%, black 78%, transparent 100%);
  mask-composite: intersect;
}

.header-artiform--right {
  /* Same padding compensation as .header-artiform--left, mirrored. */
  right: -80px;
  -webkit-mask-image: linear-gradient(to left, black 82%, transparent 100%),
                       linear-gradient(to bottom, transparent 0%, black 22%, black 78%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to left, black 82%, transparent 100%),
              linear-gradient(to bottom, transparent 0%, black 22%, black 78%, transparent 100%);
  mask-composite: intersect;
}

/* Wraps just the artwork + name/social/tagline block (not the excerpt
   panel below), so the artiform images — positioned relative to this,
   not the header itself — stay anchored to the name instead of
   recentering when the excerpt panel's height changes. */
.header-hero {
  position: relative;
}

.header-inner {
  position: relative;
  max-width: var(--max-width);
  margin: 0 auto;
}

.header-photo {
  display: inline-block;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  border: 2px solid var(--header-muted);
  padding: 3px;
  object-fit: cover;
  filter: grayscale(100%);
  margin-bottom: 1.15rem;
  transition: border-color 1s ease, box-shadow 1s ease;
}

.header-photo.is-lit {
  border-color: var(--name-lit-color);
  box-shadow: var(--name-glow);
}

header.site-header h1 {
  margin: 0;
  position: relative;
  font-family: var(--serif-name);
  font-size: clamp(2.8rem, 7.5vw + 0.3rem, 3.8rem);
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--header-muted);
  white-space: nowrap;
}

.name-text.is-glowing {
  color: var(--name-lit-color);
  text-shadow: var(--name-glow);
  filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.16));
}

.name-char,
.letter-target {
  transition: color 0.6s ease;
}

.name-char.is-lit,
.letter-target.is-lit {
  color: var(--name-lit-color);
}

.name-text.is-animate-in {
  animation: glow-settle 1.6s ease-out forwards;
}

/* The rest of the name catches first and briefly — like current arcing
   across the newly-closed contacts — then holds steady well before the
   excerpt reveals at 0.65s (see the autoOpenDelay in site.js). */
.name-text.is-animate-in .name-char,
.name-text.is-animate-in .letter-target {
  animation: circuit-flicker 0.85s linear;
}

.name-flicker.is-animate-in {
  display: inline-block;
  animation: glow-flicker-settle 1.05s linear forwards;
}

@keyframes glow-settle {
  0% { text-shadow: none; opacity: 0.8; color: var(--header-muted); filter: none; }
  100% { text-shadow: var(--name-glow); opacity: 1; color: var(--name-lit-color); filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.16)); }
}

@keyframes circuit-flicker {
  0%, 100% { opacity: 1; }
  5% { opacity: 0.35; }
  9% { opacity: 1; }
  15% { opacity: 0.5; }
  20% { opacity: 1; }
  29% { opacity: 0.65; }
  35% { opacity: 1; }
}

/* The "L" is the last connection to catch — it flickers longer and more
   erratically than the rest of the name, with its final spark landing
   right around the excerpt reveal for that "circuit just barely closed"
   feeling. */
@keyframes glow-flicker-settle {
  0% { text-shadow: none; opacity: 0.5; color: var(--header-muted); }
  4% { text-shadow: var(--name-glow); opacity: 1; color: var(--name-lit-color); }
  8% { text-shadow: none; opacity: 0.3; color: var(--header-muted); }
  13% { text-shadow: var(--name-glow); opacity: 1; color: var(--name-lit-color); }
  19% { text-shadow: none; opacity: 0.45; color: var(--header-muted); }
  25% { text-shadow: var(--name-glow); opacity: 1; color: var(--name-lit-color); }
  34% { text-shadow: none; opacity: 0.6; color: var(--header-muted); }
  42% { text-shadow: var(--name-glow); opacity: 1; color: var(--name-lit-color); }
  58% { text-shadow: none; opacity: 0.7; color: var(--header-muted); }
  66%, 100% { text-shadow: var(--name-glow); opacity: 1; color: var(--name-lit-color); }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- name puzzle: letter sockets --- */

.letter-target {
  position: relative;
  display: inline-block;
}

.letter-target[role="button"] {
  cursor: pointer;
}

.letter-target[role="button"]:focus-visible {
  outline: 2px solid var(--header-text);
  outline-offset: 3px;
}

.socket {
  position: absolute;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.socket.is-filled { opacity: 0 !important; }

/* Position is defined once per shape via custom properties and shared
   between the live socket and the static (already-solved) mark, so tuning
   a shape's placement here always keeps both in sync. */
.socket-o, .static-mark.shape-o { top: var(--pos-o-top); left: var(--pos-o-left); }
.socket-d, .static-mark.shape-d { top: var(--pos-d-top); left: var(--pos-d-left); }
.socket-y, .static-mark.shape-y { top: var(--pos-y-top); left: var(--pos-y-left); }
.socket-a, .static-mark.shape-a { top: var(--pos-a-top); left: var(--pos-a-left); }

.socket-o { width: 22px; height: 22px; border-radius: 50%; background: var(--accent-red); opacity: 0.5; transform: translate(-50%, -50%); }
.socket-d { width: 17px; height: 23px; border-radius: 0 999px 999px 0; background: var(--accent-green); opacity: 0.5; transform: translate(-50%, -50%); }
.socket-y { width: 19px; height: 13px; background: var(--accent-yellow); opacity: 0.3; clip-path: polygon(0% 0%, 100% 0%, 50% 100%); transform: translate(-50%, -50%); }
.socket-a { width: 12px; height: 14px; background: var(--accent-blue); opacity: 0.5; clip-path: polygon(50% 0%, 0% 100%, 100% 100%); transform: translate(-50%, -50%); }

/* --- name puzzle: draggable pieces + static (already-solved) marks --- */

.shape-o { width: 22px; height: 22px; border-radius: 50%; background: var(--accent-red); }
.shape-d { width: 17px; height: 23px; border-radius: 0 999px 999px 0; background: var(--accent-green); }
.shape-y { width: 17px; height: 13px; background: var(--accent-yellow); clip-path: polygon(0% 0%, 100% 0%, 50% 100%); }
.shape-a { width: 15px; height: 17px; background: var(--accent-blue); clip-path: polygon(50% 0%, 0% 100%, 100% 100%); }

.shape {
  transition: filter 0.15s ease;
}

.puzzle-piece:not(.is-locked):hover .shape,
.puzzle-piece.is-selected .shape,
.puzzle-piece.is-dragging .shape {
  filter: brightness(1.3);
}

.static-mark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.puzzle-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  pointer-events: none;
  z-index: 500;
}

.puzzle-piece {
  position: absolute;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  border-radius: 50%;
  transition: left 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), top 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.3s ease, box-shadow 0.15s ease;
}

.puzzle-piece.is-dragging {
  transition: none;
  cursor: grabbing;
  z-index: 50;
}

.puzzle-piece.is-locked {
  cursor: default;
}

.puzzle-piece.is-selected {
  box-shadow: 0 0 0 2px var(--header-text);
}

.puzzle-piece.is-rejected {
  animation: puzzle-shake 0.3s ease;
}

.puzzle-piece:focus-visible {
  outline: 2px solid var(--header-text);
  outline-offset: 3px;
}

@keyframes puzzle-shake {
  0%, 100% { margin-left: 0; }
  25% { margin-left: -4px; }
  75% { margin-left: 4px; }
}

.reveal-arrow {
  position: absolute;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  border: 0;
  background: none;
  cursor: default;
  transform: translateY(-50%);
  transition: left 0.6s ease, top 0.6s ease;
  pointer-events: none;
}

.reveal-arrow.is-visible {
  cursor: pointer;
  pointer-events: auto;
}

.reveal-arrow:focus-visible {
  outline: 2px solid var(--header-text);
  outline-offset: 3px;
}

/* Starts as a small red hint wedged against the K — the puzzle piece
   that's already "solved" — then morphs (size, color, clip-path) into
   the normal reveal arrow once the rest of the puzzle is complete. */
.arrow-shape {
  width: 14px;
  height: 30px;
  background: var(--accent-red);
  clip-path: polygon(100% 0%, 0% 50%, 100% 100%);
  transition: width 0.6s ease, height 0.6s ease, background 0.6s ease,
    clip-path 0.6s ease, transform 0.35s cubic-bezier(0.65, 0, 0.35, 1),
    filter 0.8s ease;
}

.reveal-arrow.is-visible .arrow-shape {
  width: 18px;
  height: 30px;
  background: var(--header-muted);
  clip-path: polygon(0% 0%, 100% 50%, 0% 100%);
}

.reveal-arrow.is-open .arrow-shape {
  transform: rotate(90deg);
}

.reveal-arrow.is-lit .arrow-shape {
  background: var(--name-lit-color);
  filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.55));
}

@keyframes hint-flicker {
  0%, 100% { opacity: 1; }
  8% { opacity: 0.15; }
  16% { opacity: 1; }
  30% { opacity: 0.2; }
  38% { opacity: 1; }
  50% { opacity: 0.5; }
  58% { opacity: 1; }
  70% { opacity: 0.3; }
  80% { opacity: 1; }
}

.arrow-shape.is-flickering,
.name-char.is-flickering,
.letter-target.is-flickering {
  animation: hint-flicker 0.9s ease;
}

.reload-button {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 30px;
  height: 30px;
  padding: 6px;
  border: 0;
  background: none;
  border-radius: 50%;
  color: var(--header-muted);
  cursor: pointer;
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.15s ease;
}

.reload-button.is-visible {
  opacity: 1;
  transform: scale(1);
}

.reload-button:hover,
.reload-button:focus-visible {
  color: var(--header-text);
}

.reload-button:focus-visible {
  outline: 2px solid var(--header-text);
  outline-offset: 2px;
}

.reload-icon {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.excerpt-panel {
  max-width: var(--max-width);
  margin: 0 auto;
  overflow: hidden;
  text-align: left;
  height: 0;
  visibility: hidden;
  transition: height 0.5s ease, visibility 0s linear 0.5s;
}

.excerpt-panel.is-open {
  visibility: visible;
  transition: height 0.5s ease, visibility 0s linear 0s;
}

.excerpt-panel-inner {
  background: var(--bg);
  color: var(--text);
  padding: 1.75rem 1.5rem 0.5rem;
  margin: 1.5rem 0;
  border-radius: 5px;
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.4);
}

.excerpt-heading {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--serif-display);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1rem;
  white-space: nowrap;
}

.excerpt-heading::before {
  content: "";
  width: 10px;
  height: 10px;
  flex: none;
  background: var(--muted);
}

.excerpt-heading::after {
  content: "";
  flex: 1 1 auto;
  height: 0;
  border-top: 1px solid var(--rule);
  opacity: 0.35;
}

.excerpt-break {
  width: 44px;
  height: 1px;
  margin: 1.6rem 0;
  border: none;
  background: var(--muted);
  opacity: 0.6;
}

.excerpt-text {
  font-family: var(--serif);
  font-style: normal;
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--text);
  margin: 0 0 1rem;
}

.excerpt-note {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--muted);
  margin: 1rem 1.5rem 1rem 1.5rem;
	text-align: right;
}

.header-social {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1.1rem;
  padding-left: 0;
  margin: 0.9rem 0 1rem;
}

.header-social li {
  margin: 0;
  padding: 0;
}

.header-social li::before { content: none; }

.header-inner > p {
  margin: 0;
  color: var(--header-muted);
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.05rem;
}

main {
  display: flex;
  flex-direction: column;
  gap: 3.25rem;
}

section, article {
  scroll-margin-top: 1.5rem;
}

h2 {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--serif-display);
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 1.25rem;
  white-space: nowrap;
}

.h2-chip {
  width: 10px;
  height: 10px;
  flex: none;
  display: inline-block;
}

.h2-chip--red,
.h2-chip--green,
.h2-chip--blue,
.h2-chip--yellow {
  background: var(--muted);
}

.h2-chip.is-replaced { visibility: hidden; }

h2::after {
  content: "";
  flex: 1 1 auto;
  height: 0;
  border-top: 1px solid var(--rule);
  opacity: 0.35;
	padding-bottom: 4px;
}

h3 {
  font-family: var(--serif);
  font-size: 1.05rem;
  font-style: italic;
  font-weight: 400;
  margin: 1.4rem 0 0.35rem;
}

/* A quiet, set-apart moment above the About section — a book-style
   epigraph, not a content section, so no h2 chip and a deliberately
   narrower, indented measure rather than the full paragraph width. */
.epigraph {
  max-width: 26rem;
  margin: 1rem auto 1rem;
  padding: 1.5rem 0 0 1.5rem;
}

.epigraph p {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--text);
  margin: 0 0 0.85rem;
}

.epigraph footer {
  font-family: var(--sans);
  font-style: normal;
  font-size: 0.8rem;
  color: var(--muted);
  text-align: right;
}

.epigraph footer cite {
  font-style: italic;
}

p { margin: 0 0 1rem; }

a {
  color: var(--text);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
  transition: color 0.15s ease;
}

a:hover { color: var(--muted-hover); }

ul, dl { margin: 0 0 1rem; padding-left: 1.25rem; }

ul { padding-left: 1.1rem; list-style: none; }

li {
  margin-bottom: 0.5rem;
  padding-left: 1.1rem;
  position: relative;
}

li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--muted);
}

dl {
  padding-left: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1rem;
  row-gap: 0.5rem;
}

dt {
  font-family: var(--serif);
  font-style: italic;
  color: var(--muted);
  font-weight: 400;
}

dd { margin: 0; }

.social-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--header-muted);
  transition: color 0.15s ease;
  padding: 10px;
  margin: -10px;
}

.social-link:hover,
.social-link:focus-visible {
  color: var(--header-text);
}

.social-link--linkedin {
  color: var(--muted);
}

.social-link--linkedin:hover,
.social-link--linkedin:focus-visible { color: var(--accent-yellow); }

.social-link--goodreads:hover,
.social-link--goodreads:focus-visible { color: var(--accent-red); }

.social-link--bluesky:hover,
.social-link--bluesky:focus-visible { color: var(--accent-blue); }

.social-link--github:hover,
.social-link--github:focus-visible { color: var(--accent-green); }

.social-icon {
  width: 25px;
  height: 25px;
}

.social-icon circle {
  stroke: currentColor;
  fill: none;
}

.social-icon rect {
  fill: currentColor;
}

.social-icon text,
.social-icon path {
  fill: currentColor;
}

.social-icon .ln-glyph {
  fill: var(--header-bg);
}

/* --- language switcher: pinned top-left of the header, independent of
   the centered header-inner column --- */

.lang-switcher {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 600;
}

.lang-switcher > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 4px;
  border-radius: 50%;
  color: var(--header-muted);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.lang-switcher > summary::-webkit-details-marker { display: none; }

.lang-switcher > summary:hover,
.lang-switcher > summary:focus-visible {
  color: var(--header-text);
  background-color: rgba(247, 241, 230, 0.08);
}

.lang-switcher > summary:focus-visible {
  outline: 2px solid var(--header-text);
  outline-offset: 2px;
}

.lang-switcher[open] > summary {
  color: var(--header-text);
}

.lang-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 9rem;
  margin: 0;
  padding: 6px 0;
  list-style: none;
  background: var(--header-bg);
  border: 1px solid var(--header-muted);
  border-radius: 4px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45);
}

.lang-menu li {
  margin: 0;
  padding: 0;
}

.lang-menu li::before { content: none; }

.lang-menu a {
  display: flex;
  align-items: center;
  /* px, not rem, for the gap/padding ahead of .lang-flag — at the default
     16px root, 0.9rem/0.6rem resolve to 14.4px/9.6px, landing the flag's
     circular clip at a fractional left offset (rectLeft: 29.390625).
     border-radius clipping at a sub-pixel position anti-aliases the
     rounded edge asymmetrically, reading as a faint color "bleed" on one
     side — most visible on high-contrast horizontal-stripe flags (ES,
     PL). Whole-pixel values keep the flag's box on the device pixel
     grid so the circular clip renders symmetrically. */
  gap: 10px;
  padding: 6px 14px;
  font-family: var(--sans);
  font-size: 0.78rem;
  color: var(--header-text);
  text-decoration: none;
  white-space: nowrap;
}

.lang-menu a:hover,
.lang-menu a:focus-visible {
  background-color: rgba(247, 241, 230, 0.08);
  color: var(--header-text);
}

.lang-menu a[aria-current="true"] {
  color: var(--header-muted);
  pointer-events: none;
}

/* Circular flag icons from circle-flags (MIT licensed), self-hosted under
   /assets/flags/ — https://github.com/HatScripts/circle-flags.
   The circular clip lives on this wrapper via overflow:hidden rather than
   border-radius directly on the <img> — at the sub-pixel positions flex
   layout produces here, border-radius + box-shadow on a replaced element
   can leave a hairline seam where the image's own edge peeks past the
   clip, reading as a soft color "bleed" to one side. overflow:hidden on a
   plain block wrapper clips reliably regardless of that sub-pixel offset.
   The .lang-menu a padding/gap were also switched from rem to whole px so
   this wrapper's own left offset lands on the CSS pixel grid. Even so, on
   a display with fractional OS-level scaling (125%/150%, common on
   Windows) a whole CSS pixel still isn't a whole device pixel, which can
   reintroduce the same asymmetric anti-aliasing seam on the rounded clip.
   translateZ(0) forces this element onto its own GPU compositing layer,
   which changes how Chromium rasterizes the corner clip and reliably
   eliminates that seam independent of the display's scale factor. */
.lang-flag {
  display: inline-block;
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.3);
  vertical-align: middle;
  transform: translateZ(0);
}

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

form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 480px;
}

label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.95rem;
  font-weight: 600;
}

input, textarea {
  font: inherit;
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--muted);
  border-radius: 3px;
  background: var(--bg-panel);
  color: var(--text);
}

input:focus, textarea:focus {
  outline: none;
  border-color: var(--text);
}

textarea { resize: vertical; min-height: 6rem; }

button {
  font: inherit;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 0.85rem;
  padding: 0.65rem 1.3rem;
  border: 1px solid var(--text);
  background: var(--text);
  color: var(--bg);
  border-radius: 0;
  cursor: pointer;
  align-self: flex-start;
}

button:hover { opacity: 0.85; }

button:disabled {
  background: var(--header-bg);
  border-color: var(--header-bg);
  color: var(--header-muted);
  cursor: not-allowed;
  opacity: 1;
}

button:disabled:hover { opacity: 1; }

#form-status {
  font-size: 0.95rem;
  min-height: 1.3rem;
}

.honeypot-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

footer.site-footer {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--muted);
  font-size: 0.8rem;
  color: var(--muted);
  text-align: center;
}

@media (max-width: 600px) {
  .page {
    padding: 2rem 1.25rem 3rem;
  }

  .epigraph {
    margin: 3rem auto 3.5rem;
    padding-left: 0.85rem;
  }

  header.site-header {
    padding: 1.25rem 1.25rem 1.25rem;
  }

  header.site-header.has-puzzle {
    padding-bottom: 2rem;
  }

  /* At full desktop size the artwork's fixed 380px height is a small
     fraction of the header; on a narrow phone the same fixed height would
     dwarf the header and swallow most of its width, so it's shrunk here.
     Scaled by vw (clamped) rather than a flat px value so the two images
     keep roughly the same proportion of the header's width as the
     viewport keeps shrinking below 600px — a fixed height would otherwise
     have them overlapping almost edge-to-edge on the narrowest phones.
     Offsets are re-derived for the header's narrower 1.25rem (20px)
     padding at this breakpoint (see the desktop offset comments above for
     the same left/right math). */
  .header-artiform {
    height: clamp(90px, 34vw, 130px);
  }

  .header-artiform--left {
    left: -30px;
  }

  .header-artiform--right {
    right: -40px;
  }

  .header-photo {
    width: 96px;
    height: 96px;
    margin-bottom: 0.9rem;
  }

  header.site-header h1 {
    /* Matches the desktop clamp's own value at exactly 600px width
       (7.5vw + 0.3rem = 3.1125rem there) so there's no visible jump
       crossing the breakpoint, while shrinking further for narrow
       phones than the desktop clamp's 2.8rem floor allowed. */
    font-size: clamp(1.7rem, 8.35vw, 3.11rem);
    letter-spacing: 0.03em;
  }

  .arrow-shape { width: 8px; height: 20px; }
  .reveal-arrow.is-visible .arrow-shape { width: 13px; height: 22px; }

  .socket-o { width: 12px; height: 12px; }
  .socket-d { width: 8px; height: 12px; }
  .socket-y { width: 8px; height: 8px; }
  .socket-a { width: 8px; height: 7px; }

  .shape-o { width: 15px; height: 15px; }
  .shape-d { width: 11px; height: 16px; }
  .shape-y { width: 10px; height: 10px; }
  .shape-a { width: 12px; height: 9px; }

  h2 {
    white-space: normal;
    font-size: 1rem;
  }

  dl {
    grid-template-columns: 1fr;
    row-gap: 0.2rem;
  }

  dd {
    margin-bottom: 0.65rem;
  }

  button {
    align-self: stretch;
  }

  input, textarea {
    padding: 0.7rem 0.75rem;
  }

  .lang-switcher {
    top: 10px;
    left: 10px;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    --text: #ece5d6;
    --muted: #948a78;
    --muted-hover: #f7f1e6;
    /* Noticeably lighter than --header-bg (navy, inherited from :root)
       so the header still reads as a distinct darker banner, matching the
       strong header/body contrast the light theme has — the previous
       #171310 was close enough to the header's near-black that the two
       blurred together on phone screens. */
    --bg: #2b241d;
    --bg-panel: #362e25;
    --rule: #ece5d6;
    --header-text: #f7f1e6;
    --header-muted: #8f8577;
  }
  button { background: var(--text); color: var(--bg); border-color: var(--text); }
}
