/* The door: Sixteen Volumes (DECISIONS §46, ruled 2026-10-06), then the calm
   tail. Built from the working mockup on the Door Concepts canvas as plain
   HTML and CSS; the canvas is the reference, this is the page.
   Phone rules (docs/desk/design/study-1003/report.md, section 3): the message
   and Begin are HTML text at the first paint, there is no preloader, the
   still under Reduce Motion or with JavaScript off is as loud as the moving
   door, and nothing loads that only the motion needs. The opening plays for
   under five seconds and then stands still, so nothing moves on its own long
   enough to need a pause control (WCAG 2.2.2).
   The stack is set in em on one font size that follows the screen's width,
   so the whole pile scales as one object: 16px of the mockup is 1em, and the
   mockup's 390px phone is the 1:1 size. */

/* the display voice (DECISIONS §21): Gloock, self-hosted */
@font-face {
  font-family: 'Gloock';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url(/app/gloock-400.woff2) format('woff2');
}

:root {
  /* the door: one saturated field, flat cloth, cream foil and ink */
  --field:   #2630D9;
  --cream:   #F6EFDC;
  --ink:     #16132E;
  --pale:    #F2EAD3;
  --shade:   9, 8, 64;
  --weave:   repeating-linear-gradient(0deg, rgba(0,0,0,.05) 0 1px, transparent 1px 3px),
             repeating-linear-gradient(90deg, rgba(255,255,255,.05) 0 1px, transparent 1px 4px);
  --serif:   'Gloock', Georgia, serif;
  --sans:    system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* the calm tail: the app's own room (Lounge Noir, app/style.css) */
  --ground:  #141210;
  --ground-2:#1C1916;
  --l-cream: #EDE4D3;
  --soft:    #B8AD98;
  --champ:   201, 179, 138;
  --champ-hi:#DCC9A3;
}

* { box-sizing: border-box; }
html { background: var(--field); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  color: var(--cream);
  background: var(--field);
  font: 16px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Off-screen text for assistive tech only. */
.srOnly { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

/* ---------------------------------------------------------------- the door
   One screen: the wordmark on top, the stack in the middle, the line and
   Begin at the foot, in the thumb zone. The bands top and bottom are the
   field itself and cover the ends of the stack, as a table edge would. */
#door {
  position: relative;
  height: 100vh;
  height: 100svh;
  min-height: 360px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--field);
}
.mast, .foot {
  position: relative;
  z-index: 10;
  flex: none;
  background: var(--field);
  /* on a wide screen the words keep a phone's column */
  padding-left: max(20px, calc(50% - 280px));
  padding-right: max(20px, calc(50% - 280px));
}
.mast {
  height: calc(64px + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  display: flex;
  align-items: center;
}
.wordmark {
  margin: 0;
  font: 400 21px/1 var(--serif);
  letter-spacing: .01em;
  color: var(--cream);
}
.window { position: relative; flex: 1; min-height: 0; z-index: 1; }

/* The pile, 540px by the mockup, turned four degrees. Its pivot is the
   middle of the blank spine, and that point sits in the middle of the
   window on every screen. The size follows the width, and on a short
   screen (a phone held sideways) also the window's height: the blank and
   its line need about twelve of these units of window, and the bands top
   and bottom take 210px, so the line never slides under the foot. */
.stack {
  position: absolute;
  font-size: clamp(11px, min(4.1026vw, calc((100vh - 210px) / 12)), 20px);
  font-size: clamp(11px, min(4.1026vw, calc((100svh - 210px) / 12)), 20px);
  width: 33.75em;
  left: calc(50% - 16.875em);
  top: calc(50% - 30.875em);
  transform: rotate(-4deg);
  transform-origin: 16.875em 30.875em;
  -webkit-user-select: none;
  user-select: none;
}

/* one spine: the name at one end, the numeral and a ring at the other */
.vol {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: .75em;
  width: 33.75em;
  height: var(--h);
  margin: 0 0 .1875em;
  padding: 0 5.9375em 0 calc(4.6875em + var(--x));
  background-color: var(--cloth);
  background-image: var(--weave);
  color: var(--foil);
  box-shadow: inset 0 2px 0 rgba(0,0,0,.10), inset 0 -2px 0 rgba(0,0,0,.14);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: translate 260ms cubic-bezier(.2, .9, .3, 1.25), box-shadow 260ms ease;
}
.vol.r { flex-direction: row-reverse; padding: 0 calc(4.6875em + var(--x)) 0 5.9375em; }
.vol.cream { --foil: var(--cream); }
.vol.ink { --foil: var(--ink); }
.vname {
  flex: none;
  font: 400 var(--fs)/1 var(--serif);
  letter-spacing: .02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.vrule { flex: 1; }
.vnum {
  flex: none;
  font: 400 .875em/1 var(--serif);
  letter-spacing: .14em;
  white-space: nowrap;
}
.vring {
  flex: none;
  width: .5625em;
  height: .5625em;
  border: 1.5px solid currentColor;
  border-radius: 50%;
}
/* a tapped spine lifts out of the pile and shows its place in it */
.vtag {
  position: absolute;
  top: -1.25em;
  right: 7.9167em;
  display: none;
  align-items: center;
  height: 2em;
  padding: 0 .8333em;
  border-radius: 1em;
  background: var(--foil);
  color: var(--cloth);
  font: 700 .75em/1 var(--sans);
  letter-spacing: .06em;
  white-space: nowrap;
  box-shadow: 0 2px 0 rgba(var(--shade), .35);
}
.vol.r .vtag { right: auto; left: 7.9167em; }
.vol.touched { z-index: 2; translate: .625em .5625em;
  box-shadow: inset 0 2px 0 rgba(0,0,0,.10), inset 0 -2px 0 rgba(0,0,0,.14), -4px 8px 0 rgba(var(--shade), .42); }
.vol.touched .vtag { display: inline-flex; }
html.moving .vol.touched .vtag { animation: cueIn 220ms cubic-bezier(.2, .8, .2, 1) both; }

/* the blank: THE, a window the names roll through, and the line */
.pullSlot { position: relative; z-index: 3; height: 8em; margin: 0 0 .1875em; }
.pull {
  position: absolute;
  inset: 0;
  transform-origin: 16.875em 4em;
  transition: transform 480ms cubic-bezier(.2, .9, .25, 1.12);
}
.pale {
  position: relative;
  width: 33.75em;
  height: 8em;
  padding: .875em 6.3125em 0 5.9375em;
  background-color: var(--pale);
  background-image: var(--weave);
  color: var(--ink);
  box-shadow: inset 0 3px 0 rgba(22,19,46,.10), inset 0 -3px 0 rgba(22,19,46,.10), 0 0 0 rgba(var(--shade), 0);
  transition: box-shadow 480ms ease;
}
.blankLine { display: flex; align-items: flex-end; height: 4.75em; }
.the {
  flex: none;
  margin: 0 .21875em -1px 0;
  font: 400 4em/1 var(--serif);
  letter-spacing: .01em;
  text-transform: uppercase;
}
.win { position: relative; display: block; flex: 1; height: 4.75em; overflow: hidden; }
.win::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--ink); }
.reel { position: absolute; left: 0; right: 0; top: 0; display: block; }
.reel .row {
  display: flex;
  align-items: flex-end;
  height: 4.75em;
  padding-bottom: var(--pb, 0);
}
.reel .nm {
  font: 400 var(--fs)/1 var(--serif);
  letter-spacing: .01em;
  text-transform: uppercase;
  white-space: nowrap;
}
/* registration marks: the blank is stamped once it is out */
.stamp { position: absolute; left: 0; right: 0; top: .375em; bottom: .5em; display: none; }
.stamp i { position: absolute; width: .875em; height: .875em; border: 0 solid var(--ink); }
.stamp i:nth-child(1) { left: 2px; top: 2px; border-left-width: 2px; border-top-width: 2px; }
.stamp i:nth-child(2) { right: 2px; top: 2px; border-right-width: 2px; border-top-width: 2px; }
.stamp i:nth-child(3) { left: 2px; bottom: 6px; border-left-width: 2px; border-bottom-width: 2px; }
.stamp i:nth-child(4) { right: 2px; bottom: 6px; border-right-width: 2px; border-bottom-width: 2px; }
#door.stamped .stamp { display: block; }
.lede {
  margin: .714em 0 0;
  font: 500 .875em/1.2857 var(--sans);
  letter-spacing: .01em;
  color: var(--ink);
}
/* the invitation to pull; only a page that can pull shows it */
.cue {
  position: absolute;
  right: 8.4167em;
  bottom: .6667em;
  display: none;
  align-items: center;
  gap: .5em;
  height: 2.1667em;
  padding: 0 .9167em 0 1em;
  border-radius: 1.0833em;
  background: var(--ink);
  color: var(--cream);
  font: 600 .75em/1 var(--sans);
  letter-spacing: .06em;
  pointer-events: none;
}
.cue svg { width: 1.1667em; height: 1.1667em; }
html.js .cue { display: inline-flex; }
#door.pulled .cue, #door.dragging .cue { display: none; }
/* the blank is one button over the whole spine; its words stay real text */
.pullBtn {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: grab;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}
.pullBtn:focus-visible { outline: 3px solid var(--ink); outline-offset: -7px; }
#door.dragging .pullBtn { cursor: grabbing; }

/* out of the pile */
#door.pulled .pull { transform: translate(.375em, 1.875em) rotate(2.4deg) scale(1.035); }
#door.pulled .pale { box-shadow: inset 0 3px 0 rgba(22,19,46,.10), inset 0 -3px 0 rgba(22,19,46,.10),
  -.375em 1.125em 0 rgba(var(--shade), .45); }
#door.dragging .pull, #door.dragging .pale { transition: none; }

/* The still. Without motion (Reduce Motion, the reader's own pause, or no
   JavaScript) the blank rests half out of the pile with its shadow, Begin is
   lit, and the page is complete as it first paints. */
html:not(.moving) #door:not(.pulled) .pull { transform: translate(.625em, 1.125em) rotate(1.4deg) scale(1.02); }
html:not(.moving) #door:not(.pulled) .pale { box-shadow: inset 0 3px 0 rgba(22,19,46,.10), inset 0 -3px 0 rgba(22,19,46,.10),
  -.25em .6875em 0 rgba(var(--shade), .42); }
html:not(.moving) .pull, html:not(.moving) .pale, html:not(.moving) .vol, html:not(.moving) .begin { transition: none; }

/* The opening, under five seconds: the spines are pushed in from both
   sides, the blank rolls through all sixteen names and stops on nothing,
   the cue arrives and nudges once, the blank twitches once. */
html.intro .vol.fromL { animation: volInL 640ms cubic-bezier(.2, .8, .2, 1) var(--d) both; }
html.intro .vol.fromR { animation: volInR 640ms cubic-bezier(.2, .8, .2, 1) var(--d) both; }
html.intro .reel { animation: roll 1250ms cubic-bezier(.5, .02, .12, 1) 1150ms both; }
html.intro .cue { animation: cueIn 380ms cubic-bezier(.2, .8, .2, 1) 2450ms both, cueBob 1.6s ease-in-out 2850ms 1; }
html.intro #door:not(.pulled) .pale { animation: twitch 1.6s ease-in-out 2900ms 1; }
/* a pull rolls the names again; two names for one motion so it restarts */
html.moving #door.rollA .reel { animation: roll 1000ms cubic-bezier(.5, .02, .12, 1) both; }
html.moving #door.rollB .reel { animation: rollAgain 1000ms cubic-bezier(.5, .02, .12, 1) both; }
html.moving #door.stamped .stamp { animation: stamp 340ms cubic-bezier(.3, .7, .3, 1.2) both; }
@keyframes volInL { from { transform: translateX(-9.375em); } to { transform: none; } }
@keyframes volInR { from { transform: translateX(9.375em); } to { transform: none; } }
@keyframes roll { from { transform: translateY(0); } to { transform: translateY(-80.75em); } }
@keyframes rollAgain { from { transform: translateY(0); } to { transform: translateY(-80.75em); } }
@keyframes cueIn { from { opacity: 0; transform: translate(-.6667em, -.6667em); } to { opacity: 1; transform: none; } }
@keyframes cueBob { 0%, 100% { transform: none; } 50% { transform: translate(.25em, .25em); } }
@keyframes twitch { 0%, 64%, 100% { translate: 0 0; } 76% { translate: .4375em .75em; } 88% { translate: .0625em .125em; } }
@keyframes stamp { 0% { opacity: 0; transform: scale(1.16); } 55% { opacity: 1; transform: scale(.97); } 100% { opacity: 1; transform: none; } }

/* the foot: the second line and Begin, low, where the thumb is */
.foot { padding-top: 22px; padding-bottom: calc(24px + env(safe-area-inset-bottom)); }
.steps {
  margin: 0 0 20px;
  font-size: 16px;
  line-height: 22px;
  font-weight: 500;
  letter-spacing: .005em;
}
.begin {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 58px;
  padding: 0 20px 0 22px;
  border: 2px solid var(--pale);
  border-radius: 4px;
  background: var(--pale);
  color: var(--ink);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: .01em;
  text-decoration: none;
  box-shadow: 0 6px 0 rgba(var(--shade), .45);
  -webkit-tap-highlight-color: transparent;
  transition: background-color 360ms ease, color 360ms ease, border-color 360ms ease, box-shadow 360ms ease;
}
/* While the door moves, Begin waits as an outline and lights when the
   blank is stamped. It is a working link the whole time. */
html.moving #door:not(.stamped) .begin {
  background: transparent;
  color: var(--cream);
  border-color: rgba(246, 239, 220, .9);
  box-shadow: 0 0 0 rgba(var(--shade), 0);
}
.begin:active { translate: 0 2px; }
.begin:focus-visible { outline: 3px solid var(--cream); outline-offset: 3px; }

/* ------------------------------------------------------------- the tail
   Under the fold: the ruled frames of §19 that the door does not replace,
   word for word, one message to a screen. The owner, 2026-10-06: the whole site
   is loud, so the tail is cloth too. The first frame lies on the pile as two
   more spines, the question on a crimson one and the answer on a pale one,
   between two plain spines; the second frame stands on the field in the
   largest type on the page, over a strip of all sixteen cloths. */
.tail {
  color: var(--cream);
  background: var(--field);
  overflow: hidden;
}
.calm {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.ln { display: block; }
.lyric { margin: 0; font-family: var(--serif); font-weight: 400; text-wrap: balance; }

/* frame one: a slice of the pile */
.c3 { gap: .5rem; padding: 10vh 0; }
.c3::before, .c3::after, .c3 .lyric, .c3 .answer {
  width: calc(100% + 24vw);
  margin-left: -12vw;
  transform: rotate(-4deg);
  background-image: var(--weave);
  box-shadow: inset 0 2px 0 rgba(0,0,0,.10), inset 0 -2px 0 rgba(0,0,0,.14);
}
.c3::before, .c3::after { content: ''; height: clamp(40px, 9vw, 84px); }
.c3::before { background-color: #F3C21F; }
.c3::after { background-color: #0E7A53; }
.c3 .lyric {
  padding: clamp(28px, 5vw, 64px) calc(12vw + clamp(20px, 6vw, 96px));
  background-color: #B3173A;
  color: var(--cream);
  font-size: clamp(30px, 7.6vw, 96px);
  line-height: 1.02;
  letter-spacing: .01em;
  text-transform: uppercase;
}
.c3 .lyric .ln + .ln { margin-top: .32em; font-size: .62em; line-height: 1.08; }
.c3 .answer {
  margin-top: 0;
  padding: clamp(24px, 4vw, 52px) calc(12vw + clamp(20px, 6vw, 96px));
  background-color: var(--pale);
  color: var(--ink);
  text-align: right;
  font: 600 clamp(18px, 4.4vw, 34px)/1.3 var(--sans);
  letter-spacing: .005em;
}

/* frame two: the field, the largest words, and every cloth */
.close {
  padding: 14vh clamp(20px, 6vw, 96px) 0;
  justify-content: flex-start;
}
.close .lyric {
  max-width: 15ch;
  font-size: clamp(40px, 10.4vw, 128px);
  line-height: .98;
  letter-spacing: .005em;
  text-transform: uppercase;
  color: var(--cream);
}
.sub {
  margin: clamp(22px, 4vh, 40px) 0 0;
  font: 500 clamp(16px, 2.2vw, 20px)/1.4 var(--sans);
  color: var(--cream);
}
.close::after {
  content: '';
  display: block;
  width: calc(100% + 24vw + 2 * clamp(20px, 6vw, 96px));
  height: clamp(160px, 30vh, 320px);
  margin: auto 0 0 calc(-12vw - clamp(20px, 6vw, 96px));
  transform: rotate(-4deg) translateY(30%);
  background-image: var(--weave), linear-gradient(180deg,
    #17503A 0 6.25%, #BBA2F5 0 12.5%, #B3173A 0 18.75%, #F3C21F 0 25%,
    #4F1E63 0 31.25%, #FF7466 0 37.5%, #0E7A53 0 43.75%, #93CDF2 0 50%,
    #EC5537 0 56.25%, #C9E03E 0 62.5%, #17142B 0 68.75%, #F4A3C0 0 75%,
    #0C7672 0 81.25%, #F27420 0 87.5%, #C2216F 0 93.75%, #D49A17 0 100%);
}
/* Begin on the release line takes the door's own button */
.btn {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  justify-content: center;
  min-height: 58px;
  margin-top: clamp(28px, 5vh, 48px);
  padding: 0 34px;
  border: 2px solid var(--pale);
  border-radius: 4px;
  background: var(--pale);
  color: var(--ink);
  font: 600 18px/1 var(--sans);
  letter-spacing: .01em;
  text-decoration: none;
  box-shadow: 0 6px 0 rgba(var(--shade), .45);
}
.btn:active { translate: 0 2px; }
.btn:focus-visible { outline: 3px solid var(--cream); outline-offset: 3px; }

/* -------------------------------------------------------------- wide screens
   The owner, 2026-10-06: on a computer the door fills the whole screen, with no
   empty field beside the pile. Every spine's cloth runs half a screen past
   both sides of the pile's own column (the padding grows by the same half
   screen), so the words keep their places of §46 and only the cloth grows.
   One continuous box per spine, so the weave and the shadows have no seam.
   The pile is a little larger, and the wordmark and the foot open out to the
   screen's width. */
@media (min-width: 900px) {
  .stack {
    font-size: clamp(14px, min(2.2vw, calc((100vh - 230px) / 14)), 26px);
    font-size: clamp(14px, min(2.2vw, calc((100svh - 230px) / 14)), 26px);
  }
  .vol {
    width: calc(33.75em + 100vw);
    margin-left: -50vw;
    padding: 0 calc(5.9375em + 50vw) 0 calc(4.6875em + var(--x) + 50vw);
  }
  .vol.r { padding: 0 calc(4.6875em + var(--x) + 50vw) 0 calc(5.9375em + 50vw); }
  .vtag { right: calc(7.9167em + 50vw); }
  .vol.r .vtag { right: auto; left: calc(7.9167em + 50vw); }
  .pale {
    width: calc(33.75em + 100vw);
    margin-left: -50vw;
    padding: .875em calc(6.3125em + 50vw) 0 calc(5.9375em + 50vw);
  }
  .cue { right: calc(8.4167em + 50vw); }
  .mast, .foot {
    padding-left: clamp(32px, 6vw, 96px);
    padding-right: clamp(32px, 6vw, 96px);
  }
  .mast { height: calc(76px + env(safe-area-inset-top)); }
  .wordmark { font-size: 26px; }
  .foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
    padding-top: 24px;
    padding-bottom: calc(28px + env(safe-area-inset-bottom));
  }
  .steps { margin: 0; font-size: 18px; line-height: 24px; }
  .begin { width: auto; min-width: 300px; gap: 48px; }
}

/* Reduce Motion switched on while the page is open: landing.js drops the
   classes, and this holds the line until it has. */
@media (prefers-reduced-motion: reduce) {
  *, ::before, ::after { animation: none !important; transition: none !important; }
}

/* The pre-open sign (tools/build-preopen.mjs): the founder's line stands
   where Begin will stand on 2026-11-23. Text, not a button: nothing opens yet. */
.opens {
  margin: 0;
  min-height: 58px;
  display: flex;
  align-items: center;
  font-size: 20px;
  line-height: 26px;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--pale);
  text-wrap: balance;
}
.opens-calm {
  margin: clamp(28px, 5vh, 48px) 0 0;
  font: 400 clamp(26px, 5.6vw, 52px)/1.1 var(--serif);
  letter-spacing: .01em;
  color: var(--pale);
  text-wrap: balance;
}
@media (min-width: 900px) {
  .opens { min-height: 0; font-size: 26px; line-height: 32px; text-align: right; }
}
