/* ═══════════════════════════════════════════════════════════════════════
   Penguin Bacon Studios — site styles

   One committed dark world. There is no light theme and that is a choice,
   not an omission: the brand is a polar night, the splash screen the app
   launches with is #0b1f33, and a daylight counterpart would be a second
   identity to design and keep in step. Every color is therefore painted
   explicitly rather than inherited from the viewer's settings.

   Colors are the app's own tokens wherever the app has one, so the site
   and the game are visibly the same product. See penguindoku/src/styles.scss.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── fonts ─────────────────────────────────────────────────────────────
   Self-hosted. A studio whose whole pitch is "no trackers, no network
   calls" should not open by asking Google for its typefaces. Both are
   the latin subset, 50 KB for the pair.

   Luckiest Guy is the BRAND face and is rationed: the wordmark, page
   headlines, game titles, and the three numbers on the landing page.
   Nothing else. Outfit carries everything that is actually read.        */
@font-face {
  font-family: 'Luckiest Guy';
  src: url('fonts/luckiest-guy.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Outfit';
  src: url('fonts/outfit.woff2') format('woff2');
  font-weight: 300 700;      /* variable */
  font-style: normal;
  font-display: swap;
}

:root {
  /* surfaces — --night is the exact splash background, so the browser and
     the app launch on the same color */
  --deep: #060f1e;
  --night: #0b1f33;
  --shelf: #12293f;
  --raised: #17364f;
  --line: rgba(157, 180, 199, 0.18);
  --line-bright: rgba(79, 195, 247, 0.28);

  /* ink — the app's --text / --text-dim / --text-faint */
  --snow: #e8f3fb;
  --fog: #9db4c7;
  --faint: #6b8399;

  /* aurora */
  --mint: #4be3b0;
  --violet: #a177ff;
  --cyan: #4fc3f7;          /* the app's --accent */
  --bacon: #ff8a5b;

  --shell: 1140px;
  --radius: 18px;
  --radius-sm: 12px;

  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }

/* The browser's own [hidden] rule is a UA style, so ANY author rule that sets
   display beats it. `.form { display: grid }` did exactly that: setting
   form.hidden = true had no visible effect and the sent panel appeared under
   a form that was still on screen. Author-level and !important so el.hidden
   means hidden, whatever else the element is styled as. */
[hidden] { display: none !important; }

/* Nothing may scroll the page sideways. `clip` rather than `hidden`: hidden
   turns these into scroll containers, which breaks position:sticky and can
   force a vertical scrollbar; clip just cuts. This is the backstop -- the
   decorations that would overflow are contained individually below. */
html, body { overflow-x: clip; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--deep);
  color: var(--snow);
  font: 300 17px/1.7 Outfit, system-ui, -apple-system, 'Segoe UI', sans-serif;
  -webkit-font-smoothing: antialiased;
  /* hello@penguinbacon.com is 22 unbreakable characters and appears in running
     text; below ~320px it would set the page's minimum width on its own. */
  overflow-wrap: break-word;
}

img { max-width: 100%; }

a { color: var(--cyan); }
a:hover { color: var(--mint); }

:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Skip link — visible only once focused, which is the one time it matters. */
.skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 200;
  background: var(--mint);
  color: #062418;
  font-weight: 600;
  padding: 12px 18px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: top 0.15s;
}
.skip:focus { top: 12px; }

.shell {
  max-width: var(--shell);
  margin: 0 auto;
  /* padding-inline, never `padding: 0 28px`. The shorthand also sets
     padding-block: 0, which silently wipes the vertical padding of whatever
     class shares the element -- .hero, .band, .top and .page-head all set
     theirs with padding-block for the same reason. The 640px override below
     was written as a shorthand and did exactly that to the hero, leaving the
     headline one pixel under the nav on a phone. */
  padding-inline: 28px;
}

/* ── penguins ──────────────────────────────────────────────────────────
   The Illustrator exports carry ~138 global .stN class names and generic
   gradient ids, so inlining two of them would have the second overwrite
   the first's styles. They stay as images, exactly as the app keeps them.
   The art is portrait; the aspect ratio comes from each file's viewBox
   and the caller sizes the box.                                          */
.peng {
  display: block;
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: contain;
  aspect-ratio: var(--ar, 1);
}
.peng.eat        { --ar: 0.654; background-image: url('art/penguin-bacon-eat.svg'); }
.peng.feast      { --ar: 1;     background-image: url('art/penguin-bacon-feast.svg'); }
.peng.chef       { --ar: 0.986; background-image: url('art/penguin-bacon-chef.svg'); }
.peng.architect  { --ar: 0.806; background-image: url('art/penguin-bacon-architect.svg'); }
.peng.delivery   { --ar: 1;     background-image: url('art/penguin-bacon-delivery.svg'); }
.peng.standeat   { --ar: 0.671; background-image: url('art/penguin-bacon-stand-eat.svg'); }
.peng.stuffed    { --ar: 0.910; background-image: url('art/penguin-bacon-stuffed.svg'); }

/* ── aurora ────────────────────────────────────────────────────────────
   Penguindoku already draws an aurora behind the board
   (features/game/stage.ts), so the site and the game open on the same sky.

   Five ribbons rather than three, and the palette follows a real aurora
   rather than a tidy brand one: green dominates, violet and cyan sit either
   side, and a thin rose fringe rides the top edge, which is what the red
   oxygen line actually does at altitude. The rose is kept at a third of the
   others' opacity -- it is a fringe, not a color of its own.

   The container carries a gradient of its own so the sky has depth behind
   the ribbons instead of a flat slab.                                       */
.aurora {
  position: absolute;
  inset: 0 0 auto;
  height: 820px;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(120% 70% at 50% -10%, rgba(23, 63, 92, 0.55), transparent 70%),
    linear-gradient(180deg, rgba(11, 31, 51, 0.95) 0%, rgba(8, 22, 39, 0.5) 45%, rgba(6, 15, 30, 0) 100%);
}
.aurora i {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(78px);
  will-change: transform;
}
.aurora i:nth-child(1) {
  width: 900px; height: 330px; left: -160px; top: -110px;
  background: var(--mint); opacity: 0.52;
  animation: drift 24s ease-in-out infinite alternate;
}
.aurora i:nth-child(2) {
  width: 760px; height: 290px; left: 30%; top: -160px;
  background: var(--violet); opacity: 0.46;
  animation: drift 29s ease-in-out infinite alternate-reverse;
}
.aurora i:nth-child(3) {
  width: 700px; height: 260px; right: -120px; top: -20px;
  background: var(--cyan); opacity: 0.42;
  animation: drift 20s ease-in-out infinite alternate;
}
.aurora i:nth-child(4) {
  width: 820px; height: 240px; left: 8%; top: 90px;
  background: #2bd4c8; opacity: 0.3;
  animation: drift 34s ease-in-out infinite alternate;
}
/* the red-oxygen fringe, deliberately faint */
.aurora i:nth-child(5) {
  width: 640px; height: 170px; left: 42%; top: -190px;
  background: #ff6fae; opacity: 0.17;
  animation: drift 26s ease-in-out infinite alternate-reverse;
}
@keyframes drift {
  from { transform: translate3d(0, 0, 0) scaleX(1); }
  to   { transform: translate3d(70px, 30px, 0) scaleX(1.2); }
}

/* Two star layers at different sizes and brightnesses, so the field has
   depth rather than reading as one sprinkle. The far layer breathes very
   slowly; the near one is fixed, because two pulses at different rates
   reads as flicker rather than sky. */
.stars {
  position: absolute;
  inset: 0 0 auto;
  height: 820px;
  pointer-events: none;
  z-index: 0;
  opacity: 0.9;
  background-image:
    radial-gradient(1.7px 1.7px at 12% 14%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 78% 9%, #fff, transparent),
    radial-gradient(1.9px 1.9px at 44% 26%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 64% 37%, #eaf4ff, transparent),
    radial-gradient(1.6px 1.6px at 28% 43%, #fff, transparent),
    radial-gradient(1.3px 1.3px at 90% 30%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 7% 34%, #eaf4ff, transparent),
    radial-gradient(1.2px 1.2px at 55% 6%, #fff, transparent),
    radial-gradient(1.8px 1.8px at 35% 55%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 84% 52%, #fff, transparent),
    radial-gradient(1.6px 1.6px at 18% 61%, #dCEBFF, transparent),
    radial-gradient(1.3px 1.3px at 70% 66%, #fff, transparent),
    radial-gradient(1.7px 1.7px at 50% 71%, #fff, transparent),
    radial-gradient(1.2px 1.2px at 96% 63%, #eaf4ff, transparent);
}
.stars::after {
  content: '';
  position: absolute;
  inset: 0;
  opacity: 0.55;
  background-image:
    radial-gradient(1px 1px at 22% 8%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 40% 17%, #fff, transparent),
    radial-gradient(1px 1px at 59% 23%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 86% 19%, #fff, transparent),
    radial-gradient(1px 1px at 3% 24%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 73% 45%, #fff, transparent),
    radial-gradient(1px 1px at 15% 49%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 47% 39%, #fff, transparent),
    radial-gradient(1px 1px at 92% 44%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 31% 33%, #fff, transparent),
    radial-gradient(1px 1px at 66% 57%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 8% 68%, #fff, transparent),
    radial-gradient(1px 1px at 43% 63%, #cfe3f7, transparent),
    radial-gradient(1px 1px at 80% 74%, #fff, transparent);
  animation: breathe 11s ease-in-out infinite alternate;
}
@keyframes breathe {
  from { opacity: 0.3; }
  to   { opacity: 0.75; }
}
/* The sky is the design; the drifting is the flourish. Under reduced motion
   it holds still rather than disappearing. */
@media (prefers-reduced-motion: reduce) {
  .aurora i, .stars::after { animation: none; }
}

/* everything that is not sky sits above it */
.above { position: relative; z-index: 1; }

/* ── wordmark ──────────────────────────────────────────────────────────
   The app's splash stacks PENGUIN / BACON / STUDIOS on three lines in
   Luckiest Guy at line-height 1.02, art above, all sized off the widest
   line so the three read as one block (tools/generate-splash.mjs). The
   site reuses that lockup rather than setting the name on one line, so
   launching the app and opening the site show the same mark.            */
.wordmark {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: var(--snow);
}
.wordmark .peng { width: 42px; flex: none; background-position: center; }
.wordmark .stack {
  font: 400 15px/1.02 'Luckiest Guy', system-ui, sans-serif;
  letter-spacing: 0.035em;
  text-transform: uppercase;
  display: grid;
}
.wordmark:hover .stack { color: var(--mint); }

/* the big version, in the footer. Side by side like the header whenever
   there is room, stacking only when there genuinely is not -- at 44px the
   widest line is about 200px, so with the penguin and the gap it needs
   roughly 340px of content box before it starts to crowd. */
.lockup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  text-align: left;
}
.lockup .peng { width: 104px; flex: none; }
.lockup .stack {
  font: 400 clamp(30px, 5vw, 44px)/1.02 'Luckiest Guy', system-ui, sans-serif;
  letter-spacing: 0.025em;
  text-transform: uppercase;
  color: var(--snow);
  display: grid;
}

/* ── header ────────────────────────────────────────────────────────── */
/* The bar is a full-width sticky wrapper and the header inside it stays a
   .shell, because a sticky element that is itself max-width 1140px would
   frost a strip in the middle of the screen and leave the edges clear.

   Transparent over the hero so the aurora is unbroken, then a blurred pane
   fades in once the page has moved. The class is toggled from site.js rather
   than done with scroll-driven CSS animations, which Firefox still does not
   support. `overflow-x: clip` on html/body is load-bearing here: `hidden`
   would have made them scroll containers and sticky would not stick at all. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  /* A soft scrim even at rest. Fully transparent looked right on a wide
     screen, where the header sits beside the aurora rather than on top of the
     brightest part of it; on a phone the nav wraps to its own line, lands in
     the middle of the mint ribbon, and became unreadable. The gradient fades
     to nothing, so there is no hard edge cutting across the sky. */
  background: linear-gradient(180deg, rgba(6, 15, 30, 0.66) 0%, rgba(6, 15, 30, 0.28) 55%, rgba(6, 15, 30, 0) 100%);
  transition: background 0.3s ease, backdrop-filter 0.3s ease, border-color 0.3s ease;
}
.topbar.stuck {
  background: linear-gradient(180deg, rgba(6, 15, 30, 0.82), rgba(6, 15, 30, 0.82));
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom-color: var(--line);
}
.top {
  display: flex;
  align-items: center;
  gap: 20px;
  /* padding-block, never the `padding: 22px 0` shorthand. These classes are
     always used alongside .shell, which supplies the horizontal padding, and
     a shorthand here wins on the cascade and zeroes it -- which took the side
     gutters off every section and ran the text into the screen edge on a
     phone. */
  padding-block: 22px;
  transition: padding 0.3s ease;
}
.topbar.stuck .top { padding-block: 13px; }
@media (prefers-reduced-motion: reduce) {
  .topbar, .top { transition: none; }
}
.top nav {
  margin-left: auto;
  display: flex;
  gap: 28px;
  align-items: center;
}
.top nav a {
  font: 400 16px/1 Outfit, sans-serif;
  /* --snow, not --fog. These sit over the aurora rather than over a surface,
     and dim gray-blue on mint is the one place on the site where the type
     failed to read. */
  color: var(--snow);
  text-decoration: none;
}
.top nav a:hover { color: var(--mint); }
.top nav a[aria-current='page'] { color: var(--snow); }

/* ── type scale ────────────────────────────────────────────────────── */
h1, h2, h3, h4 { text-wrap: balance; margin: 0; }

.display {
  font: 400 clamp(38px, 6.2vw, 74px)/0.98 'Luckiest Guy', system-ui, sans-serif;
  letter-spacing: 0.005em;
  text-shadow: 0 0 38px rgba(75, 227, 176, 0.3);
}
.display em { font-style: normal; color: var(--mint); }

.title {
  font: 400 clamp(28px, 3.6vw, 42px)/1.05 'Luckiest Guy', system-ui, sans-serif;
}

/* Section headings are Outfit, not the brand face — the brand face stops
   being a signal if every heading wears it. */
.sect-head {
  font: 500 14px/1 Outfit, sans-serif;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 24px;
}

.lede {
  font: 300 clamp(18px, 2vw, 21px)/1.65 Outfit, sans-serif;
  color: var(--fog);
  max-width: 46ch;
}

.prose { max-width: 64ch; }
.prose h2 {
  font: 600 26px/1.3 Outfit, sans-serif;
  color: var(--snow);
  margin: 46px 0 12px;
}
.prose h3 {
  font: 600 19px/1.4 Outfit, sans-serif;
  color: var(--snow);
  margin: 32px 0 8px;
}
.prose p { margin: 0 0 18px; color: var(--fog); }
.prose ul { margin: 0 0 18px; padding-left: 22px; color: var(--fog); }
.prose li { margin-bottom: 9px; }
.prose li::marker { color: var(--cyan); }
.prose strong { color: var(--snow); font-weight: 600; }

/* ── buttons ───────────────────────────────────────────────────────── */
.btns { display: flex; gap: 14px; flex-wrap: wrap; }
.btn {
  font: 500 16px/1 Outfit, sans-serif;
  border-radius: var(--radius-sm);
  padding: 15px 26px;
  text-decoration: none;
  border: 1.5px solid transparent;
  display: inline-block;
}
.btn.primary {
  background: var(--mint);
  color: #062418;
  font-weight: 600;
  box-shadow: 0 0 32px rgba(75, 227, 176, 0.36);
}
.btn.primary:hover { background: #6ceec2; color: #062418; }
.btn.ghost { border-color: rgba(157, 180, 199, 0.4); color: var(--snow); }
.btn.ghost:hover { border-color: var(--mint); color: var(--mint); }

/* ── hero ──────────────────────────────────────────────────────────── */
.hero {
  display: grid;
  grid-template-columns: 1.08fr 0.92fr;
  gap: 40px;
  align-items: end;
  padding-block: 40px 0;
}
.hero .copy { padding-bottom: 60px; }
.hero .display { margin-bottom: 22px; }
.hero .lede { margin: 0 0 32px; }

/* the snow ridge the hero penguin stands on */
.ridge {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  min-height: 350px;
}
.ridge .peng {
  width: 100%;
  max-width: 300px;
  position: relative;
  z-index: 2;
  filter: drop-shadow(0 0 44px rgba(79, 195, 247, 0.32));
}
.ridge::after {
  content: '';
  position: absolute;
  left: -16%; right: -16%; bottom: -1px;
  height: 124px;
  z-index: 1;
  background: linear-gradient(180deg, var(--raised), var(--night));
  border-radius: 50% 50% 0 0 / 72% 72% 0 0;
}

/* ── the one-game shelf ────────────────────────────────────────────── */
.band { padding-block: 66px; border-top: 1px solid var(--line); }
.band:first-of-type { border-top: 0; }

.shelf { display: grid; grid-template-columns: 1.1fr 1fr; gap: 34px; align-items: center; }

.gcard {
  background: linear-gradient(160deg, rgba(23, 54, 79, 0.92), rgba(11, 31, 51, 0.92));
  border: 1px solid var(--line-bright);
  border-radius: var(--radius);
  padding: 30px 32px;
  display: flex;
  gap: 26px;
  align-items: center;
}
.gcard .peng { width: 132px; flex: none; }
.gcard .title { margin-bottom: 8px; }
.gcard p { font: 300 16px/1.6 Outfit, sans-serif; color: var(--fog); margin: 0 0 16px; }

.pill {
  display: inline-block;
  font: 600 12px/1 Outfit, sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bacon);
  border: 1px solid rgba(255, 138, 91, 0.45);
  border-radius: 999px;
  padding: 8px 14px;
}

/* Three numbers, in the brand face because they are the argument.
   Not a card kit — a plain list with a rule between rows. */
.stats { display: grid; gap: 2px; }
.stat {
  display: flex;
  gap: 18px;
  align-items: baseline;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}
.stat:last-child { border-bottom: 0; }
.stat b {
  font: 400 34px/1 'Luckiest Guy', system-ui, sans-serif;
  min-width: 104px;
  font-variant-numeric: tabular-nums;
  color: var(--cyan);
}
.stat:nth-child(2) b { color: var(--mint); }
.stat:nth-child(3) b { color: var(--violet); }
.stat span { font: 300 16px/1.5 Outfit, sans-serif; color: var(--fog); }

/* ── ruled out ─────────────────────────────────────────────────────────
   The × is the game's own mark for a square a player has eliminated. The
   things the studio has ruled out wear the same mark. Not a card grid —
   these are one list, so they share one container and one rhythm.        */
.ruled {
  display: grid;
  /* 280px rather than 230px so the six items land in three columns and fill
     two complete rows. At 230px they made four columns and left the second
     row two-thirds empty. */
  /* min(280px, 100%) rather than a bare 280px: on a 320px phone the shell
     leaves exactly 280px, and anything narrower would make the single column
     wider than its container and push the page sideways. */
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
/* Direct child only. `.ruled div` also matched the wrapper inside each cell,
   which turned it into a flex row and stood the label and its sentence side
   by side in two very narrow columns. */
.ruled > div {
  background: var(--night);
  padding: 22px 24px;
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.ruled .x {
  flex: none;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  background: rgba(255, 138, 91, 0.14);
  color: var(--bacon);
  font: 600 15px/1 Outfit, sans-serif;
}
.ruled b { font: 600 16.5px/1.35 Outfit, sans-serif; color: var(--snow); display: block; }
.ruled p { font: 300 15px/1.55 Outfit, sans-serif; color: var(--fog); margin: 5px 0 0; }

/* ── the board ─────────────────────────────────────────────────────────
   A real, solved 6×6 Penguindoku position: one penguin per colony, none
   sharing a row or column, and none touching — not even at a corner.
   Colony colors are the app's --region-0..5.                            */
.board {
  --c0: #3d7fbf; --c1: #c88a35; --c2: #4f9d55;
  --c3: #9159bd; --c4: #d0605a; --c5: #2ba39b;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  width: 100%;
  max-width: 380px;
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 2px solid rgba(0, 0, 0, 0.35);
}
.board span {
  position: relative;
  border: 0.5px solid rgba(255, 255, 255, 0.09);
}
.board .r0 { background: var(--c0); }
.board .r1 { background: var(--c1); }
.board .r2 { background: var(--c2); }
.board .r3 { background: var(--c3); }
.board .r4 { background: var(--c4); }
.board .r5 { background: var(--c5); }
.board .p::after {
  content: '';
  position: absolute;
  inset: 11%;
  background: url('art/penguin-bacon-eat.svg') center/contain no-repeat;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
}
.board-note {
  font: 300 14.5px/1.6 Outfit, sans-serif;
  color: var(--faint);
  margin: 14px 0 0;
  max-width: 40ch;
}

/* ── rules list, on the game page ──────────────────────────────────────
   Deliberately not numbered. The four rules all apply at once — they are
   not steps to work through in order, and numbering them would say they
   were.                                                                  */
.rules { display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
/* Indent-and-absolute, NOT a grid or flex row. Each item is a bold lead-in
   followed by a bare text node, and a grid container makes those two things
   two separate items: the sentence gets placed in the next cell along, which
   is the 26px marker column, and wraps one word per line. Keeping the li in
   normal flow keeps its inline content in one run. */
.rules li {
  position: relative;
  padding-left: 26px;
  font: 300 17px/1.6 Outfit, sans-serif;
  color: var(--fog);
}
.rules li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 11px;
  height: 11px;
  border-radius: 3px;
  background: var(--cyan);
  transform: rotate(45deg);
}
.rules li:nth-child(2)::before { background: var(--mint); }
.rules li:nth-child(3)::before { background: var(--violet); }
.rules li:nth-child(4)::before { background: var(--bacon); }
.rules strong { color: var(--snow); font-weight: 600; }

/* ── footer ────────────────────────────────────────────────────────── */
.foot {
  border-top: 1px solid var(--line);
  background: var(--night);
  padding: 56px 0 40px;
  margin-top: 40px;
}
.foot .lockup { margin-bottom: 34px; }
.foot .links {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 30px;
  justify-content: center;
  font: 400 15px/1 Outfit, sans-serif;
  margin-bottom: 22px;
}
.foot .links a { color: var(--fog); text-decoration: none; }
.foot .links a:hover { color: var(--mint); }
.foot .fine {
  text-align: center;
  font: 300 14px/1.6 Outfit, sans-serif;
  color: var(--faint);
  margin: 0;
}

/* ── page header for the inner pages ───────────────────────────────── */
.page-head { padding-block: 34px 26px; }
.page-head .title { margin-bottom: 14px; }
.page-head p { font: 300 18px/1.6 Outfit, sans-serif; color: var(--fog); margin: 0; max-width: 56ch; }
.updated {
  font: 400 13px/1 Outfit, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 18px;
}

/* ── responsive ────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; gap: 10px; }
  .hero .copy { padding-bottom: 20px; }
  /* The snow mound is inset -16% on each side so it reads as a hill running
     past the edges of its column. Once the hero collapses to one column the
     ridge IS the full page width, so that -16% becomes -16% of the viewport
     and the page gains ~34px of horizontal scroll with a strip of the mound
     showing beside it. Full-width and let the border-radius make the dome. */
  .ridge::after { left: 0; right: 0; }
  .shelf { grid-template-columns: 1fr; }
  .gcard { flex-direction: column; align-items: flex-start; }
  .gcard .peng { width: 108px; }
}
@media (max-width: 640px) {
  .shell { padding-inline: 20px; }
  .top nav { gap: 18px; }
  .top nav a { font-size: 15px; }
  .band { padding-block: 48px; }
  .ridge { min-height: 280px; }
}
@media (max-width: 520px) {
  .lockup { flex-direction: column; text-align: center; gap: 16px; }
  .lockup .peng { width: 96px; }
}
@media (max-width: 460px) {
  .top { flex-wrap: wrap; }
  .top nav { margin-left: 0; width: 100%; }
}

/* ── contact form ──────────────────────────────────────────────────────
   The only page on the site with a form, and the only one that loads
   anything from a third party (the Turnstile challenge). Keeping it on its
   own page is what lets every other page stay free of outside requests.   */
.form { display: grid; gap: 22px; max-width: 34rem; }
.field { display: grid; gap: 7px; }
.field label {
  font: 500 15px/1.4 Outfit, sans-serif;
  color: var(--snow);
}
.field label .opt { color: var(--faint); font-weight: 400; }
.field input,
.field select,
.field textarea {
  font: 300 16px/1.5 Outfit, system-ui, sans-serif;
  color: var(--snow);
  background: var(--night);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 13px 15px;
  width: 100%;
  /* 16px minimum on the input itself, because iOS Safari zooms the whole
     page in when it focuses a field smaller than that and never zooms back. */
}
.field textarea { resize: vertical; min-height: 150px; }
.field select { appearance: none; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--fog) 50%),
                    linear-gradient(135deg, var(--fog) 50%, transparent 50%);
  background-position: calc(100% - 20px) calc(50% + 2px), calc(100% - 14px) calc(50% + 2px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 40px;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--cyan);
  outline-offset: 1px;
  border-color: transparent;
}
.field .hint { font: 300 14px/1.5 Outfit, sans-serif; color: var(--faint); margin: 0; }
.field.bad input, .field.bad textarea { border-color: #ff7a6b; }
.field .err { font: 400 14px/1.5 Outfit, sans-serif; color: #ff9b8f; margin: 0; }

/* The honeypot. Off-screen rather than display:none, and never focusable, so
   a human cannot reach it by tabbing and a bot filling every field trips it. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-actions { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.form button[type="submit"] { border: 0; cursor: pointer; font-family: Outfit, sans-serif; }
.form button[disabled] { opacity: 0.55; cursor: default; box-shadow: none; }
.form-status { font: 400 15px/1.5 Outfit, sans-serif; margin: 0; color: var(--fog); }
.form-status.bad { color: #ff9b8f; }

/* ── the thank-you dialog ──────────────────────────────────────────────
   A real <dialog>, so the browser handles the focus trap, Escape, and
   inertness of the page behind it rather than us reimplementing all three
   badly. Closing it leaves the quiet .sent panel behind, so the page never
   drops back to an empty space where the form used to be.               */
.thanks {
  border: 1px solid var(--line-bright);
  background: var(--night);
  color: var(--snow);
  border-radius: var(--radius);
  padding: 0;
  width: min(27rem, calc(100vw - 40px));
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.62);
}
.thanks::backdrop {
  background: rgba(3, 8, 16, 0.7);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.thanks .inner { padding: 30px 28px 26px; text-align: center; }
.thanks .peng { width: 132px; margin: 0 auto 14px; }
.thanks h2 {
  font: 400 clamp(26px, 7vw, 32px)/1 'Luckiest Guy', system-ui, sans-serif;
  color: var(--mint);
  margin: 0 0 12px;
}
.thanks p {
  font: 300 16px/1.6 Outfit, sans-serif;
  color: var(--fog);
  margin: 0 0 22px;
  text-wrap: pretty;
}
.thanks button {
  font: 600 16px/1 Outfit, sans-serif;
  background: var(--mint);
  color: #062418;
  border: 0;
  border-radius: var(--radius-sm);
  padding: 14px 26px;
  cursor: pointer;
  width: 100%;
}
.thanks button:hover { background: #6ceec2; }
.thanks[open] { animation: thanks-in 0.22s ease-out; }
@keyframes thanks-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .thanks[open] { animation: none; }
}

/* the confirmation that replaces the form once it has sent */
.sent {
  border: 1px solid rgba(75, 227, 176, 0.4);
  background: rgba(75, 227, 176, 0.07);
  border-radius: var(--radius);
  padding: 26px 28px;
  max-width: 34rem;
}
.sent h3 { font: 400 26px/1.1 'Luckiest Guy', system-ui, sans-serif; color: var(--mint); margin: 0 0 10px; }
.sent p { font: 300 16px/1.6 Outfit, sans-serif; color: var(--fog); margin: 0; }
