/* The playful home's opening (DESIGN-SYSTEM.md §4b), 2026-11-03: what I'm
   building now. The sentence after romemichal.pl's hero; its word follows what
   the picture shows, and the picture between its lines is repri.in's own live
   demo, cropped to a strip. Tokens only. */
:root{--nb-ease:cubic-bezier(.65,0,.65,1);   /* the page slide's ease (§6b), for the opening */
  /* The word roll, timed off the user's reference recording (2026-11-03): one
     even slide of about 1.2s, slow out, quick through the middle, slow in. */
  --nb-roll-ease:cubic-bezier(.65,0,.35,1);--nb-dur:1200ms}

.nb-hero{
  /* As tall as its content, from the page's own top gap (--page-top, as on
     every page). It used to fill the screen and sit centred in it, which
     on a tall screen left a band of empty page above the sentence (user,
     2026-11-03: "lots of negative space"). */
  box-sizing:border-box;
  /* The body already clears the fixed bar, so only the page's own gap here. */
  padding:var(--page-top) var(--edge) var(--section-y-tight);
  display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:var(--space-8);
  align-items:end;
}

/* The sentence, in the display tier. Its width is the picture's width; a line
   may run past it when its word is long. */
.nb-col{position:relative;font:600 var(--type-display)/.95 var(--face-display);letter-spacing:-.04em;color:var(--ink);width:7.5em;max-width:100%}
/* Each line is a mask the words rise out of: clipped above and below only,
   never at the ends, so a line can't lose its last letters. */
.nb-line{display:block;clip-path:inset(0 -100vw);padding-bottom:.12em;margin-bottom:-.12em;white-space:nowrap}
.nb-in{display:block;animation:nb-rise 900ms var(--nb-ease) both;animation-delay:calc(var(--i) * 90ms)}
.nb-quiet{color:var(--ink-40)}
@keyframes nb-rise{from{transform:translateY(140%)}to{transform:none}}

/* The word that follows the demo: the old one leaves upward, the new one rises
   in, and the slot's width follows so the line closes up behind it. */
/* Masked above and below only, like the lines (user, 2026-11-03). overflow:
   hidden cut the sides too: the last letter's tip, which the tight tracking
   pushes past the slot's box, and a longer word arriving before the width
   caught up with it. */
.nb-slot{display:inline-block;position:relative;clip-path:inset(0 -100vw);vertical-align:bottom;padding-bottom:.12em;margin-bottom:-.12em;transition:width var(--nb-dur) var(--nb-roll-ease)}
.nb-w{display:block;width:max-content;white-space:nowrap}
.nb-w.is-in{animation:nb-word-in var(--nb-dur) var(--nb-roll-ease) both}
.nb-w.is-out{position:absolute;left:0;top:0;animation:nb-word-out var(--nb-dur) var(--nb-roll-ease) both}
/* 140%, not 110%: at line-height .95 the tall letters stand above the line
   box, and the waiting word's tops showed under the line. */
@keyframes nb-word-in{from{transform:translateY(140%)}to{transform:none}}
@keyframes nb-word-out{from{transform:none}to{transform:translateY(-140%)}}

/* The picture: repri.in's live desktop in an iframe (repri/island.html), the
   same scene and the same files as the site, cropped, not redrawn. The strip
   shows --nb-crop-w of the desktop's width from --nb-crop-x, top aligned, so
   the island sits in it with the tops of Notepad and Downloads under it, and
   is tall enough (3:1) that the island never clips when it opens. Nothing is
   laid over it. */
/* Its size is its own, not the sentence's (user, 2026-11-03: "too big"): 6.5em
   wide, anchored top left, so a long word runs on past it instead of
   stretching it. 3.2:1 still gives the island room to open. */
.nb-frame{--nb-crop-w:.825;--nb-crop-x:.113;position:relative;overflow:hidden;width:6.5em;max-width:100%;aspect-ratio:3.2/1;margin:var(--space-5) 0;border-radius:var(--radius-sm);background:var(--paper-2);animation:nb-open 900ms var(--nb-ease) both;animation-delay:270ms}
.nb-frame iframe{position:absolute;top:0;left:calc(-100% * var(--nb-crop-x) / var(--nb-crop-w));width:calc(100% / var(--nb-crop-w));height:100%;border:0;opacity:0;transition:opacity 400ms var(--nb-ease)}
.nb-frame.is-live iframe{opacity:1}
@keyframes nb-open{from{clip-path:inset(100% 0 0 0)}to{clip-path:inset(0)}}

/* My cursor, once a visit: it comes to the island and says it can be used,
   then leaves when the visitor's pointer arrives. The playground's guide (the
   orange "Tathagata" cursor), at the visitor cursor's size. */
.nb-guide{position:absolute;z-index:2;left:0;top:0;pointer-events:none;opacity:0;translate:var(--space-8) var(--space-5);transition:opacity 300ms var(--nb-ease),translate 750ms cubic-bezier(.22,1,.36,1);font:600 var(--type-small)/1.2 var(--face-sans);letter-spacing:0}
.nb-guide.is-on{opacity:1;translate:0 0}
.nb-guide svg{display:block;width:18px;height:22px;margin:-2px 0 0 -2px;filter:drop-shadow(0 1px 2px rgba(0,0,0,.25))}
.nb-guide svg path{fill:var(--accent);stroke:#FFFFFF;stroke-width:1.4;stroke-linejoin:round}
.nb-guide__tag{position:absolute;left:var(--space-3);top:var(--space-4);padding:var(--space-1) var(--space-2);border-radius:3px 10px 10px 10px;background:var(--accent);color:#141414;white-space:nowrap;box-shadow:0 2px 6px rgba(0,0,0,.18)}
@media(prefers-reduced-motion:reduce){.nb-guide{transition:opacity 200ms;translate:none}}

/* Beside it: what Repri is, in two plain sentences, and the two ways forward,
   on the sentence's last line. No labels over them. Set as one block on the
   page's right edge (user, 2026-11-03): the text is left-aligned and exactly
   as wide as the row of buttons under it (width 0, then the column's 100%), so
   it starts at the Repri button and ends with See the work. Three lines. */
.nb-side{justify-self:end;display:grid;gap:var(--space-6);padding-bottom:var(--space-2)}
.nb-about{margin:0;width:0;min-width:100%;font:400 var(--type-body)/1.55 var(--face-sans);color:var(--ink-70);text-wrap:balance}
.nb-about b{font-weight:500;color:var(--ink)}
/* The two buttons side by side; stacked on phones (below). */
.nb-actions{display:flex;gap:var(--space-2)}
/* repri.in's button carries Repri's own lockup, as repri.in's header sets it:
   the app icon (repri/repri-icon-64.png) as the button's chip, the wordmark
   (Repri's own outlines, in the button's ink) as its label. The icon keeps its
   colours, so the chip has no fill of its own and doesn't flip on hover. */
.nb-repri .tbtn-chip{--chip-bg:transparent;--chip-line:transparent}
.nb-repri__word{display:block;height:1.3em;width:auto}

/* Laptops narrower than the sentence plus its side: the side goes under it. */
@media(max-width:1180px){
  .nb-hero{grid-template-columns:minmax(0,1fr);row-gap:var(--space-7)}
  .nb-side{justify-self:start;grid-template-columns:minmax(0,52ch) auto;align-items:end;column-gap:var(--space-8)}
  .nb-about{width:auto;min-width:0}
}
/* Phones: the sentence fills the width (now-building.js sizes it by its widest
   line with any of its words). The strip is the desktop's, only smaller (user,
   2026-11-03: a phone can't hover the island, so show all the web shows rather
   than crop in on it). Same crop, same 3.2:1. The demo is laid out at a
   desktop width (--nb-ref) and scaled down (--nb-k, set by now-building.js),
   because its own narrow-screen rules would change it in a phone-wide frame. */
@media(max-width:760px){
  .nb-col{width:100%}
  .nb-frame{--nb-ref:800px;width:auto;margin:var(--space-4) 0}
  .nb-frame iframe{width:var(--nb-ref);height:calc(var(--nb-ref) * var(--nb-crop-w) / 3.2);left:calc(-1 * var(--nb-ref) * var(--nb-crop-x) * var(--nb-k, 1));transform:scale(var(--nb-k, 1));transform-origin:0 0}
  .nb-side{grid-template-columns:minmax(0,1fr);gap:var(--space-5)}
  /* One under the other, each its own width (user, 2026-11-03). Not stretched
     to one width: a .tbtn spreads its chip and label to its two ends. */
  .nb-actions{flex-direction:column;align-items:flex-start}
}
@media(prefers-reduced-motion:reduce){.nb-in,.nb-frame{animation:none}.nb-frame iframe,.nb-slot{transition:none}}
