/* Stowit illustration primitives — soft geometric.
   Source of truth: project/docs/DESIGN.md §3 Illustration, §4 Motion.

   Flat fills, no outlines, no gradients except the sun's halo. Everything is a
   rounded rectangle, a circle, or a scalloped band. Never draw detail (rigging,
   planks, faces, wood grain); never use emoji in a surface.

   Every primitive is parameterised by custom property so a surface can keep the
   exact geometry the mockup specified. Defaults match the most common tile size. */

/* ─────────────────────────────────────────────────────────────────────────
   Motion — one loop per command. All CSS, ease-in-out, infinite.
   ───────────────────────────────────────────────────────────────────────── */

/* Ambient, always on */
@keyframes bob      { 0%, 100% { transform: translateY(0) rotate(-1.4deg) } 50% { transform: translateY(-7px) rotate(1.4deg) } }
@keyframes bobfast  { 0%, 100% { transform: translateY(0) rotate(-2.4deg) } 50% { transform: translateY(-5px) rotate(2.4deg) } }
@keyframes wavepan     { to { -webkit-mask-position-x: var(--wave-w, 170px); mask-position-x: var(--wave-w, 170px) } }
@keyframes wavepanslow { to { -webkit-mask-position-x: calc(-1 * var(--wave-w, 170px)); mask-position-x: calc(-1 * var(--wave-w, 170px)) } }
@keyframes sunglow  { 0%, 100% { transform: scale(1); opacity: .45 } 50% { transform: scale(1.14); opacity: .8 } }
@keyframes clouddrift { 0% { transform: translateX(0) } 100% { transform: translateX(-140px) } }
@keyframes tick     { 0%, 100% { opacity: .25 } 50% { opacity: 1 } }

/* hero — the whole product in one arc (9s) */
/* Home port → vault → home port. Moored 0–8%, out 8–32%, unloading 32–46%,
   back 46–70%, moored again 70–100% (that's when it takes on new cargo). */
/* One round trip, both ways, on a single cycle -- 36s, a quarter off the 48s
   it used to run, so the whole voyage reads as purposeful rather than becalmed.
   Every keyframe below is a PERCENTAGE, so the duration is the only knob and
   the ramps, the cargo and the boat cannot drift out of step with each other.
   The boat starts EMPTY in the
   middle, calls at one pier, takes that pier's cargo aboard, carries it across,
   sets it down on the far pier, returns to the middle empty -- then does the
   same run in reverse, forever.
   Three positions, and the boat is stationary for the whole of every transfer,
   because cargo stepping on or off a moving boat is the tell that it is a
   crossfade and not a delivery:
     MIDDLE +73px  ·  HOME -44px (alongside the home quay)  ·  FAR +190px
   Every dwell is 8% wide and every transfer 4%, which leaves room for the
   per-folder stagger: the last folder is .35s behind the first, and at 24s that
   is 1.5% -- so even it finishes moving before the boat does. Cargo stepping on
   or off a boat that has already left is the tell that this is a crossfade. */
@keyframes heroloop {
    0%,   5% { transform: translateX(73px) }
   14%,  22% { transform: translateX(-44px) }
   32%,  40% { transform: translateX(190px) }
   48%,  53% { transform: translateX(73px) }
   62%,  70% { transform: translateX(190px) }
   80%,  88% { transform: translateX(-44px) }
   96%, 100% { transform: translateX(73px) }
}
/* The gangways, and their timing is not decoration -- it is the same clock the
   boat and the cargo already run on. The boat is stationary at the home quay
   over 14-22% and 80-88%, and at the far jetty over 32-40% and 62-70%; cargo
   moves in the middle 4% of each of those. So each gangway lowers over the
   first 2% of its own berth and lifts over the last 2%, which leaves it flat
   for exactly the window the folders are crossing it and stowed every moment
   she is under way. Get these out of step and the cargo walks on air.
   The two swing OPPOSITE ways because they hang off opposite ends: the bow's
   far edge rises to the left, the stern's to the right. */
@keyframes rampbow {
    0%,  14% { transform: rotate(90deg); box-shadow: none }
   16%,  20% { transform: rotate(0deg);  box-shadow: var(--shadow-hull) }
   22%,  80% { transform: rotate(90deg); box-shadow: none }
   82%,  86% { transform: rotate(0deg);  box-shadow: var(--shadow-hull) }
   88%, 100% { transform: rotate(90deg); box-shadow: none }
}
@keyframes rampstern {
    0%,  32% { transform: rotate(-90deg); box-shadow: none }
   34%,  38% { transform: rotate(0deg);   box-shadow: var(--shadow-hull) }
   40%,  62% { transform: rotate(-90deg); box-shadow: none }
   64%,  68% { transform: rotate(0deg);   box-shadow: var(--shadow-hull) }
   70%, 100% { transform: rotate(-90deg); box-shadow: none }
}
/* Cargo rides in the hold, drops out at the vault, is taken back on at home. */
/* What is in the hold. Empty at the start and at every turn in the middle; it
   fills only while the boat is alongside a pier, and empties at the other. */
@keyframes cargocycle {
    0%,  16% { opacity: 0; transform: translateY(22px) scale(.72) }
   20%,  34% { opacity: 1; transform: translateY(0) scale(1) }
   38%,  64% { opacity: 0; transform: translateY(22px) scale(.72) }
   68%,  82% { opacity: 1; transform: translateY(0) scale(1) }
   86%, 100% { opacity: 0; transform: translateY(22px) scale(.72) }
}

/* The near pier: loaded at the start, handed over at 17-20%, and it is the same
   cargo coming home at 81-84%. */
@keyframes cargohome {
    0%,  16% { opacity: 1; transform: translateY(0) scale(1) }
   20%,  82% { opacity: 0; transform: translateY(10px) scale(.7) }
   86%, 100% { opacity: 1; transform: translateY(0) scale(1) }
}
@keyframes vaultfill { 0%, 34% { height: 6px } 52% { height: 74px } 100% { height: 74px } }

/* dock — copy → verify → seal → link → reclaim */
@keyframes sailout { 0% { transform: translateX(-10px) } 45% { transform: translateX(150px) } 100% { transform: translateX(300px) } }
/* undock — splashed back, verified */
@keyframes sailin  { 0% { transform: translateX(300px) } 55% { transform: translateX(120px) } 100% { transform: translateX(-10px) } }
@keyframes splash  { 0%, 40% { transform: translate(0, 0) scale(.6); opacity: 0 } 55% { opacity: 1 } 100% { transform: translate(0, -34px) scale(1); opacity: 0 } }
/* panic — everything comes home */
@keyframes fleetin { 0% { transform: translateX(280px); opacity: 0 } 12% { opacity: 1 } 100% { transform: translateX(-30px); opacity: 1 } }
/* verify — every byte re-read */
@keyframes stamp   { 0%, 55% { transform: scale(0); opacity: 0 } 68% { transform: scale(1.35); opacity: 1 } 80%, 100% { transform: scale(1); opacity: 1 } }
/* standing by — a state, not an error */
@keyframes zzz     { 0%, 100% { opacity: .2 } 50% { opacity: 1 } }
/* autopilot — slow on purpose */
@keyframes patrol  { 0% { transform: translateX(-8px) } 50% { transform: translateX(190px) } 100% { transform: translateX(-8px) } }

/* Nothing flashes, nothing bounces past 1.35×, nothing loops faster than 2.2s. */
@media (prefers-reduced-motion: reduce) {
  .scene *, .scene { animation: none !important; }
}

/* ─────────────────────────────────────────────────────────────────────────
   Scene — the frame every illustration sits in
   ───────────────────────────────────────────────────────────────────────── */

.scene {
  position: relative;
  overflow: hidden;
  background: var(--scene-sky, var(--sky-light));
}

/* ─────────────────────────────────────────────────────────────────────────
   Sun — solid circle, top-right, with a glow 1.5× its size pulsing 5s
   ───────────────────────────────────────────────────────────────────────── */

.sun {
  position: absolute;
  width: var(--sun-size);
  height: var(--sun-size);
  border-radius: 50%;
  background: var(--sun-fill, var(--sun));
}

.sun-glow {
  position: absolute;
  width: var(--glow-size);
  height: var(--glow-size);
  border-radius: 50%;
  background: var(--sun-glow-soft);
  animation: sunglow 5s ease-in-out infinite;
}

/* In the dark hero, a third radial bloom at 340px */
.sun-bloom {
  position: absolute;
  width: 340px;
  height: 340px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--sun-glow-bloom), var(--sun-glow-bloom-out) 68%);
}

/* ─────────────────────────────────────────────────────────────────────────
   Water — two bands. Each is a scalloped top edge over a solid block.
   Back band pans one full 26px cycle in 5–7s; front band pans the other
   direction 1–2s slower.
   ───────────────────────────────────────────────────────────────────────── */

.water {
  position: absolute;
  /* the dark hero bleeds its water past the scene edge so the crest never
     shows a cut end; tiles sit flush */
  left: calc(-1 * var(--water-bleed, 0px));
  right: calc(-1 * var(--water-bleed, 0px));
  bottom: 0;
  height: var(--water-h);
}

/* One soft rolling swell, not a row of scallops. The shape is an SVG mask so
   the colour still comes from --water-c and stays tokenised. The path is one
   full period and starts and ends at the same height, so it tiles seamlessly. */
.water__crest {
  height: var(--crest-h);
  background: var(--water-c);
  -webkit-mask-image: var(--wave);
          mask-image: var(--wave);
  -webkit-mask-size: var(--wave-w, 170px) 100%;
          mask-size: var(--wave-w, 170px) 100%;
  -webkit-mask-repeat: repeat-x;
          mask-repeat: repeat-x;
  animation: var(--crest-anim, wavepan) var(--crest-dur, 5s) linear infinite;
}

.water__body {
  height: var(--body-h);
  background: var(--water-c);
}

/* ─────────────────────────────────────────────────────────────────────────
   Clouds — single translucent pills of paper-warm, drifting 26s
   ───────────────────────────────────────────────────────────────────────── */

.clouds {
  position: absolute;
  display: flex;
  animation: clouddrift 26s linear infinite;
}

.cloud {
  border-radius: var(--r-chip);
  background: var(--cloud);
  flex: none;
}

/* ─────────────────────────────────────────────────────────────────────────
   Boat — hull is one rounded rect with two stacked deck stripes.
   Standard hull sizes: 178×50 (hero), 98–112×26 (tiles), 74–88×20–24 (strip).
   ───────────────────────────────────────────────────────────────────────── */

.boat { animation: bob var(--bob-dur, 3.4s) ease-in-out infinite; }

.boat__deck {
  display: flex;
  gap: var(--cargo-gap, 4px);
  justify-content: center;
  align-items: flex-end;
  padding-bottom: var(--cargo-lift, 3px);
}

.boat__hull {
  width: var(--hull-w);
  height: var(--hull-h);
  background: var(--hull-fill, var(--hull));
  border-radius: var(--hull-r) var(--hull-r) var(--hull-br) var(--hull-br)
               / var(--hull-r) var(--hull-r) var(--hull-brv) var(--hull-brv);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--deck-gap, 3px);
  padding: 0 var(--hull-pad);
  box-sizing: border-box;
}

.boat__stripe {
  height: var(--deck-h, 4px);
  border-radius: var(--stripe-r, 2px);
}
.boat__stripe--upper { background: var(--deck-1-fill, var(--deck-1)); }
.boat__stripe--lower { background: var(--deck-2-fill, var(--deck-2)); }

/* ─────────────────────────────────────────────────────────────────────────
   Cargo = files = the legend.
   Each file is a rounded rect in hull with a class-coloured top band.
   Cargo colours must be real classes from the data shown; vary heights
   (±8px) so the deck reads as a stack, never a grid.
   ───────────────────────────────────────────────────────────────────────── */

.file {
  width: var(--file-w, 14px);
  height: var(--file-h);
  border-radius: var(--file-r, 3px);
  background: var(--hull);
  box-shadow: inset 0 var(--file-band, 5px) 0 var(--file-c);
  flex: none;
}

/* verify — a green ✓ stamps onto each file, 0.3s stagger, 1.35× overshoot */
.file--stamped { position: relative; }

.file__stamp {
  position: absolute;
  top: -9px;
  right: -7px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--verified-dot);
  color: #fff;
  font: 700 10px var(--font-sans);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: stamp 3.6s ease-in-out infinite;
}

/* ─────────────────────────────────────────────────────────────────────────
   The vault — a plain rounded rect that fills bottom-up with class-coloured
   bars. Unplugged: the same rect as a 2px dashed outline.
   ───────────────────────────────────────────────────────────────────────── */

.vault {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: var(--vault-fill, var(--vault-light));
  border-radius: var(--vault-r, 6px);
  box-sizing: border-box;
}

.vault--unplugged {
  background: none;
  border: 2px dashed var(--vault-unplugged);
}

.vault__stack {
  width: 100%;
  display: flex;
  flex-direction: column-reverse;
  gap: 3px;
  overflow: hidden;
}

.vault__bar {
  height: var(--bar-h, 6px);
  border-radius: 2px;
  flex: none;
}

/* ─────────────────────────────────────────────────────────────────────────
   Status dot — 2.2–2.4s tick
   ───────────────────────────────────────────────────────────────────────── */

.status-dot {
  width: var(--dot-size, 7px);
  height: var(--dot-size, 7px);
  border-radius: 50%;
  background: var(--verified-dot);
  animation: tick var(--tick-dur, 2.4s) ease-in-out infinite;
  flex: none;
}


/* ─────────────────────────────────────────────────────────────────────────
   Folder — the cargo, seen through the open hull. Classic tabbed folder:
   body plus a tab on the top-left. Colour is always a real artifact class,
   so the hold is the legend.
   ───────────────────────────────────────────────────────────────────────── */

.folder {
  position: relative;
  flex: none;
  width: var(--folder-w, 26px);
  height: var(--folder-h, 30px);
  background: var(--folder-c);
  border-radius: 2px 4px 4px 4px;
}
.folder::before {
  content: "";
  position: absolute;
  top: calc(-1 * var(--folder-tab, 6px));
  left: 0;
  width: 52%;
  height: var(--folder-tab, 6px);
  background: var(--folder-c);
  border-radius: 3px 3px 0 0;
}
/* the paper inside the folder */
.folder::after {
  content: "";
  position: absolute;
  left: 18%;
  right: 18%;
  top: 26%;
  height: 2px;
  background: rgba(255, 255, 255, .55);
  border-radius: 1px;
}

/* The open hold: cargo sits in it, the hull wraps around it. */
.boat__hold {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: var(--hold-gap, 7px);
  height: var(--hold-h, 44px);
  padding: 0 var(--hold-pad, 4px);
  box-sizing: border-box;
}

/* A quay the boat is moored at. */
.pier {
  position: relative;
  height: var(--pier-h, 12px);
  background: var(--pier-fill, #E8DCC4);
  border-radius: 3px;
}
/* posts, drawn a bit wonky on purpose */
.pier::before, .pier::after {
  content: "";
  position: absolute;
  top: 100%;
  width: 9px;
  height: var(--post-h, 26px);
  background: var(--post-fill, #D8C7A8);
  border-radius: 0 0 3px 3px;
}
.pier::before { left: 14%;  transform: rotate(-2deg); }
.pier::after  { right: 14%; transform: rotate(2.5deg); }

/* The gangway. It belongs to the SHIP, not the shore: one at each end, stowed
   upright against the hull while she is under way and swung down onto whichever
   quay she is alongside. That is why there is one per END rather than one per
   pier -- she meets the home quay bow-on and the far jetty stern-on.
   Its band matches the pier's exactly, so lowered it continues the deck rather
   than leaving a step; and it is the HULL's white, not the quay's tan, because
   it is part of the ship: stowed against her side it disappears into the hull
   and there is simply nothing there until she starts working.
   Its SHADOW is animated rather than fixed, and that is the whole trick. White
   on `--sky-light` is a 4% difference, so crossing the gap it would vanish at
   exactly the moment it matters -- but a shadow while stowed outlines it
   against the hull and gives the game away. So it has none until it swings,
   and picks up the hull's own as it goes down.
   The base transform is the STOWED state on purpose. `prefers-reduced-motion`
   kills every animation in the scene and the boat parks mid-channel, so a
   gangway resting `down` would hang over open water. */
.boat__ramp {
  position: absolute;
  bottom: 4px;
  height: 13px;
  width: var(--ramp-w, 56px);
  background: var(--hull-fill, #FFFFFF);
  border-radius: 2px;
}
/* Inset by 6px at each end: the hull's corners are heavily rounded, so a
   gangway hinged on the bounding box would stand off the side with daylight
   behind it. */
.boat__ramp--bow   { right: calc(100% - 6px); transform-origin: 100% 100%; transform: rotate(90deg); }
.boat__ramp--stern { left:  calc(100% - 6px); transform-origin: 0 100%;    transform: rotate(-90deg); }

/* cargo sitting on a dock */
.pier__load {
  position: absolute;
  bottom: 100%;
  left: 0; right: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 5px;
  padding-bottom: 2px;
}

.quay {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 6px;
  padding: 0 10px 8px;
  background: var(--quay-fill, var(--surface-sunk-cool));
  border: 1px solid rgba(11, 18, 32, .12);
  border-radius: 6px 6px 3px 3px;
  box-sizing: border-box;
}


/* ─────────────────────────────────────────────────────────────────────────
   The boat, drawn the way a kid draws a cruise ship: a fat hull, a boxy
   cabin sat slightly off-centre, one fat funnel leaning back, a pennant.
   Nothing is perfectly square — every piece is a degree or two off.
   ───────────────────────────────────────────────────────────────────────── */

.boat__super {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 8px;
  margin-left: var(--super-shift, -14px);
  padding-bottom: 2px;
}
.boat__funnel {
  width: var(--funnel-w, 24px);
  height: var(--funnel-h, 34px);
  background: var(--funnel-fill, var(--deck-2));
  border-radius: 7px 7px 2px 2px;
  transform: rotate(-4deg);
}
.boat__funnel::after {           /* the band round the top */
  content: "";
  display: block;
  height: 7px;
  margin: 3px 3px 0;
  background: var(--paper-warm);
  border-radius: 4px;
}
.boat__cabin {
  position: relative;
  width: var(--cabin-w, 84px);
  height: var(--cabin-h, 32px);
  background: var(--hull-fill, #FFFFFF);
  border-radius: 9px 7px 3px 3px;
  transform: rotate(1.2deg);
}
.boat__cabin::after {            /* a row of windows */
  content: "";
  position: absolute;
  left: 9px; right: 9px; top: 11px;
  height: 8px;
  border-radius: 4px;
  background: repeating-linear-gradient(90deg,
    var(--sea-deep) 0 8px, transparent 8px 15px);
  opacity: .75;
}
.boat__mast {
  position: absolute;
  left: 4px; bottom: 100%;
  width: 3px; height: 20px;
  background: var(--ink-faint-warm);
  border-radius: 2px;
}
.boat__flag {
  position: absolute;
  left: 3px; bottom: calc(100% + 12px);
  width: 18px; height: 11px;
  background: var(--class-model-cache);
  border-radius: 2px 6px 6px 2px;
  transform: rotate(-3deg);
}

/* cargo appearing on the far dock as it comes off the boat */
/* The far pier: empty until the delivery lands at 34-37%, and emptied again at
   64-67% when the boat picks the same load back up for the return run. */
@keyframes dropoff {
    0%,  34% { opacity: 0; transform: translateY(10px) scale(.7) }
   38%,  64% { opacity: 1; transform: translateY(0) scale(1) }
   68%, 100% { opacity: 0; transform: translateY(10px) scale(.7) }
}
