/* Kindly Sent card engine: the paper pop-up. One open card = a WALL (upright), a FLOOR hinged to it at the fold (its
   underside is the card's cover), and cut-paper LAYERS that stand parallel to the wall at a depth z, held by the same
   parallel fold as a real pop-up: as the card opens (--open 0 -> 1) each layer slides down the wall and forward to
   its place. The default state of this stylesheet is the FINISHED, OPEN card, so no-JS and reduced motion show the
   complete still. Units: the stage is 560 x 640 scene units wide and high; --u is one unit. Contract: CARDS.md. */
.ks-card {
  container-type: inline-size;
  position: relative; width: 100%; max-width: 560px; margin-inline: auto;
  --open: 1;            /* 0 = closed card (cover showing), 1 = open */
  --tilt: 23deg;        /* how far we look down on the open card */
  --tx: 0deg; --ty: 0deg;   /* pointer parallax, set by the engine */
  color: var(--ks-ink);
}
.ks-stage {
  --u: calc(100cqw / 560);
  position: relative; width: 100%; aspect-ratio: 560 / 640;
  perspective: calc(2100 * var(--u)); perspective-origin: 50% 42%;
  user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
}
.ks-stage svg { display: block; width: 100%; height: 100%; overflow: visible; }
.ks-stage text { font-family: var(--ks-display); }

/* the soft shadow the whole card throws on the table */
.ks-table {
  position: absolute; left: calc(50 * var(--u)); right: calc(50 * var(--u));
  top: calc(548 * var(--u)); height: calc(80 * var(--u));
  background: radial-gradient(ellipse 50% 50% at 50% 50%, rgba(58, 27, 63, .26), rgba(58, 27, 63, 0) 70%);
  opacity: var(--open); pointer-events: none;
}

.ks-pop {
  position: absolute; inset: 0; transform-style: preserve-3d;
  transform-origin: 50% calc(410 * var(--u));
  /* closed, the cover is a quarter larger: it is the first thing every recipient sees, and it has the room */
  transform: translateY(calc((1 - var(--open)) * 60 * var(--u))) scale(calc(1 + (1 - var(--open)) * .25))
             rotateX(calc(var(--open) * -1 * var(--tilt) + var(--tx))) rotateY(var(--ty));
}
.ks-wall, .ks-floor, .ks-layer, .ks-sh {
  position: absolute; left: calc(60 * var(--u)); width: calc(440 * var(--u)); height: calc(380 * var(--u));
}
/* Nothing that needs an off-screen surface (filter, rounded overflow clip, opacity) may sit ON a 3D-transformed sheet:
   browsers draw such surfaces at low resolution under perspective and the paper goes soft. So the sheets themselves
   stay plain, and the clip, the shadow filter and the fade live on the <svg> INSIDE each sheet, where they are simply
   painted. */
.ks-wall { top: calc(30 * var(--u)); }
.ks-wall > svg, .ks-cover > svg { border-radius: calc(5 * var(--u)) calc(5 * var(--u)) 0 0; overflow: hidden; background: var(--ks-white); }
.ks-floor-top > svg { border-radius: 0 0 calc(5 * var(--u)) calc(5 * var(--u)); overflow: hidden; background: var(--ks-cream-2); }
/* the crease: both sheets darken a little toward the fold */
.ks-wall::after, .ks-floor-top::after {
  content: ""; position: absolute; left: 0; right: 0; height: 22%; pointer-events: none;
}
.ks-wall::after { bottom: 0; background: linear-gradient(to top, rgba(58, 27, 63, .16), rgba(58, 27, 63, 0)); }
.ks-floor-top::after { top: 0; background: linear-gradient(to bottom, rgba(58, 27, 63, .2), rgba(58, 27, 63, 0)); }

.ks-floor {
  top: calc(410 * var(--u)); transform-style: preserve-3d; transform-origin: 50% 0;
  transform: translateZ(calc((1 - var(--open)) * 2 * var(--u))) rotateX(calc(180deg - var(--open) * 90deg));
}
.ks-floor-top, .ks-cover { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.ks-cover { transform: rotateX(180deg); }
.ks-cover-tag {
  position: absolute; left: 50%; bottom: 7%; transform: translateX(-50%) rotate(-2deg);
  max-width: 78%; padding: .35em .9em .3em; background: var(--ks-white); color: var(--ks-ink);
  font: 400 calc(21 * var(--u))/1.15 var(--ks-hand-neat); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  clip-path: polygon(0 0, calc(100% - .5em) 0, 100% .5em, 100% 100%, 0 100%);
  filter: drop-shadow(0 calc(1.5 * var(--u)) calc(2 * var(--u)) rgba(58, 27, 63, .3));
}
.ks-cover-tag:empty { display: none; }

/* a layer: parallel to the wall, z units out from it. Art inside sits on the same 440 x 380 grid as the wall.
   Rule of the fold: art at depth z must stay in the bottom (380 - z) units, or it would poke out of a closed card. */
.ks-layer {
  top: calc(30 * var(--u)); transform-origin: 50% 100%; pointer-events: none;
  transform: translateY(calc(-1 * var(--z) * var(--u) * cos(var(--open) * 90deg)))
             translateZ(calc(var(--z) * var(--u) * sin(var(--open) * 90deg)))
             rotateX(var(--rise, 0deg));
}
.ks-layer > svg {
  opacity: clamp(0, calc((var(--open) - .03) * 14), 1);
  filter: drop-shadow(0 calc(2.2 * var(--u)) calc(2.6 * var(--u)) rgba(58, 27, 63, .3));
}
.ks-layer [data-tap], .ks-layer .ks-tap { pointer-events: auto; cursor: pointer; }
.ks-stage .ks-tap { outline: none; }
.ks-stage .ks-tap:focus-visible { outline: calc(1.5 * var(--u)) dashed var(--ks-ink); outline-offset: calc(2 * var(--u)); }
/* ks-flat: no shadow. Use it for glass and glows, and for any layer whose art keeps moving after the intro (flames,
   twinkles): a layer is repainted while something inside it animates, and the shadow is the costly part of that. */
.ks-layer.ks-flat > svg { filter: none; }

/* the contact shadow each layer drops on the floor in front of itself */
.ks-sh {
  top: calc(410 * var(--u)); height: calc(54 * var(--u)); transform-origin: 50% 0; pointer-events: none;
  left: calc((60 + var(--sl, 0)) * var(--u)); width: calc(var(--sw, 440) * var(--u));
  transform: translateY(calc(-1 * var(--z) * var(--u) * cos(var(--open) * 90deg)))
             translateZ(calc(var(--z) * var(--u) * sin(var(--open) * 90deg))) rotateX(90deg);
  background: radial-gradient(ellipse 50% 100% at 50% 0, rgba(58, 27, 63, .42), rgba(58, 27, 63, 0) 72%);
  opacity: clamp(0, calc((var(--open) - .75) * 4), 1);
}

/* paper grain over everything, and the particle canvas */
.ks-grain {
  position: absolute; inset: 0; pointer-events: none; background: var(--ks-grain-a) 0 0 / 160px 160px; opacity: .5;
  /* fades out towards the edges of the stage, so the grain never shows as a box on the page */
  -webkit-mask-image: radial-gradient(ellipse 62% 58% at 50% 48%, #000 62%, transparent 100%);
  mask-image: radial-gradient(ellipse 62% 58% at 50% 48%, #000 62%, transparent 100%);
}
.ks-fx { position: absolute; inset: -6% -6% -2% -6%; width: 112%; height: 108%; pointer-events: none; }

/* names inside the art */
.ks-stage [data-ks-name] { font-kerning: normal; }
.ks-script { font-family: var(--ks-hand-joined) !important; }

/* ---- controls ---- */
.ks-open, .ks-replay, .ks-hint { font-family: var(--ks-text); }
.ks-open {
  position: absolute; left: 50%; top: calc(486 * var(--u)); transform: translateX(-50%);
  display: none; align-items: center; gap: .55em; border: 0; cursor: pointer;
  padding: .85em 1.5em .85em 1.3em; background: var(--ks-button); color: #fff;
  font: 700 clamp(16px, 4.4cqw, 20px)/1 var(--ks-text); letter-spacing: .01em; white-space: nowrap;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 0 100%);
  transition: transform .2s var(--ks-ease-stand), background .2s;
}
.ks-open::before { content: ""; width: .7em; height: .9em; background: currentColor; clip-path: polygon(0 0, 100% 22%, 100% 100%, 0 78%); }
.ks-open:hover { background: var(--ks-vermilion-dark); transform: translateX(-50%) translateY(-2px); }
.ks-open:focus-visible, .ks-replay:focus-visible { outline: 3px solid var(--ks-ink); outline-offset: 3px; }
.ks-hint {
  position: absolute; left: 50%; top: calc(8 * var(--u)); transform: translateX(-50%); z-index: 3;
  padding: .45em .95em; background: var(--ks-ink); color: var(--ks-cream); border-radius: 99px;
  font: 600 clamp(15px, 4.1cqw, 16px)/1.2 var(--ks-text); white-space: nowrap; pointer-events: none;
  opacity: 0; transition: opacity .4s;
}
.ks-hint.is-on { opacity: 1; }
.ks-replay {
  position: relative; z-index: 3; grid-column: 1 / -1; min-height: 44px;
  display: none; align-items: center; gap: .45em; margin: 10px auto 0; padding: .5em .8em; border: 0; background: none;
  color: var(--ks-ink-2); font: 600 14px/1 var(--ks-text); cursor: pointer; text-decoration: underline;
  text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.ks-replay:hover { color: var(--ks-vermilion-dark); }

/* ---- the inside of the card: the sender's own words ---- */
.ks-inside { position: relative; margin: calc(-6cqw) 5cqw 0; z-index: 2; }
.ks-note {
  position: relative; padding: clamp(20px, 6cqw, 34px) clamp(20px, 6.4cqw, 38px) clamp(22px, 6cqw, 34px);
  background: var(--ks-white); box-shadow: var(--ks-shadow-2);
  clip-path: polygon(0 0, calc(100% - 22px) 0, 100% 22px, 100% 100%, 0 100%);
}
.ks-note::after {   /* the folded-over corner */
  content: ""; position: absolute; right: 0; top: 0; width: 22px; height: 22px;
  background: linear-gradient(225deg, transparent 50%, var(--ks-cream-2) 50%);
}
.ks-message { margin: 0; font-size: clamp(21px, 5.6cqw, 28px); line-height: 1.42; color: var(--ks-ink); overflow-wrap: anywhere; }
.ks-message p { margin: 0 0 .7em; }
.ks-message p:last-child { margin-bottom: 0; }
.ks-from { margin: .9em 0 0; font-size: clamp(22px, 6cqw, 30px); line-height: 1.2; color: var(--ks-vermilion-dark); text-align: right; overflow-wrap: anywhere; }
.ks-from:empty { display: none; }
.ks-hand-neat .ks-message, .ks-hand-neat .ks-from { font-family: var(--ks-hand-neat); }
/* the joined-up hand has thin strokes: a size larger than the others and a hair of stroke so older eyes can read it */
.ks-hand-joined .ks-message, .ks-hand-joined .ks-from { font-family: var(--ks-hand-joined); font-size: clamp(24px, 6.5cqw, 33px); line-height: 1.5; -webkit-text-stroke: .35px currentColor; }
.ks-hand-felt .ks-message, .ks-hand-felt .ks-from { font-family: var(--ks-hand-felt); font-size: clamp(19px, 5.1cqw, 26px); line-height: 1.45; }
.ks-photo {
  margin: 0 auto clamp(14px, 4cqw, 22px); width: min(62%, 240px); aspect-ratio: 4 / 5; overflow: hidden;
  border-radius: 999px 999px 8px 8px; background: var(--ks-cream-2);
  box-shadow: 0 0 0 6px var(--ks-white), 0 0 0 7px var(--ks-line), var(--ks-shadow-1);
}
.ks-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ks-photo[hidden] { display: none; }
.ks-empty { color: var(--ks-ink-2); opacity: .55; }

/* ---- motion mode (the engine adds .ks-live once it has taken over) ---- */
html.ks-js .ks-card[data-ks-start="tap"]:not(.ks-live) { --open: 0; }
html.ks-js .ks-card[data-ks-start="tap"]:not(.ks-live) .ks-inside { visibility: hidden; }
.ks-card.ks-live.is-closed .ks-open { display: inline-flex; }
.ks-card.ks-live.is-closed .ks-cover { cursor: pointer; }
.ks-card.ks-live.is-done .ks-replay { display: flex; }
.ks-card.ks-live.is-closed .ks-inside { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
  .ks-open, .ks-replay, .ks-hint { display: none !important; }
}
@media (min-width: 900px) {
  .ks-card.ks-wide { max-width: 1000px; display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); align-items: center; gap: 12px; container-type: normal; }
  .ks-card.ks-wide .ks-stage-wrap { container-type: inline-size; }
  .ks-card.ks-wide .ks-inside { margin: 0; container-type: inline-size; }
  .ks-card.ks-wide .ks-message { font-size: clamp(22px, 2.2vw, 30px); }
}
.ks-stage-wrap { position: relative; container-type: inline-size; }
