/* ==========================================================================
   Bootje varen door de grachten — 9 August 2026
   Mobile-first. Colours and sizing live in the variables below.
   ========================================================================== */

:root {
  /* Palette */
  --blue:         #3E9FD6;
  --blue-deep:    #2B7DAD;
  --blue-light:   #DFF0F7;
  --coral:        #D85A30;
  --coral-deep:   #B84720;
  --amber:        #EF9F27;
  --green:        #7BAE5C;
  --ink:          #20303A;
  --ink-soft:     #4C6070;
  --paper:        #FFFFFF;

  /* Shape */
  --radius:       22px;
  --radius-sm:    14px;
  --column:       40rem;   /* max width of the text column */
  --gutter:       1.25rem; /* left/right margin on phones */

  --shadow: 0 2px 0 rgba(32, 48, 58, .05), 0 10px 24px -18px rgba(32, 48, 58, .5);

  --font-display: "Fredoka", "Baloo 2", "Quicksand", ui-rounded, "Trebuchet MS", sans-serif;
  --font-body:    "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink);
  /* soft sky-to-water backdrop */
  background: var(--blue-light) linear-gradient(180deg, #EAF6FB 0%, var(--blue-light) 45%, #CFE8F2 100%) no-repeat;
  background-size: 100% 100%;
}

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

.page {
  max-width: var(--column);
  margin: 0 auto;
  overflow-x: clip;
}

/* --------------------------------------------------------------------------
   Image slots
   Three states, driven by script.js:
   - loading  → the --preview blur (a ~40px wide copy of the real artwork,
                inlined below) shows, and the real image fades in over it
   - loaded   → just the image
   - is-empty → file is missing: the coloured CSS stand-in takes over,
                so a broken-image icon never appears
   -------------------------------------------------------------------------- */

.slot {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--blue-light);
}

/* the low-res preview, scaled up and smoothed by the browser. Sits under the
   image so there is never a flat empty rectangle while the file downloads. */
.slot::before {
  content: "";
  position: absolute;
  /* bleed past the edges so the blur does not fade into the background */
  inset: -6%;
  z-index: 1;
  background-image: var(--preview, none);
  background-size: cover;
  background-position: center;
  filter: blur(14px);
  transform: scale(1.04);
}

/* <picture> only picks the file format; it still has to fill the slot, or the
   img inside it has no box to crop against and object-fit does nothing. */
.slot picture {
  display: block;
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
}

.slot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  position: relative;
  z-index: 2;
  opacity: 1;
  transition: opacity .45s ease-out;
}

/* fade the real artwork in on top of the preview rather than snapping to it */
.slot.is-loading img { opacity: 0; }

/* missing file: drop the image and the preview, show the drawn stand-in */
.slot.is-empty picture,
.slot.is-empty img { display: none; }
.slot.is-empty::before { display: none; }

.slot__stand-in {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;
}

.slot.is-empty .slot__stand-in { display: block; }

@media (prefers-reduced-motion: reduce) {
  .slot img { transition: none; }
}

/* Small hint showing the expected file path — only while the image is missing.
   Tucked into the top-right corner so it stays clear of the stand-in artwork. */
.slot.is-empty::after {
  content: attr(data-hint);
  position: absolute;
  z-index: 3;
  top: .5rem;
  right: .5rem;
  padding: .2rem .6rem;
  border-radius: 999px;
  font: 600 11px/1.5 var(--font-body);
  letter-spacing: .02em;
  white-space: nowrap;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, .78);
}

/* --- CSS stand-in scene: sky, houses, trees, water, little boat ----------- */

.scene {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #BFE4F5 0%, #E8F5FB 62%);
}

.scene__sun {
  position: absolute;
  top: 13%;
  right: 14%;
  width: 14%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--amber);
  opacity: .9;
}

.scene__houses {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 32%;
  height: 46%;
  display: flex;
  align-items: flex-end;
  gap: 2px;
  padding: 0 4%;
}

.scene__houses span {
  flex: 1;
  height: var(--h);
  background: var(--c);
  border-radius: 6px 6px 0 0;
  position: relative;
}

/* cornice */
.scene__houses span::before {
  content: "";
  position: absolute;
  left: -6%;
  right: -6%;
  top: -7px;
  height: 9px;
  border-radius: 4px;
  background: inherit;
  filter: brightness(.92);
}

/* windows */
.scene__houses span::after {
  content: "";
  position: absolute;
  inset: 22% 26% 30%;
  border-radius: 3px;
  background:
    linear-gradient(var(--blue-deep) 0 0) center / 100% 22% no-repeat,
    linear-gradient(var(--blue-deep) 0 0) top / 100% 22% no-repeat;
  opacity: .35;
}

.scene__trees {
  position: absolute;
  left: 0;
  bottom: 30%;
  width: 100%;
  height: 26%;
  display: flex;
  align-items: flex-end;
  gap: 6%;
  padding-left: 3%;
}

.scene__trees span {
  width: 13%;
  aspect-ratio: 1;
  border-radius: 50% 50% 46% 46%;
  background: var(--green);
}
.scene__trees span:nth-child(2) { width: 10%; filter: brightness(1.1); }
.scene__trees span:nth-child(3) { width: 15%; filter: brightness(.92); }

.scene__water {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 32%;
  background:
    repeating-linear-gradient(
      180deg,
      transparent 0 14px,
      rgba(255, 255, 255, .16) 14px 18px
    ),
    linear-gradient(180deg, var(--blue) 0%, var(--blue-deep) 100%);
}

.scene__boat {
  position: absolute;
  left: 50%;
  bottom: 14%;
  width: 42%;
  transform: translateX(-50%);
}

.scene__boat-roof {
  width: 66%;
  height: 16px;
  margin: 0 auto 4px;
  border-radius: 9px 9px 2px 2px;
  background: var(--coral);
}

.scene__boat-hull {
  height: 30px;
  border-radius: 4px 4px 26px 26px / 4px 4px 20px 20px;
  background: var(--paper);
  border-bottom: 7px solid var(--amber);
}

/* compact variant used in the boat section: less sky, bigger boat */
.scene--mini { background: linear-gradient(180deg, #CDE9F6 0%, #EAF6FB 60%); }

/* simple house row along the quay so the sky is not a big empty field */
.scene--mini::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 52%;
  height: 22%;
  background: repeating-linear-gradient(
    90deg,
    #D9BFA6 0 7%,
    transparent 7% 8%,
    #E8D6BF 8% 16%,
    transparent 16% 17%,
    #C9A88C 17% 23%,
    transparent 23% 24%
  );
  border-radius: 5px 5px 0 0;
  opacity: .85;
}
.scene--mini .scene__water { height: 52%; }
.scene--mini .scene__boat { width: 62%; bottom: 20%; }
.scene--mini .scene__boat-roof { height: 22px; }
.scene--mini .scene__boat-hull { height: 42px; }

/* --------------------------------------------------------------------------
   1. Hero
   -------------------------------------------------------------------------- */

.hero { margin-bottom: 2rem; }

/* 40x22 WebP copy of images/hero-canal.png, 492 bytes — inlined so it paints
   with the stylesheet, no second request. Regenerate if the artwork changes. */
.slot--hero {
  --preview: url("data:image/webp;base64,UklGRuQBAABXRUJQVlA4INgBAACQCgCdASooABYAPm0ukkakIqGhKqoAgA2JbACdMoRz7tV5YXgEyzSGOk15gPOd0xPnxf2O+Ef9xmHQbog6S0p9ftjR6qdO6yFIsWKia9MtsNAs3p5UW9Z09he9coAA26wxqyYdABFoKJ60Lu+ZA31zX4s5WdBu551DM0RCOR+ResbNomrdbfb8RBrGWtwyqkQSjYFQ1aKDjn9InQEgWcs1rXoTK2/zj+4lHNgDj/H6R/vYrCYtSMTKCxAsxj1YN7TrTmxOBZWXY5mufKCcmyaRnXjl939rmkDj1abPZYc1rI2Q6pENRiXkYeQ0ivoY9n01MrIlH0qraSyprgUe1nVJPP8vQvQVe29qy565ruJecOHVUrQ/C/o5szvDUUcmwzZXVCbGkDBNhVsto/VMjGD1277e+B2ogpnJUeONdFoIa/k6MyKpf3t+jpzafUvj2aJJz9/u5Mft+L8dqngwFlW/+xWi201KXzH0QGXwDfgbXlXvWRbbUipUt9dfz2p8Nypg/uDhdYV/Ro1h/WE93eJ9QQ1lfGGd1nXV39w26cPDxr1ZA8oAMhbQ0RFzjLmxBdQxYssRQxmqc9WtE+yEycm1GoL6xBsYfsaQo103z/Cl8V5vhh3oAAAA");
  aspect-ratio: 16 / 9;
}

.hero__text {
  padding: 1.6rem var(--gutter) 0;
  text-align: center;
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2rem, 9.5vw, 2.9rem);
  line-height: 1.05;
  letter-spacing: -.01em;
  margin: 0 0 1.15rem;
  color: var(--blue-deep);
}

.hero__date {
  display: inline-block;
  margin: 0 0 1.15rem;
  padding: .3rem 1rem;
  border-radius: 999px;
  background: var(--amber);
  color: #4A2C05;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
}

.hero__intro {
  margin: 0 auto;
  max-width: 30rem;
  color: var(--ink-soft);
  font-size: 1.05rem;
}

/* --------------------------------------------------------------------------
   Sections
   -------------------------------------------------------------------------- */

.section {
  padding: 1.6rem var(--gutter);
}

.section__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.55rem;
  line-height: 1.2;
  margin: 0 0 1.1rem;
  color: var(--blue-deep);
}

/* --------------------------------------------------------------------------
   2. Route timeline
   -------------------------------------------------------------------------- */

.route {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

/* the continuous route line */
.route::before {
  content: "";
  position: absolute;
  left: 9px;
  top: 12px;
  bottom: 12px;
  width: 3px;
  border-radius: 3px;
  transform-origin: 50% 0;
  background: repeating-linear-gradient(
    180deg,
    var(--blue) 0 10px,
    rgba(62, 159, 214, .3) 10px 16px
  );
}

/* --- scroll reveal -------------------------------------------------------
   script.js adds .is-armed only when it is going to animate (JS available,
   IntersectionObserver supported, motion not reduced), so without JS the
   timeline simply renders in its finished state. .is-revealed then draws the
   line downwards and drops the stops in one by one; --i is the stop index.
   ------------------------------------------------------------------------ */

.route.is-armed::before { transform: scaleY(0); }

.route.is-armed.is-revealed::before {
  transform: scaleY(1);
  transition: transform .9s cubic-bezier(.33, 1, .68, 1);
}

.route.is-armed .route__stop {
  opacity: 0;
  transform: translateY(10px);
}

.route.is-armed .route__marker { transform: scale(.4); }

.route.is-armed.is-revealed .route__stop,
.route.is-armed.is-revealed .route__marker {
  opacity: 1;
  transform: none;
  transition:
    opacity .45s ease-out calc(var(--i, 0) * 150ms + 120ms),
    transform .5s cubic-bezier(.34, 1.56, .64, 1) calc(var(--i, 0) * 150ms + 120ms);
}

.route__stop {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  column-gap: .8rem;
  padding: 0 0 1.35rem 2.15rem;
}

.route__stop:last-child { padding-bottom: 0; }

.route__marker {
  position: absolute;
  left: 0;
  top: .35em;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background: var(--paper);
  border: 3px solid var(--blue);
  box-shadow: 0 0 0 4px var(--blue-light);
}

/* current or next upcoming stop gets the stronger fill */
/*.route__stop.is-next .route__marker {*/
/*  background: var(--coral);*/
/*  border-color: var(--coral);*/
/*  box-shadow: 0 0 0 5px rgba(216, 90, 48, .18);*/
/*}*/

/*.route__stop.is-next .route__time { color: var(--coral); }*/
/*.route__stop.is-next .route__label { font-weight: 700; }*/

/* stops that have already passed */
.route__stop.is-done { opacity: .55; }

.route__time {
  grid-column: 1;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--blue-deep);
  white-space: nowrap;
}

.route__label {
  grid-column: 2;
  font-size: 1.02rem;
}

/* sits in the label column, on its own row, so it never widens the time column */
.route__note {
  grid-column: 2;
  margin-top: .15rem;
  font-style: normal;
  color: var(--ink-soft);
  font-size: .92em;
}

/* stack time above label on very narrow phones so "12:00–14:00" never squeezes */
@media (max-width: 359px) {
  .route__stop { grid-template-columns: 1fr; row-gap: .1rem; }
  .route__label,
  .route__note { grid-column: 1; }
}

/* --------------------------------------------------------------------------
   3. The boat
   -------------------------------------------------------------------------- */

.boat {
  display: grid;
  gap: 1.1rem;
  padding: 1rem;
  background: var(--paper);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* 32x21 WebP copy of images/boat.png, 288 bytes — see .slot--hero */
.slot--boat {
  --preview: url("data:image/webp;base64,UklGRhgBAABXRUJQVlA4IAwBAAAwBgCdASogABUAPm0ukEWkIqGYDAYAQAbEsQBOmUI8x5JVvNRSMSsui7tpuchsQ7Pu539F+HnNTadAAP7ZWKQqCq3rzrZWa+lVwXgTOKsDOND1DW8b27BB0J4z+0SRrsMtx/RaUjR0l62BatZRkZqqJs+TwG86KkJv04o662jDiRFwjm0pGxAfrRD0x1hlz8ceZpNQp08w4ZXkLzevbzdXUhf9HTa7y9J/wMZdR11WFEutFhf5QR3kJchgHaiXRtXCKLoBiSEi8jGOx/+WzFwnrR854cYUHNIRhIDkJFHMsBFiOZZXBx7ZrZpHv+VQMgqdJchy6JF1FJvvyn5YKQIfR4t3tFm5DuhK3IAA");
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-sm);
}

.boat__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.25rem;
  margin: 0 0 .5rem;
  color: var(--ink);
}

.specs {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 1rem 0 0;
  padding: 0;
}

.spec {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .4rem .8rem .4rem .6rem;
  border-radius: 999px;
  background: var(--blue-light);
  font-size: .95rem;
  color: var(--ink);
}

.spec strong { font-weight: 700; }

.spec__icon {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: var(--blue-deep);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* two columns once there is room */
@media (min-width: 34rem) {
  .boat {
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 1.25rem;
    padding: 1.15rem;
  }
  .slot--boat { aspect-ratio: 1; height: 100%; }
}

/* --------------------------------------------------------------------------
   4. Skipper note
   -------------------------------------------------------------------------- */

.skipper {
  position: relative;
  padding: 2.1rem 1.25rem 1.4rem;
  border-radius: var(--radius);
  background: linear-gradient(165deg, #FFF3E2 0%, #FFE6CE 100%);
  border: 2px solid rgba(216, 90, 48, .22);
  box-shadow: var(--shadow);
}

.skipper__badge {
  position: absolute;
  top: 0;
  left: 1.25rem;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--coral);
  box-shadow: 0 0 0 5px #FFF3E2;
}

.skipper__badge svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: #fff;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.skipper__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.35rem;
  line-height: 1.2;
  margin: 0 0 .7rem;
  color: var(--coral-deep);
}

.skipper p { color: #4A3526; }

/* --------------------------------------------------------------------------
   5. Practical information
   -------------------------------------------------------------------------- */

.facts {
  display: grid;
  gap: .7rem;
}

.fact {
  padding: .9rem 1.05rem;
  background: var(--paper);
  border-radius: var(--radius-sm);
  border-left: 5px solid var(--green);
}

.fact__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  margin: 0 0 .15rem;
  color: var(--ink);
}

.fact p {
  font-size: .98rem;
  color: var(--ink-soft);
}

/* copy that still needs filling in stands out while building */
.is-placeholder {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .85rem !important;
  color: var(--coral-deep) !important;
  background: rgba(216, 90, 48, .08);
  border-radius: 6px;
  padding: .25rem .45rem;
}

@media (min-width: 34rem) {
  .facts { grid-template-columns: repeat(3, 1fr); }
}

/* --------------------------------------------------------------------------
   Mini-game
   Every moving piece has a CSS stand-in shape. When game.js finds a matching
   sprite in images/ it adds .has-<name> to .game and the artwork takes over.
   -------------------------------------------------------------------------- */

.game__intro {
  margin: -.4rem 0 1rem;
  color: var(--ink-soft);
  font-size: .98rem;
}

.game {
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: var(--shadow);
  overflow: hidden;

  /* Phones flash a translucent grey box over whatever you tap. That reads as
     lag in a game where every tap is a jump, so it is switched off here — it
     inherits, so the canal and the Start button are both covered. The button
     keeps its own :active state, which is the feedback that belongs here. */
  -webkit-tap-highlight-color: transparent;
}

.game__hud {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .6rem .9rem;
  font-size: .9rem;
  color: var(--ink-soft);
}

.game__stat strong {
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--blue-deep);
  margin-left: .15rem;
}

.game__canal {
  position: relative;
  aspect-ratio: 16 / 10;
  max-height: 340px;
  overflow: hidden;
  background: linear-gradient(180deg, #BFE4F5 0%, #CFEAF7 26%, var(--blue) 26%, var(--blue-deep) 100%);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

/* only while playing, so the page still scrolls normally when it is idle */
.game.is-running .game__canal { touch-action: none; }

/* Custom canal background. It supplies its own houses and water, so the CSS
   stand-ins for both step aside — but only once the file has actually loaded,
   which is why this hangs off a class game.js adds rather than being the
   default. Without it the drawn-in-CSS canal below still works. */
/* Two declarations on purpose: the PNG one is the fallback for browsers that
   cannot parse image-set(), which drop the second line and keep the first. Only
   one of the two files is ever fetched. Same pattern for the sprites below. */
.game.has-background .game__canal {
  background: url("images/game-background.png") center / cover no-repeat;
  background-image: image-set(
    url("images/game-background.webp") type("image/webp"),
    url("images/game-background.png") type("image/png"));
}

.game.has-background .game__quay { display: none; }

/* Wave marks on the water — the thing that tells you how fast you are going.

   Four rows, every one repeating every 60px, so sliding the whole layer 60px
   to the left loops seamlessly. Starts at 29% because that is exactly where the
   waterline sits in game-background.png; if that drawing changes, this is the
   number to move with it.

   Each row is one little wave, drawn as an inline SVG rather than a dash of
   gradient: as flat bars these read as lane markings on a road. Same four
   lengths and opacities the bars had — only the shape changed. The rows differ
   in length so they do not march in lockstep, and each SVG is 60px wide (the
   repeat period) by 10px tall, which is the room the curve needs.

   The loop duration is NOT fixed here: game.js sets --flow so that the waves
   travel at the same speed as the obstacles. On a fixed duration they drifted
   out of step as the game sped up, which is worse than having no waves at
   all — they would have been actively lying about the speed. */
.game__canal::before {
  content: "";
  position: absolute;
  left: 0;
  right: -60px;
  top: 29%;
  bottom: 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 10'%3E%3Cpath d='M0 5q4.5-4.5 9 0t9 0' fill='none' stroke='white' stroke-opacity='0.2' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") 0 6% / 60px 10px repeat-x,
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 10'%3E%3Cpath d='M0 5q2.75-4.5 5.5 0t5.5 0' fill='none' stroke='white' stroke-opacity='0.15' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") 0 32% / 60px 10px repeat-x,
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 10'%3E%3Cpath d='M0 5q5.5-4.5 11 0t11 0' fill='none' stroke='white' stroke-opacity='0.17' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") 0 58% / 60px 10px repeat-x,
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 10'%3E%3Cpath d='M0 5q3.5-4.5 7 0t7 0' fill='none' stroke='white' stroke-opacity='0.13' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") 0 84% / 60px 10px repeat-x;
}

.game.is-running .game__canal::before {
  animation: canal-flow var(--flow, 0.2s) linear infinite;
}

@keyframes canal-flow {
  to { transform: translateX(-60px); }
}

/* far bank at the top of the canal: houses sitting in the lower part of the
   strip, so a band of sky stays visible above them */
.game__quay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 26%;
  background:
    repeating-linear-gradient(
      90deg,
      #D9BFA6 0 7%,
      transparent 7% 8%,
      #E8D6BF 8% 16%,
      transparent 16% 17%,
      #C9A88C 17% 23%,
      transparent 23% 24%
    ) 0 100% / 100% 62% no-repeat;
  opacity: .9;
}

/* --- the boat ------------------------------------------------------------- */

/* width and left come from game.js — it owns the size the hitbox is based on */
.game__boat {
  position: absolute;
  top: 0;
  left: 0;
  width: 14%;
  aspect-ratio: 16 / 10;
  will-change: transform;
}

/* stand-in: white hull, coral canopy, amber keel */
.game__boat::before,
.game__boat::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
}

.game__boat::before { /* canopy */
  top: 0;
  height: 34%;
  width: 62%;
  margin: 0 auto;
  border-radius: 7px 7px 2px 2px;
  background: var(--coral);
}

.game__boat::after { /* hull */
  bottom: 0;
  height: 56%;
  border-radius: 3px 3px 22px 22px / 3px 3px 16px 16px;
  background: var(--paper);
  border-bottom: 4px solid var(--amber);
}

/* --- obstacles ------------------------------------------------------------ */

.game__thing {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
}

.game__thing--duck {
  border-radius: 50% 50% 45% 45%;
  background: var(--amber);
}

.game__thing--duck::before { /* head */
  content: "";
  position: absolute;
  top: -42%;
  right: 4%;
  width: 46%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--amber);
}

.game__thing--buoy {
  border-radius: 40% 40% 30% 30%;
  background: var(--coral);
  box-shadow: inset 0 -35% 0 -12% rgba(255, 255, 255, .85);
}

/* moored across the far side of the canal, up where the boat must not be */
.game__thing--houseboat {
  border-radius: 6px 6px 10px 10px;
  background: linear-gradient(180deg, #E8D6BF 0%, #C9A88C 58%, #8E6E55 58%, #7A5C46 100%);
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, .12);
}

/* sprite versions: swapped in only when the file actually exists */
.game.has-boat .game__boat {
  background: url("images/game-boat.png") center/contain no-repeat;
  background-image: image-set(
    url("images/game-boat.webp") type("image/webp"),
    url("images/game-boat.png") type("image/png"));
}
.game.has-boat .game__boat::before,
.game.has-boat .game__boat::after { content: none; }

.game.has-duck .game__thing--duck {
  background: url("images/game-duck.png") center/contain no-repeat;
  background-image: image-set(
    url("images/game-duck.webp") type("image/webp"),
    url("images/game-duck.png") type("image/png"));
  border-radius: 0;
}
.game.has-duck .game__thing--duck::before { content: none; }

.game.has-buoy .game__thing--buoy {
  background: url("images/game-buoy.png") center/contain no-repeat;
  background-image: image-set(
    url("images/game-buoy.webp") type("image/webp"),
    url("images/game-buoy.png") type("image/png"));
  border-radius: 0;
  box-shadow: none;
}

.game.has-houseboat .game__thing--houseboat {
  background: url("images/game-houseboat.png") center/contain no-repeat;
  background-image: image-set(
    url("images/game-houseboat.webp") type("image/webp"),
    url("images/game-houseboat.png") type("image/png"));
  border-radius: 0;
  box-shadow: none;
}

/* --- start / game-over overlay -------------------------------------------- */

.game__overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: .1rem;
  padding: 1rem;
  text-align: center;
  /* a scrim rather than a wash, so the canal stays visible underneath */
  background: rgba(18, 58, 84, .55);
}

.game.is-running .game__overlay { display: none; }

.game__message {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.3rem;
  color: #fff;
  margin: 0;
}

.game__hint {
  margin: 0 0 .8rem;
  font-size: .9rem;
  color: rgba(255, 255, 255, .88);
}

.button--small {
  padding: .6rem 1.3rem;
  font-size: 1rem;
  box-shadow: 0 3px 0 var(--coral-deep);
}

/* --------------------------------------------------------------------------
   6. Closing / RSVP
   -------------------------------------------------------------------------- */

.closing {
  text-align: center;
  padding-top: 2rem;
  padding-bottom: 2.5rem;
}

.closing__text {
  max-width: 26rem;
  margin: 0 auto 1.4rem;
  color: var(--ink-soft);
  font-size: 1.05rem;
}

.button {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  padding: .95rem 1.6rem;
  border-radius: 999px;
  background: var(--coral);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.08rem;
  text-decoration: none;
  box-shadow: 0 4px 0 var(--coral-deep);
  transition: transform .12s ease, box-shadow .12s ease;
}

.button:hover { background: #CC5029; }

.button:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--coral-deep);
}

.button:focus-visible {
  outline: 3px solid var(--blue-deep);
  outline-offset: 3px;
}

.button__icon {
  width: 22px;
  height: 22px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --------------------------------------------------------------------------
   Footer — wave edge to close the page
   -------------------------------------------------------------------------- */

.footer__waves {
  height: 76px;
  background:
    /* scalloped top edge */
    radial-gradient(circle at 50% 100%, var(--blue) 0 23px, transparent 24px) 0 0 / 48px 24px repeat-x,
    /* the blue band underneath */
    linear-gradient(180deg, var(--blue) 0%, var(--blue-deep) 100%) 0 22px / 100% 100% no-repeat;
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
