/* ── a level's row ──────────────────────────────────────────────── */
/* Written from JS on the element named, and read only in this scope:
     --row-height   .lscroll        rowheight.js: the height the row stands at
     --rung --gaps  a page or "+n"  levelrow.js ladder: its signed rung off the
                                    page the stack is on, and the "+n"s between
     --gaps-passed  .lscroll        rowgaps.js: the "+n"s the middle has passed
     --pwn --gn     .lscroll        levelrow.js: --pwpx --gpx --gwpx as plain
     --gwn                          numbers
     --lx           a page or "+n"  rowscroll.js lie: its middle off the row's
   Set in this scope: --pw --lgap --plusw --z1 --z2 on the row, by its width.
   levelrow.js also sets each pane's --hue (colour by file, hues.css).
   The ladder's numbers are registered and not inherited, so a page that
   moves restyles itself and not the text inside it. */
@property --row-height { syntax: '*'; inherits: false; }
@property --pwpx { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --gpx { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --gwpx { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --rung { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --gaps { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --gaps-passed { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --lo1 { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --la { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lp2 { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lua { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lza { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lLa { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lsh { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lplus { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lx { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --ly { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lk { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --lu { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --ls { syntax: '<number>'; inherits: false; initial-value: 1; }
@property --lLk { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --pwn { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --gn { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --gwn { syntax: '<number>'; inherits: true; initial-value: 0; }

@layer components {
@scope (#panes > .lrow) {
  /* Each level is a row of its spans, scrolled sideways and snapped: the
     span the stack is on in the middle, the notes either side, and a thin
     "+n" where a run of spans holds nothing. A scroll container pins
     nothing to a scroll it does not own, so the middle pane's sticky head
     hangs in the row's own slot. The pages lie side by side at their own
     size, cropped by the app's own edges: the row's height is the tallest
     of the window it committed to (--row-height), and what runs past that
     is cut by the row, not by a box of its own. */
  :scope {
    position: relative; flex: none; container-type: inline-size; overflow: clip;
    view-timeline: --row block;                   /* where the row stands in the stack's scroll */
    --pw: 100cqw; --lgap: .6rem; --plusw: 1.4rem; --z1: 1; --z2: 1;
  }
  /* the last row runs to the foot, and is a viewport tall whatever it
     holds, so a tab can bring any row up to the top of the screen */
  :scope:last-child { flex: 1 0 auto; min-height: calc(100% + var(--padt)); }

  .lscroll {
    position: relative; z-index: 1; display: flex; align-items: start; gap: var(--lgap);
    overflow-x: auto; overflow-y: clip; overscroll-behavior-x: contain; scrollbar-width: none;
    scroll-snap-type: x mandatory; height: var(--row-height, auto);
    padding-inline: calc((100cqw - var(--pw)) / 2);
    /* the row's lengths resolved to px, for levelrow.js to hand back as
       numbers: calc cannot divide by a length */
    --pwpx: var(--pw); --gpx: var(--lgap); --gwpx: var(--plusw);

    &::-webkit-scrollbar { display: none; }
    &.towed { scroll-snap-type: none; }          /* riding a finer row (rowscroll tow) */
    > .pane {
      /* snap-stop stays normal: a fling must be able to carry several
         spans, not be caught by the first one it passes */
      flex: 0 0 var(--pw); scroll-snap-align: center;
      /* a neighbour is the whole page shrunk by zoom, so its lines break
         where they would at full size. The ladder clamps: further off
         than the window goes on shrinking to its last step, never back
         to full size, which only the page the stack is on wears. */
      --zs: var(--z2);
      zoom: var(--zs);
    }
    > .pane[data-d="0"] { --zs: 1; }
    > .pane[data-d="1"] { --zs: var(--z1); }
  }

  /* The ladder is where a page rests: its zoom (--zs) lays the row out
     around the page the stack is on. On the way, a page is drawn as it
     would rest were the row centred where it is now: at L(k) and the
     ladder's size for k pages off, linear between the steps, so
     neighbours part by one gap all the way. A translate and a scale over
     its zoom carry it there. --lx is where it lies, its middle off the
     row's, read off the layout (rowscroll.js lie). A "+n" keeps
     its width, so the ladder runs on the row without them: --gaps counts
     those between it and the page the stack is on, --gaps-passed those
     the middle has passed. --rung is its signed d, or a "+n"'s page
     before. Only a row that scrolls on its own runs along the spans. */
  [data-along~="seg"] > :scope .lscroll > * {
    transform-origin: 50% 0;
    --lplus: 0;
    --lo1: calc(var(--pwn) * (1 + var(--z1)) / 2 + var(--gn));
    --la: calc(var(--pwn) * (var(--z1) + var(--z2)) / 2 + var(--gn));  /* the rung from one off to two */
    --lp2: calc(var(--pwn) * var(--z2) + var(--gn));                   /* …and each past that */
    --lua: max(var(--rung), -1 * var(--rung));
    --lza: calc(1 - (1 - var(--z1)) * clamp(0, var(--lua), 1) - (var(--z1) - var(--z2)) * clamp(0, var(--lua) - 1, 1));
    --lLa: calc(var(--lo1) * clamp(-1, var(--rung), 1)
      + var(--la) * (clamp(0, var(--rung) - 1, 1) - clamp(0, -1 * var(--rung) - 1, 1))
      + var(--lp2) * (max(0, var(--rung) - 2) - max(0, -1 * var(--rung) - 2)));
    --lsh: calc((var(--gaps) - var(--gaps-passed)) * (var(--gwn) + var(--gn)));
    --ly: calc(var(--lx) - var(--lsh) - var(--lLa) - var(--lplus) * (var(--pwn) * var(--lza) + var(--gn)) / 2);
    --lk: calc(var(--rung) + clamp(-1, var(--ly) / var(--lo1), 1)
      + clamp(0, (var(--ly) - var(--lo1)) / var(--la), 1) - clamp(0, (-1 * var(--ly) - var(--lo1)) / var(--la), 1)
      + max(0, (var(--ly) - var(--lo1) - var(--la)) / var(--lp2)) - max(0, (-1 * var(--ly) - var(--lo1) - var(--la)) / var(--lp2)));
    --lu: max(var(--lk), -1 * var(--lk));
    --ls: calc(1 - (1 - var(--z1)) * clamp(0, var(--lu), 1) - (var(--z1) - var(--z2)) * clamp(0, var(--lu) - 1, 1));
    --lLk: calc(var(--lo1) * clamp(-1, var(--lk), 1)
      + var(--la) * (clamp(0, var(--lk) - 1, 1) - clamp(0, -1 * var(--lk) - 1, 1))
      + var(--lp2) * (max(0, var(--lk) - 2) - max(0, -1 * var(--lk) - 2)));
    translate: calc((var(--lLk) + var(--lplus) * (var(--ls) * var(--pwn) + var(--gn)) / 2 + var(--lsh) - var(--lx)) / var(--zs) * 1px) 0;
    scale: calc(var(--ls) / var(--zs));
    &.lgap { --lplus: 1; --zs: 1; scale: none; }
  }

  /* Which way a scroll would take you: the row the level is on, and the
     column the pages centre in, down the whole stack. It is the desk
     that darkens, not the paper: a hint, not a selection. */
  .lmark {
    position: absolute; inset: 0; pointer-events: none; z-index: 0;

    &::before, &::after {
      content: ''; position: absolute; inset-block: 0;
      background: var(--ink); transition: opacity .2s ease-out;
    }
    &::before { inset-inline: calc((100cqw - var(--pw)) / 2); opacity: .05; }
    &::after { inset-inline: 0; opacity: 0; }
  }
  :scope.cur .lmark::after { opacity: .045; }
  /* the note the stack is on, rimmed in its note's colour, over its head */
  .lscroll > .pane::after {
    content: ''; position: absolute; inset: 0; z-index: 6; pointer-events: none;
    border: 1.5px solid var(--rim, var(--accent)); opacity: 0; transition: opacity .2s ease-out;
  }
  .lscroll > .pane.at.cur::after { opacity: 1; }
  body.hues :scope .lscroll > .pane { --rim: oklch(from var(--hue-ink) calc(l + .17) c var(--hue)); }
  @media (prefers-reduced-motion: reduce) {
    .lscroll > .pane, .lscroll > .pane::after, .lmark::before, .lmark::after { transition: none; }
  }

  /* the row's overlay scrollbar (hbar.js), along its foot while a hand scrolls it */
  .hbar {
    position: absolute; left: 0; bottom: 3px; z-index: 2; height: 5px; border-radius: 3px;
    background: color-mix(in srgb, var(--ink) 38%, transparent);
    pointer-events: none; opacity: 0; transition: opacity .5s ease-out;

    &.on { opacity: 1; transition-duration: .1s; }
  }

  /* a run of spans nothing is written in: a thin edge that opens the one
     next to the note it follows */
  .lgap {
    flex: 0 0 var(--plusw); align-self: stretch; min-height: 2.5rem;
    font: inherit; font-size: .7rem; color: var(--dim); padding: 0;
    writing-mode: vertical-rl; text-orientation: mixed;
    background: none; border: 1px dashed var(--line); border-radius: calc(.3rem * var(--round));
  }

  /* How much of a neighbour shows, by the room there is: none, then its
     edge, then a squished page, then the page nearly whole, and widest of
     all the one past it, shrunk further. */
  @container (min-width: 560px) { :scope > * { --pw: calc(100cqw - 5rem); } }
  @container (min-width: 900px) { :scope > * { --pw: min(46rem, 100cqw - 9rem); --z1: .78; --z2: .78; } }
  @container (min-width: 1300px) { :scope > * { --pw: min(48rem, 100cqw - 16rem); --z1: .85; --z2: .7; } }
  @container (min-width: 1700px) { :scope > * { --pw: min(44rem, 100cqw - 30rem); --z1: .7; --z2: .5; } }
}
} /* @layer components */

@layer overrides {
/* Rows that do not run along the spans have the same columns on every
   row, so the stack scrolls sideways as one: a row is no scroller, it
   runs as wide as its pages, is as tall as the tallest of them, and a
   head sticks to the stack's own scroll. */
#panes:not([data-along~="seg"]) {
  scroll-snap-type: x mandatory;
  > .lrow { overflow: visible; }
  .lscroll { overflow: visible; width: max-content; height: auto; }
  .lmark { display: none; }
  .lrow.cur .lscroll { background: color-mix(in srgb, var(--ink) 4.5%, transparent); }
  .pane .panehead { position: sticky; top: calc(-1 * var(--padt)); animation: none; }   /* from the scrollport, not its padding */
}
} /* @layer overrides */

@layer components {
/* ⌥ held (hflip.js): what sideways crosses, its labels dealt out from the
   middle the way the pages are */
#hflip {
  position: fixed; z-index: 30; left: 50%; bottom: 3.6rem; translate: -50% .4rem;
  display: flex; align-items: baseline; gap: .7rem; max-width: calc(100vw - 2rem);
  padding: .3rem .8rem; font-size: .8rem; color: var(--dim); white-space: nowrap; overflow: hidden;
  background: var(--bg); border: 1px solid var(--line); border-radius: 1rem; box-shadow: var(--float);
  pointer-events: none; opacity: 0; transition: opacity .15s ease-out, translate .25s cubic-bezier(.2, .8, .2, 1);

  &.on { opacity: 1; translate: -50% 0; }
  > b { font-weight: normal; color: var(--ink); margin-right: .3rem; }
  > span {
    font-family: var(--mono);
    animation: hflip-deal .34s cubic-bezier(.2, .8, .2, 1) backwards;
    animation-delay: calc(max(var(--x), -1 * var(--x)) * 60ms);
    transition: color .15s;

    &.at { color: var(--ink); text-decoration: underline 2px var(--accent); text-underline-offset: .25em; }
  }
}
@keyframes hflip-deal {
  from { opacity: 0; translate: calc(var(--x) * -.6em) 0; }
}
}
