
/* ------------------------------------------------------------
   Decan Tarot, prototype. Two registers: facts in mono, readings in serif.
   Palette sampled from scans of a 1909 era Waite-Smith deck.
   ------------------------------------------------------------ */
:root{
  --paper:#f2eadb;      /* the card stock */
  --paper-2:#e8dfc9;    /* a slightly toned panel */
  --ink:#1a1416;        /* the line ink */
  --ink-2:#4a4340;      /* softened ink for secondary text */
  --ink-3:#8b8373;      /* the olive grey of worn edges */
  --rule:#cbbfa4;       /* hairlines */
  --ochre:#b9975a;      /* the yellow wash, toned for text on paper */
  --verdigris:#5f8a84;  /* the sky teal, toned for paper */
  --brick:#9c4e3d;      /* the red cloak, the active colour */
  --sun:#c98a1a;        /* 777, the Sun: reserved for a genuine match */
  --sun-ink:#1a1416;
  --card-face:#f3ecdb;
  --shadow:0 18px 50px rgba(26,20,22,.22), 0 2px 6px rgba(26,20,22,.14);
  --grain:rgba(26,20,22,.045);
  --wheel-track:#cbbfa4;
  --wheel-card:#5f8a84;
  --wheel-card-weave:#d9e6e2;
  --wheel-card-line:#2f4a47;
  --focus:#9c4e3d;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --paper:#14100f;
    --paper-2:#1d1715;
    --ink:#ece2cf;
    --ink-2:#c3b69f;
    --ink-3:#8b8373;
    --rule:#3a312c;
    --ochre:#cfb476;
    --verdigris:#84a39e;
    --brick:#c46a55;
    --sun:#e3a72f;
    --sun-ink:#14100f;
    --card-face:#efe6d4;
    --shadow:0 24px 60px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.5);
    --grain:rgba(255,255,255,.035);
    --wheel-track:#3f3630;
    --wheel-card:#2f4a47;
    --wheel-card-weave:#8fb3ad;
    --wheel-card-line:#8fb3ad;
    --focus:#e3a72f;
  }
}
:root[data-theme="dark"]{
  --paper:#14100f;
  --paper-2:#1d1715;
  --ink:#ece2cf;
  --ink-2:#c3b69f;
  --ink-3:#8b8373;
  --rule:#3a312c;
  --ochre:#cfb476;
  --verdigris:#84a39e;
  --brick:#c46a55;
  --sun:#e3a72f;
  --sun-ink:#14100f;
  --card-face:#efe6d4;
  --shadow:0 24px 60px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.5);
  --grain:rgba(255,255,255,.035);
  --wheel-track:#3f3630;
  --wheel-card:#2f4a47;
  --wheel-card-weave:#8fb3ad;
  --wheel-card-line:#8fb3ad;
  --focus:#e3a72f;
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:"Newsreader",Georgia,"Times New Roman",serif;font-variation-settings:"opsz" 18;
  font-size:1.1875rem;line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
body::before{ /* paper grain, very faint */
  content:"";position:fixed;inset:0;pointer-events:none;z-index:0;
  background-image:radial-gradient(var(--grain) 1px, transparent 1.2px);
  background-size:3px 3px;opacity:.6;
}
a{color:inherit}
:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.001ms !important;transition-duration:.001ms !important}
}

/* type roles */
.display{font-family:"Fraunces",Georgia,serif;font-weight:400;font-variation-settings:"opsz" 144,"wght" 380,"SOFT" 40,"WONK" 1;letter-spacing:-.01em;text-wrap:balance}
.display em{font-variation-settings:"opsz" 144,"wght" 380,"SOFT" 40,"WONK" 1}
.fact,.mono{font-family:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
.label{font-family:"IBM Plex Mono",ui-monospace,Menlo,monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.prose{max-width:34rem}
.prose p{margin:0 0 1em}
h1,h2,h3{margin:0;font-weight:500}
.muted{color:var(--ink-2)}
.hidden{display:none !important}

/* header */
header{
  position:relative;z-index:2;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:1.1rem clamp(1rem,4vw,3rem);
  border-bottom:1px solid var(--rule);
}
.wordmark{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 480,"SOFT" 30,"WONK" 1;font-size:1.3125rem;letter-spacing:0;text-decoration:none;display:flex;align-items:center;gap:.5rem}
.wordmark svg{width:24px;height:24px;flex:none}
.wordmark small{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin-left:.5rem;font-weight:400}
nav{display:flex;gap:1.5rem;align-items:center}
nav a{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;text-decoration:none;color:var(--ink-2)}
nav a:hover{color:var(--brick)}
.theme-btn{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  background:none;border:1px solid var(--rule);color:var(--ink-2);padding:.5rem .75rem;border-radius:999px;cursor:pointer
}
.theme-btn:hover{border-color:var(--ink-3);color:var(--ink)}
@media (max-width:720px){ nav a:not(.keep){display:none} }

main{position:relative;z-index:1}
section{padding:clamp(2.5rem,6vw,5rem) clamp(1rem,4vw,3rem)}
.wrap{max-width:1180px;margin:0 auto}

/* ---------- hero ---------- */
#hero{padding-top:clamp(1.5rem,4vw,3.5rem);padding-bottom:1rem}
.hero{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);grid-template-areas:"copy wheel" "more wheel";gap:0 clamp(1.5rem,4vw,4rem);align-items:center}
.hero-copy{grid-area:copy;align-self:end}
.hero-more{grid-area:more;align-self:start}
.hero-wheel{grid-area:wheel}
@media (max-width:900px){.hero{grid-template-columns:1fr;grid-template-areas:"copy" "wheel" "more";gap:1.5rem 0}.hero-copy{align-self:auto}}
.hero-copy h1{font-size:clamp(2.5rem,6vw,3.5rem);line-height:1.1}
.hero-copy h1 em{font-style:italic;color:var(--brick)}
.hero-copy .lede{font-size:1.0625rem;color:var(--ink-2);max-width:30rem;margin:1.25rem 0 0}
.today{
  margin-top:1.75rem;padding:1rem 1rem;border:1px solid var(--rule);border-left:3px solid var(--sun);
  background:var(--paper-2);border-radius:3px;
}
.today .label{margin-bottom:.5rem;display:block}
.today .fact{font-size:.875rem;line-height:1.5;margin:0}
.today .fact b{font-weight:500;color:var(--ink)}
.cta{margin-top:1.5rem;display:flex;gap:1rem;align-items:center;flex-wrap:wrap}
.btn{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  background:var(--ink);color:var(--paper);border:1px solid var(--ink);padding:.75rem 1.25rem;border-radius:3px;cursor:pointer;text-decoration:none
}
.btn:hover{background:var(--brick);border-color:var(--brick);color:#fff}
.btn.ghost{background:transparent;color:var(--ink);border-color:var(--rule)}
.btn.ghost:hover{border-color:var(--ink);background:transparent;color:var(--ink)}
.hint{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3)}
.linkish{background:none;border:none;padding:0;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.linkish:hover{color:var(--brick)}
.seal{margin:1rem 0 0;font-size:.75rem;line-height:1.6;color:var(--ink-3);letter-spacing:.06em;overflow-wrap:anywhere}
.seal b{color:var(--ink-2);font-weight:500}

/* ---------- wheel ---------- */
.wheel-wrap{position:relative;width:min(100%,680px);margin:0 auto;aspect-ratio:1/1;touch-action:none;user-select:none}
.wheel{width:100%;height:100%;display:block;cursor:grab}
.wheel.dragging{cursor:grabbing}
.wheel text{font-family:"IBM Plex Mono",ui-monospace,Menlo,monospace;fill:var(--ink-3);font-size:.75rem;letter-spacing:1px}
.wheel .track{fill:none;stroke:var(--wheel-track);stroke-width:1.2}
.wheel .tick{stroke:var(--wheel-track);stroke-width:1}
.wheel .tick.major{stroke:var(--ink-3);stroke-width:1.6}
.wheel .seg{fill:var(--brick);opacity:0;transition:opacity .6s ease}
.wheel .seg.on{opacity:.9}
.wheel .seg.match{fill:var(--sun)}
.wheel .cardback,.wheel .cardback-inner{transform-box:fill-box;transform-origin:center;transition:transform .15s ease-out}
.wheel .cardback{fill:var(--wheel-card);stroke:var(--wheel-card-line);stroke-width:.9}
.wheel .cardg:hover .cardback,.wheel .cardg:hover .cardback-inner{transform:translateY(-6px) scale(1.06)}
.wheel .half{transform-box:view-box;transform-origin:500px 500px;transition:transform .45s cubic-bezier(.2,.7,.2,1)}
.wheel .cutting .halfA{transform:scale(1.045)}
.wheel .cutting .halfB{transform:scale(.955)}
.wheel .cardback-inner{fill:none;stroke:var(--wheel-card-line);stroke-width:.6;opacity:.7}
.wheel .cardg{cursor:pointer}
.wheel .cardg:hover .cardback{stroke-width:1.4;stroke:var(--brick)}
.wheel .cardg.taken{opacity:0}
.wheel .sun{fill:var(--sun);stroke:var(--paper);stroke-width:3}
.wheel .sun-label{fill:var(--sun);font-weight:500}
.wheel .sunray{stroke:var(--sun);stroke-width:1;opacity:.5}
.wheel .centre-note{fill:var(--ink-3);font-size:.75rem;text-anchor:middle}
.sky-fan{position:absolute;left:50%;top:50%;width:56%;aspect-ratio:1/1;transform:translate(-50%,-50%);pointer-events:none;transition:opacity .8s ease}
.wheel-wrap.revealing .sky-fan{opacity:0}
.sky-fan figure{position:absolute;left:50%;top:45%;width:31%;aspect-ratio:480/822;margin:0;transform-origin:50% 120%;border-radius:6px;overflow:hidden;box-shadow:var(--shadow);background:var(--card-face);transition:transform .6s ease}
.sky-fan figure img{width:100%;height:100%;object-fit:cover;display:block}
.sky-fan figure.f0{transform:translate(-50%,-50%) rotate(-14deg) translateX(-60%)}
.sky-fan figure.f1{transform:translate(-50%,-50%) rotate(0deg)}
.sky-fan figure.f2{transform:translate(-50%,-50%) rotate(14deg) translateX(60%)}
.sky-fan figure.now{z-index:2;box-shadow:0 0 0 3px var(--sun),var(--shadow)}
.sky-fan figure:not(.now){filter:saturate(.75) brightness(.92)}
.sky-fan .cap{position:absolute;left:50%;top:86%;transform:translateX(-50%);width:120%;text-align:center;font-family:"IBM Plex Mono",monospace;font-size:.75rem;white-space:nowrap;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);line-height:1.6;pointer-events:none}
.sky-fan .cap b{color:var(--sun);font-weight:500}
.wheel-wrap .drawn-card{
  position:absolute;left:50%;top:50%;width:26%;aspect-ratio:480/822;transform:translate(-50%,-50%);
  transform-style:preserve-3d;pointer-events:none;opacity:0;
}
.wheel-wrap .drawn-card .face{
  position:absolute;inset:0;border-radius:6px;backface-visibility:hidden;box-shadow:var(--shadow);overflow:hidden;background:var(--card-face)
}
.wheel-wrap .drawn-card .face img{width:100%;height:100%;object-fit:cover;display:block}
.wheel-wrap .drawn-card .back{
  background:var(--card-face);border:1px solid var(--rule);
  background-image:repeating-linear-gradient(45deg, rgba(95,138,132,.22) 0 2px, transparent 2px 9px),repeating-linear-gradient(-45deg, rgba(95,138,132,.22) 0 2px, transparent 2px 9px);
}
.wheel-wrap .drawn-card .back::after{content:"";position:absolute;inset:7%;border:1.5px solid var(--brick);border-radius:3px;opacity:.75}
.wheel-wrap .drawn-card .front{transform:rotateY(180deg)}
.wheel-wrap.revealing .drawn-card{animation:lift 1.6s cubic-bezier(.2,.7,.2,1) forwards}
@keyframes lift{
  0%{opacity:0;transform:translate(-50%,-50%) scale(.28) rotateY(0deg)}
  25%{opacity:1;transform:translate(-50%,-50%) scale(.6) rotateY(0deg)}
  100%{opacity:1;transform:translate(-50%,-50%) scale(1.55) rotateY(180deg)}
}
.wheel-wrap.revealing .wheel{opacity:.35;transition:opacity 1.2s ease .3s}
.wheel-wrap.revealing .wheel .cardg{pointer-events:none}

/* ---------- reveal / socratic / reading ---------- */
#reveal{padding-top:2.5rem;scroll-margin-top:1rem}
.reveal{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);gap:clamp(1.5rem,4vw,4rem);align-items:start}
@media (max-width:900px){.reveal{grid-template-columns:1fr}}
.big-card{position:relative;margin:0 auto;width:min(100%,380px,calc(62vh * 480 / 822));aspect-ratio:480/822;border-radius:10px;overflow:hidden;box-shadow:var(--shadow);background:var(--card-face)}
.big-card img{width:100%;height:100%;object-fit:cover;display:block}
img.rev{transform:rotate(180deg)}
.big-card .dot{
  position:absolute;width:14px;height:14px;border-radius:50%;transform:translate(-50%,-50%);
  border:2px solid var(--paper);background:var(--brick);opacity:0;transition:opacity .25s;box-shadow:0 0 0 3px rgba(156,78,61,.25)
}
.big-card .dot.on{opacity:1}
.strip{
  margin:1rem 0 0;padding:1rem 1rem;border:1px solid var(--rule);border-radius:3px;background:var(--paper-2);
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1.6
}
.strip .l1{letter-spacing:.06em;text-transform:uppercase;color:var(--ink);font-weight:500}
.strip .l1 .sep{color:var(--ink-3);margin:0 .4em}
.strip .l2{color:var(--ink-2);margin-top:.25rem}
.strip.match{border-color:var(--sun);border-left:3px solid var(--sun)}
.strip.match .l2{color:var(--sun)}
.strip .why{color:var(--ink-3);font-size:.75rem;margin-top:.375rem}
.proof{margin-top:.75rem;padding-top:.5rem;border-top:1px dashed var(--rule);font-size:.75rem;line-height:1.6;color:var(--ink-3);overflow-wrap:anywhere}
.proof .muted{color:var(--ink-3)}

.socratic h2{font-size:clamp(2rem,4vw,2.5rem);line-height:1.1}
.socratic .q{font-size:1.3125rem;font-style:italic;color:var(--ink-2);margin:.5rem 0 1.25rem}
.chips{display:flex;flex-wrap:wrap;gap:.5rem}
.chip{
  font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;background:transparent;color:var(--ink);
  border:1px solid var(--ink-3);border-radius:999px;padding:.5rem 1rem;cursor:pointer;transition:all .2s
}
.chip:hover{border-color:var(--brick);color:var(--brick);transform:translateY(-1px)}
.chip.alt{border-style:dashed}
.voice{margin-top:1.25rem;display:flex;align-items:center;gap:1rem;flex-wrap:wrap}
.mic{
  width:54px;height:54px;border-radius:50%;border:1px solid var(--ink-3);background:transparent;color:var(--ink);cursor:pointer;
  display:grid;place-items:center;transition:all .2s
}
.mic:hover{border-color:var(--brick);color:var(--brick)}
.mic.listening{border-color:var(--sun);color:var(--sun);animation:pulse 1.2s infinite}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(201,138,26,.45)}100%{box-shadow:0 0 0 16px rgba(201,138,26,0)}}
.voice .hint{max-width:22rem}
.free{margin-top:1rem;display:flex;gap:.5rem}
.free input{flex:1;font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;padding:.5rem .75rem;border:1px solid var(--ink-3);background:var(--paper);color:var(--ink);border-radius:3px}
.skip{margin-top:1.5rem}
.skip button{background:none;border:none;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);cursor:pointer;padding:0}
.skip button:hover{color:var(--ink)}

.reading .echo{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 400,"SOFT" 40,"WONK" 1;font-size:clamp(1.625rem,3vw,2rem);line-height:1.2;margin-bottom:1.25rem}
.reading .echo::before{content:"";display:block;width:2.5rem;height:2px;background:var(--brick);margin-bottom:1rem}
.reading .body{font-size:1.0625rem;max-width:34rem}
.reading .body p{margin:0 0 1em}
.reading .after{margin-top:1.75rem;display:flex;gap:.75rem;flex-wrap:wrap;align-items:center}
.fade-in{animation:fadein .8s ease both}
@keyframes fadein{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ---------- three facts ---------- */
#how{border-top:1px solid var(--rule)}
.three{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(1.5rem,3vw,3rem)}
@media (max-width:820px){.three{grid-template-columns:1fr}}
.three h3{font-family:"Fraunces",Georgia,serif;font-size:1.625rem;line-height:1.1;margin:.5rem 0 .5rem}
.three p{margin:0;color:var(--ink-2);font-size:1.0625rem}
.three .label{display:block}

/* ---------- ask index ---------- */
#ask{border-top:1px solid var(--rule)}
.section-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:1.5rem}
.section-head h2{font-family:"Fraunces",Georgia,serif;font-size:clamp(2rem,4vw,2.5rem)}
.asks{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1px;background:var(--rule);border:1px solid var(--rule)}
@media (max-width:820px){.asks{grid-template-columns:1fr}}
.ask{background:var(--paper);padding:1.25rem 1.25rem 1.5rem;display:flex;flex-direction:column;gap:.5rem;text-align:left;border:none;color:inherit;font:inherit;cursor:pointer}
.ask:hover{background:var(--paper-2)}
.ask .name{font-family:"Fraunces",Georgia,serif;font-size:1.625rem;font-weight:500;line-height:1.1}
.ask .pos{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);line-height:1.6}
.ask .pos span{display:block}

/* ---------- ask flow ---------- */
#askflow{padding-top:0}
.slots{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.25rem;margin:1.5rem 0}
@media (max-width:720px){.slots{grid-template-columns:1fr}}
.slot{
  border:1.5px dashed var(--ink-3);border-radius:10px;aspect-ratio:480/822;max-width:230px;margin:0 auto;width:100%;
  display:flex;align-items:flex-end;justify-content:center;padding:1rem;position:relative;overflow:hidden;transition:border-color .3s
}
.slot.active{border-color:var(--brick);border-style:solid}
.slot.filled{border-style:solid;border-color:var(--rule)}
.slot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.slot img.rev{transform:rotate(180deg)}
.slot .cap{position:relative;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-align:center;color:var(--ink-2);background:var(--paper);padding:.25rem .5rem;border-radius:3px}
.slot.active .cap{color:var(--brick)}
.gate{
  margin-top:2rem;padding:1.25rem 1.5rem;border:1px solid var(--rule);background:var(--paper-2);border-radius:3px;
  display:grid;grid-template-columns:1fr auto;gap:1rem;align-items:center
}
@media (max-width:720px){.gate{grid-template-columns:1fr}}
.gate h3{font-family:"Fraunces",Georgia,serif;font-size:1.625rem;font-weight:500}
.gate p{margin:.25rem 0 0;color:var(--ink-2);font-size:1.0625rem}
.gate form{display:flex;gap:.5rem}
.gate input{font-family:"IBM Plex Mono",monospace;font-size:.875rem;padding:.75rem .75rem;border:1px solid var(--ink-3);background:var(--paper);color:var(--ink);border-radius:3px;min-width:14rem}

/* ---------- decans ---------- */
#decans{border-top:1px solid var(--rule)}
.decan-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:clamp(1.5rem,4vw,4rem);align-items:start}
@media (max-width:900px){.decan-grid{grid-template-columns:1fr}}
.dial{width:100%;max-width:520px;display:block;margin:0 auto}
.dial text{font-family:"IBM Plex Mono",monospace;font-size:.75rem;fill:var(--ink-3);letter-spacing:1px}
.dial .arc{fill:none;stroke:var(--wheel-track);stroke-width:14}
.dial .arc-on{fill:none;stroke:var(--verdigris);stroke-width:14;opacity:.9}
.dial .tick{stroke:var(--ink-3);stroke-width:1}
.dial .sun{fill:var(--sun);stroke:var(--paper);stroke-width:3}
.dial .big{font-family:"Fraunces",Georgia,serif;font-size:2rem;fill:var(--ink);letter-spacing:0}
.dial .mid{font-size:.75rem;fill:var(--ink-2)}
.table{width:100%;border-collapse:collapse;font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1.5}
.table th{text-align:left;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);font-size:.75rem;padding:.375rem .5rem;border-bottom:1px solid var(--rule)}
.table td{padding:.375rem .5rem;border-bottom:1px solid var(--rule);color:var(--ink-2);vertical-align:top}
.table tr{cursor:pointer}
.table tr:hover td{color:var(--ink)}
.table tr.now td{color:var(--ink);background:var(--paper-2)}
.table tr.now td:first-child{box-shadow:inset 3px 0 0 var(--sun)}
.table tr.sel td{color:var(--brick)}
.table-wrap{overflow-x:auto;max-height:520px;overflow-y:auto;border:1px solid var(--rule)}
.method{margin-top:1.5rem;font-size:1.0625rem;color:var(--ink-2);max-width:34rem}
.method p{margin:0 0 .8em}

/* ---------- birth card ---------- */
#birth{border-top:1px solid var(--rule)}
.birth{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr);gap:clamp(1.5rem,4vw,4rem);align-items:start}
@media (max-width:900px){.birth{grid-template-columns:1fr}}
.birth form{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;margin-top:1rem}
.birth input[type=date]{font-family:"IBM Plex Mono",monospace;font-size:.9375rem;padding:.5rem .75rem;border:1px solid var(--ink-3);background:var(--paper);color:var(--ink);border-radius:3px}
.results{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--rule);border:1px solid var(--rule)}
@media (max-width:640px){.results{grid-template-columns:1fr}}
.result{background:var(--paper);padding:1.25rem 1.25rem}
.result .label{display:block;margin-bottom:.5rem}
.result .big{font-family:"Fraunces",Georgia,serif;font-size:2rem;line-height:1.1;font-weight:500}
.result .fact{font-size:.75rem;color:var(--ink-2);margin-top:.5rem;line-height:1.6}
.result.ours{box-shadow:inset 0 3px 0 var(--verdigris)}
.result p.note{font-size:.9375rem;color:var(--ink-2);margin:.75rem 0 0}

/* ---------- footer ---------- */
footer{border-top:1px solid var(--rule);padding:2.5rem clamp(1rem,4vw,3rem) 4rem;font-size:.9375rem;color:var(--ink-2)}
footer .cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:2rem;max-width:1180px;margin:0 auto}
@media (max-width:820px){footer .cols{grid-template-columns:1fr}}
footer h4{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin:0 0 .5rem;font-weight:500}
footer p{margin:0 0 .6em}
footer ul{margin:0;padding-left:1.1em}
footer li{margin-bottom:.35em}

/* ---------- v4: landing around the core ---------- */
.hero{grid-template-areas:"copy wheel" "more wheel";align-items:start}
@media (max-width:900px){.hero{grid-template-columns:1fr;grid-template-areas:"copy" "wheel" "more"}}
.hero-copy{align-self:end}
.hero-copy h1{font-size:clamp(2.5rem,6vw,3.5rem)}
.under-wheel{margin:.5rem 0 0;text-align:center;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.cta.small{gap:.5rem 1.5rem;margin-top:1rem;align-items:baseline}
.section-head h2{display:flex;align-items:center;gap:.5rem}
.section-head h2 svg{width:22px;height:22px;flex:none;color:var(--ink)}
.beats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(1.2rem,3vw,2.6rem)}
@media (max-width:860px){.beats{grid-template-columns:1fr}}
.beat{margin:0;display:flex;flex-direction:column;gap:1rem}
.beat-visual{position:relative;aspect-ratio:4/3;background:var(--paper-2);border:1px solid var(--rule);border-radius:3px;overflow:hidden;display:grid;place-items:center}
.mini-card{width:38%;aspect-ratio:480/822;border-radius:6px;overflow:hidden;box-shadow:var(--shadow);background:var(--card-face);position:absolute}
.mini-card img{width:100%;height:100%;object-fit:cover;display:block}
.mini-card.back{border:1px solid var(--rule);background-image:repeating-linear-gradient(45deg, rgba(95,138,132,.22) 0 2px, transparent 2px 9px),repeating-linear-gradient(-45deg, rgba(95,138,132,.22) 0 2px, transparent 2px 9px)}
.mini-card.back::after{content:"";position:absolute;inset:7%;border:1.5px solid var(--brick);border-radius:3px;opacity:.75}
.beat-visual.turn{perspective:900px}
.beat-visual.turn .back{transform:translateX(-46%) rotateY(18deg) scale(.92);opacity:.85}
.beat-visual.turn .front{transform:translateX(24%) rotateY(-34deg)}
.beat-visual.look .still{position:absolute;left:12%;top:8%;width:36%}
.beat-chip{position:absolute;font-family:"Newsreader",Georgia,serif;font-size:.875rem;background:var(--paper);border:1px solid var(--ink-3);border-radius:999px;padding:.375rem .75rem;box-shadow:0 2px 6px rgba(0,0,0,.08)}
.beat-chip.c1{left:46%;top:22%}
.beat-chip.c2{left:52%;top:46%;border-color:var(--brick);color:var(--brick)}
.beat-chip.c3{left:44%;top:70%}
.beat-visual.read{padding:1.5rem;display:flex;flex-direction:column;justify-content:center;gap:.75rem;place-items:stretch}
.beat-echo{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.3125rem;line-height:1.2;margin:0}
.beat-echo::before{content:"";display:block;width:2rem;height:2px;background:var(--brick);margin-bottom:.5rem}
.strip.mini{margin:0;font-size:.75rem;padding:.5rem .75rem}
.beat figcaption h3{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 420,"SOFT" 40,"WONK" 1;font-size:1.625rem;line-height:1.1;margin:.375rem 0 .375rem}
.beat figcaption p{margin:0;color:var(--ink-2);font-size:1.0625rem}
/* spreads */
.spreads{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.25rem}
@media (max-width:900px){.spreads{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.spreads{grid-template-columns:1fr}}
.spread{background:var(--paper);border:1px solid var(--rule);border-radius:3px;padding:0;text-align:left;color:inherit;font:inherit;cursor:pointer;display:flex;flex-direction:column;transition:transform .15s ease-out, box-shadow .15s ease-out}
.spread:hover{transform:translateY(-3px);box-shadow:var(--shadow)}
.spread:hover .mat{border-color:var(--brick)}
.mat{width:100%;aspect-ratio:16/10;background:var(--paper-2);border-bottom:1px solid var(--rule);display:block}
.mat .slot-r{fill:none;stroke:var(--ink-3);stroke-width:1.1;stroke-dasharray:3 3;transition:stroke .2s}
.mat .slot-r.one{stroke:var(--brick);stroke-dasharray:none}
.mat .num{font-family:"IBM Plex Mono",monospace;font-size:.75rem;fill:var(--ink-3)}
.mat .sky{fill:none;stroke:var(--sun);stroke-width:1.2}
.spread .body{padding:1rem 1rem 1.25rem;display:flex;flex-direction:column;gap:.375rem}
.spread .name{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 440,"SOFT" 40,"WONK" 1;font-size:1.3125rem;line-height:1.1}
.spread .intent{color:var(--ink-2);font-size:1.0625rem;margin:0}
.spread .count{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);margin-top:.25rem}
/* the cloth */
.cloth-grid{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,.5fr);gap:2rem;align-items:start}
@media (max-width:900px){.cloth-grid{grid-template-columns:1fr}}
.cloth{position:relative;width:100%;aspect-ratio:16/10;background:var(--paper-2);border:1px solid var(--rule);border-radius:6px;overflow:hidden}
.cloth::before{content:"";position:absolute;inset:14px;border:1px solid var(--rule);border-radius:3px;pointer-events:none;opacity:.7}
.cslot{position:absolute;width:12%;aspect-ratio:480/822;transform:translate(-50%,-50%) rotate(var(--r,0deg));border:1.5px dashed var(--ink-3);border-radius:6px;transition:border-color .3s}
.cslot.active{border-color:var(--brick);border-style:solid}
.cslot.filled{border-color:transparent}
.cslot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:6px;box-shadow:var(--shadow);animation:land .55s cubic-bezier(.2,.7,.2,1) both}
@keyframes land{from{opacity:0;transform:scale(.55) translateY(-30%)}to{opacity:1;transform:none}}
.cslot .cap{position:absolute;left:50%;top:100%;transform:translateX(-50%);margin-top:.5rem;width:170%;text-align:center;line-height:1.35;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);text-transform:uppercase}
.cslot.active .cap{color:var(--brick)}
.cslot.behind{z-index:0;filter:brightness(.92)}
.cslot.front{z-index:2}
.cslot.skypos{border:none;width:14%;aspect-ratio:1/1}
.cslot.skypos svg{width:100%;height:100%}
.cloth-side{display:flex;flex-direction:column;gap:1rem}
.cloth[data-n="1"] .cslot{width:20%}
.cloth[data-n="2"] .cslot{width:16%}
/* pages */
.page section{padding-top:clamp(2rem,5vw,4rem)}
.page-title{font-size:clamp(2.5rem,6vw,3.5rem);margin:.5rem 0 .75rem}
.about-cols{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.5rem,4vw,4rem);margin-top:1.5rem}
@media (max-width:820px){.about-cols{grid-template-columns:1fr}}
/* footer, the brand block */
footer{padding-top:3rem}
.foot{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.4fr 1fr;gap:2rem;align-items:start}
@media (max-width:820px){.foot{grid-template-columns:1fr}}
.foot .wordmark{font-size:1.625rem}
.tagline{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.3125rem;margin:.5rem 0 .75rem;color:var(--ink)}
.credits{font-size:.75rem;letter-spacing:.1em;color:var(--ink-3);margin:0}
.credits .sep{margin:0 .4em}
.foot-links{display:flex;flex-direction:column;gap:.5rem;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase}
.foot-links a{text-decoration:none;color:var(--ink-2)}
.foot-links a:hover{color:var(--brick)}

/* ---------- v5: question first, the table beside the wheel, the sky on the band ---------- */
/* hero grid: the question beside the wheel */
.hero{grid-template-areas:none;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);align-items:start;gap:0 clamp(1.5rem,4vw,4rem)}
.hero-left{align-self:start;min-width:0}
.hero-wheel-slot{min-width:0}
@media (max-width:900px){.hero{grid-template-columns:1fr;gap:1.25rem 0}}
.hero-left h1{font-size:clamp(2.5rem,6vw,3.5rem);line-height:1.1}
.hero-left h1 em{font-style:italic;color:var(--brick)}
.hero-left .lede{font-size:1.0625rem;color:var(--ink-2);max-width:32rem;margin:1rem 0 1.25rem}
#hero{padding-top:clamp(1rem,2.5vw,2rem)}
.hero-wheel .wheel-wrap{width:min(100%,570px)}
.hero-wheel .today{max-width:570px;margin:.75rem auto 0;padding:.75rem 1rem}
.hero-wheel .today .fact{font-size:.8125rem}
.hero-wheel .sky-legend{max-width:570px;margin-left:auto;margin-right:auto}
.qbox{display:flex;gap:.5rem;max-width:44rem}
.qbox input{flex:1;min-width:0;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.3125rem;padding:.75rem 1rem;border:1.5px solid var(--ink-3);background:var(--paper);color:var(--ink);border-radius:3px}
.qbox input:focus{border-color:var(--brick);outline:none}
.qbox input::placeholder{color:var(--ink-3);font-style:italic}
.q-examples{display:flex;flex-wrap:wrap;gap:.25rem 1rem;align-items:baseline;margin:.75rem 0 1.25rem}
.q-examples .linkish{font-family:"Newsreader",Georgia,serif;font-size:.9375rem;letter-spacing:0;text-transform:none}
.q-result{margin:0 0 1.25rem;padding:1rem 1rem;border:1px solid var(--rule);border-left:3px solid var(--brick);background:var(--paper-2);border-radius:3px;max-width:44rem}
.q-result p{margin:.25rem 0 .75rem;font-size:1.0625rem}
.q-actions{display:flex;gap:.5rem 1.25rem;align-items:center;flex-wrap:wrap}
.cta.small{gap:.5rem 1.25rem;margin-top:.5rem;align-items:baseline}
.spread.suggested{outline:2px solid var(--brick);outline-offset:2px}
.spread.suggested .mat{border-color:var(--brick)}
.mat .slot-r.front{stroke:var(--ink-2)}

/* ---------- the table page. The cloth takes the stage; the wheel stands beside it while dealing, then leaves. ---------- */
#stage{padding-top:clamp(1rem,2.5vw,2rem);padding-bottom:1.5rem}
.stage-head{margin-bottom:1rem}
.stage-head .table-q{font-size:clamp(2rem,4vw,2.5rem);line-height:1.1;margin:.375rem 0 0;max-width:40rem}
.stage{display:flex;gap:clamp(1.2rem,3vw,2.5rem);align-items:flex-start}
.stage .stage-table{flex:1 1 58%;min-width:0;transition:flex-basis .6s cubic-bezier(.2,.7,.2,1)}
.stage .stage-wheel{flex:0 0 40%;min-width:0;transition:flex-basis .6s cubic-bezier(.2,.7,.2,1),opacity .45s ease;overflow:hidden}
.stage.turning .stage-wheel{flex-basis:0;opacity:0;pointer-events:none}
.stage.turning .stage-table{flex-basis:100%}
.stage.big .stage-table{flex-basis:64%}
.stage.big .stage-wheel{flex-basis:34%}
.stage.big.turning .stage-table{flex-basis:100%}
.stage-wheel .wheel-wrap{width:min(100%,520px);margin:0 auto}
.stage-wheel .today{display:none}
.stage-wheel .sky-legend{font-size:.75rem;gap:.25rem .75rem}
@media (max-width:900px){
  .stage{flex-direction:column}
  .stage .stage-table,.stage .stage-wheel,.stage.big .stage-table,.stage.big .stage-wheel{flex-basis:auto;width:100%}
  .stage.turning .stage-wheel{display:none}
}
.stage-table .cloth{aspect-ratio:var(--aw,16)/var(--ah,11);width:min(100%,calc(66vh * var(--aw,16) / var(--ah,11)));margin:0 auto;transition:width .6s cubic-bezier(.2,.7,.2,1)}
.stage-hints{display:flex;flex-wrap:wrap;gap:.375rem 1.5rem;align-items:baseline;margin:.75rem auto 0;max-width:min(100%,calc(66vh * var(--aw,16) / var(--ah,11)))}
.stage-hints .cta.small{margin:0}
.table-hint{margin:0;line-height:1.6;color:var(--ink-2);font-size:.8125rem}
/* slots: a numbered place, a caption under it (or beside it), and a card once dealt */
.cloth .cslot{width:var(--cw,15%)}
.cslot.skypos{width:calc(var(--cw,15%) * .9)}
.cslot{overflow:visible;cursor:default}
.cslot .num{position:absolute;left:-.55rem;top:-.55rem;z-index:4;display:grid;place-items:center;width:1.3rem;height:1.3rem;border-radius:50%;background:var(--paper);border:1px solid var(--ink-3);color:var(--ink-3);font-family:"IBM Plex Mono",monospace;font-size:.75rem;font-weight:500;transition:all .3s;transform:rotate(calc(-1 * var(--r,0deg)))}
.cslot.active .num,.cslot.next .num{background:var(--brick);border-color:var(--brick);color:#fff}
.cslot.turned .num{border-color:var(--ink);color:var(--ink)}
.cslot .cap{position:absolute;z-index:3;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);line-height:1.35;pointer-events:none;transition:color .3s}
/* the base rule sets left and top, so a rule that only sets right or bottom leaves the box over
   constrained and the browser keeps the base value: every cap="above" was rendering below its card
   and every cap="left" to its right, which is half the ring in the year ahead. Reset the axis. */
.cslot[data-cap="below"] .cap{left:50%;right:auto;top:100%;bottom:auto;transform:translateX(-50%);margin-top:.5rem;width:210%;text-align:center}
.cslot[data-cap="right"] .cap{left:100%;right:auto;top:50%;bottom:auto;transform:translateY(-50%);margin-left:.5rem;width:190%;text-align:left}
.cslot[data-cap="left"] .cap{right:100%;left:auto;top:50%;bottom:auto;transform:translateY(-50%);margin-right:.5rem;width:190%;text-align:right}
.cslot[data-cap="above"] .cap{left:50%;right:auto;bottom:100%;top:auto;transform:translateX(-50%);margin-bottom:.5rem;width:210%;text-align:center}
.cslot[data-cap="none"] .cap{display:none}
.cslot.active .cap,.cslot.next .cap{color:var(--brick)}
.cslot.turned .cap{color:var(--ink-2)}
.cslot.skypos .cap{color:var(--sun)}
.cslot.active{animation:slotpulse 1.6s ease-in-out infinite}
.cslot.next{cursor:pointer;animation:slotpulse 1.6s ease-in-out infinite;border-color:var(--brick)}
@keyframes slotpulse{0%,100%{box-shadow:0 0 0 0 rgba(156,78,61,0)}50%{box-shadow:0 0 0 6px rgba(156,78,61,.18)}}
.cslot.skypos .num{left:auto;right:-.4rem;top:-.4rem;border-color:var(--sun);color:var(--sun)}
.cslot.filled.turned{cursor:pointer}
.cslot.filled.turned:hover .card{transform:translateY(-3px) rotateY(180deg)}
/* the card in a slot: face down until it is turned, then it turns where it lies */
.cslot .card{position:absolute;inset:0;transform-style:preserve-3d;opacity:0;pointer-events:none;transition:transform .2s}
.cslot.filled .card{opacity:1}
.cslot .card .face{position:absolute;inset:0;border-radius:6px;overflow:hidden;box-shadow:var(--shadow);background:var(--card-face)}
.cslot .card .face img{position:static;width:100%;height:100%;object-fit:cover;display:block;box-shadow:none;border-radius:0;animation:none}
.cslot .card .front{opacity:0;transform:rotateY(180deg)}
.cslot.turned .card{animation:slotflip .8s ease forwards}
.cslot.turned .card .back{animation:faceback50 .8s linear forwards}
.cslot.turned .card .front{animation:facefront50 .8s linear forwards}
@keyframes slotflip{0%{transform:rotateY(0deg)}50%{transform:rotateY(90deg) scale(1.18)}100%{transform:rotateY(180deg)}}
@keyframes faceback50{0%,49.9%{opacity:1}50%,100%{opacity:0}}
@keyframes facefront50{0%,49.9%{opacity:0}50%,100%{opacity:1}}
.cslot.done .card{transform:rotateY(180deg)}
.cslot.done .card .back{opacity:0}
.cslot.done .card .front{opacity:1}
.cslot.filled{border-color:transparent}
.cslot.filled.next{border-color:var(--brick)}
.flyer{position:fixed;z-index:80;border-radius:6px;box-shadow:var(--shadow);background:var(--card-face);pointer-events:none;object-fit:cover;transition-property:left,top,width,height,transform;transition-duration:.66s;transition-timing-function:cubic-bezier(.3,.7,.2,1)}
.cloth-copy .cloth{aspect-ratio:var(--aw,16)/var(--ah,11);width:100%}
/* the lift: the card held up to you, over the table */
.lift{position:fixed;inset:0;z-index:70;display:grid;place-items:center;padding:1.5rem;overflow:auto;background:rgba(242,234,219,.82);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);opacity:0;transition:opacity .35s ease}
:root[data-theme="dark"] .lift{background:rgba(20,16,15,.84)}
.lift.shown{opacity:1}
.lift-inner{display:grid;grid-template-columns:minmax(0,340px) minmax(0,470px);gap:clamp(1.2rem,3vw,2.6rem);align-items:start;width:100%;max-width:820px;margin:auto}
.lift.nocard .lift-inner{grid-template-columns:minmax(0,560px);justify-content:center}
.lift.nocard .lift-card{display:none}
.lift .big-card{width:100%;margin:0}
.lift-panel{padding-top:.25rem}
.lift-panel h2{font-size:clamp(2rem,4vw,2.5rem);line-height:1.1}
.lift-panel .q{font-size:1.1875rem;font-style:italic;color:var(--ink-2);margin:.5rem 0 1rem}
.lift-panel .voice{margin-top:1rem}
.lift-panel .skip{margin-top:1.25rem;display:flex;gap:1.5rem}
.lift-panel .skip button{background:none;border:none;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);cursor:pointer;padding:0}
.lift-panel .skip #nextBtn{color:var(--brick);text-decoration:underline;text-underline-offset:3px}
.lift-panel .strip{margin-top:1.25rem}
@media (max-width:760px){.lift{padding:1rem;place-items:start center}.lift-inner{grid-template-columns:1fr;max-width:420px}.lift .big-card{width:min(62%,240px);margin:0 auto}}
/* the reveal: card and strip on the left, the question on the right */
.session-head{margin-bottom:1.25rem}
.q-echo{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 400,"SOFT" 40,"WONK" 1;font-size:clamp(1.625rem,3vw,2rem);line-height:1.2;margin:.25rem 0 0}
.reveal .left{display:flex;flex-direction:column;gap:1rem}
.pos-block{margin-top:1rem}
.pos-label{display:block;margin-bottom:.375rem}
.pos-obs{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.1875rem;line-height:1.35;margin:0 0 .5rem;color:var(--ink)}
.reading-text{margin-top:1.5rem}
.skytag{display:inline-block;margin-left:.6em;padding:.1em .5em;border:1px solid var(--sun);border-radius:999px;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--sun);vertical-align:.1em}
/* the wheel: card backs, the band, the bodies */
.wheel .cardback{fill:url(#backPattern);stroke:var(--wheel-card-line);stroke-width:1}
.wheel .cardback-inner{fill:none;stroke:var(--paper);stroke-width:1.1;opacity:.85}
.wheel .cardback-lozenge{fill:var(--paper);opacity:.9}
.wheel .cardg:hover .cardback{stroke:var(--brick);stroke-width:1.6}
.wheel .cardbody{transform-box:fill-box;transform-origin:center;transition:transform .14s ease-out}
.wheel .cardg:hover .cardback,.wheel .cardg:hover .cardback-inner{transform:none}
.wheel .track{stroke:var(--ink-3);stroke-width:1.1;opacity:.75}
.wheel .tick{stroke:var(--ink-3);opacity:.5}
.wheel .signlabel{font-size:.9375rem;fill:var(--ink-2);letter-spacing:1.5px}
.wheel .planet{fill:var(--paper);stroke:var(--ink-3);stroke-width:1.4}
.wheel .glyph{font-size:1.0625rem;fill:var(--ink);letter-spacing:0;font-weight:500}
.wheel .body-moon .planet{stroke:#6f8fb5}.wheel .body-mercury .planet{stroke:#b8a13a}.wheel .body-venus .planet{stroke:#3f8f5f}.wheel .body-mars .planet{stroke:#b83a2a}.wheel .body-jupiter .planet{stroke:#6a4fa0}.wheel .body-saturn .planet{stroke:#3c4a80}
.wheel .body-moon .glyph{fill:#4f6f95}.wheel .body-mercury .glyph{fill:#8a7620}.wheel .body-venus .glyph{fill:#2f6f47}.wheel .body-mars .glyph{fill:#9a2e20}.wheel .body-jupiter .glyph{fill:#54397f}.wheel .body-saturn .glyph{fill:#2c3862}
:root[data-theme="dark"] .wheel .body-moon .glyph{fill:#9fb9db}:root[data-theme="dark"] .wheel .body-mercury .glyph{fill:#d9c25a}:root[data-theme="dark"] .wheel .body-venus .glyph{fill:#7fc59a}:root[data-theme="dark"] .wheel .body-mars .glyph{fill:#e07a68}:root[data-theme="dark"] .wheel .body-jupiter .glyph{fill:#b39ddb}:root[data-theme="dark"] .wheel .body-saturn .glyph{fill:#9aa6d6}
:root[data-theme="dark"] .wheel .planet{fill:#1d1715}
.sky-legend{display:flex;flex-wrap:wrap;justify-content:center;gap:.375rem 1rem;margin:.75rem 0 0;font-size:.75rem;letter-spacing:.06em;color:var(--ink-2)}
.sky-legend .lg i{font-style:normal;margin-right:.3em;font-size:.8125rem}
.lg-sun i{color:var(--sun)}.lg-moon i{color:#6f8fb5}.lg-mercury i{color:#b8a13a}.lg-venus i{color:#3f8f5f}.lg-mars i{color:#b83a2a}.lg-jupiter i{color:#6a4fa0}.lg-saturn i{color:#3c4a80}
:root[data-theme="dark"] .lg-moon i{color:#9fb9db}:root[data-theme="dark"] .lg-mercury i{color:#d9c25a}:root[data-theme="dark"] .lg-venus i{color:#7fc59a}:root[data-theme="dark"] .lg-mars i{color:#e07a68}:root[data-theme="dark"] .lg-jupiter i{color:#b39ddb}:root[data-theme="dark"] .lg-saturn i{color:#9aa6d6}
.bdot{display:inline-grid;place-items:center;width:1.25rem;height:1.25rem;border-radius:50%;border:1px solid currentColor;margin-right:.375rem;font-size:.75rem;vertical-align:-.25em;font-family:"IBM Plex Mono",monospace}
.bdot-sun{color:var(--sun)}.bdot-moon{color:#6f8fb5}.bdot-mercury{color:#b8a13a}.bdot-venus{color:#3f8f5f}.bdot-mars{color:#b83a2a}.bdot-jupiter{color:#6a4fa0}.bdot-saturn{color:#3c4a80}
:root[data-theme="dark"] .bdot-moon{color:#9fb9db}:root[data-theme="dark"] .bdot-mercury{color:#d9c25a}:root[data-theme="dark"] .bdot-venus{color:#7fc59a}:root[data-theme="dark"] .bdot-mars{color:#e07a68}:root[data-theme="dark"] .bdot-jupiter{color:#b39ddb}:root[data-theme="dark"] .bdot-saturn{color:#9aa6d6}
.sky-fan{width:50%}
.sky-fan .cap{top:83%;width:auto;font-size:.75rem}
/* how it reads: four beats */
.beats.four{grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(1rem,2.4vw,2rem)}
@media (max-width:1000px){.beats.four{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.beats.four{grid-template-columns:1fr}}
.beats.four .beat figcaption h3{font-size:1.3125rem}
.beats.four .beat figcaption p{font-size:.9375rem}
.beat-visual.ask{padding:1rem 1rem;display:flex;flex-direction:column;justify-content:center;gap:.5rem;place-items:stretch}
.beat-visual.ask .beat-q{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.2;margin:0}
.beat-visual.ask .mat{border:1px solid var(--rule);border-radius:3px;aspect-ratio:16/8}
.beat-visual.ask .beat-mat-name{font-size:.75rem;letter-spacing:.1em;color:var(--ink-3)}
.beat-visual.ask .beat-mat-name .sep{margin:0 .4em}
/* why */
#why{border-top:1px solid var(--rule)}
.whys{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(1.2rem,3vw,2.6rem)}
@media (max-width:820px){.whys{grid-template-columns:1fr}}
.why-item h3{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 440,"SOFT" 40,"WONK" 1;font-size:1.625rem;line-height:1.1;margin:0 0 .5rem}
.why-item p{margin:0 0 1rem;color:var(--ink-2);font-size:1.0625rem;max-width:34rem}
.why-item .strip.mini{max-width:34rem}
.why-more{margin-top:clamp(1.2rem,3vw,2.2rem);max-width:none}
.why-more .l2 b{color:var(--ink);font-weight:500}
.why-more .fact{display:inline-block;margin-left:.6em;color:var(--ink-3)}
/* footer brand block */
.foot-brand{display:grid;grid-template-columns:auto 1fr;gap:.375rem 1.25rem;align-items:center}
.foot-mark{grid-row:1/4;color:var(--ink)}
.foot-word{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 500,"SOFT" 30,"WONK" 1;font-size:1.625rem;letter-spacing:.14em}
.foot .tagline{margin:0}
.foot .credits{margin:0}

/* one card back, everywhere: the same teal weave as the wheel */
.cslot .card .back,.flyer.back,.big-card.facedown,.mini-card.back{background-color:var(--wheel-card);background-image:repeating-linear-gradient(45deg,var(--wheel-card-weave) 0 1.2px,transparent 1.2px 8px);border:1px solid var(--wheel-card-line);overflow:hidden}
.cslot .card .back::after,.flyer.back::after,.big-card.facedown::after,.mini-card.back::after{content:"";position:absolute;inset:8%;border:1px solid var(--paper);border-radius:3px;opacity:.85}
.cslot .card .back::before,.flyer.back::before,.big-card.facedown::before,.mini-card.back::before{content:"";position:absolute;left:50%;top:50%;width:28%;aspect-ratio:12/18;background:var(--paper);opacity:.92;transform:translate(-50%,-50%) rotate(45deg);border-radius:3px}
.big-card.facedown img{visibility:hidden}
.big-card.facedown{position:relative}

/* the whole-table question sits under the cloth, so the cards stay in view */
.whole-panel{margin:1.25rem auto 0;max-width:min(100%,calc(66vh * var(--aw,16) / var(--ah,11)));padding:1rem 1.25rem;border:1px solid var(--rule);border-left:3px solid var(--brick);background:var(--paper-2);border-radius:3px;animation:fadein .5s ease both}
.whole-panel h3{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 420,"SOFT" 40,"WONK" 1;font-size:1.625rem;line-height:1.1;margin:.25rem 0 .25rem}
.whole-panel .q{font-size:1.0625rem;font-style:italic;color:var(--ink-2);margin:0 0 .75rem}
.whole-panel .chips{gap:.5rem}
.whole-panel .chip{font-size:.9375rem;padding:.5rem .75rem}
.whole-panel .skip{margin-top:1rem}
.whole-panel .skip button{background:none;border:none;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);cursor:pointer;padding:0}
.cslot.hi .card{transform:translateY(-6px) rotateY(180deg) scale(1.06)}
.cslot.hi .cap{color:var(--brick)}

/* the landing, quieter */
.or-line{margin:1rem 0 0;font-size:.75rem}
.or-line .linkish{font-size:.75rem}
.under-wheel .linkish{margin-left:.6em;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase}
.spreads{grid-template-columns:repeat(auto-fill,minmax(230px,1fr))}
.beat-chip{font-size:.8125rem;white-space:nowrap;padding:.25rem .75rem}
.beat-chip.c1{left:44%;top:20%}.beat-chip.c2{left:50%;top:44%}.beat-chip.c3{left:42%;top:68%}
.qbox input::placeholder{transition:opacity .4s}
.qbox input.fading::placeholder{opacity:0}
.beat-visual.read{overflow:hidden}
.beat-visual.read .beat-echo{font-size:1.0625rem}
.beat-visual.read .strip.mini{font-size:.75rem;overflow:hidden}

/* ================= v7: the cards are the hero, plain words, one fact line ================= */
header{padding:.9rem clamp(1rem,4vw,3rem);border-bottom:1px solid var(--rule);z-index:20;background:var(--paper)}
.wordmark{font-size:1.1875rem;gap:.5rem}
.wordmark svg{width:20px;height:20px}
nav{gap:1.5rem}
nav a{font-size:.75rem;letter-spacing:.14em}
.theme-btn{font-size:.75rem;padding:.375rem .5rem}
.kicker{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
/* the hero */
html,body{overflow-x:clip}
.hero7{position:relative;min-height:min(calc(100vh - 62px),880px);display:grid;grid-template-columns:minmax(0,1fr);place-items:center;padding:clamp(3rem,8vh,6rem) clamp(1rem,4vw,3rem) 4.5rem}
.scatter{position:absolute;inset:0;pointer-events:none;z-index:3}
.scatter.off{visibility:hidden}
.scatter .sc{position:absolute;width:clamp(128px,13.5vw,205px);aspect-ratio:480/822;margin:0;transform:rotate(var(--r,0deg));transform-origin:center;will-change:transform}
.scatter .sc-in{width:100%;height:100%;border-radius:10px;overflow:hidden;box-shadow:0 30px 60px rgba(26,20,22,.22),0 4px 10px rgba(26,20,22,.12);background:var(--card-face);transform:translate(var(--px,0px),var(--py,0px));transition:transform .5s ease-out;animation:scIn 1.1s cubic-bezier(.2,.7,.2,1) both}
.scatter .sc.flying .sc-in{transform:none;transition:none}
.scatter .sc img{width:100%;height:100%;object-fit:cover;display:block}
@keyframes scIn{from{opacity:0;transform:translate(var(--px,0px),calc(var(--py,0px) + 60px))}to{opacity:1}}
@media (max-width:900px){.scatter .sc{width:clamp(96px,22vw,150px)}.scatter .sc-extra{display:none}.scatter .sc-l{margin-left:-9vw}.scatter .sc-r{margin-left:9vw}.hero7{min-height:0;padding-top:4.5rem;padding-bottom:3.5rem}.hero-centre h1{font-size:clamp(2rem,4vw,2.5rem)}}
.hero-centre{position:relative;z-index:2;width:100%;max-width:46rem;text-align:center;min-width:0}
.hero-centre h1{font-size:clamp(2.5rem,6vw,3.5rem);line-height:1;margin:.75rem 0 1rem;letter-spacing:-.01em}
.hero-centre .lede{font-size:1.3125rem;color:var(--ink-2);max-width:34rem;margin:0 auto 1.75rem;line-height:1.5}
.hero-centre .qbox{max-width:40rem;margin:0 auto}
.hero-centre .qbox input{font-size:1.3125rem;padding:.75rem 1rem;border:1.5px solid var(--ink);background:rgba(255,255,255,.45)}
:root[data-theme="dark"] .hero-centre .qbox input{background:rgba(0,0,0,.25);border-color:var(--ink-2)}
.hero-centre .btn{padding:1rem 1.25rem}
.hero-centre .or-line{margin:1rem 0 0;font-size:.75rem;color:var(--ink-3)}
.hero-centre .q-result{text-align:left;margin:1rem auto 0}
.today-line{margin:2.5rem 0 0;text-align:center;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);padding:0 1rem}
.today-line .sep{margin:0 .8em}
.today-line .bdot{width:1.05rem;height:1.05rem;font-size:.75rem;margin-right:.375rem;vertical-align:-.2em}
/* how it reads */
.deck{position:relative;width:220px;aspect-ratio:480/822;margin:0 auto;visibility:hidden}
.deck.on{visibility:visible}
.dk{position:absolute;inset:0;margin:0;border-radius:10px;background:var(--card-face);box-shadow:0 2px 4px rgba(26,20,22,.18);transform:translate(calc((var(--i) - var(--n) + 1) * 1.5px),calc((var(--n) - 1 - var(--i)) * 1.5px)) rotate(calc((var(--i) - (var(--n) - 1) / 2) * 1.4deg))}
.dk:not(.top){background-color:var(--wheel-card);background-image:repeating-linear-gradient(45deg,var(--wheel-card-weave) 0 1.2px,transparent 1.2px 8px);border:1px solid var(--wheel-card-line)}
.dk.top{transform-style:preserve-3d;transition:transform .75s cubic-bezier(.2,.7,.2,1);box-shadow:0 22px 46px rgba(26,20,22,.22),0 3px 8px rgba(26,20,22,.14)}
.dk.top.up{transform:rotateY(180deg)}
.dk.top .face{position:absolute;inset:0;border-radius:10px;overflow:hidden;transition:opacity 0s .36s}
.dk.top .face.back{background-color:var(--wheel-card);background-image:repeating-linear-gradient(45deg,var(--wheel-card-weave) 0 1.2px,transparent 1.2px 8px);border:1px solid var(--wheel-card-line)}
.dk.top .face.back::after{content:"";position:absolute;inset:8%;border:1px solid var(--paper);border-radius:3px;opacity:.85}
.dk.top .face.back::before{content:"";position:absolute;left:50%;top:50%;width:28%;aspect-ratio:12/18;background:var(--paper);opacity:.92;transform:translate(-50%,-50%) rotate(45deg);border-radius:3px}
.dk.top .face.front{opacity:0;transform:rotateY(180deg)}
.dk.top.up .face.front{opacity:1}
.dk.top.up .face.back{opacity:0}
.dk.top .face img{width:100%;height:100%;object-fit:cover;display:block}
.deck-cap{margin:1rem 0 0;text-align:center;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);width:220px;margin-left:auto;margin-right:auto}
.steps{display:flex;flex-direction:column;gap:0}
.step{padding:3rem 0;max-width:36rem;border-top:1px solid var(--rule)}
.step:first-child{padding-top:0;border-top:none}
@media (max-width:900px){.deck{width:150px}.deck-cap{width:auto}.step{min-height:0;padding:2.5rem 0}}
.how-item .num,.step .num{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;color:var(--ink-3);display:inline-grid;place-items:center;width:1.6rem;height:1.6rem;border:1px solid var(--ink-3);border-radius:50%;margin-bottom:1rem}
.how-item h3,.step h3{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 440,"SOFT" 40,"WONK" 1;font-size:1.625rem;line-height:1.1;margin:0 0 .5rem}
.how-item p,.step p{margin:0;color:var(--ink-2);font-size:1.0625rem;max-width:26rem}
.demo{margin-top:1.5rem;padding-top:1.25rem;border-top:1px solid var(--rule)}
.demo-q{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-style:italic;font-size:1.1875rem;line-height:1.35;margin:0 0 1rem}
.demo-spread .mat{border:1px solid var(--rule);border-radius:3px;aspect-ratio:16/10}
.demo-spread b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;font-size:1.1875rem;margin:.125rem 0 .25rem}
.demo-spread p{font-size:.9375rem;margin:0 0 .375rem}
.demo-card{width:120px;aspect-ratio:480/822;border-radius:6px;overflow:hidden;box-shadow:var(--shadow);background:var(--card-face)}
.demo-card img{width:100%;height:100%;object-fit:cover;display:block}
.demo-chips{display:flex;flex-wrap:wrap;gap:.375rem;align-content:start}
.demo-chips .chip{font-size:.875rem;padding:.375rem .75rem;cursor:default}
.demo-chips .chip.on{background:var(--brick);border-color:var(--brick);color:#fff}
.demo-open{flex-basis:100%;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.35;margin:.5rem 0 0}
.demo-skytext b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;font-size:1.1875rem;margin:0 0 .375rem}
.demo-skytext .hint{display:block;margin-top:.5rem}
/* section heads, spreads, learn teaser */
.section-head7{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:1.5rem}
.section-head7 h2,.section-head7 h1{font-size:clamp(2rem,4vw,2.5rem)}
#spreads,#learn-teaser{border-top:1px solid var(--rule)}
.spreads{grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:1.5rem 1.5rem}
.spread{border:none;background:transparent;border-radius:0}
.spread:hover{transform:none;box-shadow:none}
.spread .mat{border:1px solid var(--rule);border-radius:3px;background:var(--paper-2)}
.spread:hover .mat{border-color:var(--brick)}
.spread .body{padding:.75rem 0 0;gap:.25rem}
.spread .name{font-size:1.3125rem}
.spread .intent{font-size:.9375rem}
.spread.suggested{outline:none}
.spread.suggested .mat{border-color:var(--brick);box-shadow:inset 0 0 0 1px var(--brick)}
.learn-links{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:2rem}
@media (max-width:820px){.learn-links{grid-template-columns:1fr}}
.learn-links a{text-decoration:none;color:inherit;border-top:1px solid var(--ink);padding-top:1rem}
.learn-links a b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 72,"wght" 440,"SOFT" 40,"WONK" 1;font-size:1.3125rem;font-weight:400;margin-bottom:.25rem}
.learn-links a span{color:var(--ink-2);font-size:1.0625rem}
.learn-links a:hover b{color:var(--brick)}
/* the learn page */
.learn .page-title{max-width:34rem}
.learn-nav{display:flex;flex-wrap:wrap;gap:.375rem 1.5rem;margin:1.25rem 0 2.5rem;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase}
.learn-nav a{color:var(--ink-3);text-decoration:none}
.learn-nav a:hover{color:var(--brick)}
.learn h3.display{font-size:clamp(1.625rem,3vw,2rem);margin:3rem 0 .75rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.learn .prose{max-width:40rem;font-size:1.0625rem}
.learn .decan-grid{margin-top:1.5rem}
.card-index{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1.5rem 3rem}
.ci-group .label{display:block;margin-bottom:.5rem}
.ci{display:grid;grid-template-columns:2rem 1fr auto;gap:.25rem .75rem;align-items:center;padding:.5rem 0;border-top:1px solid var(--rule);font-size:.9375rem}
.ci b{font-weight:500;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-size:1.0625rem}
.ci span:not(.ci-num){grid-column:2;color:var(--ink-2);font-size:.9375rem}
.ci img{grid-column:3;grid-row:1/3;width:30px;aspect-ratio:480/822;object-fit:cover;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.ci .ci-num{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);grid-row:1/3;align-self:center}
.ci.match{box-shadow:inset 3px 0 0 var(--sun);padding-left:.5rem}
.ci em.gold{color:var(--sun);font-style:normal}
/* the simplified strip, in the lift and the reading */
.strip7{margin:1.25rem 0 0;padding-top:1rem;border-top:1px solid var(--rule)}
.strip7 .l1{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;font-size:1.0625rem;margin-bottom:.25rem}
.sky-line{font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;color:var(--ink-3)}
.sky-line.match{color:var(--sun);font-family:"IBM Plex Mono",monospace;font-size:.8125rem;letter-spacing:.02em}
.sky-line .bdot{vertical-align:-.3em}
.fold{margin-top:.5rem}
.fold summary{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);cursor:pointer;list-style:none}
.fold summary::before{content:"+ ";}
.fold[open] summary::before{content:"\2013 ";}
.fold-body{margin-top:.5rem;font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1.6;color:var(--ink-3)}
.fold-body p{margin:0 0 .375rem}
.reading .strip7{margin:.375rem 0 0;padding:.75rem 0 0}
/* the lift: a bar with the context and a way out; the panel rises in */
.lift{display:block;padding:0}
.lift-bar{position:sticky;top:0;display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:1rem clamp(1rem,4vw,3rem);border-bottom:1px solid var(--rule);background:transparent}
.lift-context{display:flex;flex-direction:column;gap:.25rem;min-width:0}
.lift-context .fact{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lift-context .fact:first-child{color:var(--ink-2);text-transform:none;letter-spacing:.02em;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 420,"SOFT" 40,"WONK" 1;font-size:1.0625rem}
.lift-close{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;background:none;border:1px solid var(--ink-3);color:var(--ink);padding:.5rem .75rem;border-radius:999px;cursor:pointer;flex:none}
.lift-close:hover{border-color:var(--brick);color:var(--brick)}
.lift-inner{margin:clamp(1rem,4vh,3rem) auto;padding:0 1.5rem 2rem;transform:translateY(18px);transition:transform .45s cubic-bezier(.2,.7,.2,1)}
.lift.shown .lift-inner{transform:none}
.lift{transition:opacity .45s ease}
.lift-panel h2{margin-top:0}
.lift .strip{display:none}
@media (max-width:600px){.hero-centre .qbox{flex-direction:column}.hero-centre .qbox .btn{width:100%}.today-line{font-size:.75rem;letter-spacing:.1em}}

/* ---------- v7b: the three demonstrations ---------- */
.demo{margin-top:1.5rem;padding-top:1.25rem;border-top:1px solid var(--rule)}
.demo-q{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-style:italic;font-size:1.1875rem;line-height:1.35;margin:0 0 1rem;min-height:2.6em;color:var(--ink)}
.demo-q .caret{display:inline-block;width:2px;height:1em;background:var(--brick);vertical-align:-.12em;margin-left:2px;animation:blink 1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
.demo-spread{display:grid;grid-template-columns:132px minmax(0,1fr);gap:1rem;align-items:center;opacity:0;transform:translateY(5px);transition:opacity .5s ease,transform .5s ease}
.demo-spread.on{opacity:1;transform:none}
.demo-spread .mat{border:1px solid var(--rule);border-radius:3px;background:var(--paper-2)}
.demo-spread .label{display:block;margin-bottom:.25rem}
.demo-spread b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 470,"SOFT" 40,"WONK" 1;font-size:1.3125rem;line-height:1.1;margin-bottom:.25rem}
.demo-spread p{margin:0 0 .5rem;font-size:.9375rem;color:var(--ink-2)}
.demo-spread .fact{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.demo-look{display:block}
@media (max-width:900px){.demo-look{display:grid;grid-template-columns:118px minmax(0,1fr);gap:1.25rem;align-items:start}}
.demo-card{position:relative;width:100%;aspect-ratio:480/822;border-radius:6px;overflow:visible;background:var(--card-face)}
.demo-card img{width:100%;height:100%;object-fit:cover;display:block;border-radius:6px;box-shadow:var(--shadow)}
.demo-cardname{position:absolute;left:0;right:0;top:100%;margin-top:.5rem;text-align:center;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.demo-chips{display:flex;flex-wrap:wrap;gap:.5rem;align-content:start}
.demo-chips .chip{font-size:.9375rem;padding:.375rem .75rem}
.demo-chips .chip.on{background:var(--brick);border-color:var(--brick);color:#fff}
.demo-open{flex-basis:100%;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.35;margin:.75rem 0 0;color:var(--ink);transition:opacity .2s}
.synth{display:grid;gap:0}
.srow{display:grid;grid-template-columns:8.5rem minmax(0,1fr);gap:.25rem 1rem;align-items:baseline;padding:.5rem 0;border-bottom:1px solid var(--rule)}
.srow .label{font-size:.75rem;letter-spacing:.14em}
.srow b{font-weight:400;font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;color:var(--ink)}
.srow.gold b{color:var(--sun)}
.srow .bdot{width:1.1rem;height:1.1rem;font-size:.75rem;margin-right:.25rem;vertical-align:-.2em}
.sout{padding-top:1rem}
.sout p{margin:0;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.35;color:var(--ink)}
.demo-sky .hint{display:block;margin-top:.75rem}
@media (max-width:900px){.demo-card.m-only{display:block}}
@media (min-width:901px){.demo-card.m-only{display:none}}
@media (max-width:600px){.demo-look{grid-template-columns:92px minmax(0,1fr);gap:1rem}.srow{grid-template-columns:1fr}.demo-spread{grid-template-columns:108px minmax(0,1fr)}}
/* ---------- the sky, marked on a card ---------- */
.cslot.sky.turned .card .front,.cslot.sky.done .card .front{box-shadow:0 0 0 2px var(--sun),0 0 18px rgba(201,138,26,.4)}
.cslot .skymark{position:absolute;right:-.5rem;top:-.5rem;z-index:5;display:none;gap:.125rem;padding:.125rem .25rem;border-radius:999px;background:var(--paper);border:1px solid var(--sun);font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1;transform:rotate(calc(-1 * var(--r,0deg)))}
.cslot.sky.turned .skymark,.cslot.sky.done .skymark{display:inline-flex;animation:skyIn .5s ease both .3s}
.cslot .skymark i{font-style:normal;color:var(--sun)}
@keyframes skyIn{from{opacity:0;transform:rotate(calc(-1 * var(--r,0deg))) scale(.6)}to{opacity:1}}
.big-card.sky{box-shadow:0 0 0 2px var(--sun),var(--shadow)}
.dk.top.sky.up{box-shadow:0 0 0 2px var(--sun),0 22px 46px rgba(26,20,22,.22)}
.deck.on .dk.top.sky.up + .deck-cap{color:var(--sun)}
/* ---------- the mark ---------- */
.wordmark svg{width:26px;height:26px}
.foot-mark svg{width:56px;height:56px}

/* the composed reading */
.pos-read{margin:.25rem 0 .5rem;font-size:1.0625rem;line-height:1.5;color:var(--ink-2);max-width:36rem}
.pos-read i{color:var(--ink)}
.pos-read .gold{color:var(--sun)}
.reading-close{margin-top:1.75rem;padding-top:1.25rem;border-top:1px solid var(--ink)}
.reading-close p{margin:.25rem 0 0;font-size:1.0625rem;line-height:1.5;max-width:36rem}
.reading .body{max-width:none}

/* the why-this-one page */
.feat .feat-lede{max-width:44rem;font-size:1.1875rem;line-height:1.5;color:var(--ink-2);margin:.75rem 0 0}
.feat-block{margin-top:3rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.feat-block h3.display,.feat-block h1.display{font-size:clamp(1.625rem,3vw,2rem);margin:0 0 .75rem}
.feat .answer{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.1875rem;line-height:1.5;max-width:42rem;margin:0 0 1rem;color:var(--ink)}
.feat .prose{max-width:40rem}
.feat .prose p{color:var(--ink-2)}
.feat-table-wrap{margin-top:3rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.feat-table{margin-top:.75rem;font-family:"Newsreader",Georgia,serif;font-size:1.0625rem}
.feat-table th{font-family:"IBM Plex Mono",monospace}
.feat-table td{vertical-align:top;padding:.75rem .75rem .75rem 0;color:var(--ink-2)}
.feat-table td:first-child{color:var(--ink);width:11rem}
.faq{margin:1rem 0 0;max-width:42rem}
.faq dt{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;font-size:1.1875rem;margin-top:1.25rem}
.faq dd{margin:.375rem 0 0;color:var(--ink-2);font-size:1.0625rem;line-height:1.5}
.feat-cta{margin-top:3rem;padding-top:1.5rem;border-top:1px solid var(--ink);display:flex;gap:1.5rem;align-items:center;flex-wrap:wrap}

/* ---------- the display faces: Fraunces for the system, Cormorant Garamond for the two voice moments,
   the promise on the home page and the first line of every reading. Chosen 4 September 2026. ---------- */
.hero-centre h1,
.reading .echo,
.stage-head .table-q,
#lookTitle,
.demo-q,
.pos-obs,
.beat-echo{font-family:"Fraunces",Georgia,serif;font-variation-settings:normal;font-weight:400;letter-spacing:0}
.hero-centre h1{font-size:clamp(2.5rem,6vw,3.5rem);line-height:1}
.reading .echo{font-weight:400;font-size:clamp(2rem,4vw,2.5rem);line-height:1.1}
.pos-obs{font-weight:400;font-size:1.3125rem}
#lookTitle{font-weight:400}

/* =========================================================
   v8: the space between things
   Eight notes from the v7 review, in order: the hero cards sat too far out; step two read as
   an essay; step three did not resolve; the lift arrived as a popup; the panel felt like a
   form; the card was not named first; the reading repeated itself; the story ended nowhere.
   ========================================================= */

/* ---- the hero: the cards belong to the column, not to the screen edges ---- */
.hero7{min-height:min(calc(100vh - 62px),790px);padding:clamp(2.4rem,6vh,4.5rem) clamp(1rem,4vw,3rem) 3.6rem}
.scatter{left:50%;right:auto;transform:translateX(-50%);width:min(100%,1440px)}
/* the words sit in front of the cards, so a card drifting inwards never eats the headline */
.hero-centre{z-index:5}
.hero-centre h1{font-size:clamp(2.5rem,6vw,3.5rem);margin:.5rem 0 1rem}
.hero-centre .lede{margin-bottom:1.5rem}
.today-line{margin-top:2rem}
@media (max-width:900px){.scatter{width:100%}}

/* ---- the story: one thing said, one thing shown ---- */
.step p{max-width:29rem}
.demo{margin-top:1.25rem;padding-top:1rem}
/* the ring that marks where the eye went, on the deck at the left and on the small card on phones */
.eye{position:absolute;width:23%;aspect-ratio:1;border-radius:50%;transform:translate(-50%,-50%) scale(.7);opacity:0;pointer-events:none;
  border:2px solid rgba(156,78,61,.95);
  background:radial-gradient(circle,rgba(255,255,255,.22) 0 55%,transparent 72%);
  box-shadow:0 0 0 2.5px rgba(242,234,219,.9),0 0 0 4.5px rgba(156,78,61,.35),0 0 26px 8px rgba(242,234,219,.55);
  transition:left .85s cubic-bezier(.2,.7,.2,1),top .85s cubic-bezier(.2,.7,.2,1),opacity .4s ease,transform .5s cubic-bezier(.2,.7,.2,1)}
.eye.on{opacity:1;transform:translate(-50%,-50%) scale(1);animation:eyePulse 2.8s ease-in-out infinite .6s}
@keyframes eyePulse{0%,100%{box-shadow:0 0 0 2.5px rgba(242,234,219,.9),0 0 0 4.5px rgba(156,78,61,.35),0 0 26px 8px rgba(242,234,219,.55)}
  50%{box-shadow:0 0 0 2.5px rgba(242,234,219,.9),0 0 0 9px rgba(156,78,61,.14),0 0 30px 10px rgba(242,234,219,.4)}}
@media (prefers-reduced-motion: reduce){.eye.on{animation:none}}
.demo-look .demo-chips{margin-bottom:.25rem}
.demo-open{min-height:2.7em}
@media (max-width:900px){.demo-look .demo-open{grid-column:1/-1;margin-top:1.5rem}.demo-look .demo-card{margin-bottom:1.5rem}}

/* step three, as an addition that resolves */
.synth{display:grid;gap:0;margin-top:.25rem}
.srow{display:grid;grid-template-columns:1.6rem minmax(0,1fr);gap:0 1rem;align-items:start;padding:.75rem 0;border-bottom:1px solid var(--rule)}
.srow .op{font-family:"IBM Plex Mono",monospace;font-size:1.0625rem;color:var(--ink-3);line-height:1.6;text-align:center}
.srow .label{display:block;font-size:.75rem;letter-spacing:.14em;margin-bottom:.125rem}
.srow b{display:block;font-weight:400;font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;line-height:1.35;color:var(--ink)}
.srow.gold b{color:var(--sun)}
.srow.sout{border-bottom:none;border-top:1px solid var(--ink);padding-top:1rem;margin-top:.25rem}
.srow.sout .op{color:var(--ink)}
.srow.sout p{margin:0;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.5;color:var(--ink)}
.demo-sky .hint{display:block;margin-top:.75rem}
#synthEye,#synthOut{transition:opacity .22s ease}

/* the way in, where the story ends */

/* ---- the lift: a card held up, not a form to fill in ---- */
.lift-inner{align-items:center;max-width:880px;grid-template-columns:minmax(0,330px) minmax(0,430px);gap:clamp(1.5rem,4vw,3.4rem)}
.lift-panel{padding-top:0;max-width:30rem}
.lift-name{display:block;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin-bottom:.5rem}
.lift-panel h2{font-size:clamp(1.625rem,3vw,2rem);line-height:1.1;margin:0}
.lift-panel .q{font-size:1.0625rem;font-style:normal;color:var(--ink-3);margin:.5rem 0 1.25rem;max-width:24rem;line-height:1.5}
.lift-panel .chips{gap:.5rem}
.lift-panel .free{margin-top:1rem;display:flex;gap:.5rem;align-items:stretch}
.lift-panel .free.hidden{display:none}
.lift-panel .free input{flex:1;min-width:0;font-size:1.0625rem;padding:.5rem .75rem;border:1px solid var(--ink-3);background:transparent}
.lift-panel .free .mic{flex:none;width:2.6rem;height:auto;align-self:stretch;border-radius:3px}
.lift-panel .free .btn{flex:none;padding:.5rem 1rem}
.lift-panel .voice{margin-top:.75rem}
.lift-panel .voice.hidden{display:none}
.lift-panel .skip{margin-top:1.5rem;display:flex;gap:1.5rem}
.lift-panel .skip button{font-size:.75rem;letter-spacing:.14em;color:var(--ink-3)}
/* the name is already at the top of the panel, so the strip carries only the gold line and the fold */
.lift .strip7{margin-top:1.5rem;padding-top:1rem}
.lift .strip7:not(.match){margin-top:1rem;padding-top:0;border-top:none}
.lift .strip7 .l1{display:none}
.lift .strip7:not(.match) .sky-line{display:none}
@media (max-width:760px){.lift-inner{grid-template-columns:1fr;max-width:430px;align-items:start}.lift-panel{max-width:none}}

/* the flyer that turns over on the way up: one gesture from cloth to hand */
.flyer.flip{perspective:1100px;background:none;box-shadow:none;border-radius:0}
.flyer.flip .ff{position:absolute;inset:0;border-radius:6px;overflow:hidden;backface-visibility:hidden;transition:transform .72s cubic-bezier(.3,.7,.2,1);box-shadow:var(--shadow);background:var(--card-face)}
.flyer.flip .ff.front{transform:rotateY(180deg)}
.flyer.flip.over .ff.back{transform:rotateY(180deg)}
.flyer.flip.over .ff.front{transform:rotateY(360deg)}
.flyer.flip img{width:100%;height:100%;object-fit:cover;display:block}

/* ---- the reading: the card is named before it is read ---- */
.pos-block{padding:1.5rem 0;border-top:1px solid var(--rule)}
.pos-block:first-child{border-top:none;padding-top:.25rem}
.pos-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem 1rem;margin-bottom:.5rem}
.pos-head .pos-label{flex:none;font-size:.75rem;letter-spacing:.14em}
.pos-card{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:1.1875rem;line-height:1.1;color:var(--ink)}
.pos-sky{flex-basis:100%;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.02em;color:var(--sun);margin-top:.25rem}
.pos-sky .bdot{vertical-align:-.3em;margin-right:.25rem}
.pos-block.lit{box-shadow:inset 2px 0 0 var(--sun);padding-left:1rem}
.pos-obs{margin:0 0 .5rem;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.35;color:var(--ink);max-width:36rem}
.pos-read{margin:0;font-size:1.0625rem;line-height:1.5;color:var(--ink-2);max-width:36rem}
.pos-block.thread .pos-read{color:var(--ink-3)}
.reading-close{margin-top:1.75rem;padding-top:1.25rem;border-top:1px solid var(--ink)}
.hint.prov{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--rule);max-width:36rem;line-height:1.6}

/* the cloth stays beside the reading instead of leaving a column of nothing */
@media (min-width:901px){.reveal .left{position:sticky;top:5rem;align-self:start}}


/* the promise in Cormorant, sized for it */
.hero-centre h1{font-size:clamp(2.5rem,6vw,3.5rem);line-height:1}

/* =========================================================
   v9: the audit fixes
   Contrast, size floors, the mark at small size, the mobile table order, a mobile menu,
   tap targets, the gold in daylight, and the deck column on phones.
   ========================================================= */

/* ---- colour: the gold that carries the product's one checkable sentence was the least legible
   thing on the page in daylight (2.5:1). Text gold is now a separate token from glyph gold. ---- */
:root{--sun-text:#8a5f0e;--ink-3:#6f6757}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]){--sun-text:#e3a72f;--ink-3:#8b8373}}
:root[data-theme="dark"]{--sun-text:#e3a72f;--ink-3:#8b8373}
.sky-line.match,.pos-sky,.srow.gold b,.ci em.gold,.pos-read .gold,.gold,.deck.on .dk.top.sky.up + .deck-cap,.sout .gold,.sky-fan .cap b,.cslot.skypos .cap,.cslot.skypos .num,.skytag,.strip.match .l2{color:var(--sun-text)}
.srow.gold .bdot,.pos-sky .bdot,.sky-line .bdot{color:var(--sun)}

/* ---- size floors: nothing that carries information sits under 11px ---- */
.kicker{font-size:.75rem}
.today-line{font-size:.75rem;letter-spacing:.14em}
.today-line .bdot{width:1.15rem;height:1.15rem;font-size:.75rem}
.deck-cap{font-size:.75rem}
.srow .label,.pos-head .pos-label,.lift-name,.demo-spread .fact,.demo-cardname{font-size:.75rem}
.lift-context .fact{font-size:.75rem}
.spread .count{font-size:.75rem}
.ci .ci-num{font-size:.75rem}
.sky-line.match{font-size:.875rem}
.pos-sky{font-size:.75rem}
.theme-btn{font-size:.75rem}

/* ---- tap targets: the quiet links get a real hit area without looking bigger ---- */
.linkish,.skip button,.lift-panel .skip button,.fold summary{padding:.5rem 0;margin:-.5rem 0}
.under-wheel .linkish{padding:.5rem .25rem;margin:-.5rem 0}
nav a{padding:.5rem 0;margin:-.5rem 0}

/* ---- the "Or draw one card" line lost its space between the word and the link ---- */
.or-line .linkish{margin-left:.35em}

/* ---- the mark: at header size the ecliptic vanished, so it read as a card icon with a dot ---- */
.wordmark svg line{opacity:.85;stroke-width:2.2}
.foot-mark svg line{opacity:.7;stroke-width:1.2}

/* ---- the question box: an empty question shakes the box instead of doing nothing ---- */
@keyframes nudge{0%,100%{transform:none}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}
.qbox.nudge{animation:nudge .32s ease}

/* ---- the table: the planet legend was apparatus; the seal line and the cut stay, small ---- */
.stage-wheel .sky-legend{display:none}

/* ---- phones: the wheel is the thing you act on, so it comes first while dealing ---- */
@media (max-width:900px){
  .stage.dealing{flex-direction:column-reverse}
  .stage.dealing .stage-wheel{margin-bottom:.375rem}
  .stage-wheel .wheel-wrap{width:min(100%,400px)}
}

/* ---- phones: the deck column was three hundred pixels of nothing above the story ---- */
@media (max-width:900px){
  .scatter .sc-mid{display:none}
  .scatter .sc{width:clamp(100px,27vw,136px)}
  .scatter .sc-l{margin-left:-3vw}.scatter .sc-r{margin-left:-8vw}
  /* two cards peek in at the top corners, two at the bottom; none of them reach the words */
  .scatter .sc:nth-child(1),.scatter .sc:nth-child(4){top:-13%!important}
  .scatter .sc:nth-child(3),.scatter .sc:nth-child(6){top:auto!important;bottom:-9%}
  .hero7{padding-bottom:9.5rem}
  .hero-centre .lede{background:color-mix(in srgb,var(--paper) 78%,transparent);border-radius:6px;padding:.375rem .5rem;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}
  .today-line{background:color-mix(in srgb,var(--paper) 78%,transparent);border-radius:6px;padding:.375rem .5rem;display:inline-block}
}

/* ---- phones: a menu, since the nav links were simply gone ---- */
.menu-btn{display:none}
.menu-list{display:contents}
@media (max-width:720px){
  .menu-btn{display:inline-block}
  nav{position:relative}
  nav .menu-list{display:none}
  nav.open .menu-list{display:flex;flex-direction:column;gap:.25rem;position:absolute;right:0;top:calc(100% + .7rem);min-width:12rem;padding:.5rem 1rem;background:var(--paper);border:1px solid var(--rule);border-radius:6px;box-shadow:0 14px 34px rgba(26,20,22,.16);z-index:30}
  nav.open .menu-list a{display:block;padding:.5rem 0;margin:0;font-size:.75rem;border-top:1px solid var(--rule)}
  nav.open .menu-list a:first-child{border-top:none}
}

/* ---- the learn page: the decan table scrolls inside its own box on phones instead of being cut off ---- */
.table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
.table-scroll table{min-width:560px}

/* ---- the birth card page: the result is a card, so the card is shown ---- */
.birth-card-img{width:96px;aspect-ratio:480/822;border-radius:6px;box-shadow:var(--shadow);object-fit:cover;display:block;margin:.25rem 0 .75rem}

/* ---- the reading: the sky position is called what it is ---- */
.pos-card.sky-pos{color:var(--sun-text)}

.wheel-hint{display:none}
@media (max-width:900px){
  .stage.dealing .wheel-hint{display:block;margin:0 0 .75rem;max-width:32rem}
  .stage.dealing .stage-hints .table-hint{display:none}
}

/* ---- one press from the question to the cards: the spread is named on the table, and can be changed there ---- */
.stage-why{margin:.5rem 0 0;font-size:.9375rem;color:var(--ink-2);max-width:40rem}
.stage-why b{font-weight:500;color:var(--ink)}
.stage-why .linkish{margin-left:.5em}
.picker{margin:1rem 0 .375rem;padding:1rem 1rem 1rem;border:1px solid var(--rule);border-radius:6px;background:var(--paper);box-shadow:var(--shadow);max-width:60rem}
.picker.hidden{display:none}
.picker .label{display:block;margin-bottom:.5rem}
.picks{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:.5rem}
.pick{text-align:left;background:transparent;border:1px solid var(--rule);border-radius:3px;padding:.5rem .75rem;cursor:pointer;color:var(--ink);font-family:inherit;display:grid;gap:.125rem}
.pick:hover{border-color:var(--brick)}
.pick.on{border-color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}
.pick b{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:1.0625rem;line-height:1.1}
.pick span{font-size:.875rem;color:var(--ink-2);line-height:1.35}
.pick i{font-style:normal;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);margin-top:.125rem}
.q-result{display:none}

/* ---- the wheel's centre steps back while dealing, so the ring is the only card-like thing to tap ---- */
.stage.dealing .sky-fan{opacity:.36;transition:opacity .4s ease;pointer-events:none;filter:saturate(.7)}

/* ---- the pages get their pictures ---- */
/* why this one: the demonstrations at the right of the two claims */
.feat-block.has-demo{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:clamp(1.6rem,4vw,3.6rem);align-items:start}
.feat-demo{padding:1rem 1.25rem 1.25rem;border:1px solid var(--rule);border-radius:6px;background:var(--paper-2)}
.feat-demo > .label{display:block;margin-bottom:.375rem}
.feat-demo .demo{margin-top:0;padding-top:.5rem;border-top:none}
.demo-look.with-card{display:grid;grid-template-columns:132px minmax(0,1fr);gap:1.25rem;align-items:start}
.demo-look.with-card .demo-card{display:block;margin-bottom:1.5rem}
.demo-look.with-card .demo-open{font-size:1.0625rem}
.feat-demo .synth{margin-top:.25rem}
.feat-demo .srow.sout p{font-size:1.0625rem}
@media (max-width:900px){.feat-block.has-demo{grid-template-columns:1fr}.demo-look .demo-side{display:contents}}
@media (max-width:600px){.demo-look.with-card{grid-template-columns:104px minmax(0,1fr)}}

/* learn: the four suits, fanned */
.suit-fan{display:flex;justify-content:center;align-items:flex-end;gap:0;margin:1.25rem 0 1.75rem;padding:1rem 0 .375rem}
.suit-fan figure{margin:0 -1rem;width:clamp(96px,14vw,132px);transform:rotate(var(--r,0deg));transform-origin:50% 120%;text-align:center}
.suit-fan img{display:block;width:100%;aspect-ratio:480/822;object-fit:cover;border-radius:6px;box-shadow:var(--shadow);background:var(--card-face)}
.suit-fan figcaption{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin-top:.5rem}
/* learn: the worked card with its three details pinned */
.look-figure{display:grid;grid-template-columns:200px minmax(0,1fr);gap:1.5rem;align-items:center;margin:1rem 0 1.5rem;max-width:44rem}
.lf-card{position:relative;border-radius:6px;box-shadow:var(--shadow);background:var(--card-face)}
.lf-card img{display:block;width:100%;aspect-ratio:480/822;object-fit:cover;border-radius:6px}
.lf-pin{position:absolute;width:1.5rem;height:1.5rem;transform:translate(-50%,-50%);display:grid;place-items:center;border-radius:50%;background:var(--brick);color:#fff;font-family:"IBM Plex Mono",monospace;font-size:.75rem;box-shadow:0 0 0 2px rgba(242,234,219,.9),0 4px 10px rgba(26,20,22,.3)}
.lf-list{list-style:none;margin:0;padding:0;counter-reset:lf}
.lf-list li{display:grid;grid-template-columns:1.5rem minmax(0,1fr);gap:.25rem .75rem;padding:.5rem 0;border-top:1px solid var(--rule);counter-increment:lf}
.lf-list li::before{content:counter(lf);width:1.5rem;height:1.5rem;display:grid;place-items:center;border-radius:50%;border:1px solid var(--brick);color:var(--brick);font-family:"IBM Plex Mono",monospace;font-size:.75rem;grid-row:1/3}
.lf-list li b{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:1.0625rem}
.lf-list li span{grid-column:2;color:var(--ink-2);font-size:.9375rem;line-height:1.35}
@media (max-width:600px){.look-figure{grid-template-columns:132px minmax(0,1fr);gap:1rem}}
/* about: her lettering and her monogram */
.about-figure{display:grid;grid-template-columns:minmax(0,1fr) 190px;gap:1.5rem;align-items:end;margin:1.5rem 0 2rem;max-width:52rem}
.about-figure figure{margin:0}
.about-figure img{display:block;width:100%;border-radius:3px;box-shadow:var(--shadow)}
.about-figure figcaption{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin-top:.5rem}
@media (max-width:600px){.about-figure{grid-template-columns:1fr}}

/* ---- the hero drift: composited, no transition, and the entrance no longer shares a transform with it ---- */
.scatter .sc-in{transition:none;will-change:transform;transform:none;backface-visibility:hidden}
@keyframes scIn{from{opacity:0;transform:translate3d(0,60px,0)}to{opacity:1}}

/* ---- the home page explains less: one moment beside the deck, then your turn ---- */
.moment{padding:0 0 2.5rem;max-width:36rem}
.moment-title{font-size:clamp(2rem,4vw,2.5rem);line-height:1;margin:0 0 .5rem;font-family:"Cormorant Garamond",Georgia,serif;font-variation-settings:normal;font-weight:400;letter-spacing:0}
.moment-lede{margin:0;color:var(--ink-2);font-size:1.0625rem;max-width:30rem}
.moment .demo{margin-top:1.25rem;padding-top:1.25rem;border-top:1px solid var(--rule)}
.moment .demo-open{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.35;min-height:0}
.moment-sky{margin:1rem 0 0;font-family:"IBM Plex Mono",monospace;font-size:.8125rem;letter-spacing:.02em;line-height:1.6;color:var(--sun-text);max-width:32rem}
.moment-sky .bdot{vertical-align:-.3em;margin-right:.25rem;color:var(--sun)}
.moment-sky .hint{display:block;color:var(--ink-3);margin-top:.375rem;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase}
@media (max-width:900px){.moment{padding-bottom:1.75rem}}

/* ---- the ribbon: seventy-eight cards overlapping, the one under the hand sliding out ---- */
.wheel .cardg:hover .cardback,.wheel .cardg:hover .cardback-inner{transform:none}
.wheel .cardbody{transition:transform .18s ease-out}
.wheel .cardg.raised .cardback{stroke:var(--brick);stroke-width:1.4}
.wheel .cardg.taken{opacity:0;pointer-events:none}
/* in a ribbon what you see of each card is its edge, so the edge is paper, the way a real back has a white border */
.wheel .cardback-lozenge{display:none}
.wheel .cardback{stroke:var(--paper);stroke-width:3}
.wheel .cardback-inner{stroke:var(--paper);opacity:.45;stroke-width:1}
.wheel .cardg.raised .cardback{stroke:var(--brick);stroke-width:2.4}

/* =========================================================
   v11: the table on the home page; the pages use the width they have
   ========================================================= */
.wrap{max-width:1280px}
#stage .wrap{max-width:1460px}
.stage-wheel .wheel-wrap{width:min(100%,600px)}
.steps{max-width:34rem}
/* the stage */
.wcard{position:relative;width:100%;aspect-ratio:480/822;transform-style:preserve-3d;opacity:0;will-change:transform;
  transform:translate(var(--dx,0px),var(--dy,0px)) scale(var(--ds,1)) rotate(-7deg);
  transition:transform .85s cubic-bezier(.2,.7,.2,1) calc(var(--i)*.18s),opacity .3s ease calc(var(--i)*.18s)}
/* the deck sits on the cloth, bottom left, where a dealer keeps it */
/* the caption, one beat at a time */
@media (max-width:900px){
}

/* one frame on the table, the cloth's own */
.cloth::before{display:none}

/* ---- the memory, on this device ---- */
.gate{grid-template-columns:1fr;gap:.5rem}
.gate-ask{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:1.25rem 2rem;align-items:start}
.gate-ask>div:first-child h3{margin-top:0}
@media (max-width:720px){.gate-ask{grid-template-columns:1fr}}
.gate .gate-note{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);margin-top:.5rem}
.gate form{display:flex;flex-direction:column;align-items:flex-start;gap:.75rem}
.gate-dob{display:grid;gap:.25rem}
.gate-dob .label{font-size:.75rem}
.gate-dob .hint{font-size:.75rem}
.gate input[type=date]{min-width:11rem}
.gate-done h3{margin:.25rem 0 .25rem}
.gate-done a{color:var(--brick)}
#followup{border-top:1px solid var(--rule);background:var(--paper-2)}
#followup .wrap{padding-top:2rem;padding-bottom:2rem}
.fu h3.display{font-size:clamp(1.625rem,3vw,2rem);margin:.375rem 0 1rem;max-width:44rem}
.fu-answers{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:.5rem}
.kept-empty{color:var(--ink-2);font-size:1.0625rem}
.kept-item{border-top:1px solid var(--rule)}
.kept-item:last-child{border-bottom:1px solid var(--rule)}
.kept-head{display:grid;gap:.25rem;width:100%;text-align:left;background:none;border:none;padding:1rem 0;cursor:pointer;color:var(--ink);font-family:inherit}
.kept-head b{font-family:"Fraunces",Georgia,serif;font-variation-settings:normal;font-weight:400;font-size:1.625rem;line-height:1.1}
.kept-cards{font-size:.9375rem;color:var(--ink-2)}
.kept-fu{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--verdigris);margin-top:.25rem}
.kept-fu.muted{color:var(--ink-3)}
.kept-body{display:none;padding:0 0 1.5rem}
.kept-item.open .kept-body{display:block}
.kept-body .reading{max-width:40rem}
.kept-actions{margin:1rem 0 0}
.legal .prose{max-width:40rem}
.legal .prose p{color:var(--ink-2)}
.legal .prose b{color:var(--ink);font-weight:500}
.pos-block.birth .pos-label{color:var(--verdigris)}

/* once the wheel has gone the cloth stays under its header rather than drifting to the middle */
.stage.turning .stage-table .cloth,.stage.turning .stage-hints{margin-left:0}
.stage.turning .stage-table .cloth{width:min(100%,calc(62vh * var(--aw,16) / var(--ah,11)),920px)}

/* ---- the sky, in the colour of the body that is speaking ---- */
:root{--b-sun:#c98a1a;--b-moon:#6f8fb5;--b-mercury:#b08a2a;--b-venus:#3f8f5f;--b-mars:#b83a2a;--b-jupiter:#6a4fa0;--b-saturn:#3c4a80}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]){--b-sun:#e3a72f;--b-moon:#a9c0dc;--b-mercury:#d6b04a;--b-venus:#6fb98a;--b-mars:#d9614f;--b-jupiter:#a48ad6;--b-saturn:#7d8fc4}}
:root[data-theme="dark"]{--b-sun:#e3a72f;--b-moon:#a9c0dc;--b-mercury:#d6b04a;--b-venus:#6fb98a;--b-mars:#d9614f;--b-jupiter:#a48ad6;--b-saturn:#7d8fc4}
.bdot-natal{color:var(--verdigris)}
.cslot.sky.turned .card .front,.cslot.sky.done .card .front{box-shadow:0 0 0 2px var(--al,var(--sun)),0 0 18px color-mix(in srgb,var(--al,var(--sun)) 45%,transparent)}
.cslot .skymark{border-color:var(--al,var(--sun))}
.cslot .skymark i{color:var(--al,var(--sun))}
.big-card.sky{box-shadow:0 0 0 2px var(--al,var(--sun)),0 0 28px color-mix(in srgb,var(--al,var(--sun)) 40%,transparent),var(--shadow)}
.lift-align{display:grid;gap:.25rem;margin:-.125rem 0 .75rem}
.lift-align:empty{display:none}
.align{display:block;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.02em;line-height:1.5;color:var(--al,var(--sun-text))}
.align .bdot{vertical-align:-.3em;margin-right:.25rem;color:var(--al,var(--sun))}
.pos-block.lit{box-shadow:inset 2px 0 0 var(--al,var(--sun))}
.pos-sky{display:grid;gap:.25rem;color:inherit}
.pos-sky .align{font-size:.75rem}
:root[data-theme="light"] .align,:root:not([data-theme="dark"]) .align{color:color-mix(in srgb,var(--al,var(--sun-text)) 78%,var(--ink))}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .align{color:var(--al,var(--sun))}}
:root[data-theme="dark"] .align{color:var(--al,var(--sun))}
/* the jumper: a card that slipped out in the cut, beside the wheel */
.jumper{display:flex;gap:1rem;align-items:center;margin:1rem auto 0;max-width:600px;padding:.75rem 1rem;border:1px solid var(--rule);border-radius:6px;background:var(--paper-2);animation:skyIn .5s ease both}
.jumper img{width:44px;aspect-ratio:480/822;object-fit:cover;border-radius:3px;box-shadow:0 2px 6px rgba(26,20,22,.3)}
.jumper b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:1.0625rem}
.jumper span{font-size:.875rem;color:var(--ink-2)}
.jumper.hidden{display:none}
/* ---- the share image ---- */
.share-panel{margin-top:1.5rem;padding:1.25rem 1.25rem;border:1px solid var(--rule);border-radius:6px;background:var(--paper-2)}
.share-panel.hidden{display:none}
.share-panel .label{display:block;margin-bottom:.75rem}
.share-row{display:grid;grid-template-columns:200px minmax(0,1fr);gap:1.5rem;align-items:start}
.share-row img{width:100%;border-radius:6px;box-shadow:var(--shadow)}
.share-side{display:flex;flex-direction:column;align-items:flex-start;gap:.75rem}
.share-side p{margin:0;color:var(--ink-2)}
@media (max-width:600px){.share-row{grid-template-columns:1fr}.share-row img{max-width:220px}}
/* the cloth at night, warmer than the page so the table reads as a table */
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .cloth{background:#221a16}}
:root[data-theme="dark"] .cloth{background:#221a16}
/* ---- routes: the spread intro under the table, the decans index, one decan ---- */
.spread{text-decoration:none;color:inherit}
.route-intro{padding:2.6rem clamp(1rem,4vw,3rem) 1rem}
.route-intro .wrap{max-width:1460px}
.route-intro .intro{max-width:44rem}
.route-intro h1.page-title{font-size:clamp(2rem,4vw,2.5rem);margin:0 0 1rem}
.route-intro .answer{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.1875rem;line-height:1.5;margin:0 0 1.5rem;color:var(--ink)}
.route-intro h2{font-size:1.3125rem;margin:1.75rem 0 .5rem}
.route-intro p{color:var(--ink-2);line-height:1.6;margin:0 0 1rem}
.route-intro p a{color:inherit}
.route-positions{margin:0;padding:0 0 0 1.5rem;color:var(--ink-2);line-height:1.6;columns:2;column-gap:2rem}
.route-positions li{break-inside:avoid}
.route-positions b{color:var(--ink);font-weight:500}
.route-intro .label{display:block;margin-bottom:.5rem}
.decan-now{padding:.75rem 1rem;border-left:2px solid var(--sun);background:var(--paper-2);border-radius:0 6px 6px 0;color:var(--ink)!important}
.decan-now b{color:var(--sun-text);font-weight:500}
/* the grid gap applied to every row as well as the column, so each paragraph sat 2.4rem from
   the next and the page read as a stack of loose slabs. The column keeps its gap; the rows go
   back to the paragraph margins the rest of the site uses. */
.decan-route{display:grid;grid-template-columns:minmax(0,1fr) 220px;column-gap:2.5rem;row-gap:0;align-items:start;padding-top:4rem}
/* the card spanned six text rows, so the grid stretched those rows to the card's height and
   the first four paragraphs sat 40px apart while the last four sat 14px apart. The text is one
   grid item per column run now, and the card sits in its own column with nothing to stretch. */
.decan-route .decan-card{grid-column:2;grid-row:1/span 3;position:sticky;top:5rem;align-self:start}
.decan-route .decan-text{grid-column:1;min-width:0}
.decan-route .decan-card img{width:100%;border-radius:10px;box-shadow:var(--shadow)}
.decan-route>*{grid-column:1}
.decan-nav{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--rule);font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1.8}
.decan-nav a{text-decoration:none;color:var(--ink-2)}
.decan-nav a:hover{color:var(--brick)}
.decan-nav b{font-weight:500;color:var(--ink)}
.decan-nav .sep{margin:0 .35em;color:var(--ink-3)}
.decans{padding:4rem 0 3rem}
.decans .page-title{max-width:34rem}
.decan-list{list-style:none;margin:2rem 0 1rem;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:.5rem 1.5rem}
.decan-list li a{display:grid;gap:.125rem;padding:.75rem 1rem;border:1px solid var(--rule);border-radius:6px;background:var(--paper);text-decoration:none;color:inherit;transition:border-color .15s}
.decan-list li a:hover{border-color:var(--brick)}
.decan-list li.now a{border-color:var(--sun);box-shadow:inset 2px 0 0 var(--sun)}
.decan-list b{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:1.0625rem}
.decan-list span{font-size:.875rem;color:var(--ink-2)}
.decan-list .fact{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.02em;color:var(--ink-3)}
.decan-list .tonight{font-style:normal;color:var(--sun-text)}
.decans .hint{display:block;margin-top:1.25rem}
@media (max-width:760px){.decan-route{grid-template-columns:1fr;column-gap:0;row-gap:0;padding-top:2.5rem}.decan-route .decan-text{grid-column:1}.decan-route .decan-card{grid-column:1;grid-row:auto;position:static;max-width:200px;margin:.375rem 0 1.5rem}.route-positions{columns:1}}
/* ---- delivery: the email field in the gate, the fuller reading, the account's readings ---- */
.gate-email.hidden{display:none}
.gate input[type=email]{width:100%;min-width:0}
.gate-email{width:100%}
.gate-email .hint{font-size:.75rem;max-width:26rem;line-height:1.5}
.gate .gate-err{color:var(--brick);font-size:.875rem;margin:.25rem 0 0}
.fuller{margin-top:1.5rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.fuller .label{display:block;margin-bottom:.75rem;color:var(--sun-text)}
.fuller p{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem;line-height:1.6;margin:0 0 1em;color:var(--ink)}
.fuller.hidden{display:none}
.fuller .fuller-note{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3)}
.kept-item .fuller{margin-top:1.25rem}
.kept-from{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--verdigris);margin-left:.6em}
.kept-account{margin:0 0 1.5rem;padding:.75rem 1rem;border:1px solid var(--rule);border-radius:6px;background:var(--paper-2);font-size:.9375rem;color:var(--ink-2)}
.kept-account b{color:var(--ink);font-weight:500}
.kept-month{margin:0 0 1.5rem;padding:1rem 1rem;border-left:2px solid var(--verdigris);background:var(--paper-2);border-radius:0 6px 6px 0;font-size:.9375rem;line-height:1.5;color:var(--ink-2)}
.kept-month b{color:var(--ink);font-weight:500}
/* ---- the table on the home page: idle, then laid ---- */
/* the table sits under the hero and paints over it, so the scattered cards are cut at the line;
   in flight they are raised above it, because that is the one time they belong on the table */
#stage{border-top:1px solid var(--rule);position:relative;z-index:1;background:var(--paper)}
.scatter .sc.flying{z-index:30}
.stage-head{position:relative}
.head-idle .stage-why{max-width:34rem}
.head-idle,.head-live{display:none}
#stage.idle-on .head-idle,#stage:not(.idle-on) .head-live{display:block}
.stage-table{position:relative}
/* in idle the one line belongs under the ring, which is the thing to tap */
.stage.idle .stage-hints{display:none}
.stage.idle .wheel-hint{display:block;margin:0 0 1rem;text-align:center;max-width:none}
.stage.idle .stage-table .cloth{--ah:8;background:var(--paper-2)}
.idle-slot{width:19%;border-color:var(--rule)}
.idle-slot .cap{color:var(--ink-3)}
@media (max-width:820px){.stage.idle .stage-table .cloth{--ah:9}}
/* an /ask address opens on the table: the hero and the follow-up step aside */
.ask-route #hero,.ask-route #followup{display:none}
.ask-route #stage{border-top:none;padding-top:clamp(1.4rem,3vw,2.4rem)}

/* =========================================================
   v12: read it. The paper design was set light on purpose, but the secondary ink, the mono labels
   and the Cormorant display were all too faint on a bright screen. Everything below raises weight,
   size or contrast; nothing changes the palette itself.
   ========================================================= */
/* the olive grey carried every label, hint, caption and fact: 4.7:1 before, 6.2:1 now */
:root{--ink-3:#5c5446}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]){--ink-3:#a49a86}}
:root[data-theme="dark"]{--ink-3:#a49a86}
/* Cormorant is a light face by design; at 300 it disappeared. 400 for the big promise, 500 below it */
.hero-centre h1,.reading .echo,.stage-head .table-q,#lookTitle,.demo-q,.pos-obs,.beat-echo{font-weight:400}
.hero-centre h1{font-weight:400;letter-spacing:-.01em}
.stage-head .table-q,#lookTitle,.demo-q{font-weight:500}
.reading .echo{font-weight:500}
/* the mono voice: a size up, and the tracking loosened less, so the letters hold together */
.label{font-size:.75rem;letter-spacing:.1em;color:var(--ink-3)}
.hint{font-size:.75rem;letter-spacing:.06em}
.fact{letter-spacing:.06em}
.deck-cap,.cslot .cap{font-size:.75rem;letter-spacing:.1em}
.under-wheel.fact{font-size:.75rem}
/* the running text */
.stage-why{font-size:1.0625rem;line-height:1.5}
.head-idle .stage-why{color:var(--ink-2)}
.hero-centre .lede{color:var(--ink-2)}
/* the name of the thing */
.wordmark{font-variation-settings:"opsz" 72,"wght" 560,"SOFT" 30,"WONK" 1;color:var(--ink)}
.wordmark span{color:var(--ink)}
nav a{font-size:.75rem;letter-spacing:.14em;color:var(--ink-2)}
nav a:hover{color:var(--ink)}

/* =========================================================
   Setting the table. The cards come off the hero and stack into a deck at the centre of the ring;
   the cloth is laid with an empty place; then the deck fans out into the seventy-eight, one card
   after another, the way a dealer spreads a pack before it is cut. After that the ring is live.
   ========================================================= */
.wheel-wrap{position:relative}
.deck-wrap{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;opacity:0;transition:opacity .45s ease;z-index:3}
.deck-wrap.on{opacity:1}
.deck-wrap.gone{opacity:0;transition:opacity .28s ease}
.deck-wrap .deck{width:14%;margin:0}
/* the top of the stack is a back too: nothing turns off it here */
.deck-wrap .dk.top{background-color:var(--wheel-card);background-image:repeating-linear-gradient(45deg,var(--wheel-card-weave) 0 1.2px,transparent 1.2px 8px);border:1px solid var(--wheel-card-line)}
.deck-wrap .dk.top::after{content:"";position:absolute;inset:8%;border:1px solid var(--paper);border-radius:3px;opacity:.85}
.deck-wrap .dk.top::before{content:"";position:absolute;left:50%;top:50%;width:28%;aspect-ratio:12/18;background:var(--paper);opacity:.92;transform:translate(-50%,-50%) rotate(45deg);border-radius:3px}
/* the ring, collapsed into that stack. Each card carries its index, so they leave in order */
.wheel .cardg{transition:transform .66s cubic-bezier(.22,.68,.24,1),opacity .34s ease;transition-delay:calc(var(--k,0) * 7ms)}
.wheel.stacked .cardg{transform:translate(500px,500px) rotate(calc((var(--k,0) - 39) * .06deg)) scale(2.7);opacity:0}
.wheel.instant .cardg{transition:none}
.wheel.stacked{pointer-events:none}
/* the cloth is laid a beat before the deck is spread */
#stage.idle-on .cloth,#stage.idle-on .wheel-hint,#stage.idle-on .under-wheel,#stage.idle-on .sky-fan,#stage.idle-on .sky-legend{opacity:0;transition:opacity .55s ease}
#stage.idle-on.laying .cloth{opacity:1}
#stage.idle-on.laid .wheel-hint,#stage.idle-on.laid .under-wheel,#stage.idle-on.laid .sky-fan,#stage.idle-on.laid .sky-legend{opacity:1}
#stage.idle-on .idle-slot{opacity:0;transition:opacity .5s ease .35s}
#stage.idle-on.laying .idle-slot{opacity:1}

/* =========================================================
   v13: one table. The deck is spread on a single arc whose centre is above the frame, so it opens
   towards the reader; the cloth is laid under it, in the bowl. When the last card is dealt the fan
   is put aside and the cloth takes the whole table, which is what a reader does with the pack.
   ========================================================= */
#stage .wrap{max-width:1180px}
.stage{display:block;position:relative}
.tabletop{position:relative;display:grid;grid-template-rows:1fr auto;width:100%;background:var(--paper-2);border:1px solid var(--rule);border-radius:10px;overflow:hidden;transition:grid-template-rows .6s cubic-bezier(.2,.7,.2,1)}
.stage.turning .tabletop{grid-template-rows:0fr auto}
.fan-band{position:relative;min-height:0;overflow:hidden;transition:opacity .45s ease}
.stage.turning .fan-band{opacity:0}
.fan-band .fan{display:block;width:100%;height:auto}
.fan.dragging{cursor:grabbing}
.fan{cursor:pointer}
.fan.stacked{pointer-events:none}
/* the cloth is the lower half of the same table, so it carries no edge of its own */
.tabletop .cloth{aspect-ratio:var(--aw,16)/var(--ah,11);background:transparent;border:none;border-radius:0;width:min(100%,calc(44vh * var(--aw,16) / var(--ah,11)));margin:0 auto;padding:0;transition:width .6s cubic-bezier(.2,.7,.2,1)}
.stage.turning .tabletop .cloth{width:min(100%,calc(64vh * var(--aw,16) / var(--ah,11)),980px)}
.stage.idle .tabletop .cloth{--aw:16;--ah:3.4}
.tabletop .cloth .idle-slot{width:clamp(62px,9%,116px)}
.tabletop .whole-panel{position:absolute;left:50%;bottom:1.2rem;transform:translateX(-50%);z-index:6}
.stage-hints{display:flex;flex-wrap:wrap;gap:.375rem 1.5rem;align-items:baseline;margin:1rem auto 0;max-width:none;justify-content:center;text-align:center}
.under-wheel{text-align:center;margin:.5rem 0 0}
.jumper{margin-left:auto;margin-right:auto}
/* the deck falls into the middle of the arc; layoutFan places it from the same numbers */
.deck-wrap{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .45s ease;z-index:3}
.deck-wrap.on{opacity:1}
.deck-wrap.gone{opacity:0;transition:opacity .28s ease}
.deck-wrap .deck{position:absolute;transform:translate(-50%,-50%);width:9%;margin:0}
/* the fan, collapsed into that deck before it is spread */
/* Before the spread every card is in the deck, and none of them is anywhere else. */
.fan.stacked .cardg{transform:translate(0px,var(--fanR,1076px)) rotate(calc((var(--k,0) - 39) * .05deg)) scale(1.55);opacity:0}
.fan.instant .cardg{transition:none;animation:none}
/* A card is not thrown to its place: it is left behind by the hand, slides a little with the deck's
   drag, and settles. Short, per card, timed to the moment the deck passes over that spot. */
.fan.dealing .cardg{animation:dealIn 260ms cubic-bezier(.18,.72,.28,1) both;animation-delay:var(--d,0ms)}
@keyframes dealIn{
  0%{opacity:0;transform:rotate(calc(var(--a,0deg) - 2.6deg)) translate(0,calc(var(--fanR,1076px) + 15px)) scale(1.045)}
  22%{opacity:1}
  100%{opacity:1;transform:rotate(var(--a,0deg)) translate(0,var(--fanR,1076px)) scale(1)}
}
.deck-wrap .deck{transition:opacity .3s ease}
.deck-wrap.gone .deck{opacity:0}
/* the cut: the two halves part along the arc and close again */
.wheel .half{transform-origin:0px 0px}
.ring{transform-box:view-box}
.ring.cutting .halfA{transform:rotate(-3.4deg);transform-origin:0px 0px}
.ring.cutting .halfB{transform:rotate(3.4deg);transform-origin:0px 0px}
.half{transition:transform .26s cubic-bezier(.3,.7,.3,1)}
/* the zodiac, on the Learn page now */
.sky-figure{margin:1.5rem 0 2rem;display:flex;flex-direction:column;align-items:center;gap:1rem}
.skywheel{width:min(100%,460px);height:auto;display:block}
.skywheel .mid-card{fill:var(--sun-text);font-size:1.625rem;letter-spacing:2px}
.skywheel .mid-sub{fill:var(--ink-3);font-size:.8125rem;letter-spacing:2px}
.sky-figure .sky-legend{display:flex;flex-wrap:wrap;gap:.25rem 1rem;justify-content:center}
@media (max-width:760px){
  .stage.idle .tabletop .cloth{--aw:16;--ah:7}
  .tabletop .cloth{width:min(100%,calc(40vh * var(--aw,16) / var(--ah,11)))}
  .stage.turning .tabletop .cloth{width:min(100%,calc(58vh * var(--aw,16) / var(--ah,11)))}
}
/* at night the table is warmer than the page; the cloth inside it carries no colour of its own */
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .tabletop{background:#221a16}
  :root:not([data-theme="light"]) .tabletop .cloth{background:transparent}}
:root[data-theme="dark"] .tabletop{background:#221a16}
:root[data-theme="dark"] .tabletop .cloth{background:transparent}

/* ---- v20a: a spread you can aim at ---- */
/* one highlight, driven by which card the hand is actually nearest, not by which one the pointer
   happens to be over after the raise has reordered them */
.wheel .cardg:hover .cardback,.wheel .cardg:hover .cardback-inner{transform:none}
.wheel .cardg:hover .cardback{stroke-width:.9;stroke:var(--wheel-card-line)}
.wheel .cardg.near .cardback{stroke:var(--brick);stroke-width:1.8}
.wheel .cardbody{transition:transform .16s cubic-bezier(.2,.7,.2,1)}
/* the ruler at the top of the table: one hairline for each of the seventy-eight, the ones in front
   of you lit. It says how long the deck is and where in it you are looking, and it can be dragged. */
.fan-ruler{position:absolute;left:6%;right:6%;top:.55rem;height:16px;display:flex;align-items:center;justify-content:space-between;cursor:ew-resize;touch-action:none;z-index:4}
.fan-ruler i{display:block;width:1px;height:4px;background:var(--rule);transition:height .2s ease,background .2s ease}
.fan-ruler i.in{height:9px;background:var(--ink-3)}
.fan-ruler:hover i.in,.fan-ruler:focus-visible i.in{background:var(--brick)}
.fan-ruler:focus-visible{outline:none}
.fan-mark{display:none}
.fan-ruler.off{display:none}
.stage.turning .fan-ruler{display:none}
/* the cut, seen: the deck gathers, splits and closes before it is spread again */
.deck-wrap.cutting .deck{animation:cutDeck .48s cubic-bezier(.3,.7,.3,1)}
@keyframes cutDeck{0%{transform:translate(-50%,-50%)}40%{transform:translate(-50%,-50%) translateX(-22%) rotate(-5deg)}70%{transform:translate(-50%,-50%) translateX(14%) rotate(3deg)}100%{transform:translate(-50%,-50%)}}
/* the number on each card back. The deck is seventy-eight and the numbers are how you keep your
   place in it while you pan. Each one is turned back against the card's angle on the arc and against
   the pan, so it reads level wherever the card happens to be standing. */
.wheel .cardnum{fill:#f2eadb;opacity:.3;paint-order:stroke;stroke:rgba(18,14,13,.4);stroke-width:1.8px;stroke-linejoin:round;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.02em;
  transform-box:fill-box;transform-origin:50% 50%;
  transform:rotate(calc(-1 * (var(--rot,0deg) + var(--a,0deg))));
  transition:opacity .18s ease,fill .18s ease,font-size .18s ease}
/* the number you are on is the only one that needs to be read; the rest are a quiet ruler */
.wheel .cardg.near .cardnum{opacity:.95;fill:#f0b544;stroke:rgba(18,14,13,.6);stroke-width:2.4px;font-size:.75rem;font-weight:600}
.wheel .cardg.taken .cardnum{opacity:0}
/* the same count in words on the ruler, for the card currently under the hand */
.fan-count{position:absolute;top:.5rem;right:6%;transform:translateY(-1px);font-family:"IBM Plex Mono",monospace;
  font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);opacity:.55;pointer-events:none;z-index:5;transition:opacity .2s ease,color .2s ease}
.fan-count.aimed{opacity:1;color:var(--brass,#c98a1a)}
.stage.turning .fan-count{display:none}
/* and the reading's last word: one question to carry */
.reading-carry{margin-top:1.5rem;padding-top:1.25rem;border-top:1px solid var(--rule)}
.reading-carry p{font-family:"Fraunces",Georgia,serif;font-weight:500;font-size:1.3125rem;line-height:1.35;margin:.25rem 0 0;color:var(--ink)}
.day-block .pos-card{color:var(--sun-text)}

/* ---- the ask, on the table: no dialog anywhere in a reading ---- */
.ask-panel{margin:1rem auto 0;max-width:44rem;opacity:0;transform:translateY(10px);transition:opacity .4s ease,transform .4s cubic-bezier(.2,.7,.2,1)}
.ask-panel.shown{opacity:1;transform:none}
.ask-panel.hidden{display:none}
.ask-context{display:flex;flex-wrap:wrap;align-items:baseline;gap:.375rem 1rem;padding-bottom:.75rem;margin-bottom:1rem;border-bottom:1px solid var(--rule)}
.ask-context .fact{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.ask-context .fact:first-child{color:var(--ink-2);text-transform:none;letter-spacing:.02em;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;font-size:1.0625rem}
.ask-close{margin-left:auto;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;background:none;border:1px solid var(--ink-3);color:var(--ink-2);border-radius:999px;padding:.375rem .75rem;cursor:pointer}
.ask-close:hover{border-color:var(--brick);color:var(--brick)}
.ask-body h2{font-size:clamp(1.625rem,3vw,2rem);line-height:1.1;margin:0}
.ask-body .q{font-size:1.0625rem;color:var(--ink-3);margin:.5rem 0 1rem;max-width:32rem;line-height:1.5}
.ask-body .chips{margin-bottom:.25rem}
.ask-body .skip{margin-top:1rem;display:flex;gap:1.5rem}
.ask-body .strip7{margin-top:1.25rem}
/* the card that is being asked about comes forward; the rest of the table steps back */
.cloth.asking .cslot:not(.asking){opacity:.32;filter:saturate(.7)}
.cslot{transition:opacity .35s ease,transform .45s cubic-bezier(.2,.7,.2,1),filter .35s ease}
.cslot.asking{z-index:12;transform:translate(-50%,-50%) rotate(var(--r,0deg)) scale(var(--askscale,1.6))}
.cslot.asking .card{box-shadow:0 26px 60px rgba(26,20,22,.3)}
.cloth[data-n="1"] .cslot.asking,.stage:not(.big) .cslot.asking{--askscale:1.35}
.stage.big .cslot.asking{--askscale:2.1}
.cslot .dot{position:absolute;width:16%;aspect-ratio:1;border-radius:50%;transform:translate(-50%,-50%);border:1.5px solid var(--brick);background:rgba(156,78,61,.18);opacity:0;transition:opacity .2s ease;pointer-events:none;z-index:3}
.cslot .dot.on{opacity:1}

/* =========================================================
   v14 - the ask, framed. The step asks what you can see on a card, so the card and the question
   have to be on the screen at the same time. Before this the panel was scrolled to the bottom of
   the viewport and the card went off the top, which asked the question about a picture you could
   no longer look at, and left a screen of empty page underneath.
   Wide screens set the two side by side, the card in its own column at a size worth looking at.
   Short and narrow ones stack them and size the cloth by the height that is left.
   ========================================================= */
.stage.asking{align-items:center}
.stage.asking .fan-band{display:none}
.stage.asking .tabletop{padding:0}
.stage.asking .cloth{height:min(58vh,480px);width:auto;max-width:100%;aspect-ratio:var(--aw,16)/var(--ah,11);margin-inline:auto}
.stage.asking .ask-panel{margin-top:.5rem}

@media (min-width:900px){
  .stage.asking{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(20rem,30rem);
    align-items:center;gap:clamp(1.5rem,3vw,3rem);grid-template-areas:"table ask"}
  .stage.asking .tabletop{grid-area:table;margin:0}
  .stage.asking .ask-panel{grid-area:ask;margin:0;max-width:none}
  .stage.asking .stage-hints,.stage.asking .under-wheel,.stage.asking #jumper{grid-column:1/-1}
  .stage.asking .cloth{height:min(66vh,560px)}
  /* the card is the subject of the question, so in its own column it is worth looking at */
  .stage.asking .cslot.asking{--askscale:1.62}
  .stage.asking.big .cslot.asking{--askscale:1.2}
}
/* stacked, the cloth is sized so the card and the question both fit in the window without scrolling */
@media (max-width:899px){
  .stage.asking .cloth{height:min(33vh,260px)}
  .stage.asking .cslot.asking{--askscale:1.15}
  .stage.asking .ask-panel{margin-top:0}
  .stage.asking .ask-body h2{font-size:1.3125rem}
  .stage.asking .ask-body .q{margin:.375rem 0 .75rem;font-size:.9375rem}
  .stage.asking .ask-body .skip{margin-top:.75rem}
  .stage.asking .ask-body .strip7{margin-top:.75rem}
}
@media (max-height:720px) and (max-width:899px){
  .stage.asking .cloth{height:min(30vh,220px)}
  .stage.asking .cslot.asking{--askscale:1.08}
}
/* the ask panel, on its own, reads as a column rather than a wide band */
@media (min-width:900px){
  .ask-panel .ask-body .q{max-width:none}
  .ask-panel .chips{max-width:none}
}

/* the cut belongs before the spread, not under a reading of a card already drawn */
.stage.turning .under-wheel,.stage.asking .under-wheel,.stage.reading .under-wheel{display:none}
/* the proof of the seal is real and checkable and nobody wants it mid-reading: it has its own page */
.reading .proof{display:none}

/* ---- the birth spread: seven positions, one row each ---- */
.birth-spread{margin-top:2.5rem}
.bs-head .answer{max-width:44rem;margin:.5rem 0 1.5rem}
.bs-list{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.bs-row{display:grid;grid-template-columns:1.6rem minmax(9rem,1.1fr) 44px minmax(10rem,1.3fr) minmax(0,1fr);
  gap:1rem;align-items:center;padding:.75rem 0;border-bottom:1px solid var(--rule)}
.bs-row.lit{box-shadow:inset 3px 0 0 var(--al,var(--sun));padding-left:.75rem}
.bs-glyph{font-size:1.0625rem;text-align:center;opacity:.85}
.bs-role b,.bs-card b{display:block;font-family:"Fraunces",Georgia,serif;font-size:1.0625rem;font-weight:500;line-height:1.2}
.bs-role em,.bs-card em{display:block;font-style:normal;font-family:"IBM Plex Mono",monospace;font-size:.75rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);margin-top:.25rem}
.bs-img{width:44px;border-radius:3px;display:block;box-shadow:0 1px 6px rgba(26,20,22,.2)}
.bs-now{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--al,var(--sun))}
#birthForm #tob{margin-left:.5rem}
@media (max-width:760px){
  .bs-row{grid-template-columns:1.4rem 1fr 40px;grid-template-areas:"g r i" "n n n";row-gap:.375rem}
  .bs-glyph{grid-area:g} .bs-role{grid-area:r} .bs-img{grid-area:i} .bs-card{grid-column:2/4}
  .bs-now{grid-area:n}
}

/* =========================================================
   v15 - the table says what it is doing.
   The complaint: "it looks cool but hard to know what is what". Four things used to change in
   silence, one a second, with no overlap and no words: the heading swapped, the deck vanished, the
   card turned, the question arrived. This adds the line that narrates it, overlaps the mechanics so
   there is one pause instead of four, and puts that pause where it belongs, on looking at the card.
   ========================================================= */
.stage-step{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--brick);margin:.5rem 0 0;min-height:1.1em;opacity:1;transition:opacity .16s ease}
.stage-step.out{opacity:0}
.stage-step.empty{min-height:1.1em}
/* THE HEADING CROSSES RATHER THAN CUTS. "Take a card." became "Card of the day." on a display
   swap, so the subject of the page changed between one frame and the next. Both now sit in the same
   grid cell and fade past each other, and the box does not jump because the cell holds them both. */
.stage-head{display:grid;grid-template-columns:minmax(0,1fr)}
.head-idle,.head-live{grid-area:1/1;display:block;opacity:0;visibility:hidden;transform:translateY(5px);
  transition:opacity .38s ease,transform .38s cubic-bezier(.2,.7,.2,1),visibility 0s linear .38s}
#stage.idle-on .head-idle,#stage:not(.idle-on) .head-live{opacity:1;visibility:visible;transform:none;
  transition:opacity .38s ease .06s,transform .38s cubic-bezier(.2,.7,.2,1) .06s,visibility 0s}
.stage-head .picker{grid-area:2/1}

/* THE DECK WITHDRAWS. It used to be crushed: the row collapsed to 0fr while the band faded, so the
   fan was eaten from the bottom up. It now lifts away as one piece and the table takes the space. */
.fan-band{transition:opacity .42s ease,transform .5s cubic-bezier(.3,.7,.2,1)}
.stage.turning .fan-band{opacity:0;transform:translateY(-14px) scale(.985)}
.tabletop{transition:grid-template-rows .52s cubic-bezier(.3,.7,.2,1)}

/* THE CARD IS THE SUBJECT. On the ask step it was 30% of the cloth with 86px of dead cloth under it. */
@media (min-width:900px){
  .stage.asking .cslot.asking{--askscale:1.92}
  .stage.asking .cloth{height:min(70vh,600px)}
}
/* and the flip is quick, because the looking happens after it, not during */
.cslot.turned .card{animation-duration:.7s}
.cslot.turned .card .back,.cslot.turned .card .front{animation-duration:.7s}

/* =========================================================
   v16 - the card is the page, the reading is prose.
   The complaint, and it was right: "the card is barely visible", "so many subsections", "most of
   this astrology is not useful in a tarot reading", "to carry and later, what does that even mean".
   A one card reading was six labelled boxes around a small picture. It is now a large card, two or
   three paragraphs, one question, and a single fold for everything that is true but not wanted yet.
   ========================================================= */
.cloth-copy .cslot .card{--shadow:0 18px 44px rgba(26,20,22,.22)}
@media (min-width:900px){
  /* the picture is the point. It was 170px in a 750px box. */
  .stage.reading-on .cloth,.reveal .cloth-copy .cloth{height:auto}
  .reveal-grid{align-items:start}
  /* sticky moved to v18, where every spread is two columns and it is safe again. */
}
/* one card: no position label, the name sits alone above its own paragraph */
.pos-head.solo{margin-bottom:.5rem}
.pos-head.solo .pos-card{font-size:1.625rem}
/* the sky, when it is genuinely on this card, is the last sentence rather than a box */
.sky-inline{color:var(--sun-text,#8a5f0e)}
.pos-block.lit{box-shadow:none;border-left:2px solid var(--al,var(--sun));padding-left:1rem}
/* the question, unlabelled, set apart by weight rather than by a heading nobody understood */
.reading-carry{margin-top:1.75rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.reading-carry .pos-label{display:none}
.reading-carry p{font-family:"Fraunces",Georgia,serif;font-weight:500;font-size:1.625rem;
  line-height:1.35;margin:0;color:var(--ink)}
.reading-close{margin-top:1.5rem}
.reading-close .pos-label{display:none}
.reading-close p{color:var(--ink-2)}

/* ---- one fold for everything that is true and not wanted yet ---- */
.reading-facts{margin-top:2rem;border-top:1px solid var(--rule);padding-top:1rem}
.reading-facts summary{cursor:pointer;list-style:none;font-family:"IBM Plex Mono",monospace;font-size:.75rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);display:flex;align-items:center;gap:.5rem;
  /* the label is 15px of type. Pad it out so it is a thumb-sized strip, not a hairline. */
  min-height:44px;margin:-.5rem 0}
.reading-facts summary::-webkit-details-marker{display:none}
.reading-facts summary::before{content:"+";font-size:.875rem;line-height:1;color:var(--ink-3)}
.reading-facts[open] summary::before{content:"\2212"}
.reading-facts summary:hover{color:var(--brick)}
.rf-count{margin-left:auto;opacity:.55}
.rf-body{padding-top:1rem;animation:factsIn .3s ease}
@keyframes factsIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
.rf-item{margin-bottom:1rem}
.rf-item p{margin:.25rem 0 0;font-size:.9375rem;color:var(--ink-2);line-height:1.5}
.day-facts dl{margin:0}
.df-row{display:grid;grid-template-columns:minmax(7rem,10rem) 1fr;gap:.375rem 1rem;padding:.5rem 0;border-top:1px solid var(--rule)}
.df-row dt{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.df-row dd{margin:0;font-size:.9375rem;color:var(--ink-2);line-height:1.5}
.df-link{color:var(--brick);white-space:nowrap}
.day-facts .hint{margin-top:1rem}
@media (max-width:640px){ .df-row{grid-template-columns:1fr;gap:.125rem} }

/* ---- pointing at the picture, after the reading, never before ---- */
.refine-bar{margin-top:1.5rem;padding-top:1.25rem;border-top:1px solid var(--rule)}
.refine-bar.hidden{display:none}
.refine-q{font-family:"Fraunces",Georgia,serif;font-size:1.0625rem;margin:0}
.refine-h{font-size:.875rem;color:var(--ink-3);margin:.25rem 0 .75rem;max-width:34rem}
.refine-acts{display:flex;gap:1rem;align-items:center;flex-wrap:wrap}
.btn.ghost{background:none;border:1px solid var(--ink-3);color:var(--ink);border-radius:999px;padding:.5rem 1rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;cursor:pointer}
.btn.ghost:hover{border-color:var(--brick);color:var(--brick)}
.cslot.refinable{cursor:crosshair}
.cslot.refinable .dot{opacity:.55;animation:dotBreath 2.6s ease-in-out infinite}
.cslot.refinable:hover .dot{opacity:.9}
@keyframes dotBreath{0%,100%{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.14)}}

/* THE CARD, ACTUALLY VISIBLE. The reading was showing it at 24% of a cloth built for ten-card
   spreads, so a one-card reading put a 110px picture in a 400px box. In the reading the cloth stops
   being a table and becomes a frame around the card. */
.cloth-copy .cloth{background:none;border:0;box-shadow:none}
.cloth-copy .cloth::before,.cloth-copy .cloth::after{display:none}
.cloth-copy .cloth .cslot .cap{font-size:.75rem}
@media (min-width:900px){ .reveal-grid .cloth-copy{min-width:min(32vw,400px)} }

/* =========================================================
   v17 - one card on the page, at the size of a card.
   The same card was on the page twice: 142px in the table at the top, with 101px of empty cloth
   under it and a 411px gap, and again at 336px in the reading below. The small one is the one you
   meet first when you scroll, which is why it kept being called tiny. The table has done its job by
   the time the reading exists, so it hands over: the reading is the page, and the card in it is the
   size a card should be.
   ========================================================= */
.stage.read-on .tabletop,.stage.read-on .under-wheel,.stage.read-on .refine-bar,.stage.read-on .stage-hints{display:none}
.stage.read-on{padding-bottom:0}
#stage.read-on .stage-head{margin-bottom:0}
/* the reading takes the room the table gave up */
.reveal{grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);align-items:start}
@media (min-width:1100px){ .reveal{gap:clamp(2rem,4.5vw,4.5rem)} }
@media (max-width:900px){ .reveal{grid-template-columns:1fr} }
.reveal .left{gap:1.5rem}
/* and the refine bar moves under the card, where the card is */
.reveal .refine-bar{margin-top:0;border-top:0;padding-top:0}

/* big spreads: superseded by v18, which puts the map back beside the reading. */

/* what was asked, at the top of its own reading */
.reading-ask{font-family:"Fraunces",Georgia,serif;font-size:1.1875rem;color:var(--ink-2);
  margin:0 0 1.25rem;padding-bottom:1rem;border-bottom:1px solid var(--rule)}
.reading-ask i{color:var(--ink)}

/* =========================================================
   v18 - the map is a map, and every card is legible where you read about it.

   What the full QA pass showed. On a 1512x900 screen the Celtic Cross reading opened with a
   tableau 1400px wide and 960px tall: you scrolled a whole screen, then another, and had still
   not reached a word of the reading. v17 gave big spreads the full width so their cards would
   not be 49px, and that worked, but it bought card size with the reading's place on the page.
   On a phone the same drawing put each card at 28-32px, which is not a card, it is a stamp.

   The fix separates two jobs that were being done by one picture. The tableau is the MAP: where
   each card fell, which is which, and it is where you point at what caught your eye. It needs to
   be seen whole, in one glance, not scrolled through. The card itself belongs next to its own
   paragraph, at a size where you can see what is drawn on it. So the map goes back beside the
   reading, bounded, and each position block carries its own card.
   ========================================================= */

/* the map sits beside the reading again, at every spread size. It gets the larger share of the
   width because it is a drawing and the reading is prose, which reads better narrow than wide. */
@media (min-width:900px){
  .reveal:has(.cloth-copy .cloth[data-n="5"]),
  .reveal:has(.cloth-copy .cloth[data-n="6"]),
  .reveal:has(.cloth-copy .cloth[data-n="7"]),
  .reveal:has(.cloth-copy .cloth[data-n="9"]),
  .reveal:has(.cloth-copy .cloth[data-n="10"]),
  .reveal:has(.cloth-copy .cloth[data-n="12"]){grid-template-columns:minmax(0,1.42fr) minmax(0,1fr)}
  /* and it holds its place while the reading scrolls past, which is only safe in two columns:
     a sticky map over a full-width reading is what was pinning cards on top of the text. */
  .reveal .cloth-copy{position:sticky;top:1.5rem}
  /* never taller than the screen: a map you have to scroll is not doing a map's job. The cloth
     keeps its aspect ratio, so this has to come off the width. A max-height here only clips it,
     which is what cut the top off a single large card the first time. */
  .reveal .cloth-copy .cloth{width:min(100%,calc(78vh * var(--aw,16) / var(--ah,11)))}
}

/* ---- the card beside its own paragraph, at every width -----------------------------------
   Measured in the tableau before this: 120px at 1512, 101px at 1180, 32px at 390. The thumbnail
   is the same card at a size that does not depend on how many others are on the table. */
.pos-thumb-wrap{position:relative;display:block;width:92px;grid-row:1/4;align-self:start}
.pos-thumb{display:block;width:100%;height:auto;border-radius:3px;box-shadow:0 2px 10px rgba(26,20,22,.18)}
.pos-thumb.rev{transform:rotate(180deg)}
/* the dots that say "you can point here" sit on this copy too */
.pos-thumb-wrap .dot{position:absolute;width:16%;aspect-ratio:1;border-radius:50%;
  transform:translate(-50%,-50%);border:1.5px solid var(--brick);background:rgba(156,78,61,.18);
  opacity:0;transition:opacity .2s ease;pointer-events:none;z-index:3}
.pos-thumb-wrap.refinable{cursor:pointer}
.pos-thumb-wrap.refinable .dot{opacity:.55;animation:dotBreath 2.6s ease-in-out infinite}
.pos-thumb-wrap.refinable:hover .dot{opacity:.9}
.reveal .pos-block .pos-head{display:grid;grid-template-columns:92px 1fr;grid-template-rows:auto auto 1fr;
  column-gap:1rem;margin-bottom:.5rem}
.reveal .pos-block .pos-label{grid-column:2;grid-row:1;align-self:end}
.reveal .pos-block .pos-card{grid-column:2;grid-row:2;align-self:start}
/* a block with no card of its own is not a two column block: one card is already large in the map
   beside the reading, and the sky position has no card at all. Without this the name sits in the
   empty column where the copy would have been, indented off the block's own left edge. */
.reveal .pos-block .pos-head.solo,
.reveal .pos-block .pos-head:not(:has(.pos-thumb-wrap)){display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem 1rem}
.reveal .pos-block .pos-head.solo{display:block}
.pos-head.solo .pos-thumb-wrap{display:none}
@media (max-width:760px){
  .pos-thumb-wrap{width:118px}
  .reveal .pos-block .pos-head{grid-template-columns:118px 1fr}
}

/* the spread name was on screen three times at once: the eyebrow, the title, and the line with
   the link. With no question to explain, that line is only the link, so it sits with the title. */
#tableWhy:empty{display:none}

/* =========================================================
   v19: the reading reads as a dialogue, not a form.

   "So many weird lines kinda breaks the reading flow, the layout is clunky, it should feel more
   like a dialogue." Counted on a one card reading with a question: nine horizontal rules for two
   paragraphs of prose. Two of them sat 18px apart, which is the double line you can see. Every
   part of the reading had grown its own rule and its own padding, so the page became a stack of
   labelled slabs with a sentence in each.

   A reading has two voices. What you brought (the question you typed, what you noticed on the
   card, the question it hands back) and what the cards say. So the two voices are marked as
   voices: yours are indented behind a short brick tick, the cards' run plain and full width. That
   is the whole structure. No rules in the open reading at all, except the one above the fold,
   which is machinery rather than reading and should look like it.
   ========================================================= */

/* every rule the reading had grown */
.pos-block{border-top:none;padding:0}
.pos-block:first-child{padding-top:0}
.reading-ask{border-bottom:none;padding-bottom:0}
.reading-close{border-top:none;padding-top:0}
.reading-carry{border-top:none;padding-top:0}
.hint.prov{border-top:none;padding-top:0}

/* space carries the rhythm instead. A block is a beat, not a box. */
#readingBody > * + *{margin-top:1.5rem}
.pos-block + .pos-block{margin-top:2rem}
.pos-read + .pos-read{margin-top:.75rem}

/* ---- your voice ------------------------------------------------------------------------
   the question you typed, the thing you pointed at, and the question handed back. Set in the
   serif, indented behind a short tick, so the page alternates between two speakers. */
.reading-ask,.pos-obs,.reading-carry{position:relative;padding-left:1.25rem}
.reading-ask::before,.pos-obs::before,.reading-carry::before{content:"";position:absolute;
  left:0;top:.5em;width:5px;height:1px;background:var(--brick);opacity:.75}
.reading-ask{font-family:"Cormorant Garamond",Georgia,serif;font-size:1.1875rem;color:var(--ink-2);margin:0 0 1.5rem}
.reading-ask i{color:var(--ink)}
.pos-obs{margin:0 0 .75rem}
/* the question back is a spoken line, not a headline. It was 24px in a page of 16.8px prose,
   which made the weakest sentence in the reading the loudest thing on it. */
.reading-carry{margin-top:2rem}
.reading-carry p{font-family:"Cormorant Garamond",Georgia,serif;font-weight:500;font-size:1.3125rem;
  line-height:1.35;margin:0;color:var(--ink);max-width:34rem}

/* ---- the fold, and the machinery under it ---------------------------------------------- */
.reading-facts{margin-top:2.5rem;border-top:1px solid var(--rule);padding-top:1rem}
.hint.prov{margin-top:1rem;opacity:.85}
/* the table of the day keeps its rules: it is a table, and rows need them */

/* ---- a block is one unit: the card, its name, and its words beside it ------------------
   With the rules gone the old shape showed: the head was as tall as the thumbnail, so the name
   sat beside the top of the card and the paragraph started below the bottom of it, leaving a
   pocket of empty page against the card's lower half. The prose now runs beside the card, so a
   block is a card and what is said about it, and the next block starts when the card does. */
.reveal .pos-block:has(.pos-thumb-wrap){display:grid;grid-template-columns:92px minmax(0,1fr);
  column-gap:1rem;align-items:start}
.reveal .pos-block:has(.pos-thumb-wrap) > *{grid-column:2}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-head{display:contents}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-thumb-wrap{grid-column:1;grid-row:1/span 40}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-label{grid-column:2;align-self:end;margin-bottom:.125rem}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-card{grid-column:2;margin-bottom:.5rem}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-read{max-width:none}
@media (max-width:760px){
  .reveal .pos-block:has(.pos-thumb-wrap){grid-template-columns:118px minmax(0,1fr);column-gap:1rem}
}

/* ---- one text column, with the cards hanging into the margin ---------------------------
   Four different left edges were in play: the question you asked, the prose beside a card, the
   line about the table as a whole, and the question handed back. Straightening them is what
   turns a stack of blocks into a column of speech. The cards hang out to the left of it, the
   way a figure sits in a margin. Not on a phone, where a 132px gutter would leave 226px of
   line to read. */
@media (min-width:761px){
  #readingBody:has(.pos-thumb-wrap){--gut:calc(92px + 1.05rem)}
  #readingBody:has(.pos-thumb-wrap) > *:not(:has(.pos-thumb-wrap)){margin-left:var(--gut)}
}
/* the table as a whole steps back from the cards: quieter, and with room above it, rather than
   the full strength ink rule it used to be introduced by */
.reading-close{margin-top:2rem}
.reading-close p{color:var(--ink-2);max-width:34rem}

/* ---- the card back, printed rather than generated -----------------------------------------
   It was a flat 45 degree line gradient on a teal ground, which is why it read as digital. It is
   now a paper edge, an engraved lattice with a rosette at each crossing, and two rules inside the
   margin, which is how a card back is actually laid out. The shadow is a plain offset shape: the
   feDropShadow that was on all seventy eight of them cost a 169ms frame during the deal. */
.wheel .cardshadow{fill:rgba(26,20,22,.22)}
.wheel .cardback{fill:var(--paper);stroke:var(--wheel-card-line);stroke-width:.9}
.wheel .backfill{fill:url(#backPattern);stroke:none}
.wheel .backrule{fill:none}
.wheel .backrule.outer{stroke:var(--wheel-card-line);stroke-width:.5;opacity:.55}
.wheel .backrule.inner{stroke:var(--wheel-card-weave);stroke-width:.45;opacity:.5}
.wheel .cardg:hover .cardback,.wheel .cardg.near .cardback{stroke:var(--brick);stroke-width:1.4}

/* the same back everywhere it appears outside the fan: the deck, the flyer, the slot, the mini */
.cslot .card .back,.flyer.back,.big-card.facedown,.mini-card.back,.deck-wrap .dk.top,.dk:not(.top),.dk.top .face.back{
  background-color:var(--paper);
  background-image:
    repeating-linear-gradient(30deg, var(--wheel-card-weave) 0 .5px, transparent .5px 4.2px),
    repeating-linear-gradient(120deg, var(--wheel-card-weave) 0 .5px, transparent .5px 4.2px),
    linear-gradient(var(--wheel-card), var(--wheel-card));
  background-clip:content-box, content-box, content-box;
  background-origin:content-box;
  padding:4%;
  border:1px solid var(--wheel-card-line);
  border-radius:3px;
  overflow:hidden}
.cslot .card .back::after,.flyer.back::after,.big-card.facedown::after,.mini-card.back::after,.deck-wrap .dk.top::after{
  content:"";position:absolute;inset:4%;border:1px solid var(--wheel-card-line);opacity:.5;border-radius:3px}
.cslot .card .back::before,.flyer.back::before,.big-card.facedown::before,.mini-card.back::before,.deck-wrap .dk.top::before{
  content:"";position:absolute;inset:9%;border:1px solid var(--wheel-card-weave);opacity:.45;border-radius:3px;
  background:none;width:auto;height:auto;left:auto;top:auto;transform:none}

/* ---- the empty place on the cloth, made visible ---------------------------------------------
   It was a 1px dashed line in --rule on a cloth of nearly the same value: measured at 1.4:1, where
   a control needs 3:1 to be seen at all, and the caption under it was 10.5px. This is the target
   of the entire interaction and it was the faintest thing on the table. Carried on an id so it
   wins outright rather than fighting six stylesheets for it. */
#stage .cloth .idle-slot,#stage .cloth .cslot:not(.filled){
  border:2px dashed var(--ink-2);
  border-radius:6px;
  background:rgba(26,20,22,.05);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35)}
#stage .cloth .idle-slot .cap,#stage .cloth .cslot:not(.filled) .cap{
  color:var(--ink-2);font-size:.75rem;letter-spacing:.14em}
#stage .cloth .cslot.active:not(.filled),#stage .cloth .cslot.next:not(.filled){
  border-color:var(--brick);border-style:solid;background:rgba(156,78,61,.07)}
#stage .cloth .cslot.filled{border:0;background:none;box-shadow:none}

/* the number is printed on a teal ground, so it is cream on dark rather than dark on light, and it
   keeps the dark outline that stops it disappearing where two cards overlap */
.wheel .cardnum{fill:#f2eadb;opacity:.42;stroke:rgba(18,14,13,.45);stroke-width:1.6px}
.wheel .cardg.near .cardnum{opacity:1;fill:#f0b544}

/* the seal line under the table was 10.5px uppercase with wide tracking in the lightest ink, which
   passes on contrast and still reads as faint. It is the provenance of the draw and should be
   quiet, not invisible. */
.under-wheel{font-size:.75rem;color:var(--ink-2)}
.under-wheel .linkish{font-size:.75rem}

/* ---- the sky's own place on the cloth ------------------------------------------------------
   It was a borderless square holding a big gold ring, with a caption set 190% wide running off
   the edge of the table. Beside two card shaped slots it read as a rendering fault rather than a
   position. It is a place on the table like the others: same shape, same dashed edge, with the
   glyph small inside it. */
#stage .cloth .cslot.skypos{
  aspect-ratio:480/822;width:var(--cw,15%);
  border:2px dashed var(--sun);border-radius:6px;
  background:rgba(207,150,44,.07);
  display:grid;place-items:center}
#stage .cloth .cslot.skypos svg{width:44%;height:auto}
#stage .cloth .cslot.skypos .cap{width:150%;color:var(--sun-text)}

/* ---- what the cards will not answer ---------------------------------------------------------
   Said in the hero, in the site's own voice, before anything is dealt. Not an error box: a reader
   telling you what the tool is for, with the way forward underneath it. */
.q-result:has(.triage){display:block;border:0;background:none;padding:0;max-width:none}
.triage{max-width:34rem;margin:1.25rem auto 0;text-align:left;padding-left:1.25rem;position:relative}
.triage::before{content:"";position:absolute;left:0;top:.55em;width:5px;height:1px;background:var(--brick);opacity:.75}
.triage .label{display:block;color:var(--brick);margin-bottom:.5rem}
.triage-say{font-family:"Cormorant Garamond",Georgia,serif;font-size:1.1875rem;line-height:1.35;color:var(--ink);margin:0 0 .5rem}
.triage-offer{font-size:.9375rem;line-height:1.5;color:var(--ink-2);margin:0 0 1rem}
.triage-acts{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1rem}

/* the verdict on a yes or no, said before the card is described */
.verdict{margin:0 0 1.5rem}
.verdict .label{display:block;color:var(--brick);margin-bottom:.375rem}
.verdict-word{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 44,"wght" 520,"SOFT" 40,"WONK" 1;
  font-size:2rem;line-height:1;margin:0 0 .5rem;color:var(--ink)}
.verdict-why{margin:0;font-size:1.0625rem;line-height:1.5;color:var(--ink-2);max-width:34rem}

/* the day's card, told in the hero to somebody who has already drawn it */
.day-slot{margin:1rem auto 0;max-width:34rem}
.day-line{margin:0;font-size:1.0625rem;line-height:1.5;color:var(--ink-2)}
.day-line b{color:var(--ink)}
.day-line .fact{color:var(--ink-3);letter-spacing:.06em}
.day-line .linkish{font-size:1.0625rem}

/* the cards get their own compositor layers for the length of the deal only */
.wheel.warming .cardg,.wheel.dealing .cardg{will-change:transform}

/* the cards under the top of the stack: you only ever see their edge, so they are paper with a
   line, not a second copy of the pattern. The old rule gave them a teal rim. */
.deck-wrap .dk:not(.top),.dk:not(.top){
  background:var(--paper) !important;
  border:1px solid var(--wheel-card-line);border-radius:3px}
.deck-wrap .dk:not(.top)::before,.deck-wrap .dk:not(.top)::after{display:none}

/* the lede in two beats rather than one block: the claim, then what you do with it */
.lede-2{margin-top:.75rem;color:var(--ink-2)}

/* ==== v20 : the pick ==========================================================================
   Three faults, found by filming the deal frame by frame.

   1. The flyer's back was broken. The shared card-back rule uses padding:4% to inset the woven
      ground inside the paper edge, which is right for every card that sits in the layout. The
      flyer is position:fixed, and a percentage padding on a fixed element resolves against the
      viewport, not against itself: on a 1180px window a 119px card was given 47px of padding on
      each side, so the teal ground collapsed to a 25px ribbon and the card in flight did not
      look like the deck it came out of. Measured, not guessed.
   2. The card left the fan upright. It sits at the fan's tilt until you touch it, then the flyer
      appeared at rotation zero: a snap at the exact moment you were watching.
   3. Nothing marked where it was going, and nothing marked its arrival.
   ============================================================================================ */

/* 1. the flyer's own inset, in pixels, so it holds at every card width the layout uses */
.flyer.back{padding:5px}

/* the two beats of a pick: a lift out of the fan, then the carry across */
.flyer{transition-property:left,top,width,height,transform,box-shadow}
.flyer.lifting{
  transition-timing-function:cubic-bezier(.2,.9,.3,1);
  box-shadow:0 14px 26px rgba(26,20,22,.30),0 3px 7px rgba(26,20,22,.20);
  z-index:82}
.flyer.carrying{
  transition-timing-function:cubic-bezier(.36,.02,.2,1);
  box-shadow:0 6px 14px rgba(26,20,22,.20),0 1px 3px rgba(26,20,22,.14);
  z-index:82}

/* the gap closes behind the card instead of trailing it: no stagger delay on the one you took */
.wheel .cardg.taken{transition:opacity .2s ease;transition-delay:0ms}

/* 2. the place it is going, while it is in the air. Firm enough to read across the table, and it
      replaces the idle pulse so the two are never animating against each other. */
/* the slots are .place, not .cslot: this block has never matched an element on the table. Both
   selectors are listed so the rule applies wherever the class lands. */
#stage .cloth .place.incoming,
#stage .cloth .cslot.incoming{
  animation:none;
  border-style:solid;
  border-color:var(--brick);
  background:rgba(156,78,61,.09);
  box-shadow:0 0 0 3px rgba(156,78,61,.10), inset 0 1px 0 rgba(255,255,255,.35)}
#stage .cloth .place.incoming .cap,#stage .cloth .cslot.incoming .cap{color:var(--brick)}
#stage .cloth .place.incoming .num,#stage .cloth .cslot.incoming .num{background:var(--brick);border-color:var(--brick);color:#fff}

/* 3. and the arrival: the card settles rather than appearing */
.cslot.landed .card{animation:cardSettle .5s cubic-bezier(.2,.9,.28,1) both}
@keyframes cardSettle{
  0%{transform:scale(1.05) translateY(-4px)}
  55%{transform:scale(.985) translateY(0)}
  100%{transform:scale(1) translateY(0)}}

@media (prefers-reduced-motion:reduce){
  .cslot.landed .card{animation:none}
  .flyer.lifting,.flyer.carrying{box-shadow:var(--shadow)}
}

/* The woven ground on the flyer, the slot and the deck is drawn in CSS; the same ground on the 78
   cards in the fan is an SVG pattern in the wheel's own units, so it grows with the card. At the
   fan's working scale that pattern lands at a 6px cell. The CSS one was cut at 4.2px, so the card
   you lifted had a visibly finer weave than the card it came out of. Same cell now, both sides of
   the pick. (The pattern's rosette is a rotated lattice a CSS tile cannot repeat; the crossing
   gradients carry the weave alone, which at card size is what the eye reads.) */
.cslot .card .back,.flyer.back,.big-card.facedown,.mini-card.back,.deck-wrap .dk.top,.dk:not(.top),.dk.top .face.back{
  background-image:
    repeating-linear-gradient(30deg, var(--wheel-card-weave) 0 .42px, transparent .42px 6px),
    repeating-linear-gradient(120deg, var(--wheel-card-weave) 0 .42px, transparent .42px 6px),
    linear-gradient(var(--wheel-card), var(--wheel-card))}

/* ==== the deck bar ============================================================================
   The two things a reader does to a deck were a link in 10px small caps under the table, below the
   fold on a laptop, next to the reset. So the table read as something we had set for you. They sit
   above the deck now, at the size of a control, with the seal beside them: you can see the deck is
   sealed, and you can see that both ways of unsealing it are yours. */
.deck-bar{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  margin:0 0 .5rem;padding:.375rem .125rem .5rem;
  border-bottom:1px solid var(--rule)}
.deck-bar-seal{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3);line-height:1.35}
.deck-bar-acts{display:flex;gap:.5rem;flex-shrink:0}
.deck-act{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);background:var(--paper);
  border:1px solid var(--ink-3);border-radius:999px;
  padding:.375rem .75rem;min-height:30px;cursor:pointer;
  transition:background .18s ease,border-color .18s ease,color .18s ease}
.deck-act:hover{background:var(--brick);border-color:var(--brick);color:#fff}
.deck-act:focus-visible{outline:2px solid var(--brick);outline-offset:2px}
.deck-act[disabled]{opacity:.45;cursor:default}
.deck-act[disabled]:hover{background:var(--paper);border-color:var(--ink-3);color:var(--ink)}
/* the fan collapses when the reading is being turned, and its controls go with it */
.stage.turning .deck-bar,.stage.big.turning .deck-bar{opacity:0;pointer-events:none;transition:opacity .35s ease}
#stage.idle-on .deck-bar{opacity:0;transition:opacity .55s ease}
#stage.idle-on.laid .deck-bar{opacity:1}

/* the riffle: the stack springs open and closes again, once */
.deck-wrap.riffling .deck{animation:riffleDeck .62s cubic-bezier(.32,.86,.28,1)}
@keyframes riffleDeck{
  0%{transform:translate(-50%,-50%)}
  22%{transform:translate(-50%,-50%) translateX(-8%) rotate(-5deg) scale(1.03)}
  48%{transform:translate(-50%,-50%) translateX(7%) rotate(4deg) scale(.99)}
  72%{transform:translate(-50%,-50%) translateX(-3%) rotate(-1.6deg) scale(1.01)}
  100%{transform:translate(-50%,-50%)}}

@media (max-width:640px){
  .deck-bar{gap:.5rem;padding-bottom:.5rem}
  .deck-bar-seal{font-size:.75rem;flex:1 1 100%;order:2}
  .deck-bar-acts{order:1;width:100%}
  .deck-act{flex:1;text-align:center}
}
@media (prefers-reduced-motion:reduce){ .deck-wrap.riffling .deck{animation:none} }

/* ==== the captions under the cloth ============================================================
   v19 made the empty slot's caption readable by raising it to .74rem with .15em of tracking. On a
   three card row that made "THE PRESENT" 97px of text in an 88px column, so on a phone the three
   captions ran into one another: THE PASTTHE PRESENTTHE FUTURE. The caption box is 210% of a card,
   which is only safe when the cards are far apart. Bound it to the card plus a little, let it wrap,
   and take the tracking back to where the words still separate. */
#stage .cloth .cslot[data-cap="below"] .cap,#stage .cloth .cslot[data-cap="above"] .cap,
#stage .cloth .idle-slot[data-cap="below"] .cap{
  width:calc(100% + 16px);
  overflow-wrap:break-word}
#stage .cloth .idle-slot .cap,#stage .cloth .cslot:not(.filled) .cap{letter-spacing:.06em}
#stage .cloth .cslot .cap{letter-spacing:.06em}

/* ==== the question box, answering back ========================================================
   The box took a question and produced a table. Which spread, why that one, and whether the cards
   should be answering it at all were all decided in the half second between, and only reported
   afterwards. This is that decision, shown while there is still time to argue with it. */
.hero-centre .qbox{position:relative}
.q-live{
  position:relative;z-index:6;
  margin:.5rem auto 0;max-width:min(100%,38rem);
  text-align:left;
  background:var(--paper);
  border:1px solid var(--ink-3);border-radius:10px;
  box-shadow:0 10px 26px rgba(26,20,22,.10);
  padding:.75rem 1rem .75rem}
.q-live-wait{margin:0;font-size:.9375rem;line-height:1.5;color:var(--ink-2)}
.q-live-pick{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap}
.q-live-pick .label{font-size:.75rem;letter-spacing:.14em;color:var(--ink-3)}
.q-live-name{font-family:"Newsreader",Georgia,serif;font-size:1.1875rem;line-height:1.2;color:var(--ink)}
.q-live-n{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3)}
.q-live-why{margin:.25rem 0 0;font-size:.9375rem;line-height:1.5;color:var(--ink-2)}
.q-live-offer{margin:.25rem 0 .5rem;font-size:.9375rem;line-height:1.5;color:var(--ink-2)}
.q-live-alts{display:flex;align-items:center;gap:.375rem;flex-wrap:wrap;
  margin-top:.5rem;padding-top:.5rem;border-top:1px solid var(--rule)}
.q-alt-lead{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-3);margin-right:.125rem}
.q-alt{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink);background:transparent;border:1px solid var(--ink-3);border-radius:999px;
  padding:.375rem .5rem;min-height:28px;cursor:pointer;
  transition:background .16s ease,border-color .16s ease,color .16s ease}
.q-alt:hover{background:var(--brick);border-color:var(--brick);color:#fff}
.q-alt:focus-visible{outline:2px solid var(--brick);outline-offset:2px}
.q-live-flag{margin:-.125rem 0 .5rem;padding:0 0 .5rem;border-bottom:1px solid var(--rule)}
.q-live-flag .label{display:block;font-size:.75rem;letter-spacing:.14em;margin-bottom:.25rem}
.q-live-flag p{margin:0;font-size:.9375rem;line-height:1.5;color:var(--ink-2)}
.q-live-flag.stop .label{color:var(--brick)}
.q-live-flag.note .label{color:var(--sun-text,var(--ink-3))}

/* ==== and on the table, the same decision, said plainly ======================================
   "Change spread is faint here." It was a 12px underlined link at the end of a sentence, which is
   how you style a footnote, not how you style the control for the single choice that shapes the
   whole reading. */
.stage-why .linkish,#changeSpread{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);background:var(--paper);text-decoration:none;
  border:1px solid var(--ink-3);border-radius:999px;
  padding:.375rem .75rem;min-height:28px;display:inline-block;margin-left:.375rem;
  transition:background .16s ease,border-color .16s ease,color .16s ease}
.stage-why .linkish:hover,#changeSpread:hover{background:var(--brick);border-color:var(--brick);color:#fff}

/* no widowed word at the end of a lede: the browser balances the last two lines itself */
.lede,.q-live-why,.q-live-flag p,.stage-why,.answer{text-wrap:pretty}
/* the sky line under the box sits above the scattered cards, so it is never half covered by one */
.today-line{position:relative;z-index:3}

/* the headline is nine words; let the browser even out the lines rather than leaving one word
   stranded on the last one */
.hero-centre h1{text-wrap:balance}
/* the headline is two sentences; break it between them rather than wherever the line runs out */
.hero-centre h1{text-wrap:balance}
.h1br{display:none}
@media (min-width:340px){ .hero-centre h1{text-wrap:initial} .h1br{display:inline} }

/* ==== v21 : the card, the chips, and what the sky is doing ====================================
   Three faults, all measured against the app Will put beside this one.

   The card in a reading was 92px wide. Theirs is about 350. Ours also carried four invisible
   targets on it, 16% of 92px each, and the instruction "touch it on the card" without saying what
   was touchable, so the best thing in the product was unreachable in practice.

   And the sky arrived as astronomy: degrees, a scheme, a disclaimer, in the middle of a paragraph
   about a picture. It is a state of the card now, and most of the time it is silence.
   ============================================================================================ */

/* ---- the card, at a size you can look at ---- */
.pos-thumb-wrap{width:150px}
.reveal .pos-block:has(.pos-thumb-wrap){grid-template-columns:150px minmax(0,1fr);column-gap:1rem}
#readingBody:has(.pos-thumb-wrap){--gut:calc(150px + 1.1rem)}
@media (min-width:1100px){
  .pos-thumb-wrap{width:190px}
  .reveal .pos-block:has(.pos-thumb-wrap){grid-template-columns:190px minmax(0,1fr);column-gap:1.25rem}
  #readingBody:has(.pos-thumb-wrap){--gut:calc(190px + 1.25rem)}
}
/* on a phone a 150px card beside a 200px column is two narrow things; the card goes over the words */
@media (max-width:700px){
  .reveal .pos-block:has(.pos-thumb-wrap){display:block}
  .reveal .pos-block:has(.pos-thumb-wrap) > *{grid-column:auto}
  .reveal .pos-block:has(.pos-thumb-wrap) .pos-head{display:block}
  .pos-thumb-wrap{width:min(62vw,260px);margin:0 auto .75rem;display:block}
  #readingBody:has(.pos-thumb-wrap){--gut:0px}
  #readingBody:has(.pos-thumb-wrap) > *:not(:has(.pos-thumb-wrap)){margin-left:0}
}
.pos-thumb{border-radius:6px;box-shadow:0 3px 16px rgba(26,20,22,.22)}
/* the dots are gone: the chips do that job, from a target you can see */
.pos-thumb-wrap .dot,.cslot .dot{display:none!important}
.pos-thumb-wrap.refinable{cursor:default}

/* ---- lit, yours, quiet ----------------------------------------------------------------------
   A ring on the card and one sentence under the prose. Nothing at all when nothing is standing on
   it, which is most draws and is the point: the mark means something because it is usually absent. */
.pos-block.rz-on .pos-thumb{box-shadow:0 0 0 2px var(--al),0 0 18px -2px var(--al),0 3px 16px rgba(26,20,22,.22)}
.rz{display:inline-flex;align-items:center;gap:.3em;margin-left:.55em;vertical-align:.08em;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;
  padding:.24em .5em .2em;border-radius:999px;border:1px solid var(--al);color:var(--al);
  background:color-mix(in srgb,var(--al) 12%,transparent)}
.rz i{font-style:normal;font-size:.8125rem;line-height:1}
.pos-rz{margin:.5rem 0 0;padding-left:.75rem;border-left:2px solid var(--al);
  font-size:.9375rem;line-height:1.5;color:var(--ink)}

/* ---- what caught your eye ----
   The bar asked and the dots answered, a screen apart. This asks where the answer is. */
.pos-chips{display:flex;align-items:center;gap:.375rem;flex-wrap:wrap;margin:.75rem 0 .125rem}
.pos-chips-lead{width:100%;font-size:.75rem;letter-spacing:.14em;color:var(--ink-3);margin-bottom:.125rem}
.eye-chip{
  font-family:"Newsreader",Georgia,serif;font-size:.875rem;line-height:1.2;
  color:var(--ink);background:var(--paper);border:1px solid var(--ink-3);border-radius:999px;
  padding:.375rem .75rem;min-height:32px;cursor:pointer;text-align:left;
  transition:background .16s ease,border-color .16s ease,color .16s ease}
.eye-chip:hover{background:var(--brick);border-color:var(--brick);color:#fff}
.eye-chip:focus-visible{outline:2px solid var(--brick);outline-offset:2px}
.eye-chip.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.eye-chip.whole{font-style:italic;color:var(--ink-2)}
.eye-chip.whole.on{color:var(--paper)}

/* a tap on the cloth points at the paragraph rather than covering it with a panel */
.pos-block.pointed{animation:pointAt 1.4s ease}
@keyframes pointAt{0%,100%{background:transparent}22%{background:rgba(156,78,61,.10)}}

@media (prefers-reduced-motion:reduce){ .pos-block.pointed{animation:none} }

/* ---- the day's card, and the fact that it is the day's ---- */
.day-lock{margin:0 0 1rem;padding:.5rem .75rem;border:1px solid var(--rule);border-radius:10px;
  background:var(--paper-2);font-size:.9375rem;line-height:1.5;color:var(--ink-2)}
.day-lock b{color:var(--ink)}
.day-lock .linkish{margin-left:.35em}
.day-lock .fact{font-size:.75rem;letter-spacing:.1em;color:var(--ink-3)}

/* ---- the chips sit in the card's column, under the card they are about ---- */
.reveal .pos-block:has(.pos-thumb-wrap) .pos-thumb-wrap{grid-column:1;grid-row:1}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-chips{grid-column:1;grid-row:2/span 40;align-self:start;
  margin:.75rem 0 0;gap:.25rem}
.reveal .pos-block:has(.pos-thumb-wrap) .pos-chips .eye-chip{font-size:.8125rem;padding:.375rem .5rem;min-height:30px}
@media (max-width:700px){
  .reveal .pos-block:has(.pos-thumb-wrap) .pos-chips{grid-column:auto;grid-row:auto;
    justify-content:center;max-width:min(72vw,320px);margin:.5rem auto 1rem}
}
.pos-thumb{cursor:zoom-in}

/* ---- the card, opened ---- */
.card-zoom{position:fixed;inset:0;z-index:200;display:none;place-items:center;
  background:rgba(18,14,13,.86);padding:4vmin;cursor:zoom-out}
.card-zoom.on{display:grid}
.card-zoom img{max-width:min(92vw,520px);max-height:92vh;width:auto;height:auto;
  border-radius:10px;box-shadow:0 24px 70px rgba(0,0,0,.55);background:var(--card-face)}
.card-zoom img.rev{transform:rotate(180deg)}
.zoom-close{position:absolute;top:max(1rem,3vmin);right:max(1rem,3vmin);
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  color:#f2eadb;background:transparent;border:1px solid rgba(242,234,219,.5);border-radius:999px;
  padding:.5rem .75rem;min-height:32px;cursor:pointer}
.zoom-close:hover{background:rgba(242,234,219,.14)}
/* Tried putting these after the paragraph on a phone, on the theory that you answer once you have
   read. Wrong: the paragraph is two hundred words, so the chips ended up a screen below the card
   they are about and you had to scroll back up to see what you were choosing between. Directly
   under the card, where the card still is. */

/* ---- the card is the surface -------------------------------------------------------------- */
.card-zoom figure{margin:0;display:grid;justify-items:center;gap:1rem}
.zoom-hint{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:rgba(242,234,219,.72);text-align:center;max-width:32rem}
.zoom-hint:empty{display:none}
.pos-thumb{cursor:zoom-in}
.eye-chip.say{font-style:italic;color:var(--ink-2);border-style:dashed}
.eye-say{display:inline-flex;gap:.25rem;align-items:center;flex:1 1 12rem;min-width:11rem}
.eye-say input{flex:1;min-width:0;font-family:"Newsreader",Georgia,serif;font-size:.875rem;
  padding:.375rem .5rem;min-height:30px;border:1px solid var(--ink-3);border-radius:999px;
  background:var(--paper);color:var(--ink)}
.eye-say .btn{padding:.375rem .75rem;min-height:30px;font-size:.75rem}

/* ---- why you would ever press Cut ----
   Reversals are impossible until the deck is cut, and nobody cuts a deck a website has already
   shuffled for them, so a whole half of the reading was unreachable in practice. */
.deck-bar-why{flex:1 1 100%;order:3;font-family:"IBM Plex Mono",monospace;font-size:.75rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);margin-top:.25rem;line-height:1.35}
.deck-bar-hide{display:none}
.rz-rare{font-weight:500}
.pos-block.rz-rare .pos-thumb{box-shadow:0 0 0 2px var(--al),0 0 26px 0 var(--al),0 3px 16px rgba(26,20,22,.22)}


/* ==== v24 : the back of the card ==============================================================
   The deck was a crosshatch, which is a texture rather than a card back. The first Waite-Smith
   printing, William Rider and Son, December 1909, the same run as the faces on the other side,
   carried a grid of alternating roses and lilies in framed squares; collectors name that edition
   after it. Same year, same publisher, same public domain as the pictures.

   Drawn rather than scanned. The museum's own note is that the current US Games and Lo Scarabeo
   reproductions do not reproduce the original pattern accurately, so tracing a deck on sale today
   would be copying somebody's reconstruction. This is our rendition of a public domain design, in
   our own teal rather than the 1909 blue, which also means it tiles perfectly and stays sharp at
   any size: it holds together at the 40px sliver in the fan, which a scan would not.
   ============================================================================================ */
.cslot .card .back,.flyer.back,.big-card.facedown,.mini-card.back,.deck-wrap .dk.top,.dk:not(.top),.dk.top .face.back{
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2720%27%20height%3D%2720%27%20viewBox%3D%270%200%2020%2020%27%3E%3Crect%20width%3D%2720%27%20height%3D%2720%27%20fill%3D%27%235f8a84%27%2F%3E%3Cdefs%3E%3Cg%20id%3D%22r%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%23e4efec%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%23e4efec%22%3E%3Cellipse%20cx%3D%225%22%20cy%3D%222.9%22%20rx%3D%221.35%22%20ry%3D%221.02%22%2F%3E%3Cellipse%20cx%3D%227.05%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%2872%207.05%204.42%29%22%2F%3E%3Cellipse%20cx%3D%226.27%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28144%206.27%206.85%29%22%2F%3E%3Cellipse%20cx%3D%223.73%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28216%203.73%206.85%29%22%2F%3E%3Cellipse%20cx%3D%222.95%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28288%202.95%204.42%29%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%221.28%22%20fill%3D%22%235f8a84%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%22.58%22%20fill%3D%22%23e4efec%22%2F%3E%3C%2Fg%3E%3Cg%20id%3D%22l%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%23e4efec%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%23e4efec%22%3E%3Cpath%20d%3D%22M5%201.55C5.95%203.15%206.1%204.75%205.45%206.15L4.55%206.15C3.9%204.75%204.05%203.15%205%201.55Z%22%2F%3E%3Cpath%20d%3D%22M2.35%204.15C3.05%203.55%203.85%203.75%204.45%204.7C4.75%205.2%204.8%205.75%204.6%206.25L3.85%206.35C2.9%205.95%202.35%205.2%202.35%204.15Z%22%2F%3E%3Cpath%20d%3D%22M7.65%204.15C7.65%205.2%207.1%205.95%206.15%206.35L5.4%206.25C5.2%205.75%205.25%205.2%205.55%204.7C6.15%203.75%206.95%203.55%207.65%204.15Z%22%2F%3E%3Crect%20x%3D%224.66%22%20y%3D%226.1%22%20width%3D%22.68%22%20height%3D%221.85%22%20rx%3D%22.3%22%2F%3E%3Cellipse%20cx%3D%225%22%20cy%3D%228.3%22%20rx%3D%221.7%22%20ry%3D%22.46%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fdefs%3E%3Cuse%20href%3D%27%23r%27%20x%3D%270%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%2710%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%270%27%20y%3D%2710%27%2F%3E%3Cuse%20href%3D%27%23r%27%20x%3D%2710%27%20y%3D%2710%27%2F%3E%3C%2Fsvg%3E");
  /* The fan draws the pattern in the wheel's own units so it grows with the card: eight motifs
     across, whatever size the card is. A fixed 20px tile made the flyer twice as dense as the card
     it had just been lifted out of. A percentage keeps the count instead of the pixel size, which
     is what makes it read as the same deck. */
  background-size:25% auto;
  background-repeat:repeat;
  background-clip:content-box;
  background-origin:content-box}
:root[data-theme="dark"] .cslot .card .back,:root[data-theme="dark"] .flyer.back,
:root[data-theme="dark"] .big-card.facedown,:root[data-theme="dark"] .mini-card.back,
:root[data-theme="dark"] .deck-wrap .dk.top,:root[data-theme="dark"] .dk:not(.top),
:root[data-theme="dark"] .dk.top .face.back{background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2720%27%20height%3D%2720%27%20viewBox%3D%270%200%2020%2020%27%3E%3Crect%20width%3D%2720%27%20height%3D%2720%27%20fill%3D%27%232f4a47%27%2F%3E%3Cdefs%3E%3Cg%20id%3D%22r%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cellipse%20cx%3D%225%22%20cy%3D%222.9%22%20rx%3D%221.35%22%20ry%3D%221.02%22%2F%3E%3Cellipse%20cx%3D%227.05%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%2872%207.05%204.42%29%22%2F%3E%3Cellipse%20cx%3D%226.27%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28144%206.27%206.85%29%22%2F%3E%3Cellipse%20cx%3D%223.73%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28216%203.73%206.85%29%22%2F%3E%3Cellipse%20cx%3D%222.95%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28288%202.95%204.42%29%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%221.28%22%20fill%3D%22%232f4a47%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%22.58%22%20fill%3D%22%238fb3ad%22%2F%3E%3C%2Fg%3E%3Cg%20id%3D%22l%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cpath%20d%3D%22M5%201.55C5.95%203.15%206.1%204.75%205.45%206.15L4.55%206.15C3.9%204.75%204.05%203.15%205%201.55Z%22%2F%3E%3Cpath%20d%3D%22M2.35%204.15C3.05%203.55%203.85%203.75%204.45%204.7C4.75%205.2%204.8%205.75%204.6%206.25L3.85%206.35C2.9%205.95%202.35%205.2%202.35%204.15Z%22%2F%3E%3Cpath%20d%3D%22M7.65%204.15C7.65%205.2%207.1%205.95%206.15%206.35L5.4%206.25C5.2%205.75%205.25%205.2%205.55%204.7C6.15%203.75%206.95%203.55%207.65%204.15Z%22%2F%3E%3Crect%20x%3D%224.66%22%20y%3D%226.1%22%20width%3D%22.68%22%20height%3D%221.85%22%20rx%3D%22.3%22%2F%3E%3Cellipse%20cx%3D%225%22%20cy%3D%228.3%22%20rx%3D%221.7%22%20ry%3D%22.46%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fdefs%3E%3Cuse%20href%3D%27%23r%27%20x%3D%270%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%2710%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%270%27%20y%3D%2710%27%2F%3E%3Cuse%20href%3D%27%23r%27%20x%3D%2710%27%20y%3D%2710%27%2F%3E%3C%2Fsvg%3E")}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .cslot .card .back,:root:not([data-theme="light"]) .flyer.back,
  :root:not([data-theme="light"]) .big-card.facedown,:root:not([data-theme="light"]) .mini-card.back,
  :root:not([data-theme="light"]) .deck-wrap .dk.top,:root:not([data-theme="light"]) .dk:not(.top),
  :root:not([data-theme="light"]) .dk.top .face.back{background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2720%27%20height%3D%2720%27%20viewBox%3D%270%200%2020%2020%27%3E%3Crect%20width%3D%2720%27%20height%3D%2720%27%20fill%3D%27%232f4a47%27%2F%3E%3Cdefs%3E%3Cg%20id%3D%22r%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cellipse%20cx%3D%225%22%20cy%3D%222.9%22%20rx%3D%221.35%22%20ry%3D%221.02%22%2F%3E%3Cellipse%20cx%3D%227.05%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%2872%207.05%204.42%29%22%2F%3E%3Cellipse%20cx%3D%226.27%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28144%206.27%206.85%29%22%2F%3E%3Cellipse%20cx%3D%223.73%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28216%203.73%206.85%29%22%2F%3E%3Cellipse%20cx%3D%222.95%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28288%202.95%204.42%29%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%221.28%22%20fill%3D%22%232f4a47%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%22.58%22%20fill%3D%22%238fb3ad%22%2F%3E%3C%2Fg%3E%3Cg%20id%3D%22l%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cpath%20d%3D%22M5%201.55C5.95%203.15%206.1%204.75%205.45%206.15L4.55%206.15C3.9%204.75%204.05%203.15%205%201.55Z%22%2F%3E%3Cpath%20d%3D%22M2.35%204.15C3.05%203.55%203.85%203.75%204.45%204.7C4.75%205.2%204.8%205.75%204.6%206.25L3.85%206.35C2.9%205.95%202.35%205.2%202.35%204.15Z%22%2F%3E%3Cpath%20d%3D%22M7.65%204.15C7.65%205.2%207.1%205.95%206.15%206.35L5.4%206.25C5.2%205.75%205.25%205.2%205.55%204.7C6.15%203.75%206.95%203.55%207.65%204.15Z%22%2F%3E%3Crect%20x%3D%224.66%22%20y%3D%226.1%22%20width%3D%22.68%22%20height%3D%221.85%22%20rx%3D%22.3%22%2F%3E%3Cellipse%20cx%3D%225%22%20cy%3D%228.3%22%20rx%3D%221.7%22%20ry%3D%22.46%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fdefs%3E%3Cuse%20href%3D%27%23r%27%20x%3D%270%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%2710%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%270%27%20y%3D%2710%27%2F%3E%3Cuse%20href%3D%27%23r%27%20x%3D%2710%27%20y%3D%2710%27%2F%3E%3C%2Fsvg%3E")}
}

/* the card's own sense, one line, where the mood tags would go */
.pos-gist{display:block;grid-column:2;font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:1.0625rem;line-height:1.35;color:var(--ink-2);margin:.125rem 0 .5rem}
.pos-head.solo .pos-gist{grid-column:auto}
@media (max-width:700px){ .pos-gist{grid-column:auto;font-size:.9375rem} }
/* the badge is a badge, not a banner: moving it out of the card's name made it a grid item */
.pos-head .rz,.pos-block .rz{justify-self:start;align-self:center;width:max-content;grid-column:2}
.pos-head.solo .rz{grid-column:auto}
@media (max-width:700px){ .pos-head .rz,.pos-block .rz{grid-column:auto} }

/* ==== v26 : the reading is a reading again ====================================================
   Sixteen elements on a one card reading against seven in the app it was being measured with. The
   chips were the worst of it: eleven words of mono instruction and six controls filling a phone
   screen under a card you could not see all of. They belong inside the card, where you have already
   decided to look, not stacked under it while you are trying to read. */
.pos-chips{margin:0}
.reading-open{margin:1rem 0 0;font-size:.9375rem;line-height:1.5;color:var(--ink-2)}

/* the chips, in the picture */
.card-zoom figure{gap:.75rem;max-height:96vh}
.zoom-chips{display:flex;flex-wrap:wrap;gap:.375rem;justify-content:center;max-width:min(92vw,520px)}
.zoom-chips .pos-chips{display:contents}
.card-zoom .eye-chip{background:rgba(242,234,219,.10);border-color:rgba(242,234,219,.45);color:#f2eadb}
.card-zoom .eye-chip:hover{background:#9c4e3d;border-color:#9c4e3d;color:#fff}
.card-zoom .eye-chip.whole,.card-zoom .eye-chip.say{color:rgba(242,234,219,.7)}
.card-zoom .eye-say input{background:rgba(242,234,219,.10);border-color:rgba(242,234,219,.45);color:#f2eadb}
@media (max-width:700px){
  .card-zoom img{max-height:62vh}
  .card-zoom .eye-chip{font-size:.875rem;padding:.375rem .75rem;min-height:30px}
}

/* ---- the significator, laid at the corner of the cloth --------------------------------------
   Not a slot and not in the geometry: the spread's own positions are computed as percentages of
   the cloth, and adding a fourteenth to a thirteen card layout would move every one of them. This
   sits outside that, small, at the edge, present rather than dealt. */
.sig-slot{position:absolute;left:.5rem;bottom:.5rem;width:8.5%;min-width:38px;max-width:58px;
  display:flex;flex-direction:column;align-items:center;gap:.25rem;opacity:.9;cursor:zoom-in;
  transition:opacity .2s ease,transform .2s ease}
.sig-slot:hover,.sig-slot:focus-visible{opacity:1;transform:translateY(-2px)}
.sig-slot:focus-visible{outline:2px solid var(--brick);outline-offset:3px}
.sig-slot img{width:100%;height:auto;border-radius:3px;display:block;
  box-shadow:0 1px 6px rgba(26,20,22,.22);border:1px solid var(--rule)}
.sig-slot .cap{position:static;font-family:"IBM Plex Mono",monospace;font-size:.75rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);line-height:1}
@media (max-width:760px){.sig-slot{width:11%;min-width:32px}}

/* ---- and on the birth page, as the third result --------------------------------------------- */
.result.sig .fact{text-transform:none;letter-spacing:.06em}
/* three results in a two column grid left a rule-coloured hole where the fourth would be */
.results .result:nth-child(3):last-child{grid-column:1/-1}
@media (max-width:640px){.results .result:nth-child(3):last-child{grid-column:auto}}


/* ---- the card's own line, promoted ------------------------------------------------------------
   Every card carries one: 78 of 78, five words on average, and no two cards share one, which is
   the test a keyword row fails. It was set smaller and greyer than the prose under it, so the most
   digestible thing on the page was the least visible thing on it. It is the line you read after the
   name now: same voice, one step up in size, full ink, and air under it before the prose starts. */
.pos-gist{font-size:1.0625rem;color:var(--ink);margin:.25rem 0 .75rem}
@media (max-width:700px){ .pos-gist{font-size:1.0625rem} }

/* ---- what the flow test found -----------------------------------------------------------------

   1. The deck bar faded and kept its space. Once a card is taken the fan collapses to nothing, but
   the shuffle and cut controls above it only went to opacity 0, so 106px of invisible bar sat
   between the spread's name and the card, at the exact moment the card is the only thing that
   matters. It collapses now, a beat after it fades. */
.deck-bar{max-height:14rem}
.stage.turning .deck-bar,.stage.big.turning .deck-bar{
  max-height:0;padding-top:0;padding-bottom:0;margin-bottom:0;border-bottom-color:transparent;overflow:hidden;
  transition:opacity .3s ease,max-height .4s ease .12s,padding .4s ease .12s,margin .4s ease .12s}

/* 2. The card count sat on the ruler. Both are pinned to the same top and both run to 6% of the
   band, so "40 OF 78" printed over the right-hand ticks. The ruler stops short of it now. */
.fan-ruler{right:calc(6% + 4.6rem)}

/* 3. Every secondary control was a 27 to 30px tall target on a phone. Measured on the table:
   shuffle and cut 30px, change spread 28px, start over 28px, the header's night and menu 27px,
   draw another 28px. 44px is the size a thumb actually hits. The controls keep their drawn size,
   which is tuned, and gain the missing height as an invisible hit area centred on them, so nothing
   moves and everything is reachable. Only on touch, where it matters. */
@media (pointer:coarse){
  .deck-act,.linkish,.pill,.hint .linkish,.after .btn.ghost,.theme-btn,.wordmark{position:relative}
  .deck-act::before,.linkish::before,.pill::before,.after .btn.ghost::before,.theme-btn::before,.wordmark::before{
    content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%);
    z-index:0}
  .deck-act > *,.linkish > *,.pill > *{position:relative;z-index:1}
}

/* ---- position captions on a phone -------------------------------------------------------------
   The caption box is sized off the card, and on a phone the Celtic Cross draws each card at 39px
   and the horseshoe at 51px. "THE PEOPLE AROUND IT" ran to four lines in a 51px box, broke
   mid-word, and landed on the card below it; six of the horseshoe's seven captions were doing it.
   The box is a fixed width here rather than a share of a card that has become tiny, and words are
   not allowed to break. The horseshoe also gained the short labels the Celtic Cross already had. */
@media (max-width:760px){
  /* the two rules that actually own this: the caption is card width plus 16px, with break-word on,
     which is what chopped words in half. Same specificity, after them. */
  #stage .cloth .cslot[data-cap="below"] .cap,
  #stage .cloth .cslot[data-cap="above"] .cap,
  #stage .cloth .idle-slot[data-cap="below"] .cap{
    min-width:70px;overflow-wrap:normal;word-break:keep-all;hyphens:none}
  #stage .cloth .idle-slot .cap,#stage .cloth .cslot:not(.filled) .cap,
  #stage .cloth .cslot .cap{font-size:.75rem;letter-spacing:.06em;line-height:1.2;margin-top:.375rem}
}

/* ---- the landing page's live line -------------------------------------------------------------
   It was a sentence set in uppercase mono at .6rem with .16em tracking, which is a style for three
   words and this is now sixteen. On a phone it ran to three shouted lines. Sentence case, a little
   larger, tracking back to normal reading: it is a thing to read once, not a label. */
.today-line{text-transform:none;letter-spacing:0;font-size:.75rem;line-height:1.6;max-width:30rem;margin-left:auto;margin-right:auto}
@media (max-width:600px){.today-line{font-size:.75rem;letter-spacing:0}}

/* the birth page ended on its last result and offered nothing to do. */
.result.birth-go{display:flex;flex-direction:column;justify-content:center}
.result.birth-go .btn{display:inline-block;text-decoration:none;margin-top:.375rem}
.result.birth-go p{margin:0}

/* ---- three controls, three weights ------------------------------------------------------------
   Change spread, Shuffle and Cut the deck were drawn identically, so the table offered three equal
   controls and none of them was the thing to do. The thing to do is take a card off the fan, which
   is not a button at all and should stay the loudest object on the screen. Below it, the two acts
   that change the deck in front of you keep their weight. Change spread leaves this table for
   another one, it belongs to the spread's name rather than to the deck, and it is quieter than
   both. It keeps the shape it was given when it was promoted out of being a footnote. */
.stage-why .linkish,#changeSpread{
  background:transparent;border-color:var(--rule);color:var(--ink-2)}
.stage-why .linkish:hover,#changeSpread:hover{
  background:transparent;border-color:var(--ink-3);color:var(--ink)}

/* ---- the daily card opt-in, in the keep gate ---------------------------------------------------
   A tick box rather than a pre-ticked one, and separate from the address field above it, because
   giving an address to have this reading sent is not the same act as joining a list. Only a ticked
   box puts anybody on one. */
.gate-daily{display:flex;flex-wrap:wrap;align-items:flex-start;gap:.5rem;
  margin:1rem 0 0;cursor:pointer;width:100%;max-width:26rem}
.gate .gate-daily input[type=checkbox]{flex:0 0 auto;width:1.05rem;height:1.05rem;min-width:0;
  margin:.25rem 0 0;accent-color:var(--brick);cursor:pointer}
.gate-daily > span:not(.hint){flex:1 1 10rem;min-width:0;font-family:"Newsreader",Georgia,serif;
  font-size:.9375rem;line-height:1.5;color:var(--ink)}
.gate .gate-daily .hint{flex:1 1 100%;margin:0 0 0 1.5rem;font-size:.75rem;letter-spacing:.02em;
  color:var(--ink-3);line-height:1.5}

/* ---------- v26: the pages that say no, the rulers table, the Sun today ---------- */
.route-intro .intro h2{font-size:1.3125rem;margin:1.75rem 0 .5rem}
.route-intro .intro p{color:var(--ink-2);line-height:1.6;margin:0 0 1rem}
.route-intro .intro .answer{color:var(--ink)}
.route-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:1.5rem 0 1rem}
.route-table{width:100%;border-collapse:collapse;font-size:.9375rem}
.route-table th{text-align:left;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;font-weight:500;color:var(--ink-3);padding:.5rem .75rem .5rem 0;border-bottom:1px solid var(--rule);white-space:nowrap}
.route-table td{padding:.5rem .75rem .5rem 0;border-bottom:1px solid var(--rule);vertical-align:top;color:var(--ink-2);line-height:1.35}
.route-table td b{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:500;color:var(--ink)}
.route-table td a{color:inherit}
.route-table .mono{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.02em;white-space:nowrap;color:var(--ink-3)}
.route-table tr.now td{color:var(--ink)}
.route-table tr.now td:first-child{box-shadow:inset 3px 0 0 var(--sun);padding-left:.75rem}
.route-table tr.now .mono{color:var(--sun-text)}
.rule-block{margin:1.25rem 0;padding:1rem 1rem 1rem;border:1px solid var(--rule);border-radius:6px}
.route-intro .intro .rule-block h2{margin:0 0 .25rem;font-size:1.1875rem}
.route-intro .intro .rule-block .trigger{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);margin:0 0 .75rem;line-height:1.6}
.route-intro .intro .rule-block .offer{margin:.5rem 0 0}
.rule-block blockquote{margin:.375rem 0;padding:.125rem 0 .125rem 1rem;border-left:2px solid var(--rule);font-style:italic;color:var(--ink);line-height:1.5}
.rule-block .offer{margin:.5rem 0 0;color:var(--ink-2)}
.kinds{display:grid;grid-template-columns:repeat(auto-fit,minmax(12.5rem,1fr));gap:1rem;margin:1.25rem 0 .375rem}
.kinds>div{border:1px solid var(--rule);border-radius:6px;padding:1rem 1rem}
.kinds .label{display:block;margin-bottom:.375rem}
.kinds p{margin:0;font-size:.9375rem}
.today-answer{font-size:1.1875rem}
.today-stamp{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--rule)}
@media (max-width:760px){.route-table{font-size:.8125rem}.route-table th,.route-table td{padding-right:.375rem}.route-table .mono{font-size:.75rem}.route-table .ph{display:none}.route-table th{white-space:normal}.route-table tr.now td:first-child{padding-left:.5rem}}

/* the keep gate: one field, one checkbox line, one action row. The hints were three sizes of type in
   four places; now there is one, next to the button, and it says what this deployment does. */
.gate form{gap:.75rem}
.gate-email{display:grid;gap:.375rem;width:100%;max-width:26rem}
.gate .gate-daily{margin:0;align-items:center;gap:.5rem;max-width:26rem}
.gate .gate-daily input[type=checkbox]{margin:0}
.gate-daily > span:not(.hint){font-size:.9375rem;line-height:1.35}
.gate-act{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;margin-top:.25rem}
.gate-act .hint{font-size:.75rem;letter-spacing:.06em;line-height:1.5;max-width:20rem;color:var(--ink-3)}
.gate-act .hint:empty{display:none}
/* the kept page: a reading list is text, and text has a measure */
.kept #keptList,.kept .kept-account,.kept .kept-month{max-width:44rem}
.kept .kept-head b{font-size:1.3125rem}
.kept-body .reading{max-width:40rem}
.kept-body .reading .pos-read,.kept-body .reading p{line-height:1.6}

/* flights and the growing table move by transform alone (parts_flow.js, fly/flyPick/growTable) */
.flyer{position:absolute;transition-property:transform,box-shadow;will-change:transform;transform-origin:50% 50%}
.stage.noanim .tabletop,.stage.noanim .fan-band,.stage.noanim .cloth,.stage.noanim .cslot,.stage.noanim .stage-hints,.stage.noanim .deck-bar{transition:none !important}
/* THE LANDING. The deck bar collapses when the table turns (v25), and it was not in the no-animation
   scope, so the final layout was measured with the bar still open: the flyer landed about ninety
   pixels below the slot, over the cloth's lower edge, and the card then snapped up into place. That
   was the "card cut off at the bottom". The bar is measured collapsed now, and it collapses on the
   same curve and clock as the cloth and the tabletop, so the three move as one. */
.stage.turning .deck-bar,.stage.big.turning .deck-bar{transition:opacity .3s ease,max-height .6s cubic-bezier(.2,.7,.2,1),padding .6s cubic-bezier(.2,.7,.2,1),margin .6s cubic-bezier(.2,.7,.2,1)}
.tabletop .cloth,.stage.turning .tabletop .cloth{transition:none;transform-origin:50% 0;will-change:transform}
.tabletop{transition:none}
.stage.turning .fan-band{position:absolute;left:0;right:0;top:0;z-index:2;pointer-events:none}
/* with the deck out of the flow the cloth would be auto-placed into the collapsed first row; it is pinned to its own */
.tabletop .fan-band{grid-row:1}
.tabletop .cloth{grid-row:2}
@media (max-width:760px){.tabletop .cloth,.stage.turning .tabletop .cloth{transition:none}}

/* the fan runs past the frame on both sides, as a deck longer than the table would; a hard clip
   read as a bug, so the ends fade instead */
.fan-band{-webkit-mask-image:linear-gradient(to right,transparent 0,#000 7%,#000 93%,transparent 100%);mask-image:linear-gradient(to right,transparent 0,#000 7%,#000 93%,transparent 100%)}
.stage.turning .fan-band{-webkit-mask-image:none;mask-image:none}
/* the shuffle and the cut (parts_wheel.js, riffleAnim and cutAnim) */
.deck-wrap .deck-half{will-change:transform;backface-visibility:visible}
.deck-wrap .riff{position:absolute;height:2.2%;min-height:2px;border-radius:3px;background:var(--wheel-card-weave);border:1px solid var(--wheel-card-line);box-sizing:border-box;opacity:0;pointer-events:none;z-index:4;transform:translate(-50%,-50%)}
.deck-wrap.riffling .deck,.deck-wrap.cutting .deck{animation:none}

/* the reading screen, per READING-SCREEN.md: keys under the name, the fold in Chang's format, the day strip, the next step */
.pos-keys{display:flex;flex-wrap:wrap;gap:.375rem;margin:.125rem 0 .75rem}
.pos-head.solo+.pos-keys{margin-top:.25rem}
.eye-chip.key{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;padding:.25rem .5rem;min-height:26px;border-radius:3px;border-color:var(--rule);color:var(--ink-2);background:transparent}
.eye-chip.key:hover{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.eye-chip.key.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.rf-decan dl{margin:.375rem 0 0;display:grid;gap:.25rem}
.rf-decan dl>div{display:grid;grid-template-columns:8.5rem minmax(0,1fr);gap:.375rem 1rem;align-items:baseline}
.rf-decan dt{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.rf-decan dd{margin:0;font-size:.9375rem;color:var(--ink-2);line-height:1.5}
.rf-decan dd a{color:inherit}
.rf-today,.rf-refusal{margin-top:1rem}
.rf-refusal a{color:inherit}
@media (max-width:600px){.rf-decan dl>div{grid-template-columns:1fr;gap:.125rem}}
.day-strip{display:flex;justify-content:space-between;align-items:flex-end;gap:1rem;flex-wrap:wrap;margin:0 0 1.25rem;padding:0 0 1rem;border-bottom:1px solid var(--rule)}
.day-strip .ds-left{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap}
.day-strip .ds-left b.display{font-weight:400;font-size:1.3125rem}
.day-strip .fact{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
/* the week sits under the date, flush left with it, whether the strip is on one line or two */
.day-strip .ds-right{display:flex;flex-direction:column;align-items:flex-start;gap:.5rem}
.day-strip .week{display:flex;gap:.75rem}
.day-strip .wd{display:flex;flex-direction:column;align-items:center;gap:.25rem}
.day-strip .wd i{font-style:normal;font-family:"IBM Plex Mono",monospace;font-size:.75rem;color:var(--ink-3)}
.day-strip .wd b{width:7px;height:7px;border-radius:50%;border:1px solid var(--ink-3);background:transparent}
.day-strip .wd.is-done b{background:var(--ink-3)}
.day-strip .wd.is-today b{width:9px;height:9px;background:var(--ink);border-color:var(--ink)}
.next-step{margin-top:2rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
.next-step .label{display:block;margin-bottom:.5rem}
.next-step .qbox-next{margin:0 0 1rem;max-width:40rem}
.next-step .after{margin-top:.25rem}
/* the birth page, READING-SCREEN.md section 7: two results, one line under the decan, the time behind a link */
.result .note.saved{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);margin-top:1rem}
.result .fact{letter-spacing:.06em;font-size:.75rem}
#birthForm #tob.hidden{display:none}

/* the picker in two groups: the three free spreads first, on a verdigris rule; the ten of the full
   table after them, each with its length. Same markup in the chooser and in "Lay it another way". */
.picker .picker-title{margin-bottom:1rem}
.picker .picks-label{margin-top:1rem}
.picker .picks.free .pick{border-top:2px solid var(--verdigris)}
.picker .picks.free{margin-bottom:.25rem}

/* THE DECK IN THREE DIMENSIONS. The tabletop has a vanishing point a little above its centre, the
   stack has thickness (each card under the top one a hair further back), the riffle bends its halves
   on their near edge, and the three piles of a cut lift off the cloth with a shadow that grows with
   their height. All of it is transforms on clones of the stack; nothing is laid out per frame. */
.tabletop{perspective:1600px;perspective-origin:50% 30%}
.deck-wrap,.deck-wrap .deck{transform-style:preserve-3d}
.deck-wrap .dk{backface-visibility:hidden}
.deck-wrap .dk:not(.top){transform:translate(calc((var(--i) - var(--n) + 1) * 1.5px),calc((var(--n) - 1 - var(--i)) * 1.5px)) translateZ(calc((var(--i) - var(--n) + 1) * 1.2px)) rotate(calc((var(--i) - (var(--n) - 1) / 2) * 1.4deg))}
.deck-wrap .deck-half{will-change:transform;backface-visibility:visible;box-shadow:0 18px 30px rgba(26,20,22,.22)}
.deck-wrap .pile{pointer-events:auto;cursor:pointer;box-shadow:0 26px 40px rgba(26,20,22,.26),0 4px 8px rgba(26,20,22,.12);transition:box-shadow .3s ease,filter .3s ease;outline:none}
.deck-wrap .pile:hover,.deck-wrap .pile:focus-visible{filter:brightness(1.04);box-shadow:0 34px 52px rgba(26,20,22,.3),0 4px 8px rgba(26,20,22,.12)}
.deck-wrap .pile::after{content:"";position:absolute;inset:-14%;border-radius:10px}
#stage.cutting .deck-wrap{pointer-events:auto}
.deck-act.hidden{display:none}
.deck-bar-why{display:none}
#stage.cutting .deck-bar-why{display:inline}
@media (prefers-reduced-motion:reduce){ .tabletop{perspective:none} }

/* the ask of the cut, on the table under the piles */
.deck-wrap .cut-cap{position:absolute;left:50%;bottom:4%;transform:translateX(-50%);text-align:center;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2);line-height:1.8;opacity:0;transition:opacity .4s ease;pointer-events:auto;white-space:nowrap}
.deck-wrap .cut-cap.on{opacity:1}
.deck-wrap .cut-cap b{font-weight:500;color:var(--ink)}
.deck-wrap .cut-cap .linkish{font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}
@media (max-width:640px){ .deck-wrap .cut-cap{font-size:.75rem;white-space:normal;width:90%} }
#stage.cutting .fan-ruler,#stage.cutting .fan-count{opacity:0;transition:opacity .3s ease}
@media (max-width:640px){ .deck-wrap .cut-cap{bottom:2%;line-height:1.6} }
/* on a phone the cut's line lives in the step line above the table */
@media (max-width:640px){ #stage.cutting .stage-step b{color:var(--ink);font-weight:500} #stage.cutting .stage-step .linkish{font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;margin-top:.25rem} }

/* =========================================================
   v27 : the table, taken from the prototype (proto/b2-space.html) and put on paper.

   The table was a fan of seventy-eight drawn in SVG, a riffle, three piles and a cut. It is one
   squared deck now, sealed on the cloth. The hero's plates fly into it. Tap it and it waits at a
   crossroads: a card, or a spread. A card fans the whole deck across the table and you take one.
   A spread lays its places above the deck and fans it into a hand you take from, place by place,
   then the places turn in order with a moment on each. Everything below is that, and nothing
   here touches the reading except the cloth beside it, which is the same cloth so the captions
   never clip.
   ========================================================= */
:root{
  --back-tile:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2720%27%20height%3D%2720%27%20viewBox%3D%270%200%2020%2020%27%3E%3Crect%20width%3D%2720%27%20height%3D%2720%27%20fill%3D%27%235f8a84%27%2F%3E%3Cdefs%3E%3Cg%20id%3D%22r%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%23e4efec%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%23e4efec%22%3E%3Cellipse%20cx%3D%225%22%20cy%3D%222.9%22%20rx%3D%221.35%22%20ry%3D%221.02%22%2F%3E%3Cellipse%20cx%3D%227.05%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%2872%207.05%204.42%29%22%2F%3E%3Cellipse%20cx%3D%226.27%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28144%206.27%206.85%29%22%2F%3E%3Cellipse%20cx%3D%223.73%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28216%203.73%206.85%29%22%2F%3E%3Cellipse%20cx%3D%222.95%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28288%202.95%204.42%29%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%221.28%22%20fill%3D%22%235f8a84%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%22.58%22%20fill%3D%22%23e4efec%22%2F%3E%3C%2Fg%3E%3Cg%20id%3D%22l%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%23e4efec%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%23e4efec%22%3E%3Cpath%20d%3D%22M5%201.55C5.95%203.15%206.1%204.75%205.45%206.15L4.55%206.15C3.9%204.75%204.05%203.15%205%201.55Z%22%2F%3E%3Cpath%20d%3D%22M2.35%204.15C3.05%203.55%203.85%203.75%204.45%204.7C4.75%205.2%204.8%205.75%204.6%206.25L3.85%206.35C2.9%205.95%202.35%205.2%202.35%204.15Z%22%2F%3E%3Cpath%20d%3D%22M7.65%204.15C7.65%205.2%207.1%205.95%206.15%206.35L5.4%206.25C5.2%205.75%205.25%205.2%205.55%204.7C6.15%203.75%206.95%203.55%207.65%204.15Z%22%2F%3E%3Crect%20x%3D%224.66%22%20y%3D%226.1%22%20width%3D%22.68%22%20height%3D%221.85%22%20rx%3D%22.3%22%2F%3E%3Cellipse%20cx%3D%225%22%20cy%3D%228.3%22%20rx%3D%221.7%22%20ry%3D%22.46%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fdefs%3E%3Cuse%20href%3D%27%23r%27%20x%3D%270%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%2710%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%270%27%20y%3D%2710%27%2F%3E%3Cuse%20href%3D%27%23r%27%20x%3D%2710%27%20y%3D%2710%27%2F%3E%3C%2Fsvg%3E");
  --dw:100px;                /* the width of a card in the deck and the hand */
}
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]){ --back-tile:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2720%27%20height%3D%2720%27%20viewBox%3D%270%200%2020%2020%27%3E%3Crect%20width%3D%2720%27%20height%3D%2720%27%20fill%3D%27%232f4a47%27%2F%3E%3Cdefs%3E%3Cg%20id%3D%22r%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cellipse%20cx%3D%225%22%20cy%3D%222.9%22%20rx%3D%221.35%22%20ry%3D%221.02%22%2F%3E%3Cellipse%20cx%3D%227.05%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%2872%207.05%204.42%29%22%2F%3E%3Cellipse%20cx%3D%226.27%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28144%206.27%206.85%29%22%2F%3E%3Cellipse%20cx%3D%223.73%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28216%203.73%206.85%29%22%2F%3E%3Cellipse%20cx%3D%222.95%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28288%202.95%204.42%29%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%221.28%22%20fill%3D%22%232f4a47%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%22.58%22%20fill%3D%22%238fb3ad%22%2F%3E%3C%2Fg%3E%3Cg%20id%3D%22l%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cpath%20d%3D%22M5%201.55C5.95%203.15%206.1%204.75%205.45%206.15L4.55%206.15C3.9%204.75%204.05%203.15%205%201.55Z%22%2F%3E%3Cpath%20d%3D%22M2.35%204.15C3.05%203.55%203.85%203.75%204.45%204.7C4.75%205.2%204.8%205.75%204.6%206.25L3.85%206.35C2.9%205.95%202.35%205.2%202.35%204.15Z%22%2F%3E%3Cpath%20d%3D%22M7.65%204.15C7.65%205.2%207.1%205.95%206.15%206.35L5.4%206.25C5.2%205.75%205.25%205.2%205.55%204.7C6.15%203.75%206.95%203.55%207.65%204.15Z%22%2F%3E%3Crect%20x%3D%224.66%22%20y%3D%226.1%22%20width%3D%22.68%22%20height%3D%221.85%22%20rx%3D%22.3%22%2F%3E%3Cellipse%20cx%3D%225%22%20cy%3D%228.3%22%20rx%3D%221.7%22%20ry%3D%22.46%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fdefs%3E%3Cuse%20href%3D%27%23r%27%20x%3D%270%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%2710%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%270%27%20y%3D%2710%27%2F%3E%3Cuse%20href%3D%27%23r%27%20x%3D%2710%27%20y%3D%2710%27%2F%3E%3C%2Fsvg%3E"); } }
:root[data-theme="dark"]{ --back-tile:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2720%27%20height%3D%2720%27%20viewBox%3D%270%200%2020%2020%27%3E%3Crect%20width%3D%2720%27%20height%3D%2720%27%20fill%3D%27%232f4a47%27%2F%3E%3Cdefs%3E%3Cg%20id%3D%22r%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cellipse%20cx%3D%225%22%20cy%3D%222.9%22%20rx%3D%221.35%22%20ry%3D%221.02%22%2F%3E%3Cellipse%20cx%3D%227.05%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%2872%207.05%204.42%29%22%2F%3E%3Cellipse%20cx%3D%226.27%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28144%206.27%206.85%29%22%2F%3E%3Cellipse%20cx%3D%223.73%22%20cy%3D%226.85%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28216%203.73%206.85%29%22%2F%3E%3Cellipse%20cx%3D%222.95%22%20cy%3D%224.42%22%20rx%3D%221.35%22%20ry%3D%221.02%22%20transform%3D%22rotate%28288%202.95%204.42%29%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%221.28%22%20fill%3D%22%232f4a47%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%22.58%22%20fill%3D%22%238fb3ad%22%2F%3E%3C%2Fg%3E%3Cg%20id%3D%22l%22%3E%3Crect%20x%3D%22.7%22%20y%3D%22.7%22%20width%3D%228.6%22%20height%3D%228.6%22%20rx%3D%22.7%22%20fill%3D%22none%22%20stroke%3D%22%238fb3ad%22%20stroke-width%3D%22.42%22%20opacity%3D%22.62%22%2F%3E%3Cg%20fill%3D%22%238fb3ad%22%3E%3Cpath%20d%3D%22M5%201.55C5.95%203.15%206.1%204.75%205.45%206.15L4.55%206.15C3.9%204.75%204.05%203.15%205%201.55Z%22%2F%3E%3Cpath%20d%3D%22M2.35%204.15C3.05%203.55%203.85%203.75%204.45%204.7C4.75%205.2%204.8%205.75%204.6%206.25L3.85%206.35C2.9%205.95%202.35%205.2%202.35%204.15Z%22%2F%3E%3Cpath%20d%3D%22M7.65%204.15C7.65%205.2%207.1%205.95%206.15%206.35L5.4%206.25C5.2%205.75%205.25%205.2%205.55%204.7C6.15%203.75%206.95%203.55%207.65%204.15Z%22%2F%3E%3Crect%20x%3D%224.66%22%20y%3D%226.1%22%20width%3D%22.68%22%20height%3D%221.85%22%20rx%3D%22.3%22%2F%3E%3Cellipse%20cx%3D%225%22%20cy%3D%228.3%22%20rx%3D%221.7%22%20ry%3D%22.46%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fdefs%3E%3Cuse%20href%3D%27%23r%27%20x%3D%270%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%2710%27%20y%3D%270%27%2F%3E%3Cuse%20href%3D%27%23l%27%20x%3D%270%27%20y%3D%2710%27%2F%3E%3Cuse%20href%3D%27%23r%27%20x%3D%2710%27%20y%3D%2710%27%2F%3E%3C%2Fsvg%3E"); }
@media (max-width:560px){ :root{ --dw:76px; } }
@media (min-width:900px){ :root{ --dw:108px; } }

/* ---------- the tabletop, one panel ---------- */
.stage{display:block;position:relative}
.tabletop{
  display:block;position:relative;overflow:clip visible;perspective:none;
  padding:1.25rem 0 0;background:var(--paper-2);border:1px solid var(--rule);border-radius:10px;
}
.tabletop > *{transition:none}
/* what each mode shows */
.tabletop .clothwrap,.tabletop .deckzone,.tabletop .handzone,.tabletop .xroads,.tabletop .takeline,.tabletop .handacts,.tabletop .handacts > *{display:none}
.tabletop[data-mode="idle"] .deckzone,.tabletop[data-mode="gather"] .deckzone,.tabletop[data-mode="crossroads"] .deckzone{display:flex}
.tabletop[data-mode="crossroads"] .xroads{display:flex}
.tabletop[data-mode="hand"] .handzone,.tabletop[data-mode="centre"] .handzone,.tabletop[data-mode="deal"] .handzone,.tabletop[data-mode="turn"] .handzone{display:flex}
.tabletop[data-mode="hand"] .takeline,.tabletop[data-mode="deal"] .takeline{display:block}
.tabletop[data-mode="deal"] .clothwrap,.tabletop[data-mode="turn"] .clothwrap,.tabletop[data-mode="whole"] .clothwrap{display:block}
.tabletop[data-mode="deal"] .handacts,.tabletop[data-mode="turn"] .handacts{display:flex}
.tabletop[data-mode="deal"] .handacts #dealRest{display:inline-block}
.tabletop[data-mode="turn"] .handacts #turnAll,.tabletop[data-mode="turn"] .handacts .turnhint{display:inline-block}
.tabletop[data-mode="turn"] .sealline{display:none}
.tabletop[data-mode="centre"] .sealline{visibility:hidden}
.tabletop[data-mode="read"]{display:none}
.hidden.hidden{display:none !important}

/* the deck zone: the squared deck, the crossroads under it, the seal line */
.deckzone{flex-direction:column;align-items:center;gap:1rem;padding:.5rem 1rem 1.25rem}
.deck-anchor{width:var(--dw);aspect-ratio:84/136;border-radius:6px;cursor:pointer;touch-action:none;position:relative;outline-offset:8px;
  box-shadow:0 16px 30px -6px rgba(26,20,22,.3),0 3px 6px rgba(26,20,22,.12)}
.deck-anchor::before{content:"";position:absolute;inset:-10px;border-radius:10px}
.xroads{gap:.5rem;flex-wrap:wrap;justify-content:center;margin-top:.25rem}
.xroads .btn.ghost{min-width:9.5rem;justify-content:center;text-align:center;padding:.5rem 1rem;min-height:40px}
.sealline{
  margin:0;text-align:center;line-height:1.8;max-width:36rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);
}
.sealline .seal-text{color:var(--ink-2)}
.sealline .seal-text::after{content:"";display:inline-block;width:.9em}
.sealline button{
  background:none;border:0;padding:0;font:inherit;letter-spacing:inherit;text-transform:inherit;color:var(--ink-3);
  text-decoration:underline;text-underline-offset:3px;cursor:pointer;margin:0 .5em;
}
.sealline button:hover{color:var(--brick)}
.sealline button[aria-pressed="true"]{color:var(--ink)}
.sealline [data-flash]{display:block;color:var(--brick)}
@media (max-width:560px){ .sealline{font-size:.75rem;letter-spacing:.06em;line-height:1.8} .xroads{width:100%} .xroads .btn.ghost{flex:1 1 40%;min-width:0} }

/* the hand zone: the take line, the box the hand is laid in, the two acts, the seal line */
.handzone{flex-direction:column;align-items:center;gap:.75rem;padding:.25rem 1rem 1rem;position:relative;z-index:6}
/* a drag across the hand is a drag, not a text selection */
.tabletop[data-mode="hand"],.tabletop[data-mode="deal"]{user-select:none;-webkit-user-select:none}
.takeline{margin:0;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink);text-align:center}
.fan-anchor{width:100%;pointer-events:none;min-height:40px;border-radius:10px;outline-offset:-2px}
.tabletop[data-mode="turn"] .fan-anchor,.tabletop[data-mode="centre"] .fan-anchor{pointer-events:none}
.handacts{align-items:center;justify-content:center;gap:.75rem 1rem;flex-wrap:wrap}
.handacts .btn{padding:.75rem 1.25rem;min-height:40px}
.handacts .btn.ghost{padding:.5rem 1rem;min-height:40px}
.turnhint{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
/* on a phone, while dealing, the hand is a strip pinned to the bottom of the window */
@media (max-width:560px){
  .tabletop[data-mode="deal"] .handzone,.tabletop[data-mode="turn"] .handzone{
    position:sticky;bottom:0;z-index:8;margin-top:.375rem;padding:.5rem .5rem .75rem;gap:.5rem;
    background:var(--paper-2);border-top:1px solid var(--rule);border-radius:0 0 10px 10px;
    box-shadow:0 -12px 24px -12px rgba(26,20,22,.18);
  }
  .tabletop[data-mode="deal"] .handacts .btn,.tabletop[data-mode="turn"] .handacts .btn{width:100%;justify-content:center;text-align:center}
  .handacts{width:100%}
  .takeline{font-size:.75rem}
}

/* ---------- the pile: seventy-eight backs, moved by transform alone ---------- */
.pile{position:absolute;inset:0;pointer-events:none;z-index:9}
.pile .origin{position:absolute;left:0;top:0;width:0;height:0;transform:translate(var(--px,0px),var(--py,0px));transform-style:preserve-3d}
.pile .origin.moving{transition:transform .55s cubic-bezier(.22,.8,.3,1)}
.tabletop[data-mode="idle"] .pile .origin,.tabletop[data-mode="crossroads"] .pile .origin{animation:deckbreathe 3.6s ease-in-out infinite}
@keyframes deckbreathe{0%,100%{scale:1}50%{scale:1.018}}
.pc{
  position:absolute;left:0;top:0;width:var(--dw);aspect-ratio:84/136;
  margin:calc(var(--dw) * -0.8095) 0 0 calc(var(--dw) * -0.5);
  transform-style:preserve-3d;will-change:transform;
}
.tabletop[data-mode="hand"] .pc,.tabletop[data-mode="deal"] .pc{pointer-events:auto;cursor:pointer;touch-action:pan-y}
.pc .pin{position:absolute;inset:0;transform-style:preserve-3d;transition:transform .7s cubic-bezier(.4,.1,.25,1)}
.pc.up .pin{transform:rotateY(180deg)}
.pc .pb,.pc .pf{position:absolute;inset:0;border-radius:6px;backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:hidden}
.pc .pf{transform:rotateY(180deg);background:var(--card-face);box-shadow:0 0 0 1px var(--rule),0 18px 40px rgba(26,20,22,.26)}
.pc .pf img{width:100%;height:100%;object-fit:cover;display:block}
.pc .pf img.rev{transform:rotate(180deg)}
.pc.up .pb{visibility:hidden}
.pc.up .pf::after{content:"";position:absolute;inset:-8px;border-radius:10px;pointer-events:none;animation:tglow 1.1s ease-out both}
/* the flights: the fan opening, the ranks closing, a card to its place, the fold home */
.pile.fanning .pc{transition:transform .5s cubic-bezier(.22,.8,.3,1)}
.pile.reflow .pc{transition:transform .45s cubic-bezier(.22,.8,.3,1)}
.pile.folding .pc{transition:transform .5s cubic-bezier(.22,.8,.3,1)}
.pile.fanned .pc{transition:transform .18s ease}
.pile.riffle .pc{transition:transform .28s cubic-bezier(.3,.7,.3,1)}
.pile.cut .pc{transition:transform .32s cubic-bezier(.3,.7,.3,1)}
.pile .pc.flying{transition:transform .42s cubic-bezier(.3,1.15,.4,1)}
.pile .pc.chosen{transition:transform .55s cubic-bezier(.22,.8,.3,1)}
.pile .pc.home{transition:transform .45s cubic-bezier(.22,.8,.3,1)}
.pile .pc{transition:transform .45s cubic-bezier(.22,.8,.3,1)}   /* the thickening after the gather */

/* ---------- one card back, everywhere on the table ----------
   The 1909 roses and lilies (parts_css_v24.css), drawn as a tile, on a paper edge. Inset by a
   pseudo element rather than a percentage padding, which is what broke the flyer's back before:
   an absolutely positioned card's percentage padding resolves against its container. */
.tback{position:absolute;inset:0;border-radius:6px;background:var(--paper);border:1px solid var(--wheel-card-line);overflow:hidden;
  box-shadow:0 1px 2px rgba(26,20,22,.18),0 10px 22px rgba(26,20,22,.16)}
.tback::before{content:"";position:absolute;inset:4%;border-radius:3px;background:var(--back-tile) 0 0/25% auto repeat}
.tback::after{content:"";position:absolute;inset:8%;border:1px solid var(--paper);border-radius:3px;opacity:.55}
/* the cards under the top one show only an edge: paper, with a faint line, not seventy-seven dark rules */
.pc .pb.tback{box-shadow:none;border-color:color-mix(in srgb,var(--wheel-card-line) 34%,var(--paper))}
.pc[data-k="77"] .pb.tback,.pile.fanned .pc .pb.tback,.pile.fanning .pc .pb.tback,.pile.reflow .pc .pb.tback,.pile .pc.flying .pb.tback,.pile .pc.chosen .pb.tback{border-color:var(--wheel-card-line)}
.pile.fanned .pc .pb.tback,.pile.fanning .pc .pb.tback,.pile.reflow .pc .pb.tback{box-shadow:-2px 0 3px rgba(26,20,22,.14)}
.pile .pc.flying .pb.tback,.pile .pc.chosen .pb.tback{box-shadow:0 14px 28px rgba(26,20,22,.28),0 3px 7px rgba(26,20,22,.18)}

/* ---------- the cloth: the places of the spread ---------- */
.clothwrap{padding:0 46px 22px;max-width:900px;margin:0 auto;position:relative;z-index:4}
@media (max-width:560px){ .clothwrap{padding:0 30px 16px} }
@media (min-width:900px){ .clothwrap{padding:4px 64px 26px} }
.tcloth{position:relative;width:100%;margin:0 auto}
.place{position:absolute;transform:translate(-50%,-50%);width:var(--cw);transition:opacity .35s ease}
.place.behind{z-index:1}.place.front{z-index:3}
.place .card{position:relative;width:100%;aspect-ratio:84/136;border-radius:6px;transform:rotate(var(--r,0deg));transform-origin:50% 50%;transform-style:preserve-3d;transition:transform .7s cubic-bezier(.4,.1,.25,1)}
.place .empty{position:absolute;inset:0;border:2px dashed var(--ink-2);border-radius:6px;background:rgba(26,20,22,.045);box-shadow:inset 0 1px 0 rgba(255,255,255,.35);transition:border-color .3s,background .3s}
.place .card .tback,.place .card .face{visibility:hidden}
.place.filled .empty{visibility:hidden}
.place.filled .card .tback{visibility:visible}
.place .face{position:absolute;inset:0;border-radius:6px;overflow:hidden;background:var(--card-face);box-shadow:0 0 0 1px var(--rule),0 10px 24px rgba(26,20,22,.22);
  transform:rotateY(180deg);backface-visibility:hidden;-webkit-backface-visibility:hidden}
.place .card .tback{backface-visibility:hidden;-webkit-backface-visibility:hidden}
.place .face img{width:100%;height:100%;object-fit:cover;display:block}
.place .face.rev img{transform:rotate(180deg)}
.place.turned .card{transform:rotate(var(--r,0deg)) rotateY(180deg)}
.place.turned .card .face{visibility:visible}
.place.turned .card .tback{visibility:hidden;transition:visibility 0s .35s}
.place.turned .card::after{content:"";position:absolute;inset:-7px;border-radius:10px;pointer-events:none;animation:tglow 1.1s ease-out both;transform:rotateY(180deg)}
@keyframes tglow{0%{box-shadow:0 0 0 0 rgba(201,138,26,0)}30%{box-shadow:0 0 30px 9px rgba(201,138,26,.45)}100%{box-shadow:0 0 0 0 rgba(201,138,26,0)}}
.place.landed .card{animation:tsettle .5s cubic-bezier(.2,.9,.28,1) both}
@keyframes tsettle{0%{transform:rotate(var(--r,0deg)) scale(1.05) translateY(-4px)}55%{transform:rotate(var(--r,0deg)) scale(.985)}100%{transform:rotate(var(--r,0deg))}}
.place .num{
  position:absolute;left:-.5rem;top:-.5rem;z-index:4;width:1.25rem;height:1.25rem;border-radius:50%;
  background:var(--paper);border:1px solid var(--ink-3);display:flex;align-items:center;justify-content:center;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;font-weight:500;color:var(--ink-2);letter-spacing:0;transition:all .3s;
}
.place.turned .num{opacity:0;visibility:hidden;transition:opacity .3s,visibility 0s .3s}
.place.up-next .num,.place.incoming .num{background:var(--brick);border-color:var(--brick);color:#fff}
.place .cap{
  position:absolute;top:calc(100% + 7px);left:50%;transform:translateX(-50%);z-index:3;
  width:100%;min-width:64px;text-align:center;pointer-events:none;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1.35;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);transition:color .3s;
}
.place.cap-above .cap{top:auto;bottom:calc(100% + 7px)}
.place.cap-right .cap{top:50%;left:calc(100% + 20px);transform:translateY(-50%);width:76px;min-width:0;text-align:left}
.place.cap-left .cap{top:50%;left:auto;right:calc(100% + 20px);transform:translateY(-50%);width:76px;min-width:0;text-align:right}
.place.cap-none .cap{display:none}
.place[style*="--r"] .cap{top:calc(100% + 16px)}
.place.up-next .cap,.place.incoming .cap{color:var(--brick)}
.place.turned .cap{color:var(--ink-2)}
.place.up-next .empty{border-color:var(--brick);border-style:solid;background:rgba(156,78,61,.07);animation:placepulse 1.6s ease-in-out infinite}
@keyframes placepulse{0%,100%{box-shadow:0 0 0 0 rgba(156,78,61,0)}50%{box-shadow:0 0 0 6px rgba(156,78,61,.16)}}
.place.incoming .empty{animation:none;border-color:var(--brick);border-style:solid;background:rgba(156,78,61,.09);box-shadow:0 0 0 3px rgba(156,78,61,.10)}
.place.filled.up-next .card{cursor:pointer}
.place.filled.up-next .tback{box-shadow:0 0 0 2px var(--brick),0 10px 22px rgba(26,20,22,.16);animation:backpulse 1.6s ease-in-out infinite}
@keyframes backpulse{0%,100%{box-shadow:0 0 0 2px var(--brick),0 0 0 0 rgba(156,78,61,0)}50%{box-shadow:0 0 0 2px var(--brick),0 0 0 6px rgba(156,78,61,.16)}}
.place.skypos .card{border:2px dashed var(--sun);border-radius:6px;background:rgba(207,150,44,.07);display:flex;align-items:center;justify-content:center}
.place.skypos .cap{color:var(--sun-text,#8a5f0e)}
.place .ring{width:34%;aspect-ratio:1;border-radius:50%;border:1.5px solid var(--sun);margin:auto;position:relative}
.place .ring::after{content:"";position:absolute;left:50%;top:-3px;width:5px;height:5px;margin-left:-2.5px;border-radius:50%;background:var(--sun)}
.place.filled.turned{cursor:pointer}
/* the sky, when it is on a card: a ring in the body's colour */
.place.sky.turned .face{box-shadow:0 0 0 2px var(--al,var(--sun)),0 0 18px color-mix(in srgb,var(--al,var(--sun)) 45%,transparent),0 10px 24px rgba(26,20,22,.22)}
.place .skymark{position:absolute;right:-.5rem;top:-.5rem;z-index:5;display:none;gap:.125rem;padding:.125rem .25rem;border-radius:999px;background:var(--paper);border:1px solid var(--al,var(--sun));font-family:"IBM Plex Mono",monospace;font-size:.75rem;line-height:1}
.place.sky.turned .skymark{display:inline-flex;animation:skyIn .5s ease both .3s}
.place .skymark i{font-style:normal;color:var(--al,var(--sun))}
@media (max-width:560px){ .place .num{width:1.1rem;height:1.1rem;font-size:.75rem;left:-.4rem;top:-.4rem} .place .cap{font-size:.75rem} }
@media (prefers-reduced-motion:reduce){
  .place.up-next .empty,.place.filled.up-next .tback{animation:none}
  .place.turned .card::after,.pc.up .pf::after{animation:none}
  .pile .origin{animation:none !important}
  .pile .pc,.pile.fanned .pc,.pile.fanning .pc,.pile.reflow .pc,.pile.folding .pc,.pile .pc.flying,.pile .pc.chosen,.pile .origin.moving{transition:none}
}
/* the whole-table question sits under the places, in the flow of the table */
.tabletop .whole-panel{position:relative;left:auto;bottom:auto;transform:none;margin:.25rem auto 1.25rem;max-width:min(100% - 2rem,44rem);z-index:6}

/* ---------- the head and the hints, on the new table ---------- */
.stage-hints{margin-top:.75rem}
.stage-hints .table-hint:empty{display:none}
/* the gather: the hero's plates fly into the deck on the table. The table paints over the hero,
   so the scattered plates are cut at its line rather than lying over the heading; while they fly
   the scatter is raised above it, because that is the one time they belong on the table. */
#stage{z-index:4}
.scatter.gathering{z-index:40}
.scatter .sc.flying{z-index:30}
.scatter.off{visibility:hidden}

/* ---------- the cloth beside the reading: the same cloth, face up ---------- */
.cloth-copy .clothwrap{padding:8px 34px 22px;max-width:none}
.cloth-copy .tcloth{max-width:100%}
.cloth-copy .place .cap{color:var(--ink-2)}
.cloth-copy .place.refinable .face{cursor:crosshair}
.cloth-copy .place .num{display:none}
@media (min-width:900px){
  .reveal:has(.cloth-copy .tcloth[data-n="5"]),
  .reveal:has(.cloth-copy .tcloth[data-n="6"]),
  .reveal:has(.cloth-copy .tcloth[data-n="7"]),
  .reveal:has(.cloth-copy .tcloth[data-n="9"]),
  .reveal:has(.cloth-copy .tcloth[data-n="10"]),
  .reveal:has(.cloth-copy .tcloth[data-n="12"]){grid-template-columns:minmax(0,1.42fr) minmax(0,1fr)}
  /* never taller than the screen: the width comes off, the aspect stays */
  .cloth-copy .clothwrap{max-width:min(100%,calc(80vh * 16 / var(--ah,11) + 68px))}
  .cloth-copy .clothwrap:has(.tcloth[data-n="1"]){max-width:min(100%,calc(74vh * 16 / var(--ah,17) + 68px))}
}
@media (max-width:899px){
  .cloth-copy .clothwrap:has(.tcloth[data-n="1"]){max-width:min(100%,360px);margin:0 auto}
  .cloth-copy .clothwrap:has(.tcloth[data-n="2"]),.cloth-copy .clothwrap:has(.tcloth[data-n="3"]){max-width:min(100%,560px);margin:0 auto}
}

/* ============================================================================
   v28: the table is the screen.
   Four things, all of them the same complaint from different angles.
   (1) The scattered cards in the hero ended in a hard horizontal cut, at the
       header line above and the table line below. Both read as a clipping bug
       rather than a deck lying under the page. They fade into the paper now.
       The mask is lifted while they fly into the deck, because a mask clips
       its children to the hero box and the deck is below it.
   (2) The hero was emptied by the gather and left as a screen of blank paper.
       The cards lie back down in it once the flight is over (parts_table.js).
   (3) The table was a panel with a card in the middle of it, inset further
       from the edge than every other section on the page. It runs the width
       of the screen now and has the height to sit at.
   (4) A panel with a tone and a border is a box. A table is a cloth: a weave
       too fine to read as texture, light falling where the deck is, the edges
       going dark, and the deck large enough to be the thing you reach for.
   ============================================================================ */

/* ---------- (1) the hero's cards, dissolving at both edges ---------- */
/* The fade is painted over the cards, not masked out of them. A mask on .scatter clips to that
   element's box, and the box is capped at 1440px and centred, so on any window wider than that it
   sliced four of the hero cards down a dead straight vertical line at 160px and 1600px. repeat-x
   does not lift it. Two bands of the paper colour, the full width of the hero, above the cards and
   below nothing else, do the same job at the top and bottom and cannot clip anything. */
#hero{position:relative}
#hero::before,#hero::after{
  content:"";position:absolute;left:0;right:0;height:132px;z-index:4;pointer-events:none;
}
#hero::before{top:0;background:linear-gradient(to bottom,var(--paper) 0,color-mix(in srgb,var(--paper) 72%,transparent) 42px,transparent 100%)}
#hero::after{bottom:0;height:142px;background:linear-gradient(to top,var(--paper) 0,color-mix(in srgb,var(--paper) 70%,transparent) 48px,transparent 100%)}
@media (max-width:900px){
  #hero::before{height:86px;background:linear-gradient(to bottom,var(--paper) 0,color-mix(in srgb,var(--paper) 72%,transparent) 26px,transparent 100%)}
  #hero::after{height:96px;background:linear-gradient(to top,var(--paper) 0,color-mix(in srgb,var(--paper) 70%,transparent) 30px,transparent 100%)}
}
/* while they fly into the deck they pass through those bands, so the bands step aside */
#hero:has(.scatter.gathering)::before,#hero:has(.scatter.gathering)::after{opacity:0}

/* ---------- (2) they lie back down after the flight ---------- */
.scatter.settling{animation:scSettle .95s ease both}
@keyframes scSettle{from{opacity:0}to{opacity:1}}

/* ---------- (3) the table runs the width of the screen ---------- */
/* the heading keeps the gutter every other section has; the cloth breaks out of it */
#stage .wrap{max-width:1280px}
/* full bleed once there is something on the table. Idle, the table holds a deck and three choices,
   and a screen-wide field around them is the emptiness that reads as broken rather than as space. */
.stage:has(.tabletop:not([data-mode="idle"])){width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw)}
.stage:has(.tabletop[data-mode="idle"]) .tabletop{border-radius:10px;border-left:1px solid var(--rule);border-right:1px solid var(--rule)}
.tabletop{border-radius:0;border-left:0;border-right:0;padding-top:0}

/* the height to sit at. The deck is centred in it; the seal line sits under the deck. */
.deckzone{justify-content:center;min-height:min(64vh,560px);padding:1.6rem clamp(1rem,4vw,3rem) 2rem;gap:1.5rem}
/* only where the hand IS the table: in deal and turn the hand sits under the places and must not
   push them off the screen */
.tabletop[data-mode="hand"] .handzone,.tabletop[data-mode="centre"] .handzone{min-height:min(58vh,520px);justify-content:center}
@media (max-width:560px){
  .deckzone{min-height:min(54vh,420px);padding:1.25rem 1rem 1.5rem}
  .tabletop[data-mode="hand"] .handzone,.tabletop[data-mode="centre"] .handzone{min-height:min(48vh,380px)}
}

/* the deck, large enough to be the thing you reach for */
:root{ --dw:112px; }
@media (min-width:560px){  :root{ --dw:132px; } }
@media (min-width:900px){  :root{ --dw:164px; } }
@media (min-width:1240px){ :root{ --dw:184px; } }
@media (min-width:1600px){ :root{ --dw:204px; } }
.deck-anchor{box-shadow:0 26px 46px -10px rgba(26,20,22,.34),0 5px 10px rgba(26,20,22,.14)}

/* ---------- (4) the cloth ---------- */
.tabletop{
  background:
    radial-gradient(58% 78% at 50% 44%, rgba(255,251,240,.72), rgba(255,251,240,0) 70%),
    repeating-linear-gradient(90deg, rgba(26,20,22,.030) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(26,20,22,.030) 0 1px, transparent 1px 4px),
    var(--paper-2);
  box-shadow:inset 0 1px 0 rgba(255,252,244,.5), inset 0 0 150px rgba(26,20,22,.12);
}
[data-theme="dark"] .tabletop{
  background:
    radial-gradient(58% 78% at 50% 44%, rgba(255,240,214,.07), rgba(255,240,214,0) 70%),
    repeating-linear-gradient(90deg, rgba(0,0,0,.16) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(0,0,0,.16) 0 1px, transparent 1px 4px),
    var(--paper-2);
  box-shadow:inset 0 1px 0 rgba(255,246,226,.05), inset 0 0 150px rgba(0,0,0,.42);
}

/* ---------- the choice, under the spread instead of in front of it ---------- */
/* the crossroads moved into the hand: the seventy-eight go out first and the other road is a
   line under them. The deck zone keeps its own (now empty) crossroads rule harmless. */
.tabletop[data-mode="hand"] .xroads{display:flex}
.tabletop[data-mode="hand"] .xroads .btn.ghost{min-width:0}
.handzone .xroads{margin-top:.125rem}

/* a link inside the sentence, not beside it: the seal line's standalone buttons carry side margin,
   which left a gap before the full stop when one sits mid-sentence */
.sealline .seal-text button{margin:0}

/* ---------- the hand is subordinate to the places once a spread is laid ----------
   The deck at rest, and the hand you take today's card from, are the table: they get the big
   card. Under a laid spread the hand is a strip you take from, and it was coming out at 161px
   against a 74px card on the cloth, so the thing you were holding was twice the thing you were
   building. That is what read as squished. */
.tabletop[data-mode="deal"]{--dw:clamp(70px,13vh,160px)}
.tabletop[data-mode="turn"],.tabletop[data-mode="whole"]{--dw:clamp(54px,8.6vh,94px)}

/* "Deal the rest" was the only button on the screen while the hand was out, which made the
   shortcut the call to action and the choosing look optional. It is the quiet way out now. */
.handacts #dealRest{
  background:none;border:0;padding:0;min-height:0;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);text-decoration:underline;text-underline-offset:3px;
}
.handacts #dealRest:hover{color:var(--brick);background:none}

/* ---------- the deck is the reader's, not yours ----------
   Will: imagine you are at a reading in real life. You are the querent. The deck is on the far
   side of the table, the reader holds it, and the cards come down toward you as they are laid. So
   on a desktop the hand sits above the cloth and the spread fills downward. The pile is absolutely
   positioned and layoutPile measures live rects, so order alone moves it. On a phone the hand
   stays at the bottom, where a thumb is. */


/* the hand's small print stays with the hand, tight under it, so it reads as the edge of the
   reader's side of the table rather than a block of text cutting the cloth in half. An absolute
   pull to the foot of the tabletop does not work here: .handzone is itself positioned, so it is
   the containing block, and the line lands at the bottom of the hand instead. */
@media (min-width:900px){
  .tabletop[data-mode="deal"] .handzone,.tabletop[data-mode="turn"] .handzone{gap:.5rem}
  .tabletop[data-mode="deal"] .handzone .sealline{margin-top:-.125rem}
}

/* ---------- choose, then the spread ----------
   While you are choosing there is no cloth on the table. The seventy-eight get the whole of it and
   each card you take goes face down on a stack, the way a reader takes them from you one at a
   time. When the last one is taken the hand folds away, the cloth appears, and the spread is laid
   from the stack (layFromStack in parts_table.js). Two activities, one screen each. */
.tabletop[data-mode="deal"] .clothwrap{display:none}
.tabletop[data-mode="lay"] .clothwrap{display:block}
.tabletop[data-mode="lay"] .handzone{display:flex}
.tabletop[data-mode="lay"] .takeline,.tabletop[data-mode="lay"] .handacts,
.tabletop[data-mode="lay"] .xroads,.tabletop[data-mode="lay"] .sealline,
.tabletop[data-mode="lay"] .stack-anchor{display:none}

/* the stack: a marked place under the hand, so the first card has somewhere to be going */
.stack-anchor{
  display:none;width:calc(var(--dw) * .6);aspect-ratio:84/136;border-radius:6px;margin:.375rem auto 1rem;
  border:1px dashed color-mix(in srgb,var(--rule) 78%,transparent);
}
/* a card that has been chosen is on the stack, not in the hand: it must not swallow the tap meant
   for the link underneath it, and it must not read as still takeable */
.pile .pc.flying{pointer-events:none}
.tabletop[data-mode="deal"] .stack-anchor{display:block}
.tabletop[data-mode="deal"]{--dw:clamp(74px,13.5vh,164px)}

/* the resolved card width, for dw() in parts_table.js */
.dw-probe{position:absolute;left:0;top:0;width:var(--dw);height:0;visibility:hidden;pointer-events:none}

/* ---------- the spread is chosen before anything touches the deck ----------
   Three on the table with the popular one first and thirteen a tap away. The idle table used to be
   a very large field with one card in it, about seven per cent covered; this is what fills it, and
   it is also the step the flow was missing: you pick what you are asking before you draw. */
.pickrow{display:none;flex-wrap:wrap;justify-content:center;align-items:stretch;gap:.5rem;margin-top:.25rem;max-width:46rem}
.tabletop[data-mode="idle"] .pickrow{display:flex}
.pick3{
  display:flex;flex-direction:column;gap:.25rem;align-items:flex-start;text-align:left;
  min-width:11rem;padding:.75rem 1rem;cursor:pointer;
  background:color-mix(in srgb,var(--paper) 78%,transparent);
  border:1px solid var(--rule);border-radius:10px;color:var(--ink);
  box-shadow:0 2px 0 rgba(26,20,22,.05);transition:border-color .18s,transform .18s,box-shadow .18s;
}
.pick3 b{font-family:"Newsreader",Georgia,serif;font-weight:500;font-size:1.0625rem;line-height:1.2}
.pick3 i{font-style:normal;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.pick3:hover{border-color:var(--brick);transform:translateY(-1px);box-shadow:0 6px 14px -6px rgba(26,20,22,.28)}
.pick3.taken i{color:var(--brick)}
.pickrow .pickall{align-self:center;margin-left:.25rem;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase}
@media (max-width:560px){
  .pickrow{gap:.5rem;width:100%}
  .pick3{flex:1 1 100%;min-width:0;padding:.5rem .75rem}
  .pick3 b{font-size:.9375rem}
}
/* the idle table is an invitation, not a stage: it is only as tall as what is on it */
.deckzone{min-height:0;padding:1.5rem clamp(1rem,4vw,3rem) 1.8rem;gap:1.25rem}
@media (min-width:900px){ .deckzone{padding:2rem clamp(1rem,4vw,3rem) 2.2rem} }

/* ---------- the ritual: three steps on one surface ----------
   It opens when the table comes into view, once a visit, and closes on Escape, on the backdrop,
   or on "Not now". The table stays visible behind it, dimmed, so the surface reads as something
   laid over the table rather than a page you were taken to. */
.ritual{position:fixed;inset:0;z-index:200;display:grid;place-items:center;padding:clamp(1rem,4vw,2.5rem);
  background:color-mix(in srgb,var(--ink) 46%,transparent);backdrop-filter:blur(3px);
  opacity:0;transition:opacity .24s ease}
.ritual.on{opacity:1}
.ritual-sheet{
  position:relative;width:min(100%,40rem);max-height:calc(100dvh - 3rem);overflow:auto;
  padding:clamp(1.5rem,3.2vw,2.4rem) clamp(1.2rem,3vw,2.4rem) clamp(1.4rem,3vw,2rem);
  background:
    radial-gradient(70% 60% at 50% 22%, rgba(255,251,240,.6), rgba(255,251,240,0) 70%),
    repeating-linear-gradient(90deg, rgba(26,20,22,.028) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(26,20,22,.028) 0 1px, transparent 1px 4px),
    var(--paper-2);
  border:1px solid var(--rule);border-radius:10px;
  box-shadow:0 40px 80px -24px rgba(26,20,22,.5), inset 0 1px 0 rgba(255,252,244,.5);
  transform:translateY(10px);transition:transform .3s cubic-bezier(.22,.8,.3,1);text-align:center}
.ritual.on .ritual-sheet{transform:none}
[data-theme="dark"] .ritual-sheet{background:
  radial-gradient(70% 60% at 50% 22%, rgba(255,240,214,.06), rgba(255,240,214,0) 70%),
  repeating-linear-gradient(90deg, rgba(0,0,0,.16) 0 1px, transparent 1px 4px),
  repeating-linear-gradient(0deg,  rgba(0,0,0,.16) 0 1px, transparent 1px 4px),
  var(--paper-2)}
.ritual-x{position:absolute;top:.7rem;right:.8rem;background:none;border:0;padding:.25rem .375rem;cursor:pointer;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.ritual-x:hover{color:var(--brick)}
.ritual-step{margin:0 0 .5rem;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.ritual-sheet h2{margin:0 0 .375rem;font-size:clamp(1.625rem,3vw,2rem);line-height:1.1}
.ritual-sub{margin:0 0 1.25rem;color:var(--ink-2);font-size:.9375rem}
.rpicks{display:flex;flex-direction:column;gap:.5rem;text-align:left}
.rpicks.all{display:grid;grid-template-columns:repeat(auto-fill,minmax(13rem,1fr));gap:.5rem}
.rpicks .pick3{min-width:0;width:100%}
.rmore{margin:1rem 0 0}
.rmore .linkish{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase}

/* the deck in the sheet: sixteen backs, enough to riffle and cut legibly */
.rdeck{position:relative;width:104px;aspect-ratio:84/136;margin:.375rem auto 1rem}
.rcard{position:absolute;inset:0;border-radius:6px;
  transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg));
  transition:transform .42s cubic-bezier(.3,.75,.3,1);
  box-shadow:0 1px 0 rgba(26,20,22,.06)}
.rcard:last-child{box-shadow:0 16px 30px -8px rgba(26,20,22,.34)}
.rdeck.riffle .rcard:nth-child(odd){transform:translate(calc(var(--i) * .6px - 26px), calc(var(--i) * -.7px - 5px)) rotate(-7deg)}
.rdeck.riffle .rcard:nth-child(even){transform:translate(calc(var(--i) * .6px + 26px), calc(var(--i) * -.7px + 3px)) rotate(7deg)}
.rdeck.cut .rcard:nth-child(-n+8){transform:translate(calc(var(--i) * .6px - 42px), calc(var(--i) * -.7px + 16px)) rotate(-4deg)}
.rdeck.cut .rcard:nth-child(n+9){transform:translate(calc(var(--i) * .6px + 42px), calc(var(--i) * -.7px - 16px)) rotate(4deg)}
@media (prefers-reduced-motion:reduce){ .rcard{transition:none} .ritual,.ritual-sheet{transition:none} }

.racts{display:flex;gap:.5rem;justify-content:center;flex-wrap:wrap}
.rgo{margin:1rem 0 .5rem}
.rgo .btn{min-width:12rem}
.rseal{margin:0;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
@media (max-width:560px){ .rdeck{width:92px} .racts .btn{flex:1 1 45%} }

/* the deck at step one is smaller: it is the object you just watched land, not the subject yet */
.ritual-body .rpicks{margin-top:.25rem}
#ritual .ritual-body > .rdeck:first-child{width:76px;margin:.125rem auto 1rem}
.ritual-sheet:has(.racts) .rdeck{width:104px;margin:.375rem auto 1rem}
@media (max-width:560px){ #ritual .ritual-body > .rdeck:first-child{width:66px;margin-bottom:.75rem} }

/* ---------- the table takes the screen ----------
   Coming out of a full-screen ritual into a 416px band with the hero above it and the spreads list
   below was the weakest moment in the flow. From the first draw to the last turn the table is the
   window: the cloth is the background, the page behind is locked, and nothing else is on screen. */
body.table-on{overflow:hidden}
#stage.full{
  position:fixed;inset:0;z-index:150;width:100vw;margin:0;
  display:block;
  padding:clamp(.6rem,2vh,1.4rem) 0 clamp(.6rem,2vh,1.4rem);
  /* centred while it fits, scrollable when it does not: on a phone a ten card spread is taller
     than the window and the page behind is locked, so the table has to carry its own scroll */
  overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  background:
    radial-gradient(58% 70% at 50% 46%, rgba(255,251,240,.72), rgba(255,251,240,0) 72%),
    repeating-linear-gradient(90deg, rgba(26,20,22,.030) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(26,20,22,.030) 0 1px, transparent 1px 4px),
    var(--paper-2);
  box-shadow:inset 0 0 180px rgba(26,20,22,.14);
  animation:tableIn .34s ease both;
}
@keyframes tableIn{from{opacity:0}to{opacity:1}}
[data-theme="dark"] #stage.full{
  background:
    radial-gradient(58% 70% at 50% 46%, rgba(255,240,214,.07), rgba(255,240,214,0) 72%),
    repeating-linear-gradient(90deg, rgba(0,0,0,.16) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(0,0,0,.16) 0 1px, transparent 1px 4px),
    var(--paper-2);
  box-shadow:inset 0 0 180px rgba(0,0,0,.45);
}
#stage.full .wrap{max-width:none;width:100%;padding:0;margin:0;min-height:100%;display:flex;flex-direction:column;justify-content:center}
#stage.full .tabletop{background:none;border:0;border-radius:0;box-shadow:none;padding:0}
#stage.full .tabletop::before{display:none}
/* the head is a line at the top of the table, not a page heading */
#stage.full .stage-head{text-align:center;margin:0 auto clamp(.4rem,1.4vh,1rem);padding:0 1rem;max-width:44rem}
#stage.full .stage-head .table-q{font-size:clamp(1.3125rem,2.4vw,1.625rem);margin:0 0 .125rem}
/* the reason the spread was laid, and the way to change your mind, stay on the screen: one small
   line under the count rather than a pill button outranking the instruction */
#stage.full .stage-head .stage-why{margin:.375rem auto 0;max-width:34rem;font-size:.75rem;color:var(--ink-3);line-height:1.5}
#stage.full .stage-head .stage-why .linkish{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase}
#stage.full .stage-head .label{font-size:.75rem}
#stage.full .stage-step{margin:.125rem 0 0;font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--brick)}
/* the way out is quiet and out of the way, not the loudest control on the screen */
#stage.full .stage-head .picker-open,#stage.full .stage-head .btn.ghost{
  position:fixed;top:.9rem;right:1rem;z-index:4;background:none;border:0;padding:.25rem .375rem;min-height:0;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
#stage.full .stage-head .btn.ghost:hover{color:var(--brick);background:none}

/* the stack says what it is for, so a dashed rectangle does not read as a missing card */
.stack-anchor{position:relative}
.stack-anchor::after{
  content:"YOURS";position:absolute;left:50%;top:calc(100% + .4rem);transform:translateX(-50%);
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;color:var(--ink-3);white-space:nowrap}

/* nothing else on the screen means nothing else: the site's own header and footer step out while
   the table has it, and the way back to a different spread sits where a close button would */
body.table-on > header,body.table-on > footer{display:none}
#stage.full .stage-head .btn.ghost{top:1rem;right:1.2rem}

/* the hand has the whole window now, so it is drawn at the size of a hand */
.tabletop[data-mode="deal"]{--dw:clamp(84px,17vh,196px)}

/* the stack matches whatever size the laid-out hand came out at */
.stack-anchor{width:var(--handcw,calc(var(--dw) * .6))}

/* the two ways of being handed the deck, and the count that says how many are left */
.viewswap{display:none;gap:.125rem;justify-content:center;margin:.125rem 0 .5rem}
.tabletop[data-mode="hand"] .viewswap,.tabletop[data-mode="deal"] .viewswap{display:flex}
.viewswap button{
  background:none;border:1px solid transparent;border-radius:999px;padding:.25rem .75rem;cursor:pointer;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.viewswap button[aria-pressed="true"]{border-color:var(--rule);color:var(--ink);background:color-mix(in srgb,var(--paper) 70%,transparent)}
.viewswap button:hover{color:var(--brick)}
.takeline .takecount{
  display:inline-block;margin-left:.5rem;padding:.125rem .5rem;border-radius:999px;
  background:var(--brick);color:var(--paper);font-weight:500;letter-spacing:.1em}

/* the rest of the deck has no business over the whole-table question. In "whole" the deck zone is
   hidden, so its anchor measures zero, layoutPile bails and the pile stays wherever it last was,
   which is on top of the panel. It is simply not on the table at that point. */
.tabletop[data-mode="turn"] .pile,.tabletop[data-mode="whole"] .pile,.tabletop[data-mode="read"] .pile{display:none}
.tabletop[data-mode="turn"] .fan-anchor{height:0 !important;min-height:0}
.tabletop[data-mode="turn"] .handzone{padding-top:0;gap:.5rem}

/* the two views are a control, not a caption: both read as buttons, the live one is filled */
.viewswap{gap:.25rem;margin:.375rem 0 .75rem}
.viewswap button{border-color:var(--rule);color:var(--ink-2);padding:.25rem .75rem;background:color-mix(in srgb,var(--paper) 45%,transparent)}
.viewswap button[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.viewswap button[aria-pressed="true"]:hover{color:var(--paper)}

/* the picker panel is gone: everything that opened it opens the ritual. Belt and braces in case a
   stale path still tries to show it, and the head's own lines stop colliding. */
.picker{display:none !important}
#stage.full .stage-head > *{position:relative}
#stage.full .stage-head .stage-step{margin:.25rem 0 .125rem}
#stage.full .stage-head .stage-why{margin-top:.5rem}

/* ---------- the deck looks like a deck ----------
   It was one card lying flat: no edges under it, so seventy-eight cards read as one, and it sat a
   thumb's width above the choices with nothing to separate them. Four card edges stacked under the
   top one, a real shadow beneath, and room between it and what you pick next. */
.deck-anchor{
  box-shadow:
    1.5px 2.5px 0 -1px var(--card-face), 1.5px 2.5px 0 0 color-mix(in srgb,var(--rule) 80%,transparent),
    3px 5px 0 -1px var(--card-face),     3px 5px 0 0 color-mix(in srgb,var(--rule) 70%,transparent),
    4.5px 7.5px 0 -1px var(--card-face), 4.5px 7.5px 0 0 color-mix(in srgb,var(--rule) 60%,transparent),
    6px 10px 0 -1px var(--card-face),    6px 10px 0 0 color-mix(in srgb,var(--rule) 50%,transparent),
    7.5px 12.5px 0 -1px var(--card-face),7.5px 12.5px 0 0 color-mix(in srgb,var(--rule) 42%,transparent),
    14px 34px 44px -14px rgba(26,20,22,.42),
    0 2px 4px rgba(26,20,22,.16);
  transition:transform .25s cubic-bezier(.22,.8,.3,1),box-shadow .25s ease;
}
.deck-anchor:hover{transform:translate(-2px,-4px)}
[data-theme="dark"] .deck-anchor{
  box-shadow:
    1.5px 2.5px 0 -1px var(--card-face), 1.5px 2.5px 0 0 rgba(0,0,0,.5),
    3px 5px 0 -1px var(--card-face),     3px 5px 0 0 rgba(0,0,0,.44),
    4.5px 7.5px 0 -1px var(--card-face), 4.5px 7.5px 0 0 rgba(0,0,0,.38),
    6px 10px 0 -1px var(--card-face),    6px 10px 0 0 rgba(0,0,0,.32),
    7.5px 12.5px 0 -1px var(--card-face),7.5px 12.5px 0 0 rgba(0,0,0,.26),
    14px 34px 44px -14px rgba(0,0,0,.6);
}
/* and it is not crowding the choices */
.deckzone{gap:2.5rem}
@media (min-width:900px){ .deckzone{gap:3rem;padding:2.6rem clamp(1rem,4vw,3rem) 2.4rem} }
@media (max-width:560px){ .deckzone{gap:1.75rem} }
.pickrow{margin-top:0}

/* ============================================================================
   THE READING: the spread on top, the answer next, the cards as evidence.
   It was a two-column grid with the spread stuck in a sticky column beside the
   text, which cost half the screen for the whole scroll and put the answer to
   the question at the very bottom of 1,500 words.
   ============================================================================ */
#reveal .reveal{grid-template-columns:minmax(0,1fr) !important;gap:clamp(1.6rem,3vw,2.6rem)}
#reveal .reveal .left{position:static !important;top:auto !important;width:100%}
#reveal .cloth-copy .clothwrap{max-width:min(100%,720px) !important;margin:0 auto}
@media (min-width:900px){ #reveal .cloth-copy .clothwrap{max-width:min(100%,860px) !important} }
#reveal .reveal .right{max-width:min(100%,46rem);margin:0 auto;width:100%}

/* the answer, in the reading's own voice, first */
.interp{margin:0 0 1.5rem;padding:0 0 1.5rem;border-bottom:1px solid var(--rule)}
.interp .label{display:block;margin-bottom:.5rem}
.interp p{margin:0 0 .75rem;font-size:1.0625rem;line-height:1.6}
.interp .lede-read{font-size:1.1875rem;line-height:1.6}
.interp .reading-carry-line{font-family:"Newsreader",Georgia,serif;font-style:italic;color:var(--ink);margin-top:1rem}
@media (min-width:900px){ .interp .lede-read{font-size:1.1875rem} }

/* the second reading, offered as more of the same rather than as a banner */
.offer{margin:0 0 1.75rem;padding:1rem 0 1rem 1rem;border-left:2px solid var(--brick)}
.offer .label{display:block;margin-bottom:.375rem;color:var(--brick)}
.offer p{margin:0;color:var(--ink-2);font-size:.9375rem;line-height:1.6}
.offer .offer-act{margin-top:.75rem}
.offer .linkish{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}

/* the card by card, labelled as the working rather than as the reading */
.evidence-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin:0 0 1rem;padding-bottom:.375rem;border-bottom:1px solid var(--rule)}
.evidence-n{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}

/* the ways out of the reading are a line, not five buttons */
.after-quiet{display:flex;flex-wrap:wrap;gap:1rem;align-items:center;margin-top:1rem}
.after-quiet .linkish{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.after-quiet .linkish:hover{color:var(--brick)}

/* the spread, pinned back when you have scrolled past it */
.spread-recall{
  position:fixed;left:50%;transform:translateX(-50%);top:.6rem;z-index:120;
  display:flex;align-items:center;gap:.5rem;cursor:pointer;
  padding:.375rem .75rem;border:1px solid var(--rule);border-radius:999px;
  background:var(--paper);
  box-shadow:0 8px 22px -10px rgba(26,20,22,.35);
  animation:recallIn .28s ease both;
}
@keyframes recallIn{from{opacity:0;transform:translateX(-50%) translateY(-6px)}to{opacity:1;transform:translateX(-50%)}}
.spread-recall .sr-cards{display:flex;gap:2px}
.spread-recall img{width:17px;height:28px;object-fit:cover;border-radius:3px;box-shadow:0 1px 2px rgba(26,20,22,.25)}
.spread-recall img.rev{transform:rotate(180deg)}
.spread-recall .sr-label{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-2)}
.spread-recall:hover{border-color:var(--brick)}
.spread-recall.hidden{display:none}
@media (max-width:560px){ .spread-recall img{width:13px;height:21px} .spread-recall .sr-label{display:none} }

/* room to breathe through the reading: the spread, the answer and the working are three things,
   not one column of paragraphs */
#reveal .reveal .left{margin-bottom:clamp(1.4rem,3vh,2.6rem)}
#reveal .cloth-copy .clothwrap{padding:8px 40px 34px}
.interp{margin-bottom:clamp(1.8rem,3.5vh,2.8rem);padding-bottom:clamp(1.4rem,2.6vh,2rem)}
.offer{margin-bottom:clamp(2rem,4vh,3.2rem)}
.evidence-head{margin-bottom:clamp(1.1rem,2.4vh,1.8rem)}
.evidence .pos-block{margin-bottom:clamp(1.8rem,3.6vh,3rem)}
.evidence .pos-block:last-child{margin-bottom:0}
#reveal #gate{margin-top:clamp(2rem,4vh,3.4rem)}

/* ---------- no card is cropped ----------
   The scans are 380x656, an aspect of 0.579. The frame they are drawn in is 84/136, which is
   0.618. object-fit:cover scales the scan to the frame's width, which makes it about 6% taller
   than the frame, and that 6% comes off the top and the bottom: the white border goes first and
   then the art. Contain shows the whole card, and the sliver left over is card stock, which is
   what the border of a real card is anyway. */
.place .face img,.pc .pf img{object-fit:contain}
.place .face,.pc .pf{background:var(--card-face)}

/* ---------- the route pages read in the same column as everything else ----------
   The prose under a spread was flush left at the page gutter in a 1280px measure while the reading
   above it is a centred 46rem column, so the page changed shape halfway down. And the positions
   were a two-column list, which numbers 1 and 3 across the top row and 2 underneath: a numbered
   list that does not read in its own order. */
.route-intro .intro{max-width:46rem;margin-left:auto;margin-right:auto}
.route-positions{columns:1 !important;column-count:1 !important}
.route-positions li{margin-bottom:.375rem}

/* ---------- hit areas ----------
   Ten text links across the site measured 17 to 26 pixels tall. The type stays the size it is; the
   box around it grows to something a thumb can land on. 44, the same floor as R6 in v29: the two
   descendant selectors here outrank the flat .linkish rule there, and were holding the ways out
   of a reading at 36. */
.linkish,.sealline button,.viewswap button,.after-quiet .linkish,.rmore .linkish,.pickrow .pickall{
  min-height:44px;display:inline-flex;align-items:center;
}
.sealline button{padding:0 .25rem}
.route-intro a,.reading a{padding:.125rem 0}

/* ---------- the ritual's own lines stop touching ---------- */
.ritual-step{margin-bottom:.75rem}
.ritual-sheet h2{margin-bottom:.5rem}
.ritual-sub{margin-bottom:1.5rem;line-height:1.5}

/* ---------- one card is not a spread ----------
   Spread on top is right for three to twelve cards and wrong for one: a single card at full width
   came out 577px tall with an empty screen beside it and the reading pushed below the fold. One
   card goes back beside its reading, and stays there while you read it. */
@media (min-width:900px){
  #reveal .reveal:has(.tcloth[data-n="1"]){
    grid-template-columns:minmax(0,.8fr) minmax(0,1fr) !important;
    align-items:start;gap:clamp(2rem,4.5vw,4.5rem)}
  #reveal .reveal:has(.tcloth[data-n="1"]) .left{position:sticky !important;top:84px !important;margin-bottom:0}
  #reveal .reveal:has(.tcloth[data-n="1"]) .cloth-copy .clothwrap{max-width:min(100%,360px) !important;padding:0 0 12px}
  #reveal .reveal:has(.tcloth[data-n="1"]) .right{margin:0;max-width:none}
  #reveal .reveal:has(.tcloth[data-n="1"]) .interp{margin-top:0}
}

/* ============================================================================
   v29  Round 1 of the audit (claude/UX-AUDIT.md)
   One global layer that fixes the three systemic classes, plus the spreads
   index. Written to be verifiable: every block below closes a numbered finding
   and the linter counts it.
   ========================================================================= */

/* --- R1  One type scale. Nine sizes were in use for the same mono label:
       9.0 9.3 9.6 9.9 10.9 11.2 11.8 12.2 12.5. Floor is 12px, and the line
       that tells you what to do is 16, not 10. --------------------------- */
.label,.fact,.credits,.sealline,.stage-step,#stageStep,#ritualStep,#sealLine,#rseal,
.or-line,#todayLine,#tableWhy,#tableHint,.takecount,.cap,.pos-card .num{
  font-size:.75rem;letter-spacing:.1em
}
.place .cap{font-size:.75rem;letter-spacing:.06em}      /* 11px, sits under a card */
.takeline,#takeLine{font-size:1.0625rem;letter-spacing:.02em;text-transform:none;color:var(--ink)}
.takeline .takecount{font-size:.75rem}
@media (max-width:700px){
  .takeline,#takeLine{font-size:1.0625rem}
  .label,.fact,.credits,#stageStep,#sealLine,#ritualStep{font-size:.75rem}
}

/* --- R2  One card-image rule. There were 21 object-fit:cover declarations on
       tarot scans across 10 files; v28 fixed one pair. The scans are 0.578,
       the frames run 0.618 to 0.825, so cover was throwing away 19 to 30 per
       cent of every card. This beats all of them at once. ---------------- */
img[src*="cards/"]{object-fit:contain !important;background:var(--card-face)}

/* --- R6  44px floor on anything you tap. 22 distinct controls were under it. */
header nav a,.wordmark,#themeBtn,.theme-btn,
.linkish,.sealline button,.viewswap button,#changeSpread,#ritualX,#tableReset,
.pickrow .pickall,.deck-act,.pill{
  min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center
}
/* the rule above must not un-hide anything a media query hid, and the breakpoint
   has to be the one the nav actually uses. At 820 this said menu while the links
   were still on, so from 721 to 820 the header carried both: five links, the
   theme, and a Menu button, seven things wide. The nav switches at 720. */
.menu-btn{display:none}
@media (max-width:720px){.menu-btn{display:inline-flex}}

/* ============================================================================
   The header carries the name and three ways on. It had five links plus the
   theme, and Ask pointed at the page the wordmark already goes to. Ask and
   About stay in the footer, which lists everything, and in the phone menu,
   which still holds all five.
   ========================================================================= */
@media (min-width:721px){
  .menu-list .nav-ask,
  .menu-list a[data-nav="about"]{display:none}
}
header nav a{padding:0 .5rem}
#changeSpread,#ritualX,#tableReset{padding:0 .75rem}
#turnAll{min-height:44px;margin-inline:14px}

/* --- Nested padding. section + .wrap + .route-intro each applied 64px of
       padding-top, so every route page opened with 192px of nothing. ----- */
main > .page > section{padding-top:0}
main > .page > section > .wrap{padding-top:clamp(1.6rem,3vh,2.4rem)}
.route-intro{padding-top:0}

/* ============================================================================
   The spreads index
   Thirteen identical tiles, eight of them carrying the same two boilerplate
   lines, with no hierarchy and no way in. Now: three bands, a card count you
   can read at a glance, and the one good line per spread left to do its job.
   ========================================================================= */
.route-spreads .answer{max-width:40rem;margin-bottom:0}
.sp-head{margin:0 0 .375rem}
.sp-head .page-title{margin-bottom:0}
@media (min-width:1000px){
  .sp-head{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.9fr);
    gap:clamp(2rem,5vw,4.5rem);align-items:end}
  .sp-head .answer{padding-bottom:.375rem}
}
.sp-band{margin:2.5rem 0 0}
.sp-band:first-of-type{margin-top:1.75rem}
.sp-band > .label{
  display:flex;align-items:baseline;gap:.75rem;margin:0 0 1rem;color:var(--ink-3)
}
.sp-band > .label::after{
  content:"";flex:1;height:1px;background:var(--rule);opacity:.55
}
.sp-grid{
  list-style:none;margin:0;padding:0;display:grid;gap:.75rem;
  grid-template-columns:repeat(auto-fill,minmax(270px,1fr))
}
.sp-grid li{display:flex}
.sp-grid li a{
  position:relative;display:grid;grid-template-columns:auto minmax(0,1fr);
  column-gap:.75rem;row-gap:.25rem;align-content:start;width:100%;
  padding:1rem 1rem 1rem;border:1px solid var(--rule);border-radius:6px;
  background:var(--paper);text-decoration:none;color:inherit;
  transition:border-color .18s,transform .18s,box-shadow .18s
}
.sp-grid li a:hover{
  border-color:var(--verdigris);transform:translateY(-2px);
  box-shadow:0 8px 22px rgba(26,20,22,.09)
}
.sp-grid b{
  grid-column:2;font-family:"Fraunces",Georgia,serif;
  font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;
  font-weight:400;font-size:1.0625rem;line-height:1.2;color:var(--ink)
}
.sp-grid .sp-intent{
  grid-column:2;color:var(--ink-2);font-size:.9375rem;line-height:1.5
}

/* the count, drawn as the thing it counts */
.sp-count{
  grid-column:1;grid-row:1/3;align-self:start;position:relative;isolation:isolate;
  width:30px;height:46px;border-radius:3px;
  background:var(--verdigris);border:1px solid rgba(26,20,22,.22);
  box-shadow:1px 1px 0 rgba(26,20,22,.1);
  display:flex;align-items:center;justify-content:center;
  font-family:"IBM Plex Mono",monospace;font-size:.875rem;color:#f3ecdb;
  transition:transform .18s
}
.sp-count::before,.sp-count::after{
  content:"";position:absolute;inset:0;border-radius:3px;
  background:var(--verdigris);border:1px solid rgba(26,20,22,.18);z-index:-1
}
.sp-count::before{transform:translate(3px,3px)}
.sp-count::after{transform:translate(6px,6px);opacity:.55}
.sp-grid li[data-n="1"] .sp-count::before,
.sp-grid li[data-n="1"] .sp-count::after{display:none}
.sp-grid li[data-n="2"] .sp-count::after{display:none}
.sp-grid li a:hover .sp-count{transform:translateY(-1px) rotate(-2deg)}
.sp-grid li[data-lead="1"] a{border-color:var(--ochre);box-shadow:inset 3px 0 0 var(--sun)}
.sp-grid li[data-lead="1"] .sp-count{background:var(--brick)}
.sp-grid li[data-lead="1"] .sp-count::before,
.sp-grid li[data-lead="1"] .sp-count::after{background:var(--brick)}

@media (max-width:560px){
  .sp-grid{grid-template-columns:minmax(0,1fr);gap:.5rem}
  .sp-grid li a{padding:.75rem 1rem 1rem}
  .sp-count{width:26px;height:40px;font-size:.75rem}
}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* --- R1 continued. The legacy files set the same labels at .62 to .78rem from
   selectors more specific than these (for example "#stage.full .stage-step"),
   so the floor is asserted once, here, rather than chased through ten files.
   Deleting those legacy declarations is the follow-up to this round. ----- */
.stage-step,#stageStep,#ritualStep,#sealLine,#rseal,.or-line,.or-line .linkish,
#todayLine,#tableWhy,#tableHint,.credits,.fact,.label{font-size:.75rem !important}
.takeline,#takeLine{font-size:1.0625rem !important}
.place .cap{font-size:.75rem !important}

/* --- Containers must grow with the controls inside them. #tableWhy was 30px
   tall around a button that is now 44, so the button fell into the paragraph
   underneath it. Same class of bug as the ritual close button. ---------- */
#tableWhy{display:flex;align-items:center;min-height:44px;margin-block:.125rem}
#tableWhy:empty{display:none}
.stage-head{padding-bottom:.375rem}

/* ritual: the close button is absolute, so the step line has to keep clear of it */
#ritualStep{margin-right:110px;min-height:24px}
#ritualX{top:.55rem;right:.55rem}
@media (max-width:560px){
  #ritualStep{margin-right:86px}
}

/* remaining sub-44 controls that are not inline links inside a sentence */
.eye-chip,.eye-chip.key{min-height:44px;display:inline-flex;align-items:center}
header nav a{min-width:44px}

/* ============================================================================
   Round 2. The spread choice happens here and only here, so the row has to
   hold thirteen without pushing the deck off the screen. Expanded it becomes
   a grid of compact tiles and the deck stands down, because at that moment
   you are reading names, not looking at a deck.
   ========================================================================= */
.pickrow.all{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(13rem,1fr));
  gap:.5rem;max-width:52rem;width:100%;justify-content:stretch
}
.pickrow.all .pick3{min-width:0;padding:.5rem .75rem;box-shadow:none}
.pickrow.all .pick3 b{font-size:.9375rem}
.pickrow.all .pickall{grid-column:1/-1;justify-self:center;margin-top:.25rem}
/* THE DECK STANDS DOWN, AND THIS TIME IT IS THE RIGHT ELEMENT. These two rules named .dk and
   .deck-wrap, which belong to the old wheel deck and are not on this table at all, so the deck
   never shrank and its bottom edge sat on the first row of tiles. The table deck is #deckAnchor,
   and width reflows where transform does not. */
.tabletop:has(.pickrow.all) .deck-anchor{width:calc(var(--dw) * .64);transition:width .24s}
.tabletop:has(.pickrow.all) #deckZone{gap:1.75rem}
@media (max-width:700px){
  /* thirteen names on a phone is a list, not a grid of cards */
  .pickrow.all{grid-template-columns:minmax(0,1fr);gap:0;max-width:100%;
    border-top:1px solid var(--rule)}
  .pickrow.all .pick3{
    flex-direction:row;align-items:baseline;justify-content:space-between;gap:.5rem;
    padding:.5rem .25rem;border:0;border-bottom:1px solid var(--rule);border-radius:0;
    background:none;box-shadow:none;min-height:44px}
  .pickrow.all .pick3 b{font-size:.9375rem;line-height:1.2}
  .pickrow.all .pick3 i{font-size:.75rem;white-space:nowrap}
  .pickrow.all .pick3:hover{transform:none;border-color:var(--rule)}
  .tabletop:has(.pickrow.all) .deck-anchor{width:calc(var(--dw) * .5)}
}

/* ============================================================================
   Contrast. The linter now measures WCAG AA on every visible text node against
   the background actually painted behind it. Two real failures, both invisible
   in the theme they do not occur in.
   ========================================================================= */

/* The cloth and the ritual sheet are both #e8dfc9, two steps darker than the
   paper, so brick text that passes at 4.92 on the page reads 4.43 on either of
   them. Two points of red fix it and the colour is the same colour. */
:root:not([data-theme="dark"]) #stage.full,
:root:not([data-theme="dark"]) .ritual-sheet{--brick:#9a4c3b}
/* and it is light-mode only. Written without that guard for one build, it handed
   the dark table a dark red on a dark cloth: 2.93 against a 4.5 floor, 81 failures,
   from a fix aimed at the other theme. Every colour change is now checked in both. */

/* Dark, hover. .btn:hover sets the label to #fff on var(--brick); in dark that
   brick is #c46a55 and white on it is 3.79. The resting state is fine, 4.99,
   because the resting label is the near-black sun ink. So the hover state keeps
   that ink rather than going white. Ghost buttons are excluded: their hover is
   a brick label on the sheet, which is light on dark and passes.

   The first attempt at this darkened the fill instead, which took the resting
   state from 4.99 to 4.15 and filled .btn.ghost, whose label IS light, dropping
   it to 3.55. One rule, 105 new failures, from fixing a number without reading
   the colour it was made of. */
:root[data-theme="dark"] .btn:not(.ghost):hover{color:var(--sun-ink)}

/* ============================================================================
   Round 2, part two. The draw screen said the same thing three times in four
   type treatments before you could reach a card: an eyebrow naming the spread,
   a heading repeating the eyebrow, a status line, a change-spread button, the
   instruction, and a view toggle. 220px of a phone screen to say take one for
   the past, one of three. While you are drawing, the instruction is the screen.
   ========================================================================= */
/* the drawing modes, the same list parts_table.js calls "drawing" */
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"],[data-mode="centre"],[data-mode="turn"])) #tableLabel,
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"],[data-mode="centre"],[data-mode="turn"])) #tableQ,
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"],[data-mode="centre"],[data-mode="turn"])) #stageStep{display:none}
/* the way back is a corner link, not a pill with a band of its own. It was
   taking 90px of a phone screen to offer something you rarely want. */
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"])) .stage-head{
  padding:0;margin:0;min-height:3.4rem;max-width:none
}
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"])) #headLive{
  display:block;min-height:0
}
/* THE ROW IS AS TALL AS ITS TWO CONTROLS. The idle head shares the grid cell with the live one
   and is hidden by visibility, which keeps its size: three lines of text nobody could see held
   the row at 84px on a laptop and 96px on a phone, over a corner link. It is display:none while
   the hand is out, and the row is the 3.4rem the two corner controls need. */
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"])) .head-idle{display:none}
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"])) #tableWhy{
  position:absolute;top:.5rem;right:.9rem;z-index:6;min-height:0;margin:0;display:block
}
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"])) #changeSpread{
  min-height:44px;padding:0 .375rem;font-size:.75rem;color:var(--ink-3);
  background:none;border:0;box-shadow:none;text-decoration:underline;
  text-decoration-color:color-mix(in srgb,var(--ink-3) 45%,transparent);text-underline-offset:3px
}
#stage.full:has(.tabletop:is([data-mode="hand"],[data-mode="deal"],[data-mode="lay"])) #changeSpread:hover{color:var(--brick)}


/* the instruction and the count are one line, and it is the line you read */
/* the line keeps a step off the strip's own edge. On a phone the dealing hand is a sticky panel
   with a border and a 4px inset of its own, which is right for a panel. The count pill used to wrap
   under the instruction because the two did not fit; putting the gap on the scale saved 1.6px,
   which was just enough for them to fit, and the pill landed 9.6px from the screen edge. The line
   wraps a step early now, so the pill sits under the instruction on purpose and not by accident. */
#stage.full .takeline{
  display:flex;align-items:baseline;justify-content:center;gap:.5rem;flex-wrap:wrap;
  margin:.125rem 0 .5rem;padding-inline:.25rem
}
#stage.full:has(.tabletop[data-mode="hand"]) #viewSwap{margin-top:.125rem}
@media (max-width:700px){
  #stage.full:has(.tabletop[data-mode="hand"]) .stage-head{margin-bottom:.125rem}
  #stage.full .takeline{margin:.125rem 0 .375rem}
}

/* ============================================================================
   Round 3. The handover. The table was a fixed full-screen panel that stopped
   existing between two frames while the reading faded in beneath it over 0.8s.
   ========================================================================= */
/* THE FADE NEVER RAN. #stage.full carries animation:tableIn with fill-mode both, and a filled
   animation owns the property it animated: opacity was held at 1 by the animation and the
   transition to 0 below it never had a chance. Measured: computed opacity 1 for the whole
   handover, then the panel simply ceased at 580ms. The animation is cleared when the panel
   hands over, and the transition runs. */
#stage.full.handing-over{
  animation:tableOut .5s ease both;
  pointer-events:none;
}
@keyframes tableOut{from{opacity:1;transform:none}to{opacity:0;transform:translateY(-10px)}}
@media (prefers-reduced-motion: reduce){
  #stage.full.handing-over{animation:none;opacity:0;transform:none}
}

/* ============================================================================
   DECODE. The reader for a spread somebody laid themselves, and the page of
   text around it that the crawlers can actually read.
   ========================================================================= */
/* one left edge down the page: the intro is centred by the route rule, so the
   reader and the spread grid sit on the same measure rather than at the gutter */
.route-decode .intro{max-width:46rem}
.dc-app{margin:1.5rem auto 2rem;max-width:46rem;width:100%}
.dc-spreads{max-width:calc(46rem + 18rem);margin-left:auto;margin-right:auto}
.dc-step > .label{display:block;margin-bottom:.5rem}
.dc-h{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;
  font-weight:400;font-size:clamp(1.3125rem,2.4vw,1.625rem);line-height:1.1;margin:0 0 .25rem}
.dc-sub{color:var(--ink-2);margin:0 0 1rem}
.dc-choose{display:flex;flex-wrap:wrap;gap:.5rem}
.dc-choose .pick3{min-width:10.5rem}

.dc-fields{list-style:none;margin:0 0 1.25rem;padding:0;display:grid;gap:.75rem}
.dc-field{display:grid;gap:.25rem}
.dc-label{display:flex;align-items:baseline;gap:.5rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-2)}
.dc-n{display:inline-flex;align-items:center;justify-content:center;
  width:1.35rem;height:1.35rem;border-radius:50%;border:1px solid var(--rule);
  font-size:.75rem;color:var(--ink-3);flex:0 0 auto}
.dc-row{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}
.dc-select{
  flex:1 1 15rem;min-height:44px;padding:0 .75rem;
  font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;color:var(--ink);
  background:var(--paper);border:1px solid var(--rule);border-radius:6px}
.dc-select:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.dc-rev{display:inline-flex;align-items:center;gap:.5rem;min-height:44px;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-2);cursor:pointer;white-space:nowrap}
.dc-rev input{width:18px;height:18px;accent-color:var(--brick)}
.dc-acts{display:flex;flex-wrap:wrap;align-items:center;gap:1rem;margin:0 0 .75rem}
.dc-acts .btn[disabled]{opacity:.45;cursor:default}
.dc-note{color:var(--ink-3);margin:.25rem 0 0;max-width:36rem;text-transform:none;letter-spacing:0}
.dc-out{margin-top:1.75rem}
.dc-out:empty{margin:0}
.dc-reading{border-top:1px solid var(--rule);padding-top:1.5rem}

/* the crawlable half: thirteen spreads, every position named */
.dc-spreads{display:grid;gap:1rem;grid-template-columns:repeat(auto-fill,minmax(17rem,1fr));margin:1rem auto 2rem}
.dc-spread{border:1px solid var(--rule);border-radius:6px;padding:1rem 1rem;background:var(--paper)}
.dc-spread h3{font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;
  font-weight:400;font-size:1.0625rem;margin:0 0 .25rem;display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem}
.dc-spread h3 a{color:inherit;text-decoration:none;border-bottom:1px solid transparent}
.dc-spread h3 a:hover{border-bottom-color:var(--brick);color:var(--brick)}
.dc-spread p{color:var(--ink-2);font-size:.9375rem;margin:0 0 .5rem;line-height:1.5}
.dc-pos{margin:0;padding-left:1.25rem;color:var(--ink-2);font-size:.875rem;line-height:1.5}
.dc-pos li{margin:0}
.dc-stamp{color:var(--ink-3);text-transform:none;letter-spacing:0}
@media (max-width:560px){
  .dc-choose .pick3{min-width:0;flex:1 1 100%}
  .dc-select{flex:1 1 100%}
  .dc-spreads{grid-template-columns:minmax(0,1fr)}
}

/* the door into decode, wherever it appears */
.dc-door{
  margin:1rem 0 1rem;padding:.75rem 1rem;
  border-left:2px solid var(--ochre);background:color-mix(in srgb,var(--ochre) 7%,transparent);
  border-radius:0 6px 6px 0;color:var(--ink-2)
}
.dc-door a{color:var(--brick)}
@media (max-width:560px){
  .dc-select{flex:1 1 58%;min-width:0}
  .dc-rev{flex:0 0 auto}
}

/* ============================================================================
   THE ROUTE HERO. Every page that is not the table opened on a label, a
   heading and a paragraph on an empty field, which at 1440 left two thirds of
   the screen doing nothing. The band states what the site is made of, three
   fixed numbers and one live one, and the graphic is the thirty-six decans
   themselves: a wheel of ticks with the Sun's own tick lit, turning once every
   two minutes. The subject of the site rather than an ornament.
   ========================================================================= */
/* the hero positions its own graphic, because it is injected into pages with
   three different wrappers and only one of them was .route-intro .intro */
.route-hero{margin:0 0 .375rem}
.rh-text{min-width:0}

.rh-band{
  list-style:none;display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem 2rem;
  margin:0;padding:1rem 0 0;border-top:1px solid var(--rule)
}
.rh-band li{display:flex;align-items:baseline;gap:.5rem}
.rh-band b{
  font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 460,"SOFT" 40,"WONK" 1;
  font-weight:400;font-size:1.3125rem;line-height:1;color:var(--ink)
}
.rh-band span{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-3)
}
.rh-band .rh-now{flex:1 1 100%;margin-top:.5rem;gap:.5rem;align-items:center}
.rh-band .rh-now b{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);
  font-family:"IBM Plex Mono",monospace}
.rh-live{
  display:inline-flex;align-items:center;gap:.5rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  text-transform:none;color:var(--ink-2)
}
.rh-live a{color:var(--brick)}
.rh-dot{
  width:7px;height:7px;border-radius:50%;background:var(--sun);flex:0 0 auto;
  box-shadow:0 0 0 0 color-mix(in srgb,var(--sun) 60%,transparent);
  animation:rh-pulse 3.4s ease-in-out infinite
}
@keyframes rh-pulse{
  0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--sun) 55%,transparent)}
  50%{box-shadow:0 0 0 5px color-mix(in srgb,var(--sun) 0%,transparent)}
}

/* the card sits beside the band. It is the page's own card, a real scan at a real
   src with a real alt, which is also the cheapest half of the image problem in
   SEO-GEO-AEO-AUDIT.md section 7: sixty-two of the seventy-eight were reachable
   only through JavaScript, so they were not image-search candidates at all. */
/* on a phone it rides beside the band rather than disappearing: the page still
   gets its card, at a size that does not spend the fold on it */
.rh-card{display:block;float:right;width:5.25rem;margin:.125rem 0 .5rem 1rem}
.rh-card figcaption{display:none}
.rh-card img{
  display:block;width:100%;height:auto;border-radius:6px;
  border:1px solid color-mix(in srgb,var(--ink) 14%,transparent);
  box-shadow:0 10px 26px -14px rgba(26,20,22,.5), 0 2px 5px rgba(26,20,22,.1);
  background:var(--card-face)
}
.rh-card figcaption{
  margin-top:.5rem;flex-direction:column;gap:.125rem;
  font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2)
}
.rh-card figcaption span{text-transform:none;letter-spacing:0;color:var(--ink-3);font-size:.8125rem}
@media (min-width:860px){
  .route-hero{display:grid;grid-template-columns:minmax(0,1fr) auto;
    align-items:start;gap:clamp(1.6rem,4vw,3.2rem)}
  .route-hero.rh-plain{display:block}
  .rh-card{display:block;float:none;width:clamp(8rem,11vw,10.5rem);margin:.25rem 0 0}
  .rh-card figcaption{display:flex}
  .rh-card img{transform:rotate(-1.6deg);transition:transform .5s ease}
  .rh-card:hover img{transform:rotate(0)}
}
@media (prefers-reduced-motion: reduce){
  .rh-card img{transition:none}
  .rh-dot{animation:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--sun) 22%,transparent)}
}

/* ---- decode: the reader is a tool, so it looks like one rather than like a
   stack of loose form controls on an empty page ---- */
.dc-app{
  border:1px solid var(--rule);border-radius:10px;
  background:color-mix(in srgb,var(--paper) 62%,transparent);
  padding:clamp(1rem,2.4vw,1.6rem);
  box-shadow:0 1px 0 rgba(26,20,22,.04)
}
:root[data-theme="dark"] .dc-app{background:color-mix(in srgb,var(--paper) 40%,transparent)}
.dc-step > .label{color:var(--brick)}
.dc-field{padding:.5rem .75rem;border-radius:6px;background:color-mix(in srgb,var(--rule) 13%,transparent)}
.dc-select{background:var(--paper)}
@media (max-width:560px){
  .dc-app{padding:1rem .75rem}
  .dc-field{padding:.5rem .5rem}
}

/* ============================================================================
   THE MEASURE. Measured, not guessed: at 46rem the body paragraphs on the route
   pages run 89 to 92 characters a line, and the one beside the hero card runs
   63. The comfortable range for continuous reading is roughly 45 to 75, so the
   wide ones are the defect and the narrow one is correct. The inconsistency is
   what makes the narrow block look wrong.

   Prose gets a measure that lands in the sixties. Everything that is not prose,
   the grids, the reader panel, the tables, keeps the full width, which is also
   what stops the page reading as one narrow column.
   ========================================================================= */
/* in ch, not rem: at 38rem the 19px paragraphs land at 73 and the 17.6px ones at
   80, because a fixed pixel measure gives more characters to a smaller face */
.route-intro .intro > p,
.route-intro .intro > ol,
.route-intro .intro > ul,
.rh-text > p,
.wrap.learn p,
.wrap.decans > p,
.decan-text p,.decan-text li,
#page-features .wrap p,#page-features .wrap li,
#page-about .wrap p,#page-legal .wrap p,#page-birth .wrap p,
#page-refuse .wrap p,#page-written .wrap p,#page-rulers .wrap p{max-width:60ch}
.route-intro .intro > h2{max-width:60ch}
/* the spreads head is already two columns, so capping its paragraph as well took
   it to 304px and 36 characters a line, which is worse than the 89 it started at */
/* the spreads head is its own two columns, so putting the hero row inside one of
   them nested a column in a column: 304px and 36 characters a line. It goes back
   to one column when it is carrying a hero. */
.sp-head:has(.route-hero){display:block}
.sp-head .answer,.sp-head p{max-width:60ch}
/* the blocks that are not prose keep the room */
.dc-app,.dc-spreads,.sp-grid,.sp-head,.route-hero,.rh-band{max-width:none}

/* ============================================================================
   THE READING HAS ONE LEFT EDGE. Measured at 1600: the spread started at 160,
   the text column at 432, the card block at 480 and the interpretation at 642.
   Four edges, each nesting level indenting again, which is what reads as narrow
   and adrift rather than as a column. They all sit on one now.
   ========================================================================= */
#reveal .reveal{--read-measure:min(100%,62rem)}
#reveal .reveal .left,
#reveal .reveal .right{
  width:var(--read-measure);max-width:var(--read-measure);
  margin-left:auto;margin-right:auto
}
#reveal .interp,#reveal .offer,#reveal .evidence,
#reveal .reading-tail,#reveal .gate,#reveal .after-quiet{max-width:none}
#reveal .interp > p,#reveal .offer > p{max-width:60ch}

/* The card-by-card block was NOT patched here, deliberately. Measured: .pos-block is
   already a grid whose first column is 224px and empty, because the card image lives
   inside .pos-head, which is display:contents, so a rule written against the block's
   direct children reserves a column for a card that is not its child. Adding a second
   grid on top of that made the empty gutter wider, not narrower. It needs the block
   rebuilt, not another selector. */

/* ---- the footer was one column of eleven links ---- */
.foot-links{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(9.5rem,1fr));
  gap:.375rem 2rem;align-content:start
}
.foot-links a{min-height:44px;display:inline-flex;align-items:center}
@media (min-width:900px){
  .foot{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1.6fr);gap:clamp(2rem,5vw,5rem)}
  .foot-links{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (max-width:480px){
  .foot-links{grid-template-columns:repeat(2,minmax(0,1fr))}
}

/* ---- card of the day is the way in, so it is marked as one ---- */
.pickrow .pick3[data-pick="today"]{
  border-color:var(--ochre);box-shadow:inset 3px 0 0 var(--sun)
}
.pickrow .pick3[data-pick="today"] b{color:var(--ink)}
/* the marker is the rule, not the words: brick on the cloth measures 4.43 against
   a 4.5 floor, and recolouring the label to mark it put three failures back */
.pickrow.all .pick3[data-pick="today"]{box-shadow:inset 3px 0 0 var(--sun);border-color:var(--ochre)}

/* the ritual's own buttons were 31 and 42 tall */
.racts .btn,.rgo .btn,#ritual .btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center}

/* the card block: the picture in column one, everything said about it in column two,
   both starting at the top. Replaces the display:contents head whose thumbnail spanned
   rows the text could not be placed beside. */
#reveal .pos-block{
  display:grid;grid-template-columns:auto minmax(0,1fr);
  align-items:start;column-gap:clamp(1rem,2.2vw,2rem);margin:0 0 2.5rem
}
#reveal .pos-block .pos-thumb-wrap{grid-column:1;grid-row:1;display:block}
#reveal .pos-block .pos-body{grid-column:2;grid-row:1;min-width:0;display:block}
#reveal .pos-block .pos-body.solo{grid-column:1 / -1}
#reveal .pos-block .pos-body > *{max-width:60ch}
#reveal .pos-block .pos-label{display:block;margin-bottom:.125rem}
#reveal .pos-block .pos-card{display:block}
@media (max-width:760px){
  #reveal .pos-block{grid-template-columns:minmax(0,1fr);row-gap:.75rem}
  #reveal .pos-block .pos-thumb-wrap,
  #reveal .pos-block .pos-body{grid-column:1;grid-row:auto}
}

/* one edge, enforced. Something upstream was resolving .interp to margin-left:210px
   inside a 992px column, which is the third of the four left edges the reading had. */
#reveal .reading > *,
#reveal #readingBody > *,
#reveal .interp,#reveal .offer,#reveal .evidence,#reveal .reading-tail{
  margin-left:0;margin-right:0
}

/* ---------------------------------------------------------------
   THE RITUAL IS ONE BOX. Two steps, one size. The controls are built with
   step one and unarmed; step two arms them. Nothing is inserted, so nothing
   resizes. The deck had two widths written for it, keyed off whether the
   controls were in the DOM, which is the resize you could see.
   --------------------------------------------------------------- */
/* unarmed, the controls are on the sheet at a quarter strength rather than invisible: the box
   is the same, and the shuffle no longer plays over an empty lower half of it */
.racts-wrap{transition:opacity .35s ease}
.racts-wrap[data-armed="0"]{opacity:.28;pointer-events:none}
.racts-wrap[data-armed="0"] .btn,.racts-wrap[data-armed="0"] .sealline{filter:grayscale(1)}
.racts-wrap[data-armed="1"]{opacity:1}
/* the same shadow, the same fix: the deck in the sheet falls 16px with a 30px blur, about 23px
   below its box, and Cut the deck sat inside it */
#ritual .ritual-body > .rdeck:first-child,
.ritual-sheet:has(.racts) .rdeck{width:104px;margin:.375rem auto 2.5rem}
@media (max-width:560px){
  #ritual .ritual-body > .rdeck:first-child,
  .ritual-sheet:has(.racts) .rdeck{width:92px;margin:.25rem auto 2rem}
}
.rseal{min-height:1.2em}

/* ---------------------------------------------------------------
   THE WEEK SITS BESIDE THE DAY, NOT UNDER IT. The strip was a flex row with
   wrap: at 1440 the reading column is 675px and the two halves wanted 685,
   so it wrapped by ten pixels and the calendar dropped under the title,
   which reads as a second block rather than a stamp on the first. A grid
   with a content sized right column cannot wrap, so the left half takes a
   second line before the week ever moves.
   --------------------------------------------------------------- */
@media (min-width:561px){
  .day-strip{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:1.25rem;flex-wrap:nowrap}
  .day-strip .ds-right{align-items:flex-end;text-align:right}
  .day-strip .ds-left{align-content:end}
}

/* ===========================================================================
   ONE GUTTER.
   Measured blind across eleven routes at 390px, body text started from three
   different left edges: 16 on home, learn, about and birth-card; 32 on spreads,
   decans and decode; 49 inside decode's panel. Nothing chose that. Pages that
   carry a route-intro nest a second section inside the first, and section
   carries the page gutter, so the gutter was applied twice. A nested section is
   a band inside a page, not a page, and does not re-inset its contents.

   This is the shape of "the layout formats are inconsistent": no single token
   said what the gutter is, so each page inherited whatever its nesting gave it.
   ======================================================================== */
.page section section{padding-left:0;padding-right:0}

/* the hint under the table sat six pixels off the phone gutter everything
   else on the page uses */
#stageGrid .stage-hints{padding-left:16px;padding-right:16px}

/* a row of uppercase nav links is a set of targets, not a sentence, so each one
   is at least 44px tall. The links inside running prose are exempt by WCAG 2.5.8
   and stay inline. */
.learn-nav a{min-height:44px;display:inline-flex;align-items:center}

/* The sky line is a sentence, so it is laid out as one. It was an inline-flex run
   inside a flex list item, which blockifies it and its link: the card name became a
   39px tall block, and the target check was right to ask why a link in the middle of
   a written line was a 39px box. The pulsing dot aligns as a character instead. */
.rh-band .rh-live{display:block;line-height:1.5}
.rh-band .rh-live .rh-dot{display:inline-block;vertical-align:middle;margin-right:.375rem}

/* The week belongs on the day's line, not stacked under a timestamp beside it.
   Stamp and dots run as one row, so the right half is a single line at the same
   height as the title rather than a two row block that reads as its own section. */
@media (min-width:561px){
  .day-strip .ds-right{flex-direction:row;align-items:center;gap:1rem;text-align:left}
  .day-strip{align-items:center}
}

/* ===========================================================================
   ONE CARD, ONE COLUMN.
   The solo block sat in grid column two beside an empty thumbnail column, so it
   started ninety-six pixels right of the prose above it: two formats, two left
   edges, nothing saying which to read first. With one card there is no thumbnail
   and no card-by-card, so there is no second column either.
   ======================================================================== */
#reveal .pos-block.solo{display:block}
#reveal .pos-block.solo .pos-body.solo{grid-column:auto;grid-row:auto}
#reveal .evidence.solo{border-top:0;padding-top:0;margin-top:0}

/* the card's name is the reading's heading now, not a sub-label inside a block */
#reveal .pos-block.solo .pos-card{
  display:block;font-size:clamp(1.3125rem,2.4vw,1.625rem);line-height:1.2;margin:0 0 .125rem
}
#reveal .pos-block.solo .pos-read{margin:0 0 1rem}
#reveal .pos-block.solo .pos-read:last-of-type{margin-bottom:.5rem}

/* ---------------------------------------------------------------
   The week, at a size you can read. Seven 7px circles with 9px letters under a
   timestamp was a legend, not a strip. The dots carry the ink now, today is a
   filled ring rather than a slightly larger dot, and the letters are on the
   type floor instead of under it.
   --------------------------------------------------------------- */
.day-strip{align-items:center;padding-bottom:1rem;margin-bottom:1.5rem}
.day-strip .week{gap:.75rem;align-items:end}
.day-strip .wd{gap:.375rem}
.day-strip .wd i{font-size:.75rem;letter-spacing:.06em;color:var(--ink-3)}
.day-strip .wd b{width:9px;height:9px;border-color:color-mix(in srgb,var(--ink) 38%,transparent)}
.day-strip .wd.is-done b{background:var(--ink-2);border-color:var(--ink-2)}
.day-strip .wd.is-today b{
  width:11px;height:11px;background:var(--sun);border:2px solid var(--ink);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--sun) 26%,transparent)
}

/* ===========================================================================
   A VERTICAL RHYTHM, THE SAME WAY THERE IS ONE GUTTER.
   Measured on /learn at 1440: eighteen blocks, seven different gaps between
   them. The gap before a section heading was a consistent 48, and everything
   inside a section was whatever two adjacent components' own margins happened
   to make: a heading to its prose was 13, 19, 16, 13 and 13 in five places
   that are the same relationship. Nothing was individually wrong, which is why
   it survived, and there was no rhythm anywhere, which is what you see.

   The column owns the gaps now. Children carry no vertical margin of their
   own, the column sets one step between blocks, and a section heading adds the
   one larger step. Two values instead of seven.
   ======================================================================== */
.wrap.learn{display:flex;flex-direction:column;gap:1.75rem}
.wrap.learn > *{margin-block:0 !important}
.wrap.learn > h2,
.wrap.learn > h3{margin-top:1.25rem !important}

/* the ask page intro takes the same rhythm as the learn column: the column owns
   the gaps, the children bring none, and a section heading is the one larger step */
.route-intro .intro{display:flex;flex-direction:column;gap:1.5rem}
.route-intro .intro > *{margin-block:0 !important}
.route-intro .intro > h2{margin-top:1rem !important}
.route-positions-line{font-size:.9375rem;color:var(--ink-2)}
.route-positions-line b{font-weight:400;color:var(--ink)}

/* ===========================================================================
   THE CARD PAGE. An explorer: the plate, four marks on it, and the four things
   written about what is there. The marks are anchors, not buttons, so the page
   works with no script at all and a crawler sees every word.
   ======================================================================== */
.card-route .card-text{max-width:60ch}
.card-plate{margin:0;display:flex;flex-direction:column;gap:.75rem;align-items:flex-start}
.plate-frame{position:relative;display:inline-block;width:min(100%,340px);line-height:0}
.plate-frame img{
  display:block;width:100%;height:auto;border-radius:6px;
  border:1px solid color-mix(in srgb,var(--ink) 16%,transparent);
  box-shadow:0 18px 40px -22px rgba(26,20,22,.55), 0 2px 6px rgba(26,20,22,.12)
}
.eye-dot{
  position:absolute;transform:translate(-50%,-50%);
  display:flex;align-items:center;gap:.375rem;
  min-width:44px;min-height:44px;justify-content:center;
  text-decoration:none;line-height:1
}
.eye-dot i{
  width:15px;height:15px;border-radius:50%;flex:0 0 auto;
  background:color-mix(in srgb,var(--sun) 88%,transparent);
  border:2px solid var(--ink);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--paper) 70%,transparent)
}
.eye-dot span{
  position:absolute;left:50%;top:calc(50% + 16px);transform:translateX(-50%);
  white-space:nowrap;font-family:"IBM Plex Mono",monospace;font-size:.75rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink);
  background:color-mix(in srgb,var(--paper) 92%,transparent);
  padding:.125rem .375rem;border-radius:3px;
  opacity:0;transition:opacity .18s ease;pointer-events:none
}
.eye-dot:hover span,.eye-dot:focus-visible span{opacity:1}
.eye-dot:focus-visible i{outline:2px solid var(--brick);outline-offset:3px}

.card-eyes{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1.5rem;counter-reset:eye}
.card-eyes li{padding-left:1rem;border-left:2px solid var(--rule)}
.card-eyes li:target{border-left-color:var(--ochre)}
.card-eyes li:target .eye-label{color:var(--brick)}
.eye-label{
  display:block;font-family:"IBM Plex Mono",monospace;font-weight:400;
  font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-2);margin-bottom:.25rem
}
.card-eyes p{margin:0 0 .5rem;max-width:60ch}
.eye-carry{font-style:italic;color:var(--ink-2)}
.card-decan{max-width:60ch}
.card-nav{font-size:.9375rem}
.card-nav .sep{color:var(--ink-3);margin:0 .25rem}

/* the column owns its gaps here too */
.card-route{display:flex;flex-direction:column;gap:1.75rem}
.card-route > *{margin-block:0 !important}
.card-route h2{margin-top:1.25rem !important}
@media (min-width:900px){
  .card-route{display:grid;grid-template-columns:minmax(0,1fr) auto;
    column-gap:clamp(2rem,4vw,3.5rem);row-gap:1.75rem;align-items:start}
  .card-route > .card-text:first-of-type{grid-column:1;grid-row:1}
  .card-route > .card-plate{grid-column:2;grid-row:1 / span 2;position:sticky;top:5rem}
  .card-route > .card-text:last-of-type{grid-column:1;grid-row:2}
  .plate-frame{width:clamp(240px,24vw,340px)}
}

/* ===========================================================================
   THE PICTURE IS ON THE LEFT. On every page that shows a card beside words.
   The reading screen already did this and the decan page did the opposite, so
   the two pages that show the same card showed it on opposite sides. Left to
   right is the order you use the page in: look at the card, then read what is
   written about it. One convention, three pages.
   ======================================================================== */
@media (min-width:900px){
  .card-route{grid-template-columns:auto minmax(0,1fr)}
  .card-route > .card-plate{grid-column:1;grid-row:1 / span 2}
  .card-route > .card-text:first-of-type{grid-column:2;grid-row:1}
  .card-route > .card-text:last-of-type{grid-column:2;grid-row:2}
}
@media (min-width:761px){
  .decan-route{grid-template-columns:220px minmax(0,1fr)}
  .decan-route > *{grid-column:2}
  .decan-route .decan-card{grid-column:1;grid-row:1 / span 3}
  .decan-route .decan-text{grid-column:2}
}

/* ===========================================================================
   THE FOLLOW-UP IS A CARD IN THE CORNER, NOT A BAND ACROSS THE PAGE.
   It was a full width section with its own ground between the hero and the
   table, carrying a display heading the size of a page title, for a question
   that is a footnote. And it never cleared: answering was the only thing that
   removed it, so an unanswered reading held that band for ever.
   ======================================================================== */
#followup{
  position:fixed;right:1.25rem;bottom:1.25rem;z-index:60;
  width:min(23rem,calc(100vw - 2.5rem));
  border:0;background:none;padding:0
}
#followup .wrap{max-width:none;margin:0;padding:0}
#followup .fu{
  position:relative;
  background:var(--paper);
  border:1px solid color-mix(in srgb,var(--ink) 16%,transparent);
  border-radius:10px;padding:1rem 1rem 1rem;
  box-shadow:0 22px 48px -24px rgba(26,20,22,.55), 0 3px 10px rgba(26,20,22,.12)
}
[data-theme="dark"] #followup .fu{background:color-mix(in srgb,var(--paper) 88%,#000)}
#followup{opacity:0;transform:translateY(10px);transition:opacity .26s ease,transform .26s ease}
#followup.on{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){ #followup{transition:none} }

.fu-x{
  position:absolute;top:.45rem;right:.5rem;
  background:none;border:0;cursor:pointer;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3);
  min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:flex-end;padding:0 .25rem
}
.fu-x:hover{color:var(--brick)}
.fu-q{
  font-family:"Fraunces",Georgia,serif;font-size:1.0625rem;line-height:1.35;
  margin:.375rem 0 .75rem;max-width:none;color:var(--ink)
}
#followup .fu-answers{display:flex;flex-wrap:wrap;gap:.375rem;margin-bottom:.5rem}
#followup .fu-answers .chip{font-size:.8125rem;padding:.375rem .75rem;min-height:36px}
#followup .hint{margin:0;font-size:.75rem}

/* it does not float over the full screen table, or a sheet */
#stage.full ~ #followup,
:root:has(#stage.full) #followup,
:root:has(#ritual:not(.hidden)) #followup{opacity:0;pointer-events:none}

@media (max-width:560px){
  #followup{left:.75rem;right:.75rem;bottom:.75rem;width:auto}
  #followup .fu{padding:1rem 1rem 1rem}
  .fu-q{font-size:1.0625rem}
}

/* ===========================================================================
   THE READING'S OWN SECTIONS ARE NOT PAGES.
   `section{padding: clamp(2.5rem,6vw,5rem) clamp(1rem,4vw,3rem)}` is the page
   inset, and .interp, .evidence and .offer are <section> elements inside the
   reading, so at 1440 each one took 48px of side padding and up to 80px top and
   bottom from a rule written for the page.

   Measured inside one reading at 1440 before this: four left edges (685 for the
   day strip, the touch line and the fold, 733 for the card name and every
   paragraph of the actual reading, 708 for the keep note) and six right edges.
   The 48 was the whole of the indent, and the 80 was the dead space between the
   closing question and the line under it.

   Same cause as the page gutter fix: a section inside a section is a band, not a
   page. That rule was scoped to .page and the reading is not under it.
   ======================================================================== */
#reveal section,
#reading section,
.reading section{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}
#reveal .gate{padding:0}
#reveal .gate-ask{padding-left:0;padding-right:0}
#reveal .gate-note{margin-left:0}

/* the card breathes into its beat instead of stopping dead the instant it is up */
.pc.chosen.up.settling{
  transition:transform 760ms cubic-bezier(.22,.61,.36,1), opacity 300ms ease
}
.pc.chosen.up.settling .pf{
  transition:box-shadow 760ms ease;
  box-shadow:0 26px 54px -24px rgba(26,20,22,.5), 0 3px 8px rgba(26,20,22,.12)
}
@media (prefers-reduced-motion:reduce){ .pc.chosen.up.settling{transition:none} }

/* the keep block, after the panel came off it: the one button is a target and the one line
   is above the type floor */
#reveal #keepBtn{min-height:44px}
#reveal #gateNote,#reveal .gate-note{font-size:.75rem}

/* ---------------------------------------------------------------
   THE DAY'S LINE SITS BESIDE THE SPREAD'S NAME.
   It was printed at the top of the reading body, so "Monday's card, until
   midnight, draw another" and the week landed between the lead sentence and the
   card, in a column that is about the card. The table's header is already where
   the day is named, so that is where it goes: name on the left, day on the right.
   --------------------------------------------------------------- */
.head-day{display:none}
.head-day.on{display:block}
.head-day .day-strip{margin:0;padding:0;border-bottom:0}
/* Only when the day's line is actually there. #tableWhy inside the head is absolutely
   positioned against it, so turning the head into a grid on every state moved that button
   down onto "Take one for the answer" while the hand was still open. The head keeps its
   original layout until there is a day strip to place. */
@media (min-width:860px){
  .stage-head:has(.head-day.on){display:grid;grid-template-columns:minmax(0,1fr) auto;
    column-gap:clamp(1.5rem,4vw,3rem);align-items:end}
  .stage-head:has(.head-day.on) > .head-idle,
  .stage-head:has(.head-day.on) > .head-live{grid-column:1}
  .stage-head:has(.head-day.on) .head-day.on{grid-column:2;grid-row:1;justify-self:end;align-self:start;padding-top:.125rem}
  .head-day .day-strip{display:flex;flex-direction:column;align-items:flex-end;gap:.5rem}
  .head-day .ds-left{justify-content:flex-end}
  .stage-head:has(.head-day.on) > .picker{grid-column:1 / -1}
}
@media (max-width:859px){
  .head-day.on{margin-top:1rem;padding-top:.75rem;border-top:1px solid var(--rule)}
}

/* the taken card hands over to the reading instead of being deleted mid air */
.pc.chosen.up.leaving{
  opacity:0;
  transform:translate(0px,-26px) scale(1.30) !important;
  transition:opacity 380ms ease, transform 460ms cubic-bezier(.4,0,.2,1) !important
}
@media (prefers-reduced-motion:reduce){ .pc.chosen.up.leaving{transition:none} }

/* the fold's own definition lists measure like everything else */
#reveal .rf-body dd,#reveal .rf-body dt,#reveal .rf-body p{max-width:60ch}

/* ===========================================================================
   THE KEEP BLOCK IS A ROW, NOT A PANEL WITH A HOLE IN IT.
   `.gate` is a bordered, filled two column box and `.gate-ask` inside it is a
   second two column grid. Its left column used to hold a heading and a
   twenty-one word explanation. Those came off, per READING-SCREEN section 6
   point 9, and nothing replaced them, so half a bordered grey box was empty.
   Section 6 says one button and one line on press. No panel at all.
   ======================================================================== */
#reveal .gate{
  border:0;background:none;border-radius:0;padding:0;
  display:block;margin-top:clamp(1.6rem,3vh,2.4rem)
}
#reveal .gate-ask{
  display:flex;flex-direction:column;align-items:flex-start;gap:.75rem;
  max-width:34rem
}
#reveal .gate form{
  /* the base rule sets flex-direction:column, so flex:1 1 16rem was setting a 256px HEIGHT
     on the email label rather than a width, which is what made the field a square. */
  display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;gap:.5rem;width:100%
}
#reveal .gate .gate-email{flex:1 1 16rem;min-width:0;width:auto}
#reveal .gate .gate-daily{flex:1 1 100%;order:3}
#reveal .gate .gate-act{flex:0 0 auto;display:flex;align-items:center;gap:.75rem}
#reveal .gate .gate-note{margin:0;order:4;flex:1 1 100%}

/* ---------------------------------------------------------------
   AND THE ROUTE INTRO SHARES THE PAGE'S COLUMN.
   `.route-intro .intro` is a 44rem measure centred inside a 1460px wrap, so at
   1440 it began at 417 while the reading above it began at 80 for the card and
   685 for its text. Three starts on one page. It is measured, not centred: the
   measure stays, the centring goes, and it begins at the gutter like the card.
   --------------------------------------------------------------- */
.route-intro .intro{margin-left:0;margin-right:0}
/* and its wrap is the page's 1280, not the 1460 the wide grids on the decan, decode and
   spreads routes need, so it starts at the same gutter as the card above it */
.route-intro:not(.decan-route):not(.route-decode):not(.route-spreads) > .wrap{max-width:1280px}

/* the email field is a field, not a 256px square. The label computes to display:grid and
   was stretching to the form's cross size, taking the input with it. */
#reveal .gate .gate-email{display:block;height:auto;align-self:center}
#reveal .gate input[type=email]{
  display:block;width:100%;height:auto;min-height:44px;line-height:1.2
}
#reveal .gate .gate-daily{align-items:center}

/* the field reads as a field: the placeholder is legible and the border is the ink's, not a hairline */
#reveal .gate input[type=email]{
  border-color:color-mix(in srgb,var(--ink) 34%,transparent);
  font-size:.9375rem;color:var(--ink)
}
#reveal .gate input[type=email]::placeholder{color:var(--ink-3);opacity:1}
#reveal .gate input[type=email]:focus-visible{border-color:var(--brick);outline:2px solid color-mix(in srgb,var(--brick) 30%,transparent);outline-offset:1px}
#reveal .gate .gate-note:empty{display:none}

/* the whole-table panel's chips and its skip are targets. Measured on the Celtic Cross:
   eleven chips at 34px and a Skip this one at 13px, which is a line of text pretending
   to be a button. */
#wholePanel .chip{min-height:44px;display:inline-flex;align-items:center}
#wholePanel #wholeSkip{min-height:44px;display:inline-flex;align-items:center}

/* the strip that pins the spread to the top is a button, so it is a target at every width */
#spreadRecall{min-height:44px}


/* =========================================================================
   THE SPREAD PICKER, ROUND 3
   "all thirteen should be under the 3 choices of the day, and it actually expands"

   It was a flex row that sized every tile to its own text, so three tiles came out
   three different widths, and the link to the other ten sat inline at the end of
   the row as a fourth thing of a fourth width. It is one grid now, in both states:
   three equal columns, the link on its own row underneath, and expanding adds rows
   without moving the column edges. The block grows downward and nothing else shifts.
   ========================================================================= */
.pickrow{
  display:none;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:.5rem;margin-top:.25rem;max-width:46rem;width:100%;align-items:stretch;
}
.tabletop[data-mode="idle"] .pickrow{display:grid}
.pick3{min-width:0}
.pickrow .pickall{
  grid-column:1/-1;justify-self:center;align-self:center;margin:.375rem 0 0;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
}
/* expanded: the same three columns, more rows */
.pickrow.all{grid-template-columns:repeat(3,minmax(0,1fr));max-width:46rem;gap:.5rem}
.pickrow.all .pickall{margin-top:.5rem}
@media (max-width:700px){
  .pickrow{grid-template-columns:minmax(0,1fr);gap:.5rem}
  .pickrow.all{grid-template-columns:minmax(0,1fr)}
  .pick3{padding:.5rem .75rem}
}

/* =========================================================================
   THE KEYS, AND WHAT THE READING OPENED FROM
   "no colored label indicating changes in text - hard to know whats happening,
    where is the intrepration text and waite interpretations?"

   Two things, both at the top of the card block where the eye already is.
   The label is what you touched, in colour, so when the paragraphs change you
   can see what changed them. The keys are Waite's own divinatory meanings for
   this card, 1910, and they are text, not controls: nothing here is pressable,
   because a row of targets in the middle of a reading is a control panel.
   ========================================================================= */
#reveal .pos-card .pos-from{
  display:inline-block;margin-left:.5rem;vertical-align:.14em;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;font-weight:400;letter-spacing:.1em;
  text-transform:uppercase;padding:.25rem .5rem .25rem;border-radius:999px;
  background:var(--brick);color:var(--paper);white-space:nowrap;
}
#reveal .pos-block.solo .pos-card .pos-from{vertical-align:.34em}

.card-keys{display:flex;flex-wrap:wrap;gap:.375rem;align-items:center;margin:0 0 1rem}
.card-keys .key{
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;
  border:1px solid var(--rule);border-radius:3px;padding:.25rem .5rem;color:var(--ink-2);
  background:color-mix(in srgb,var(--paper) 62%,transparent);
}
.card-keys.rev .key{border-style:dashed;color:var(--ink-3)}
.card-keys .keys-src{
  flex:1 1 100%;margin-top:.125rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3);
}
@media (max-width:560px){
  .card-keys .key{font-size:.75rem;padding:.25rem .5rem}
}

/* The deck's drawn stack and its shadow reach past its layout box, so a one rem gap under it put
   the first row of tiles against the bottom edge of the cards. The zone gives it room. */
.deckzone{gap:1.25rem}
.deckzone .sealline{margin-top:-.25rem}
/* AND THE SHADOW IS PART OF THE DECK. Will, 18 September: "there should be more space between the
   deck and the options". The gap was measured to the deck's layout box, but the drop shadow falls
   34px with a 44px blur and a -14 spread, so it reaches about 42px below that box and the first
   row of tiles sat inside it on 24px of nominal gap. The deck carries its own room under it, so
   the zone's rhythm between the tiles and the seal line is unchanged. */
.deckzone .deck-anchor{margin-bottom:2.5rem}
@media (max-width:560px){ .deckzone .deck-anchor{margin-bottom:2rem} }

/* =========================================================================
   THE HEADER STRIP, BALANCED
   "this strip looks off and unbalanced"

   It was two clusters with two hundred pixels of nothing between them and no
   shared line: a label, a title and a pill on the left, a serif day heading and
   a week of dots on the right, each starting and ending somewhere different.

   One band now. The mono line runs the full width, the label at one end and the
   day's state at the other. The title sits under it on the left, the week under
   it on the right, and a hairline closes the band so the two halves belong to
   the same thing instead of floating apart.
   ========================================================================= */
@media (min-width:860px){
  #stage.full .stage-head:has(.head-day.on),
  .stage-head:has(.head-day.on){
    align-items:start;
    border-bottom:1px solid var(--rule);
    padding-bottom:1rem;margin-bottom:1.5rem;
  }
  .stage-head:has(.head-day.on) .head-day.on{align-self:start;padding-top:0}
  /* the day's name joins the line it is on instead of being a second heading
     beside the first one, in the same serif, at half the size */
  .stage-head .head-day .ds-left b.display{
    font-family:"IBM Plex Mono",monospace;font-size:.75rem;font-weight:400;
    letter-spacing:.1em;text-transform:uppercase;color:var(--ink);line-height:1.5;
  }
  .stage-head .head-day .ds-left{align-items:baseline;gap:.5rem;line-height:1.5}
  .stage-head .head-day .day-strip{gap:.75rem}
  /* THE TWO HALVES ARE ONE BAND, SO THEY CARRY THE SAME WEIGHT. Will, 18 September: "the sizing
     on the right is small, it should be bigger to feel like its one piece, not 2 separate
     pieces". The band's left half ends in a forty pixel title and its right half ended in seven
     nine pixel dots under twelve pixel letters, 147px wide against 640: a caption beside a
     heading. The week keeps its register and grows into the half it has. */
  .stage-head .day-strip .week{gap:1.25rem;align-items:end}
  .stage-head .day-strip .wd{gap:.5rem}
  .stage-head .day-strip .wd i{font-size:.8125rem;letter-spacing:.1em}
  .stage-head .day-strip .wd b{width:14px;height:14px;border-width:1.5px}
  .stage-head .day-strip .wd.is-today b{width:17px;height:17px}
}
/* the way back out of a spread is a link, not a pill with its own band. It was a
   pill only in the read state, because the rule that quiets it names the drawing
   modes and the table is not in one by then. */
#stage .stage-head #tableWhy{margin:.5rem 0 0}
#stage .stage-head #changeSpread{
  min-height:0;padding:0;font-size:.75rem;color:var(--ink-3);
  background:none;border:0;box-shadow:none;border-radius:0;
  text-decoration:underline;text-decoration-color:color-mix(in srgb,var(--ink-3) 45%,transparent);
  text-underline-offset:3px;
}
#stage .stage-head #changeSpread:hover{color:var(--brick)}

/* the whole line is one line: the link at the end of it matches the type it sits in */
@media (min-width:860px){
  .stage-head .head-day .ds-left .linkish{
    font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  }
}
#stage .stage-head #tableWhy{margin:.375rem 0 0}
@media (min-width:860px){ .stage-head .head-day .ds-left b.display::after{content:" \00B7"} }

/* The lead on a route ran the full column: 720px at 18.9px is 83 characters a line, past the 76
   the rest of the site holds to. A measure, not a width. */
.route-intro .answer,.route-intro .intro > p{max-width:38rem}
/* and the way back out of a spread is still something you have to hit with a thumb. Quieting it
   took its height to 14px, which is a third of the minimum. The look stays, the target returns. */
#stage .stage-head #changeSpread{
  display:inline-flex;align-items:center;min-height:44px;padding:0 .125rem;margin:-.75rem 0 -.75rem
}
/* the lead lives in .wrap > .intro on the ask routes, not under .route-intro */
.intro > .answer,.intro > p.answer{max-width:38rem}
/* the attribution on a card page is its own line under both rows */
/* the type floor is 12px and .62rem is 9.9. The keys and their line sit on the floor, not under it. */
p.keys-src{
  margin:-.5rem 0 1.25rem;font-family:"IBM Plex Mono",monospace;font-size:.75rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);line-height:1.6;max-width:38rem;
}
p.keys-src a{color:var(--ink-2)}
.card-keys + .card-keys{margin-top:-.75rem}

/* the position you are filling, in the line above the hand. It read in the same weight as the
   rest of the sentence, so on a ten card spread nothing on screen changed between one card and
   the next except two digits. */
.takeline .take-pos{color:var(--brick);font-weight:500;font-family:inherit}

/* THE CLOSED FOLD WAS STILL ON THE PAGE. #reveal details reported open:false, its own box was 43px
   tall, and .rf-body inside it was laid out at 219px below that box, on top of the Keep button.
   Something in the cascade is beating the user agent rule that hides a closed details' content, so
   the site says it itself. Caught by overlap on a one card reading of a numbered minor, which is
   the only card that has a decan fold to open. */
.reading-facts:not([open]) .rf-body{display:none}

/* THE MEASURE IN REM, NOT CH. 60ch on this serif resolved to 540px and rendered 82 characters a
   line, because ch is the width of the zero glyph and this face's average character is a third
   narrower than that. Every measure written in ch on the site has been running wide for the same
   reason. Thirty rem is 480px, which is about 73 characters at the reading's size. */
#reveal .pos-block .pos-body > *{max-width:30rem}
#reveal .pos-block .pos-body > .card-keys{max-width:100%}
/* and the same cap on every run of prose in the reading, wherever it is composed from */
#reveal #readingBody p,#reveal #readingBody li{max-width:30rem}
#reveal #readingBody .card-keys,#reveal #readingBody .pos-head{max-width:100%}

/* =========================================================================
   THE AESTHETIC AUDIT, ROUND 1: the routes nothing had ever looked at.

   The gate drives ten states. The site has 143 routes, and eleven written
   pages, twelve of the thirteen spread intros, the card pages and the decan
   pages had never been measured by anything. qa/audit.py walks them. These
   are the findings it returned that are real.
   ========================================================================= */

/* 1. Targets an inch short. Each of these is a control you press, at 27, 40 or 43px. */
.xroads .btn.ghost{min-height:44px}
#birthForm #dob,#birthForm #tob,#birthForm #dobGo{min-height:44px}
.demo-chips .chip{min-height:44px;display:inline-flex;align-items:center}

/* 2. A table of links is a table of targets. Thirty-six rows of 18px links on the decan
      rulers page: the link fills its cell and the row is a row you can hit. */
.route-table td a{display:block;padding:.75rem 0;margin:-.75rem 0}
.route-table td:first-child a{padding-right:.75rem}

/* 3. Under the type floor. The trigger line on the refusals page was 10.9px. */
.route-intro .intro .rule-block .trigger{font-size:.75rem}

/* 4. Contrast. "Tonight" on a decan page came to 4.25 against the panel it sits on, and
      4.5 is the line. The sun keeps its hue and loses a little of its light. */
:root[data-theme="light"] .decan-now b,
:root:not([data-theme="dark"]) .decan-now b{color:color-mix(in srgb,var(--sun-text) 84%,var(--ink))}

/* 5. Dark theme, on the features page. The chosen demo chip put white on the dark theme's
      brick, which is a lighter brick, and came to 3.8. Paper on brick is what the reading's own
      label uses and it passes in both themes. The caption under the demo card was ink-3 on the
      panel at 12px, 2.25 to 1, which is not a caption, it is a rumour. */
.demo-chips .chip.on{color:var(--paper)}
/* (the caption finding was the probe's: it read the card face as the background of a caption
   that hangs below the card. Fixed in bgOf. The caption stays ink-3 like every other label.) */

/* The card page's text column owns its rhythm, like every other column on the site. Its children
   carried their own margins, so the attribution line plus the paragraph after it opened a 70px
   hole under the keys. The measure is in em of the column's own size: this serif averages about
   0.39em a character, so 29em is 74 characters a line at any size, where 60ch was 82. */
.card-route .card-text{max-width:29em;display:flex;flex-direction:column;gap:1rem}
.card-route .card-text > *{margin-block:0 !important}
.card-route .card-text > h2{margin-top:1rem !important}
.card-route .card-text > .card-keys + .card-keys{margin-top:-.5rem !important}
.card-route .card-text > p.keys-src{margin-top:-.5rem !important}

/* =========================================================================
   THE DAILY RITUAL, WATCHED FRAME BY FRAME
   The whole flow was recorded and sampled every fifty milliseconds. Three
   things were not what the code said they were.
   ========================================================================= */

/* 1. The table kept its card through the handover. .stage.read-on hides the tabletop with
      display:none, and read-on lands in the same tick as handing-over, so the 500ms fade ran on
      a panel that had already lost its contents: the card vanished at 1816ms and the background
      faded alone until 2400. While the panel is handing over the tabletop stays. */
#stage.handing-over .stage.read-on .tabletop,
#stage.handing-over .tabletop[data-mode="read"]{display:block}
#stage.handing-over .tabletop[data-mode="read"] .pile{display:block}
#stage.handing-over .stage.read-on .tabletop *{pointer-events:none}

/* 2. The riffle. Keyframed, with each card starting 26ms after the one under it, so the two
      halves open in a cascade and fall back into each other in a cascade. The old version
      transitioned all sixteen at once between two poses, which is a deck opening like a book. */
.rdeck.riffle .rcard{
  animation:rriffle 1.05s cubic-bezier(.45,.05,.3,1) both;
  animation-delay:calc(var(--i) * 26ms);
  transition:none;
}
.rdeck.riffle .rcard:nth-child(odd){--sx:-30px;--sy:-7px;--sr:-9deg}
.rdeck.riffle .rcard:nth-child(even){--sx:30px;--sy:5px;--sr:9deg}
@keyframes rriffle{
  0%  {transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
  28% {transform:translate(calc(var(--i) * .6px + var(--sx)), calc(var(--i) * -.7px + var(--sy))) rotate(var(--sr))}
  52% {transform:translate(calc(var(--i) * .6px + var(--sx)), calc(var(--i) * -.7px + var(--sy))) rotate(var(--sr))}
  100%{transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
}

/* 3. The cut, in two beats: the top half lifts off and sets down beside the deck, holds, and
      then the bottom half comes over onto it. The old cut pulled both halves apart at once and
      pushed them back, which is the riffle again with a different angle. */
.rdeck.cut .rcard{animation:rcut-bottom 1.3s cubic-bezier(.4,.05,.3,1) both;transition:none}
.rdeck.cut .rcard:nth-child(n+9){animation-name:rcut-top}
/* three beats inside one animation: the top half off and aside, the bottom half over onto it,
   and the whole deck, halves swapped, back to where it sat. The end of the animation is the base
   pose, so taking the class off afterwards changes nothing. (A transition back from a pose an
   animation was holding does not run; Chrome snaps. So the return is inside the keyframes.) */
@keyframes rcut-top{
  0%  {transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
  26% {transform:translate(calc(var(--i) * .6px + 58px), calc(var(--i) * -.7px + 10px)) rotate(4deg)}
  70% {transform:translate(calc(var(--i) * .6px + 58px), calc(var(--i) * -.7px + 10px)) rotate(4deg)}
  100%{transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
}
@keyframes rcut-bottom{
  0%  {transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
  34% {transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
  60% {transform:translate(calc(var(--i) * .6px + 58px), calc(var(--i) * -.7px - 14px)) rotate(-3deg)}
  70% {transform:translate(calc(var(--i) * .6px + 58px), calc(var(--i) * -.7px - 14px)) rotate(-3deg)}
  100%{transform:translate(calc(var(--i) * .6px), calc(var(--i) * -.7px)) rotate(calc((var(--i) - 8) * .18deg))}
}
@media (prefers-reduced-motion:reduce){
  .rdeck.riffle .rcard,.rdeck.cut .rcard{animation:none}
}

/* 4. The table is there before the sheet lifts. Draw your cards closes the sheet over 240ms and
      the table goes full screen with a 340ms fade-in, and the page under both reflowed the
      moment the table left the flow: the spreads index jumped up into the gap and was seen
      through the closing sheet. While the sheet is still up the table arrives at full opacity,
      so what the sheet lifts off is the table. */
body:has(#ritual.on) #stage.full{animation:none}

/* 5. The rest of the deck does not peek out from behind the card. When one card is taken the
      other seventy-seven fly home to the pile, which sits at the hand's origin, forty pixels to
      the right of the card's centre and at a third of its size: a little stack of backs stuck
      out from behind the big card the whole time it was being looked at. They fade as they go. */
.tabletop[data-mode="centre"] .pc:not(.chosen){
  opacity:0;
  transition:transform .45s cubic-bezier(.22,.8,.3,1), opacity .3s ease .12s;
}

/* the paid reading's one line: text, price, button, and the checkout mounted under it */
.offer-wrap{margin:0 0 1.5rem}
.offer-line{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1rem;padding:1rem 0;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule)}
.offer-line .offer-p{margin:0;flex:1 1 18rem;max-width:30rem}
.offer-line .offer-price,.hook .offer-price{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--brick);margin-left:.375rem}
.hook .offer-price{margin-left:0}
.offer-line .offer-say{flex:1 1 100%}
.offer-line .offer-say:empty{display:none}
.offer-mount{margin:1rem 0 0;min-height:20rem}
/* every button is a target: .btn was 43px tall, one short of the minimum, on the birth form, the
   Read it fuller button and anywhere else it stood alone */
.btn{min-height:44px}
/* the daily checkbox is pressed through its label, so the label is the target */
#reveal .gate .gate-daily{min-height:44px;display:flex;align-items:center;gap:.5rem}
#reveal .gate .gate-daily input{width:18px;height:18px;margin:0}
/* the reason comes before the field it explains. The note carried order:4 from when it was empty
   and sat under the checkbox as a footnote; it opens the block now. */
#reveal .gate .gate-ask{display:flex;flex-direction:column;gap:.5rem}
#reveal .gate .gate-note{order:-1}
/* the keep row on a phone: the hint beside the button ran off the right edge ("opens them on" then
   "device.", with "any" clipped). The row wraps and the hint takes what is left, or the next line. */
#reveal .gate .gate-act{flex:1 1 100%;flex-wrap:wrap;align-items:center}
#reveal .gate .gate-act .hint{flex:1 1 12rem;min-width:0;max-width:24rem}

/* ===========================================================================
   THE END OF A READING IS ONE BLOCK, NOT A LADDER.
   Between the last line of a reading and the ways out of it there were four hairlines in
   700px (the fold's, the offer's top and bottom, the next-step's); two black buttons stacked,
   which is the thing 21 took out; two voices for two asks (the offer in the serif at body
   size, the keep's note in 12px grey mono); and the keep's field on one row with its button
   and a hint on the next. Now: two rules, where the tail starts and where it ends. One black
   button, the keep; the offer is the outlined one in the same shape. Both asks are one
   sentence in the serif with the control beside it. The field and its button share a row.
   ======================================================================== */
.offer-wrap{margin:clamp(1.4rem,3vh,2rem) 0 0}
.offer-line{padding:0;border:0;gap:.5rem 1rem}
.offer-line .offer-p{flex:0 1 auto;max-width:30rem;font-size:1.0625rem;line-height:1.5;color:var(--ink)}
.offer-line .btn.ghost{
  border-radius:3px;padding:.75rem 1.25rem;border:1px solid var(--ink-3);background:transparent;
  color:var(--ink);font-size:.75rem;letter-spacing:.1em
}
.offer-line .btn.ghost:hover{background:none;border-color:var(--brick);color:var(--brick)}
#reveal .gate{margin-top:clamp(1.4rem,3vh,2rem)}
#reveal .gate .gate-note,#reveal #gateNote{
  font-family:inherit;font-size:1.0625rem;letter-spacing:0;text-transform:none;
  color:var(--ink);line-height:1.5;max-width:30rem
}
#reveal .gate .gate-ask{gap:.75rem}
#reveal .gate .gate-email{flex:1 1 14rem;max-width:22rem}
#reveal .gate .gate-act{flex:0 0 auto;margin:0}
#reveal .gate .gate-act .hint:empty{display:none}
.next-step{margin-top:clamp(1.8rem,4vh,2.6rem);padding-top:1rem}
.next-step .after-quiet{margin-top:0}

/* ---------------------------------------------------------------
   THE HOOK. The first paragraph of the fuller reading, written for this draw, under one label.
   It is set a step above the body size because it is the one thing on the screen that reads
   the draw as a whole, and the reader has just read the cards one at a time. While the reading
   is still free the keep's field joins it as one block; while it is for sale the hook's button
   is the black one and the keep's goes quiet, so there is one black button in the tail either
   way. `.btn.ghost` elsewhere is a pill; here it takes the keep button's own shape.
   --------------------------------------------------------------- */
.hook{display:flex;flex-direction:column;align-items:flex-start;gap:.75rem;max-width:34rem}
.hook .hook-label{color:var(--brick)}
.hook .hook-p{margin:0;font-size:1.1875rem;line-height:1.5;color:var(--ink)}
.hook .hook-act{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1rem}
.hook .hook-act .offer-say{flex:1 1 100%}
.hook .hook-act .offer-say:empty{display:none}
/* v28 sets the gate's gap on #reveal #gate, two ids, which nothing with one id can move */
#reveal #gate{margin-top:clamp(1.4rem,3vh,2rem)}
#reveal #gate.hooked{margin-top:1rem}
.offer-line .btn.ghost,.hook .btn.ghost,#reveal .gate .btn.ghost{
  border-radius:3px;padding:.75rem 1.25rem;border:1px solid var(--ink-3);background:transparent;
  color:var(--ink);font-size:.75rem;letter-spacing:.1em
}
.offer-line .btn.ghost:hover,.hook .btn.ghost:hover,#reveal .gate .btn.ghost:hover{background:none;border-color:var(--brick);color:var(--brick)}

/* ===========================================================================
   THE RIGHT HALF OF A LAPTOP SCREEN.
   qa/voids.py, 17 September 2026, at 1440: twenty-one of forty-six page templates spent more
   than thirty percent of their height with less than half the width in use, and the median at
   tablet and phone was zero. A 44rem measure is the right width for prose and nothing stood
   beside it. Four answers, one per shape of page.
   ======================================================================== */

/* 1. THE READING COLUMN IS AS WIDE AS WHAT IT HOLDS. It was 62rem with 60ch of text in it,
   which left 450px of the column empty beside every paragraph. A card block is 190px of
   picture, a gap and 30rem of prose: 45rem. The map above the reading scales to the same. */
#reveal .reveal{--read-measure:min(100%,45rem)}
/* the map is a drawing, not prose: on a ten card table it takes the width it can use, centred
   over the narrower text column. At 45rem the Celtic Cross was 55px cards in a field of paper. */
#reveal .reveal .left{width:min(100%,60rem);max-width:min(100%,60rem)}

/* 2. THE KEYS ARE THE PICTURE'S CAPTION. On a spread they are a direct child of the block now,
   under the thumbnail in its column, and the prose beside them runs name, line, paragraphs. */
#reveal #readingBody .pos-block > .card-keys{
  grid-column:1;grid-row:2;align-self:start;
  flex-direction:column;align-items:flex-start;gap:.25rem;margin:.5rem 0 0;max-width:190px;width:190px
}
#reveal .pos-block > .card-keys .keys-src{margin:.25rem 0 0}
#reveal .pos-block:has(> .card-keys) .pos-body{grid-row:1 / span 2}
@media (max-width:760px){
  #reveal #readingBody .pos-block > .card-keys{grid-column:1;grid-row:auto;flex-direction:row;flex-wrap:wrap;max-width:100%;width:auto;margin:0 0 .25rem}
  #reveal .pos-block:has(> .card-keys) .pos-body{grid-row:auto}
}

/* 3. THE SPREAD'S SHAPE BESIDE ITS INTRODUCTION, and the ring of decans beside a one card page.
   The figure is the second column at laptop width and sticks while the text scrolls; below
   that the shape sits in the flow at a small size and the ring is not drawn. */
.intro-fig{margin:1.25rem 0 0;max-width:22rem}
.fig-mat{border:1px solid var(--rule);border-radius:6px;background:color-mix(in srgb,var(--ink) 4%,transparent);padding:.75rem}
.fig-mat .mat{display:block;width:100%;height:auto}
.fig-pos{list-style:none;margin:1rem 0 0;padding:0;display:flex;flex-direction:column;gap:.375rem}
.fig-pos li{display:flex;gap:.75rem;align-items:baseline;font-size:.9375rem;line-height:1.35;color:var(--ink-2)}
.fig-pos b{font-family:"IBM Plex Mono",monospace;font-size:.75rem;color:var(--brick);font-weight:400;min-width:1.1rem}
.fig-sky .skywheel{width:100%;max-width:20rem;height:auto;display:block}
.fig-sky figcaption{display:flex;flex-direction:column;gap:.25rem;margin-top:.75rem;font-size:.9375rem;line-height:1.35;color:var(--ink-2)}
.fig-sky figcaption a{color:var(--brick)}
.intro-fig.fig-sky{display:none}
@media (min-width:1100px){
  .route-intro .intro.with-fig{
    display:grid;grid-template-columns:minmax(0,44rem) minmax(16rem,20rem);
    column-gap:clamp(2.5rem,5vw,5rem);align-items:start;max-width:none
  }
  .route-intro .intro.with-fig > *{grid-column:1;min-width:0}
  .route-intro .intro.with-fig > .intro-fig{
    grid-column:2;position:sticky;top:5.5rem;align-self:start;
    margin:.375rem 0 0;max-width:none;width:100%
  }
  .intro-fig.fig-sky{display:block}
}

/* 4. THE WRITTEN PAGES: the article, and beside it the page's card and the four facts, which
   were the hero band inside the text column. The band stays there for narrow screens; at
   laptop width its card and its facts are hidden and the aside carries them, sticky. */
.page-aside{display:none}
@media (min-width:1100px){
  .wrap.with-aside{
    display:grid;grid-template-columns:minmax(0,1fr) minmax(16rem,19rem);
    column-gap:clamp(2.5rem,5vw,5rem);align-items:start
  }
  .wrap.with-aside.learn{row-gap:1.75rem}
  .wrap.with-aside > *{grid-column:1;min-width:0}
  /* the aside owns the whole right column, not the one row it was auto placed into. Without a
     grid-row the sticky had nothing to travel in, so the birth page ran 3800px of text beside an
     empty half. It keeps its own height at the top of that column and rides down with the text. */
  .wrap.with-aside > .page-aside{grid-column:2;grid-row:1/-1;position:sticky;top:5.5rem;align-self:start;display:block;max-height:calc(100vh - 7.5rem);overflow:auto;scrollbar-width:thin}
  .wrap.with-aside .route-hero{display:block}
  .wrap.with-aside .route-hero .rh-card,.wrap.with-aside .route-hero .rh-band{display:none}
  /* a sign's three decans in one row beside the aside, the same height; and one rhythm down
     the column, since grid rows do not collapse margins the way the block layout does */
  .wrap.with-aside .sign-list{grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}
  .sign-list li a{height:100%;box-sizing:border-box}
  .sign-route .wrap.with-aside{row-gap:1rem}
  .sign-route .wrap.with-aside > *{margin-block:0}
  .sign-route .wrap.with-aside > h2{margin-top:.75rem}
  .page-aside .rh-card{float:none;width:clamp(10rem,13vw,13rem);margin:0}
  .page-aside .rh-card figcaption{display:flex}
  .page-aside .rh-band{flex-direction:column;align-items:flex-start;gap:.5rem;margin-top:1rem;padding-top:1rem}
  .page-aside .rh-band .rh-now{margin-top:.25rem;flex-direction:column;align-items:flex-start;gap:.25rem}
}
/* THE BIRTH PAGE: one column. The old two column grid put the title in four lines beside a
   floating card and the empty result box in the right half of the screen. */
.birth{display:block}
.birth .birth-lead{max-width:34rem}
.birth .birth-hint{margin:.5rem 0 0}
.birth .results{margin-top:1.5rem}
.birth .results:empty{display:none}
.birth-spread:empty{display:none}
#birth .wrap.birth-notes{padding-top:clamp(2rem,4vh,3rem)}
/* THE TWO RESULTS FILL THE PAGE'S WIDTH, and each is a record: the card at its real size on
   the left, the name and the facts beside it. At 60rem the box stopped 320px short of the
   title above it, and a 96px card sat alone in the top corner of a 480px panel. */
.birth .results{max-width:none}
@media (min-width:700px){
  .birth .result:has(.birth-card-img){
    display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:1.5rem;align-items:start;
    padding:1.5rem 1.5rem 1.5rem
  }
  .birth .result:has(.birth-card-img) > .label{grid-column:1 / -1}
  .birth .result .birth-card-img{grid-column:1;grid-row:2 / span 6;width:9.5rem;margin:.125rem 0 0}
  .birth .result:has(.birth-card-img) > :not(.label):not(.birth-card-img){grid-column:2;min-width:0}
  .birth .result .big{font-size:1.625rem}
}
/* the birth Sun on a ring, when a page carries one (markBirthOnRing in parts_table.js) */
.skywheel .seg.birth{fill:color-mix(in srgb,var(--brick) 28%,transparent)}
.skywheel .birthdot{fill:var(--brick);stroke:var(--paper);stroke-width:4}

/* THE DECAN PAGE'S CARD WAS A CARD IN A TALL TINTED BOX. The image carries width and height
   attributes at 380 by 658; the column sets width to 220 and nothing reset the height, so the
   box stayed 658 tall with the picture contained in the middle of it and the card face colour
   filling the rest. And the facts band ran straight into the first paragraph. */
.decan-route .decan-card img{height:auto}
.decan-route .route-hero{margin-bottom:1.5rem}
.decan-card .rh-band{flex-direction:column;align-items:flex-start;gap:.5rem;margin-top:1rem;padding-top:1rem}
.decan-card .rh-band .rh-now{margin-top:.25rem;flex-direction:column;align-items:flex-start;gap:.25rem}
@media (max-width:760px){ .decan-card .rh-band{display:none} }
/* beside the aside the title has the column, not the 34rem it was given when the card stood
   next to it: three lines of display type were two */
@media (min-width:1100px){ .wrap.with-aside .page-title{max-width:46rem} }
/* the spreads index: the card beside the lead ran 180px past the facts band and the tiles waited
   for it. Smaller card, and the row starts where the text ends. */
@media (min-width:860px){ .route-spreads .rh-card{width:8.25rem} }
/* decode: the lead's column is 44rem and the card stood at its right edge with the right third of
   the page empty. The row runs the width and the card takes the far edge, as on the spreads index. */
@media (min-width:860px){
  .route-decode .intro{max-width:none}
  .route-decode .intro > *:not(.route-hero){max-width:44rem}
  .route-decode .route-hero .rh-text{max-width:44rem}
}
/* the map to the words: 186px between the last caption and "What the table says" on a three
   card reading at 1440. The cloth is drawn at the live table's aspect, so it carries the table's
   empty margin under the cards; the copy of a small spread is capped and the row gap is tighter. */
@media (min-width:900px){
  /* v28 caps the copy at 860px with !important; a small spread needs less */
  #reveal .cloth-copy .clothwrap:has(.tcloth[data-n="2"]),
  #reveal .cloth-copy .clothwrap:has(.tcloth[data-n="3"]),
  #reveal .cloth-copy .clothwrap:has(.tcloth[data-n="4"]){max-width:min(100%,640px) !important;margin-left:auto;margin-right:auto}
}
#reveal .cloth-copy .clothwrap{padding-bottom:0}
#reveal .reveal{gap:clamp(1rem,2vw,1.5rem)}

/* REVERSALS ARE A SWITCH IN THE CORNER OF THE TABLE. It was the last word of the seal line under
   the deck, a link reading "Reversals on", which is where nobody looks for a setting. On the idle
   table only: once a spread is being drawn the deck is settled and the seal line states it. */
.rev-switch{
  position:absolute;top:.85rem;right:1rem;z-index:6;display:inline-flex;align-items:center;gap:.5rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-2);min-height:44px
}
/* the button is the 44px target; the pill inside it is the picture of a switch */
.rev-switch .switch{
  width:54px;height:44px;min-height:44px;min-width:44px;border:0;background:transparent;padding:0;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border-radius:999px
}
.rev-switch .pill{
  display:block;width:46px;height:26px;border-radius:999px;border:1px solid var(--ink-3);background:transparent;
  position:relative;transition:background .2s ease,border-color .2s ease;
  /* R6 gives every .pill a 44px floor as a tap target. This one is the picture inside the
     target, not the target, and the floor drew it as a 46 by 44 disc with a dot: a brick
     button, not a switch. */
  min-height:0;min-width:0
}
.rev-switch .knob{position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--ink-3);transition:transform .2s ease,background .2s ease}
.rev-switch .switch[aria-checked="true"] .pill{background:var(--brick);border-color:var(--brick)}
.rev-switch .switch[aria-checked="true"] .knob{transform:translateX(20px);background:#fff}
.rev-switch .switch:focus-visible{outline:2px solid var(--brick);outline-offset:2px}
/* where it shows: the idle table, the crossroads and the gather (41), and the full table while the
   hand is untouched (.untaken, parts_table.js paint). The switch moves into the head row for the
   full table (setMode), so the test is on the stage, not on the switch's parent. */
#stage:not(:has(.tabletop:is([data-mode="idle"],[data-mode="crossroads"],[data-mode="gather"]))):not(:has(.tabletop.untaken:is([data-mode="hand"],[data-mode="deal"]))) .rev-switch{display:none}
/* on the full table: the head row's left corner, Change spread's mirror */
/* the same line as Change spread: that button pulls itself up by .7rem to keep its 44px out of the
   flow, so the switch starts where the button's box starts and the two centre on one line */
#stage.full #headLive .rev-switch{top:-.2rem;left:.9rem;right:auto}
/* On a phone the table is 360px wide and the deck sits in the middle of it, so the corner is not
   clear of the deck: the word was painted under the top of the pile, "ALS ON" showing to the right
   of it. The deck starts below the switch's row there. (The gate's overlap check compares text
   with text and could not see a card over a word; the covered check, added with this, can.) */
@media (max-width:560px){
  .rev-switch{top:.6rem;right:.7rem;gap:.5rem}
  .tabletop:is([data-mode="idle"],[data-mode="crossroads"],[data-mode="gather"]) .deckzone{padding-top:3.5rem}
}

/* THE LEVER UNDER THE FAN. A range input styled as a handle on a track, shown only when the fan
   is wider than the table. The track is a hairline in the ink; the handle is the deck's brick. */
.fan-lever{width:min(100%,22rem);margin:.25rem auto 0;padding:.25rem 0;position:relative;z-index:12}
.fan-lever input{
  -webkit-appearance:none;appearance:none;width:100%;height:44px;background:transparent;margin:0;cursor:pointer;display:block
}
.fan-lever input::-webkit-slider-runnable-track{height:2px;background:color-mix(in srgb,var(--ink) 30%,transparent);border-radius:999px}
.fan-lever input::-moz-range-track{height:2px;background:color-mix(in srgb,var(--ink) 30%,transparent);border-radius:999px}
.fan-lever input::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:22px;height:22px;margin-top:-10px;border-radius:50%;
  background:var(--brick);border:2px solid var(--paper);box-shadow:0 2px 6px rgba(26,20,22,.25)
}
.fan-lever input::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:var(--brick);border:2px solid var(--paper);box-shadow:0 2px 6px rgba(26,20,22,.25)}
.fan-lever input:focus-visible{outline:none}
.fan-lever input:focus-visible::-webkit-slider-thumb{outline:2px solid var(--brick);outline-offset:3px}
/* the card under the pointer and its neighbours move on the same curve as the ribbon */
.pile.fanned .pc{transition:transform .22s cubic-bezier(.22,.8,.3,1)}

/* THE DECODE READING IS THE READING. It is composed by the same engine into its own panel, and
   none of the reading's layout reached it: the card, then a row of keys, then the words, all
   stacked in a 1280px box. It takes the reading column's own shape here: the column at 45rem,
   the picture with its keys under it on the left, the words beside. */
.dc-reading{max-width:45rem;margin:0 auto}
.dc-reading .pos-block:has(.pos-thumb-wrap){
  display:grid;grid-template-columns:190px minmax(0,1fr);column-gap:1.25rem;align-items:start;margin:0 0 2.5rem
}
.dc-reading .pos-block .pos-thumb-wrap{grid-column:1;grid-row:1;display:block}
.dc-reading .pos-block > .card-keys{
  grid-column:1;grid-row:2;align-self:start;flex-direction:column;align-items:flex-start;gap:.25rem;
  margin:.5rem 0 0;max-width:190px;width:190px
}
.dc-reading .pos-block > .pos-body{grid-column:2;grid-row:1;min-width:0;display:block}
.dc-reading .pos-block .pos-body > *{max-width:30rem}
.dc-reading .pos-block .pos-label{display:block;margin-bottom:.125rem}
.dc-reading .pos-block .pos-card{display:block}
.dc-reading p,.dc-reading li{max-width:30rem}
.dc-reading .hook,.dc-reading .offer-line,.dc-reading .fuller.sheet p{max-width:none}
@media (max-width:760px){
  .dc-reading .pos-block:has(.pos-thumb-wrap){grid-template-columns:minmax(0,1fr);row-gap:.75rem}
  .dc-reading .pos-block .pos-thumb-wrap,.dc-reading .pos-block > .pos-body{grid-column:1;grid-row:auto}
  .dc-reading .pos-block > .card-keys{grid-column:1;grid-row:auto;flex-direction:row;flex-wrap:wrap;max-width:100%;width:auto;margin:0 0 .25rem}
}

/* THE FIELD AT THE TOP OF A LONG READING: one line and a field, under the map, on five cards
   and more. The same shape as the keep at the end, the button quiet so the reading stays the
   loudest thing on the screen. */
.gate-top{margin:0 0 1.5rem;padding:0 0 1.5rem;border-bottom:1px solid var(--rule)}
.gate-top form{display:grid;grid-template-columns:minmax(0,22rem) auto;align-items:center;gap:.5rem;justify-content:start}
#reveal .gate-top .gate-note{grid-column:1 / -1;margin:0 0 .25rem;font-size:1.0625rem;line-height:1.5;color:var(--ink);font-family:inherit;letter-spacing:0;text-transform:none;max-width:30rem;order:0}
.gate-top .gate-email{grid-column:1;display:block;min-width:0}
.gate-top .btn.ghost{grid-column:2}
@media (max-width:480px){ .gate-top form{grid-template-columns:minmax(0,1fr)} .gate-top .btn.ghost{grid-column:1;justify-self:start} }
.gate-top input[type=email]{display:block;width:100%;min-height:44px;line-height:1.2;border-color:color-mix(in srgb,var(--ink) 34%,transparent);font-size:.9375rem;color:var(--ink)}
.gate-top input[type=email]::placeholder{color:var(--ink-3);opacity:1}
.gate-top .btn.ghost{border-radius:3px;padding:.75rem 1.25rem;border:1px solid var(--ink-3);background:transparent;color:var(--ink);font-size:.75rem;letter-spacing:.1em}
.gate-top .btn.ghost:hover{background:none;border-color:var(--brick);color:var(--brick)}
.gate-top .gate-top-done{margin:0}
/* the date of birth at the hook: one small row, label, field, three words */

/* --- R47  ONE ASK AT THE END OF A READING.
   Will, 17 September: the deciphered paragraph with Read them together, and directly under it
   the keep's field, dark button and daily box, read as two forms for the same thing, one paid
   and one free. While the reading is for sale the keep folds to one line (#gate.folded, set by
   paintOffer) that says what the address gets, and opens on press. A paid reading is kept on
   this device without a press, and its done state carries the daily card as one tap. */
#reveal .gate .gate-open{display:none}
#reveal .gate.folded .gate-open{
  display:inline-flex;align-items:center;min-height:44px;min-width:0;padding:0;margin:0;
  border:0;background:none;font-family:inherit;font-size:.9375rem;line-height:1.5;letter-spacing:0;
  text-transform:none;color:var(--ink-2);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:color-mix(in srgb,var(--ink) 30%,transparent);cursor:pointer;text-align:left
}
#reveal .gate.folded .gate-open:hover{color:var(--brick);text-decoration-color:currentColor}
#reveal .gate.folded .gate-note,#reveal .gate.folded form{display:none}
#reveal #gate.folded{margin-top:.5rem}
/* the daily card, one tap, under the paid reading's kept line */
#reveal .gate-done .daily-ask{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1rem;margin:1rem 0 0;color:var(--ink);font-size:1.0625rem}
#reveal .gate-done .daily-ask span{flex:0 1 auto;min-width:0}
#reveal .gate-done .daily-ask .btn.ghost{flex:0 0 auto}

/* --- R49  THE PAID READING IS A SHEET.
   Will, 17 September: the bought reading looked like the rest of the free interpretations, the
   same label and the same prose, so nothing said it was a different thing. It is a written sheet
   laid on the page: its own paper (the Sun's colour at a tenth into the page's), a plate border
   (a hairline and an inner rule), the mark with a brick label, the question as its title in the
   display face, a brick initial, the body a step larger than the reading above it, and the
   colophon under a rule. One gap inside the sheet; the paragraphs carry one margin. */
.fuller.sheet{
  --sheet:color-mix(in srgb,var(--sun) 9%,var(--paper));
  display:flex;flex-direction:column;gap:1rem;
  margin:1.5rem 0 0;padding:clamp(1.4rem,3.2vw,2.4rem);
  background:var(--sheet);border:1px solid color-mix(in srgb,var(--ink) 28%,transparent);border-radius:3px;
  outline:1px solid color-mix(in srgb,var(--ink) 16%,transparent);outline-offset:-6px;
  max-width:46rem;border-top:1px solid color-mix(in srgb,var(--ink) 28%,transparent);padding-top:clamp(1.4rem,3.2vw,2.4rem)
}
.fuller.sheet .fuller-head{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.fuller.sheet .fuller-mark{display:inline-flex;flex:none}
.fuller.sheet .fuller-mark svg{width:22px;height:22px;color:var(--brick)}
.fuller.sheet .fuller-label{margin:0;color:var(--brick);letter-spacing:.14em}
.fuller.sheet .fuller-when{margin-left:auto;font-size:.75rem;letter-spacing:.06em;color:var(--ink-3)}
.fuller.sheet .fuller-q{
  margin:0;font-size:1.625rem;font-style:italic;line-height:1.2;color:var(--ink);max-width:32rem;
  font-variation-settings:"opsz" 96,"wght" 400,"SOFT" 40,"WONK" 1
}
.fuller.sheet .fuller-body p{
  font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;
  font-size:1.1875rem;line-height:1.6;margin:0 0 1em;color:var(--ink)
}
.fuller.sheet .fuller-body p:last-child{margin-bottom:0}
.fuller.sheet .fuller-body > p:first-child::first-letter{
  float:left;font-size:3.6em;line-height:.8;margin:.04em .12em 0 0;color:var(--brick);
  font-variation-settings:"opsz" 144,"wght" 480,"SOFT" 40,"WONK" 1
}
.fuller.sheet .fuller-note{margin:0;padding-top:1rem;border-top:1px solid color-mix(in srgb,var(--ink) 16%,transparent);color:var(--ink-3)}
.kept-item .fuller.sheet{margin-top:1.25rem}
@media (max-width:480px){
  .fuller.sheet{padding:1.25rem 1rem;outline-offset:-5px}
  .fuller.sheet .fuller-q{font-size:1.3125rem}
  .fuller.sheet .fuller-body p{font-size:1.0625rem}
}
/* the sheet's done line sits under it with the page's own gap, not the gate's fold gap */
#reveal #offerOut .fuller.sheet{margin-top:.375rem}
/* the hook carries the sheet's mark, so the offer and the thing it buys share one identity */
.hook .hook-label{display:inline-flex;align-items:center;gap:.5rem}
.hook .hook-label .fuller-mark{display:inline-flex;flex:none}
.hook .hook-label .fuller-mark svg{width:18px;height:18px;color:var(--brick)}
/* THE HOOK IS THE SHEET, UNWRITTEN. The offer stands in the sheet's own frame with the first
   paragraph on it, in the sheet's face and size, and buying fills the frame in place: the same
   box, now on its paper. The offer and the thing it buys are one object at two moments. */
.hook{
  --sheet:color-mix(in srgb,var(--sun) 9%,var(--paper));
  max-width:46rem;width:100%;box-sizing:border-box;gap:1rem;
  padding:clamp(1.2rem,2.8vw,2rem);border:1px solid color-mix(in srgb,var(--ink) 28%,transparent);border-radius:3px;
  outline:1px solid color-mix(in srgb,var(--ink) 16%,transparent);outline-offset:-6px;
  /* the same paper as the written sheet (R49): it is that sheet, unwritten. An outline drawn on
     the page's own paper read as one more box; a sheet laid on the page reads as the thing to
     attend to (Will, 17 September). Not a solid colour: the register is a written page, not a
     banner. */
  background:var(--sheet)
}
.hook .hook-p{
  font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 400,"SOFT" 40,"WONK" 1;
  font-size:1.1875rem;line-height:1.6;max-width:36rem
}
.hook .hook-label .fuller-mark svg{width:22px;height:22px}
@media (max-width:480px){
  .hook{padding:1rem 1rem;outline-offset:-5px}
  .hook .hook-p{font-size:1.0625rem}
}
/* --- R51  THE ARRIVAL AT THE DECIPHERED SECTION.
   Will, 17 September: reaching the paid section should feel like a moment, and it looked like
   the rest of the cards. With the frame on screen the paragraph writes itself word by word, the
   frame draws itself with one warm breath of light behind it, the mark's sun pulses once, and the
   button rises last. Until the frame is on screen the words are held (`pending`), so nothing is
   seen twice. The bought reading's sheet arrives the same way. Opacity and a hair of movement
   only: no box changes size, so the gate's stability and layout checks see the settled state.
   Reduced motion: none of it, everything stands at once. */
.hook .hook-p .w,.fuller.sheet .fuller-body .w{display:inline-block}
.hook.pending .hook-p .w,.fuller.sheet.pending .fuller-body .w{opacity:0}
.hook.pending,.fuller.sheet.pending{border-color:transparent;outline-color:transparent;background:transparent}
.hook.pending > .hook-label,.hook.pending > .hook-act,
.fuller.sheet.pending > .fuller-head,.fuller.sheet.pending > .fuller-q,.fuller.sheet.pending > .fuller-note{opacity:0}
.hook.arrive .hook-p .w,.fuller.sheet.arrive .fuller-body .w{
  opacity:0;animation:wordIn .55s ease both;animation-delay:calc(var(--t0,0ms) + var(--i,0) * var(--step,40ms))
}
@keyframes wordIn{from{opacity:0;transform:translateY(.12em)}to{opacity:1;transform:none}}
.hook.arrive{animation:frameIn 1.6s ease both}
@keyframes frameIn{
  0%{border-color:transparent;outline-color:transparent;background:transparent;box-shadow:0 0 0 0 transparent}
  35%{box-shadow:0 0 110px -18px color-mix(in srgb,var(--brick) 42%,transparent)}
  100%{border-color:color-mix(in srgb,var(--ink) 28%,transparent);outline-color:color-mix(in srgb,var(--ink) 16%,transparent);background:var(--sheet);box-shadow:0 0 0 0 transparent}
}
.fuller.sheet.arrive{animation:sheetIn 1.4s ease both}
@keyframes sheetIn{
  0%{border-color:transparent;outline-color:transparent;background:transparent;box-shadow:0 0 0 0 transparent}
  40%{box-shadow:0 0 110px -18px color-mix(in srgb,var(--brick) 36%,transparent)}
  100%{border-color:color-mix(in srgb,var(--ink) 28%,transparent);outline-color:color-mix(in srgb,var(--ink) 16%,transparent);background:var(--sheet);box-shadow:0 0 0 0 transparent}
}
.hook.arrive > .hook-label,.fuller.sheet.arrive > .fuller-head{animation:riseIn .6s ease .15s both}
.fuller.sheet.arrive > .fuller-q{animation:riseIn .6s ease .3s both}
.hook.arrive > .hook-act,.fuller.sheet.arrive > .fuller-note{animation:riseIn .6s ease var(--after,2s) both}
@keyframes riseIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.hook.arrive .hook-label svg circle,.fuller.sheet.arrive .fuller-head svg circle{
  transform-box:fill-box;transform-origin:center;animation:sunPulse 1.2s ease .5s 1
}
@keyframes sunPulse{0%{transform:scale(1)}40%{transform:scale(1.7)}100%{transform:scale(1)}}
/* the button and its one line */
.hook .hook-act{gap:.5rem 1rem;align-items:center}
.hook .hook-terms{font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);flex:1 1 14rem;min-width:0}
@media (prefers-reduced-motion:reduce){
  .hook.pending,.fuller.sheet.pending,.hook.arrive,.fuller.sheet.arrive{animation:none}
  .hook.pending *,.hook.arrive *,.fuller.sheet.pending *,.fuller.sheet.arrive *{animation:none !important;opacity:1 !important}
}
.hook.writing .hook-label svg circle{transform-box:fill-box;transform-origin:center;animation:sunPulse 1.4s ease-in-out infinite}
.hook.writing .hook-terms{display:none}
/* --- R50  THE ASK AT THE LAST TURN. The ritual's own sheet, so it is the site's dialog and not a
   web popup: paper, hairline, the step in mono, the display face. As the drawer it rises from the
   foot of the screen with the cards left in view above it, under a light scrim and no blur. */
.reveal-ask.hidden{display:none}
.reveal-ask .ritual-sheet{text-align:left}
.reveal-ask .ritual-sub{margin:0;color:var(--ink-2)}
.reveal-ask .reveal-form{display:flex;flex-wrap:wrap;gap:.5rem .75rem;margin-top:1rem}
.reveal-ask .reveal-form input[type=email]{flex:1 1 14rem;min-width:0;min-height:44px;font-family:"IBM Plex Mono",monospace;font-size:.9375rem;padding:.5rem .75rem;border:1px solid color-mix(in srgb,var(--ink) 34%,transparent);border-radius:3px;background:var(--paper);color:var(--ink)}
.reveal-ask .reveal-form input[type=email]::placeholder{color:var(--ink-3);opacity:1}
.reveal-ask .reveal-form .btn{flex:0 0 auto}
.reveal-ask.drawer{align-items:end;justify-items:center;padding:0;backdrop-filter:none;background:color-mix(in srgb,var(--ink) 22%,transparent)}
.reveal-ask.drawer .ritual-sheet{width:min(100%,44rem);max-height:70dvh;border-radius:10px 10px 0 0;transform:translateY(100%);transition:transform .36s cubic-bezier(.22,.8,.3,1);box-shadow:0 -24px 60px -24px rgba(26,20,22,.45)}
.reveal-ask.drawer.on .ritual-sheet{transform:none}
@media (prefers-reduced-motion:reduce){ .reveal-ask.drawer .ritual-sheet{transition:none} }
/* the sheet's Not now is a tap target like the ritual's (#ritualX is in the 44px list, R6) */
.reveal-ask .ritual-x{min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center;top:.3rem;right:.5rem}
.reveal-ask.drawer .ritual-x{right:1rem}


/* the floated hero card on narrow screens was overlapping the first row of the list under it */
.decan-list{clear:both}
.sign-list{margin:1.75rem 0 1rem}
@media (max-width:859.98px){ .sign-route .route-hero{display:flow-root} }

/* THE NINE BIRTH-CARD PAIRS: a gallery, each line with its own cards, two across beside the aside
   at laptop width and one column on a phone. Nine headings and nine paragraphs in a 60ch column
   was 2,000px of prose with nothing beside it. */
.pairs{display:grid;grid-template-columns:repeat(auto-fill,minmax(19rem,1fr));gap:1.75rem 2.5rem}
.pair{min-width:0}
.pair-cards{display:flex;gap:.5rem;margin:0 0 .75rem}
.pair-cards img{width:4.25rem;height:auto;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.18)}
.pair h3{margin:0 0 .375rem}
.pair p{margin:0}
/* --- R52  ONE EMAIL MECHANISM.
   Will, 17 September: the form at the end of the reading was a poor use of the space, and the
   drawer already asks. The form is the engine now, hidden; the drawer asks at the last turn and
   folds into a tab in the bottom right corner that reopens it; the end of a reading is the
   deciphered frame and the ways out. The daily tick lives in the drawer. */
#reveal .gate .gate-ask.engine{display:none}
.reveal-ask .reveal-daily{flex:1 1 100%;display:flex;align-items:center;gap:.5rem;min-height:44px;font-size:.9375rem;color:var(--ink-2)}
.reveal-ask .reveal-daily input{width:18px;height:18px;margin:0}
.reveal-pill{
  position:fixed;right:1rem;bottom:calc(1rem + env(safe-area-inset-bottom));z-index:140;
  display:none;align-items:center;gap:.5rem;min-height:44px;padding:0 1rem 0 .75rem;
  border:1px solid color-mix(in srgb,var(--ink) 30%,transparent);border-radius:999px;background:var(--paper);color:var(--ink);
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;cursor:pointer;
  box-shadow:0 14px 34px -18px rgba(26,20,22,.55);transition:transform .2s ease,border-color .15s
}
body:has(#reading:not(.hidden)) .reveal-pill.on{display:inline-flex}
.reveal-pill:hover{border-color:var(--brick);color:var(--brick)}
.reveal-pill .fuller-mark{display:inline-flex}
.reveal-pill .fuller-mark svg{width:18px;height:18px;color:var(--brick)}
/* the keys are one row under the block, not a column under the picture (R40 made them the
   picture's caption; under a short paragraph that left a 190px stack with the right side empty) */
#reveal #readingBody .pos-block > .card-keys{
  grid-column:1 / -1;grid-row:2;flex-direction:row;flex-wrap:wrap;align-items:center;gap:.375rem;
  width:auto;max-width:100%;margin:.375rem 0 0
}
#reveal .pos-block:has(> .card-keys) .pos-body{grid-row:1}
.dc-reading .pos-block > .card-keys{grid-column:1 / -1;grid-row:2;flex-direction:row;flex-wrap:wrap;width:auto;max-width:100%;margin:.375rem 0 0}
.dc-reading .pos-block:has(> .card-keys) .pos-body{grid-row:1}

/* --- R53  THE SIGN HUB USES ITS WIDTH. Three decans as three columns with the card as the
   picture; the six cards of the sign as a strip of six. On a phone the three stack, picture
   beside text; the six run three to a row. */
.sign-three{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.5rem;margin:1.5rem 0 1.5rem}
.sign-decan{display:block;text-decoration:none;color:inherit;min-width:0}
.sign-decan img{display:block;width:100%;max-width:200px;height:auto;border-radius:6px;box-shadow:0 10px 26px -16px rgba(26,20,22,.55);background:var(--card-face)}
.sign-decan .sd-text{display:block;margin-top:.75rem}
.sign-decan b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:1.1875rem;line-height:1.2}
.sign-decan:hover b{color:var(--brick)}
.sign-decan .fact{display:block;font-size:.75rem;letter-spacing:.02em;color:var(--ink-3);margin-top:.25rem}
.sign-decan .sd-when{color:var(--ink-2)}
.sign-decan p{margin:.5rem 0 0;font-size:.9375rem;line-height:1.5;color:var(--ink-2);max-width:none}
.sign-six{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:1rem;margin:1.25rem 0 1.25rem}
.sign-card{margin:0;min-width:0}
.sign-card img{display:block;width:100%;height:auto;border-radius:3px;box-shadow:0 8px 20px -14px rgba(26,20,22,.5);background:var(--card-face)}
.sign-card figcaption{margin-top:.5rem}
.sign-card b{display:block;font-family:"Fraunces",Georgia,serif;font-variation-settings:"opsz" 36,"wght" 480,"SOFT" 40,"WONK" 1;font-weight:400;font-size:.9375rem;line-height:1.2}
.sign-card .fact{display:block;font-size:.75rem;color:var(--ink-3);margin-top:.25rem}
@media (max-width:720px){
  .sign-three{grid-template-columns:minmax(0,1fr);gap:1.25rem}
  .sign-decan{display:grid;grid-template-columns:96px minmax(0,1fr);gap:1rem;align-items:start}
  .sign-decan img{max-width:96px}
  .sign-decan .sd-text{margin-top:0}
  .sign-six{grid-template-columns:repeat(3,minmax(0,1fr))}
}/* one rhythm down the sign hub at every width: the with-aside grid already owns its gaps at
   laptop width (row-gap 1rem, children without margins); below it the column was block layout
   with five different gaps in twelve blocks. */
@media (max-width:1099.98px){
  .sign-route .wrap.decans{display:flex;flex-direction:column;gap:1rem}
  .sign-route .wrap.decans > *{margin-block:0}
  .sign-route .wrap.decans > h2{margin-top:.75rem}
}

/* YOUR CARD, TO SEND (GROWTH.md loop 1): the button on the birth result and on a decan page's
   born block, the panel under it, and the line a sent card's receiver arrives on. */
.born-share{margin:.5rem 0 0}
.birth .result .note.born-share{margin-top:1rem}
.share-panel.born-panel{margin-top:1rem}
.birth .result:has(.birth-card-img) > .share-panel.born-panel{grid-column:1 / -1}
.born-from{font-family:"IBM Plex Mono",monospace;font-size:.8125rem;letter-spacing:.06em;text-transform:uppercase;color:var(--brick);margin:0 0 .5rem}
.born-from a{color:inherit}

/* THE POSITIONS, WRITTEN (posnotes.py): a definition list under the spread's shape, the
   position's name in the text face with its number in brick mono, the note in the body face. */
.pos-notes{margin:0;display:grid;gap:1rem}
.pos-note{margin:0}
.pos-note dt{font-family:"Fraunces",Georgia,serif;font-weight:500;font-size:1.0625rem;line-height:1.35;margin:0 0 .25rem}
.pos-note dt b{font-family:"IBM Plex Mono",monospace;font-weight:400;font-size:.75rem;color:var(--brick);margin-right:.5rem}
.pos-note dd{margin:0;max-width:60ch;color:var(--ink-2)}

/* R55  THE PAYMENT IS A SHEET OVER THE READING (parts_pay.js). The same overlay as the ritual
   and the ask at the last turn: centred, the reading dimmed behind it, Not now in the corner.
   The chart's date comes first when none is saved; then Stripe's form, in the sheet, which
   scrolls when the form is taller than the screen. The frame's mount is gone with it. */
.pay-ask.hidden{display:none}
.pay-ask .ritual-sheet{--px:clamp(1.2rem,3vw,2.4rem);--py:clamp(1.5rem,3.2vw,2.4rem);width:min(100%,34rem);padding:var(--py) var(--px) clamp(1.4rem,3vw,2rem);text-align:left}
/* the label and Not now share one line, and that line sticks to the top of the sheet while the
   form scrolls under it: it is the only way out on a phone. It spans the sheet's padding so the
   paper runs edge to edge behind it. */
.pay-ask .pay-head{position:sticky;top:calc(var(--py) * -1);z-index:2;display:flex;align-items:center;justify-content:space-between;gap:1rem;
  margin:calc(var(--py) * -1) calc(var(--px) * -1) 0;padding:var(--py) var(--px) .5rem;background:var(--paper-2)}
.pay-ask .ritual-step{display:inline-flex;align-items:center;gap:.5rem;color:var(--brick);margin:0}
.pay-ask .ritual-step .fuller-mark svg{width:16px;height:16px;display:block}
.pay-ask .ritual-x{position:static;min-height:44px;min-width:44px;margin:-13px -.375rem -13px 0;display:inline-flex;align-items:center;justify-content:center}
.pay-ask .ritual-sub{margin:0;color:var(--ink-2)}
/* the date step is one column of one width: heading, why, then one row of controls at one
   height (the field grows to the button, as the keep's field does, 38), then the quiet way out */
.pay-ask .pay-born{margin-top:.375rem;display:flex;flex-direction:column;align-items:flex-start;gap:.75rem}
.pay-ask .pay-born h2{margin:0}
.pay-ask .pay-born .ritual-sub{margin:-.375rem 0 .25rem;text-wrap:balance}
.pay-ask .pay-born.hidden{display:none}
.pay-ask .pay-born-row{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;align-self:stretch}
.pay-ask .pay-born-row .fact{font-size:.75rem}
.pay-ask .pay-born-row input[type=date]{
  flex:1 1 10rem;min-width:0;font-family:"IBM Plex Mono",monospace;font-size:.9375rem;padding:.5rem .75rem;min-height:44px;
  border:1px solid color-mix(in srgb,var(--ink) 34%,transparent);background:var(--paper);color:var(--ink);border-radius:3px
}
.pay-ask .pay-born-row .btn{min-height:44px}
.pay-ask .pay-mount{margin-top:.375rem;min-height:12rem}
.pay-ask .pay-mount.hidden{display:none}
.pay-ask .pay-say{margin:.75rem 0 0;min-height:1.2em}
.pay-ask .pay-say:empty{display:none}
/* THE FOOT OF THE FIRST SCREEN. The fold lands on the hero's rule and the deck is 200 to 260px
   below it, so the first screen ended with no sign of a table. This block sits at the bottom edge
   where a way down belongs: the week's own count, when there is one, and the arrow, always. On a
   phone the hero is only as tall as its content, so it stays in the flow rather than pinning to a
   bottom that is already the content's bottom. */
.begin{position:absolute;left:50%;bottom:1.6rem;transform:translateX(-50%);z-index:2;
  display:flex;flex-direction:column;align-items:center;gap:.125rem;margin:0}
.begin.gone{opacity:0;pointer-events:none;transition:opacity .3s ease}
.begin-n{margin:0;color:var(--ink-3);white-space:nowrap}
.begin-n b{font-weight:400;color:var(--ink)}
.begin-go{display:inline-flex;align-items:center;justify-content:center;min-height:44px;min-width:44px;
  padding:0;background:none;border:0;cursor:pointer;color:var(--ink-3);transition:color .2s}
.begin-go:hover{color:var(--brick)}
.begin-go svg{width:14px;height:24px;display:block;overflow:visible}
.begin-go path{stroke:currentColor;stroke-width:1.3;fill:none;stroke-linecap:round}
@media (prefers-reduced-motion:no-preference){
  .begin-go .stem{stroke-dasharray:18;animation:beginDraw 2.8s ease-in-out infinite}
  @keyframes beginDraw{
    0%{stroke-dashoffset:18;opacity:.25}
    40%{stroke-dashoffset:0;opacity:1}
    78%{opacity:1}
    100%{stroke-dashoffset:0;opacity:.25}
  }
}
@media (max-width:900px){ .begin{position:static;transform:none;margin-top:2rem} }
/* the page behind a sheet does not scroll under it */
body.modal-on{overflow:hidden}
/* on a phone the sheet takes nearly the whole width, so Stripe's form has the room it asks for
   (about 320px): a 390px phone gives it 339, a 360px one 309 */
@media (max-width:480px){ .pay-ask{padding:.5rem} .pay-ask .ritual-sheet{--px:1rem} }
/* THE LANGUAGE SWITCH (LANGUAGES.md; Will, 17 September, with a picture of one): a pill with the
   page's language that opens the list of the site's languages, the current one marked. From
   tablet width up it stands in the header; on a phone a fourth thing beside the wordmark wrapped
   it to two lines, so there the choice is a row in the menu and the pill is hidden. */
.lang{position:relative}
.lang-btn{display:inline-flex;align-items:center;gap:.5rem;letter-spacing:.14em}
.lang-caret{width:.4rem;height:.4rem;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(45deg);transition:transform .18s}
.lang.open .lang-caret{transform:translateY(1px) rotate(225deg)}
.lang-list{display:none;position:absolute;right:0;top:calc(100% + .6rem);min-width:11.5rem;margin:0;padding:.5rem .375rem;list-style:none;background:var(--paper);border:1px solid var(--rule);border-radius:10px;box-shadow:0 14px 34px rgba(26,20,22,.16);z-index:31}
.lang.open .lang-list{display:block}
.lang-list a,.lang-list span.on{display:flex;align-items:center;justify-content:flex-start;gap:1rem;min-height:44px;padding:.375rem .75rem;border-radius:6px;text-decoration:none;text-transform:none;letter-spacing:0;font-family:"Newsreader",Georgia,serif;font-size:1.0625rem;color:var(--ink)}
.lang-list b{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.1em;font-weight:400;color:var(--ink-3);min-width:1.7rem}
.lang-list span.on{font-weight:600}
.lang-list span.on b{color:var(--brick)}
.lang-list a:hover{background:color-mix(in srgb,var(--rule) 45%,transparent);color:var(--ink)}
@media (max-width:720px){ .lang.ll-head{display:none} }
@media (min-width:721px){ .menu-list .lang-link{display:none} }

/* the Spanish sign line on /es/decanatos runs to 121 characters at laptop width (Capricornio,
   Sagitario); held to a measure so it wraps to two lines rather than one long one */
.decan-signs.es{max-width:90ch}

/* the name for the gold: a body standing in the card's own decan at the moment it was drawn. Set
   apart from the sentence it introduces, in the same gold, so the line reads as a label and a fact
   rather than one long sentence. */
/* the legend is prose, not the link row above it, so it takes a measure. Without one it ran 112
   characters a line in a 1280 column, which the audit caught. */
.decan-legend{max-width:62ch}
/* the label carries its own colour. Inside a reading it sat in a gold line and inherited it; on a
   card page and a decan page it sits in a plain paragraph, where it came out the same ink as the
   sentence and named a gold that was not there. Caught on the live site, not by the gate. */
/* THE NAME AND THE SENTENCE NEED A WORD BOUNDARY, not only a gap. The margin drew 8px of air
   and the text content read "Power drawthe Sun is on this card tonight", which is what a
   crawler extracts and what a copy and paste yields. Half the gap is a space character now. */
.pdraw{font-family:"IBM Plex Mono",monospace;font-size:.75rem;font-weight:500;letter-spacing:.14em;text-transform:uppercase;margin-right:.25rem;white-space:nowrap;color:var(--sun-text)}

/* THE ONLY INVITATION THE MECHANIC HAS, RESTORED ON THE ONE READING PEOPLE USE. The four marks
   are built for every written card in a reading (parts_flow.js appends them to the face), and the
   rules that make them visible were written for `.cslot` and `.pos-thumb-wrap`. The single card
   reading lays its card as a `.place` on the cloth, so the four spans have been appended with no
   position, no size and no colour, and have rendered 0 by 0 ever since: four invisible dots on the
   card of the day. Measured in a real draw, 19 September, after the analytics showed forty-six page
   views and no spread opened. The dots do not take the click; the whole card opens the picture,
   which is where the labelled, full size version of this lives. */
/* and the mark has to come forward in 3D, not in z-index. The face is the thing that flips, so it
   carries a 3D transform, and inside a preserve-3d context the painting order is depth and not
   z-index: the card's own picture sat in front of every dot and z-index 3 did nothing. A two pixel
   translateZ puts the marks on the glass in front of the picture, and the breath keeps it. */
/* and it is the card page's marker, not the cloth's. A 16 percent circle of thin brick at 18
   percent fill is invisible on a 1909 lithograph: all four were rendering and only the one over
   a flat patch of sky could be seen. The /card pages already solved this, with a small solid
   dot, an ink edge and a paper halo that reads on any part of any card, and it is the same mark
   a reader meets there, so it is the one to use here.

   AND ONLY ON THE ONE CARD READING. A fixed 12px mark with a 3px halo is right on a 266px card and
   wrong on a ten card spread, where the cloth draws each card at about 32px on a phone and the face
   clips what hangs over its edge: the gate found a dot cut by 4px on the Tree of Life. That case
   was already decided anyway. The dots on the bigger card beside each paragraph are where the
   pointing happens in a multi card spread, which is the note in parts_flow.js, so the cloth's own
   marks belong to the draw that has one card on it. */
.tcloth[data-n="1"] .place .dot{position:absolute;width:12px;height:12px;border-radius:50%;transform:translate(-50%,-50%) translateZ(2px);border:2px solid var(--ink);background:color-mix(in srgb,var(--sun) 88%,transparent);box-shadow:0 0 0 3px color-mix(in srgb,var(--paper) 70%,transparent);opacity:0;transition:opacity .2s ease;pointer-events:none;z-index:3}
.tcloth[data-n="1"] .place .dot.on{opacity:1}
.tcloth[data-n="1"] .place.refinable .dot{opacity:.55;animation:dotBreathZ 2.6s ease-in-out infinite}
.tcloth[data-n="1"] .place.refinable:hover .dot{opacity:.9}
@keyframes dotBreathZ{0%,100%{transform:translate(-50%,-50%) translateZ(2px) scale(1)}50%{transform:translate(-50%,-50%) translateZ(2px) scale(1.14)}}
@media (prefers-reduced-motion:reduce){ .tcloth[data-n="1"] .place.refinable .dot{animation:none} }

/* ---------------------------------------------------------------
   THE MORNING ASK, at the end of the day's card. Will, 19 September: that reading should end with
   the email capture. It ended with five ways out, because the drawer that asks for an address
   opens on two cards or more and the day's card is one. Under a hairline, the label, the line that
   says what arrives, and the field with it: the same field and the same black button as the
   drawer, so the two asks are one object in two places rather than two designs for one job.
   --------------------------------------------------------------- */
.morning{display:flex;flex-direction:column;align-items:flex-start;gap:.75rem;max-width:34rem;
  margin-bottom:1.5rem;padding-top:1.25rem;border-top:1px solid var(--rule)}
.morning.hidden{display:none}
.morning-say{font-size:1.0625rem;line-height:1.5;color:var(--ink-2);margin:0;max-width:30rem}
.morning-act{display:flex;flex-wrap:wrap;gap:.5rem .75rem;align-items:center;width:100%;margin:0}
.morning-field{flex:1 1 14rem;min-width:0;max-width:22rem;display:block}
.morning-field input[type=email]{display:block;width:100%;min-width:0;min-height:44px;
  font-family:"IBM Plex Mono",monospace;font-size:.9375rem;line-height:1.2;padding:.5rem .75rem;
  border:1px solid color-mix(in srgb,var(--ink) 34%,transparent);border-radius:3px;
  background:var(--paper);color:var(--ink)}
.morning-field input[type=email]::placeholder{color:var(--ink-3);opacity:1}
.morning-field input[type=email]:focus-visible{border-color:var(--brick);
  outline:2px solid color-mix(in srgb,var(--brick) 30%,transparent);outline-offset:1px}
.morning-act .btn{flex:0 0 auto}
.morning-note{font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.06em;
  line-height:1.5;color:var(--brick);margin:0}
.morning-note:empty{display:none}
.morning-sent{font-size:1.0625rem;line-height:1.5;color:var(--ink-2);margin:0;max-width:30rem}
.morning-sent b{color:var(--ink)}

/* ================================================================================================
   R77, 24 September 2026. Will, on the birth page and the other written pages: "the clock on the
   right makes everything squished on the left and its not a good look. We need a beautiful title
   then you scroll down, keep it simple." And on the reading: "awkward copy to the side".
   ================================================================================================ */

/* 1. THE WRITTEN PAGES ARE A HERO, THEN ONE COLUMN, IN ONE CENTRED CONTAINER. The sticky panel
   (40, 65) is gone from every page that carried it. Two tries on 24 September taught the rule:
   a 34rem column was too narrow under a full-width header, and running the page to the header's
   edges put the card 700px from its title. The layout now follows three plain rules. Proximity
   (NN/g): the card belongs to the title, so it stands one gutter from it, not at the screen's
   edge. Measure (Baymard, 50 to 75 characters): prose stays at 35rem. Containment: the page is a
   centred container as wide as what it holds, 56rem on a written page (the title and lead, a
   gutter, the card) and 76rem on an index of tiles, while the header stays full width as chrome. */
/* important: v29 sets the route-intro wrap at 1280px through a selector of five classes */
.wrap.page-col{max-width:56rem !important;margin-left:auto;margin-right:auto;position:relative;
  padding-top:clamp(1rem,4vh,2.5rem)}
/* the index pages hold grids of tiles and rows, which want more room than prose does */
#page-spreads .wrap.page-col,#page-decode .wrap.page-col,#page-decans .wrap.page-col{max-width:76rem !important}
.wrap.page-col > *{min-width:0}
.page-col > :not(.ph-card):first-of-type,.page-col > .ph-card + *{margin-top:0}
.page-col .rh-band{display:none}
.page-col .intro,.page-col .route-hero,.page-col .rh-text{max-width:none;margin-left:0;margin-right:0}
/* the prose measure: this serif runs about 0.4em a character, so 35rem at 19px is seventy-odd */
.page-col p,.page-col .prose,.page-col .prose > *,.page-col h2,.page-col h3,.page-col ul:not([class]),.page-col ol:not([class]),
.page-col .answer,.page-col .lede,.page-col .intro > *{max-width:35rem}
.page-col .prose p,.page-col > p:not([class]),.page-col .intro > p:not([class]){font-size:1.1875rem;line-height:1.5}
.page-col .route-hero.rh-plain{display:block}
.ph-card{display:none}

/* the title is the page's first and largest thing: the top clamp of the scale, set wide enough to
   read as a title rather than a paragraph, with the lead under it at the lead's size */
.page-col .page-title,.page-col h1.route-h1{
  font-size:clamp(2.5rem,6vw,3.5rem);line-height:1.1;letter-spacing:-.01em;max-width:40rem
}
.page-col .route-hero .rh-text > .answer,.page-col .route-hero + .answer,
.page-col .birth-lead,.page-col .feat-lede,.page-col > .lede{font-size:1.3125rem;line-height:1.5;max-width:38rem}

/* the card stands beside the title and the lead, one gutter from them (NN/g, proximity: what sits
   far from the thing it belongs to reads as unrelated, and at the header's right edge it was 700px
   from its title), level with the first line of the hero, and scrolls away with it. Narrower, the route hero keeps its
   own card beside the lead. */
@media (min-width:1280px){
  /* floated, not absolute: the title and the lead wrap beside it, and anything wide clears it,
     so nothing can ever run underneath the card whatever a page puts after its title */
  .page-col > .ph-card{display:block;position:static;float:right;width:13rem;margin:0 0 2rem 3rem}
  /* an index page aligns its hero to the grid under it: the title and lead span the first
     columns of tiles, the card stands centred over the last one, so the hero is as wide as the
     page it heads and its right edge is the tiles' right edge */
  #page-decans .page-col{--n:3;--g:1.5rem}
  #page-spreads .page-col{--n:4;--g:.75rem}
  #page-decode .page-col{--n:4;--g:1rem}
  #page-spreads .page-col > .ph-card,#page-decode .page-col > .ph-card,#page-decans .page-col > .ph-card{
    width:calc((100% - (var(--n) - 1) * var(--g)) / var(--n));margin:0 0 2rem var(--g);
    display:flex;flex-direction:column;align-items:center}
  #page-spreads .page-col > .ph-card img,#page-decode .page-col > .ph-card img,#page-decans .page-col > .ph-card img,
  #page-spreads .page-col > .ph-card figcaption,#page-decode .page-col > .ph-card figcaption,#page-decans .page-col > .ph-card figcaption{
    width:13rem}
  #page-spreads .page-col .page-title,#page-decode .page-col .page-title,#page-decans .page-col .page-title{max-width:none}
  #page-spreads .page-col .answer,#page-decode .page-col .answer,#page-decans .page-col .answer{
    font-size:1.625rem;line-height:1.5;max-width:50rem}
  #page-spreads .page-col .route-hero,#page-decode .page-col .route-hero,#page-decans .page-col .route-hero,
  #page-spreads .page-col .rh-text,#page-decode .page-col .rh-text,#page-decans .page-col .rh-text{max-width:none}
  .page-col .about-cols,.page-col .feat-block,.page-col .sign-three,
  .page-col .sign-six,.page-col .sp-band,.page-col .route-table-wrap,.page-col .decan-grid,
  .page-col .results,.page-col .birth-spread,.page-col .dc-app,.page-col .kinds,.page-col .decan-list,
  .page-col .sky-figure{clear:right}
  /* the about page's lettering stands under its short title, beside the card, rather than
     clearing it and leaving a hole under the title */
  .page-col .about-figure{max-width:40rem}
  /* a flex column ignores a float, which put the learn page's card above its title: where a card
     stands, the column is a block with the same two steps the flex gap gave */
  .wrap.page-col.learn:has(> .ph-card){display:block}
  .wrap.page-col.learn:has(> .ph-card) > *{margin:0 0 1.75rem !important}
  .wrap.page-col.learn:has(> .ph-card) > h2,.wrap.page-col.learn:has(> .ph-card) > h3{margin-top:3rem !important}
  .wrap.page-col.learn:has(> .ph-card) > .ph-card{margin:0 0 2rem 3rem !important}
  .page-col > .ph-card figcaption{display:flex}
  .page-col .route-hero{display:block}
  .page-col .route-hero .rh-card:not(.ph-card){display:none}
}

/* what is not prose takes the width it needs, from the same left edge */
.page-col .sign-list{grid-template-columns:repeat(3,minmax(0,1fr));max-width:60rem}
@media (max-width:640px){ .page-col .sign-list{grid-template-columns:minmax(0,1fr)} }
.page-col .sign-three,.page-col .sign-six,.page-col .route-table-wrap,.page-col .decan-grid,.page-col .about-figure,
.page-col .about-cols,.page-col .feat-block.has-demo,.page-col .table-wrap{max-width:64rem}
.page-col .about-cols p,.page-col .feat-block.has-demo p{max-width:35rem}
.birth.page-col .results{max-width:60rem}

/* 2. THE READING IS ONE COLUMN WITH ONE RIGHT EDGE. What the table says ran 30rem inside a 45rem
   column, so the right third beside it was empty while the rule and the cards under it ran the
   full width. Everything runs the column now: 34rem, the same measure as the written pages, with
   the lead and the paragraphs a step up so the line stays near seventy characters. Decode reads
   through the same blocks and takes the same shape. */
#reveal .reveal{--read-measure:min(100%,34rem)}
#reveal #readingBody .interp p,#reveal #readingBody .interp .lede-read{max-width:none}
#reveal #readingBody .interp p{font-size:1.1875rem;line-height:1.5}
#reveal #readingBody .interp .lede-read{font-size:1.3125rem;line-height:1.5}

/* the card and everything said about it: the picture in its column; the name, the line, the
   prose and then the keys in the other, so the keys close the text they belong to instead of
   hanging under the picture as a stray row with the source line under them. */
#reveal #readingBody .pos-block:has(.pos-thumb-wrap),.dc-reading .pos-block:has(.pos-thumb-wrap){
  grid-template-columns:clamp(7.5rem,24%,9.5rem) minmax(0,1fr)}
#reveal #readingBody .pos-block .pos-thumb-wrap,.dc-reading .pos-block .pos-thumb-wrap{grid-row:1 / span 2;width:100%}
#reveal #readingBody .pos-block .pos-thumb-wrap img,.dc-reading .pos-block .pos-thumb-wrap img{width:100%;height:auto}
#reveal #readingBody .pos-block .pos-body > *,#reveal #readingBody .pos-block p,
.dc-reading .pos-block .pos-body > *,.dc-reading .pos-block p{max-width:none}
#reveal #readingBody .pos-block > .card-keys,.dc-reading .pos-block > .card-keys{grid-column:2;grid-row:2;margin:.75rem 0 0}
#reveal #readingBody .pos-block:has(> .card-keys) .pos-body,.dc-reading .pos-block:has(> .card-keys) .pos-body{grid-row:1}
/* the sky's place has no picture: it runs the column, head then paragraph */
#reveal #readingBody .pos-block:not(:has(.pos-thumb-wrap)){display:block}
#reveal #readingBody .pos-block:not(:has(.pos-thumb-wrap)) .pos-head{display:flex;gap:.75rem;align-items:baseline;flex-wrap:wrap}
#reveal #readingBody .pos-block:not(:has(.pos-thumb-wrap)) > .pos-read{max-width:none;margin:.5rem 0 0}
#reveal #readingBody .rf-body p{max-width:none}
@media (max-width:760px){
  #reveal #readingBody .pos-block:has(.pos-thumb-wrap),.dc-reading .pos-block:has(.pos-thumb-wrap){grid-template-columns:minmax(0,1fr)}
  #reveal #readingBody .pos-block .pos-thumb-wrap,.dc-reading .pos-block .pos-thumb-wrap{grid-row:auto;width:min(100%,11rem)}
  #reveal #readingBody .pos-block > .card-keys,.dc-reading .pos-block > .card-keys{grid-column:1;grid-row:auto}
  #reveal #readingBody .pos-block .pos-thumb-wrap,.dc-reading .pos-block .pos-thumb-wrap{justify-self:start}
  #reveal #readingBody .pos-block:has(> .card-keys) .pos-body,.dc-reading .pos-block:has(> .card-keys) .pos-body{grid-row:auto}
  #reveal #readingBody .interp p{font-size:1.0625rem}
  #reveal #readingBody .interp .lede-read{font-size:1.1875rem}
}

/* 3. THE SPREAD, RECALLED, WAITS IN THE CORNER. Pinned at the top centre it sat over the first
   line of whatever card you were reading. Bottom left now, the mirror of Keep this reading. */
.spread-recall{top:auto;bottom:1rem;left:clamp(1rem,2vw,1.5rem);transform:none;animation-name:recallIn2}
@keyframes recallIn2{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* on a phone the card floated beside the facts band; with the band gone it stood alone under the
   title with a hole beside it. A phone gets the title and the column. */
@media (max-width:859.98px){ .page-col .route-hero .rh-card{display:none} }
/* the sign hub was one gap at every width but laptop, where the panel's grid owned the rhythm;
   with the grid gone it is the flex column at every width */
/* block, not flex, so the card can float in it: one gap under each block and one larger step
   above a heading, which is the same rhythm the flex column gave */
.sign-route .wrap.page-col > *{margin:0 0 1rem}
.sign-route .wrap.page-col > h2{margin-top:1.75rem}
/* one card is the reading itself, not the working under one: its paragraphs run the column at the
   size of What the table says, which keeps the line under the measure */
#reveal #readingBody .pos-block.solo p.pos-read{font-size:1.1875rem;line-height:1.6}
@media (max-width:760px){ #reveal #readingBody .pos-block.solo p.pos-read{font-size:1.0625rem} }
/* in a 56rem container the demo beside its text left the text a 440px column at the lead's size,
   41 characters a line: the demo stands under the text it demonstrates */
.page-col .feat-block.has-demo{display:block}
.page-col .feat-block.has-demo > * + *{margin-top:1.5rem}
/* a route-intro section nested in the column carried its own top padding, so on the index pages
   the card stood 75px above the kicker it is meant to be level with */
.page-col > section.route-intro{padding-top:0}
/* a page with no card (birth card, kept, questions) holds only a column, so its container is the
   column, centred; the two birth results and the birth spread are wider than prose and stand out
   of it, centred on it */
.wrap.page-col:not(:has(> .ph-card)){max-width:40rem !important}
.wrap.page-col:not(:has(> .ph-card)) .results,.wrap.page-col:not(:has(> .ph-card)) .birth-spread{
  --wide:min(calc(100vw - 2rem),56rem);width:var(--wide);max-width:none !important;margin-left:calc(50% - var(--wide) / 2)}
/* the questions are a definition list, which the prose measure did not reach: 672px of 17px type,
   about a hundred characters a line */
.page-col dl.faq{max-width:35rem}
.page-col dl.faq dd{font-size:1.1875rem;line-height:1.5}

/* 4. THE DECAN PAGES TAKE THE SAME CONTAINER. The card column stood at the page's left edge with
   the text beside it and the right third of the screen empty, and the facts band under the card
   carried the Sun's position baked at build. Centred now at 56rem: the card, a gutter, the text,
   which is the written pages' hero turned the other way round. */
@media (min-width:1100px){
  .wrap.decan-page{max-width:56rem;margin-left:auto;margin-right:auto}
  .wrap.decan-page .decan-route{grid-template-columns:13rem minmax(0,1fr);column-gap:3rem}
}
.decan-card .rh-band{display:none}
