/* ═══════════════════════════════════════════════════════════════════════════
   Home — the screen a Wabi opens on.

   THE HOUSE RULES THIS SHEET KEEPS
   ─────────────────────────────────
   1. EVERY LENGTH IS A DESIGN POINT: calc(var(--pt)*n), where --pt is one
      point of the 402pt width the layout was drawn at. The framed desktop
      view and a real phone then get the SAME layout rather than two designs.
      The one exception is a tap target, which is 44 REAL pixels — the one
      measurement that must not scale is the one about a thumb.
   2. ONE DECLARED LIGHT, from just left of straight above (11 o'clock). Every
      raised thing has a lit hairline on its TOP inner edge, a shaded one along
      its BOTTOM, and a cast shadow BELOW it.
   3. GEOMETRY IS FIGMA'S, MEASURED off node 21431:22948 of 🌻 Wabi 2.0:
        gutter 20 · widget 140 square, radius 24 (--sm), 1.5px white border,
        gap 13 · row 361 wide, radius 24, fill rgba(147,147,147,.08), pad 16,
        gap 8, icon 56 (radius 20 for an app, round for an orb), name 16/18
        #090909, sub 14/16 #636363, time 14 at .7 · dock 282x54 pill + 54
        square, gap 14, radius 60, rgba(244,244,244,.3) with the glass-1 inner
        shadows · top-rail 126 tall, a gradient from #f2f2f2 to nothing.
   4. THREE INKS and no more: --ink for what you came to read, --ink-58 for
      what supports it, --ink-34 for the small print.
   ═══════════════════════════════════════════════════════════════════════════ */

@font-face{font-family:'Selecta';src:url(../fonts/Selecta-Regular.otf) format('opentype');font-weight:400;font-display:swap}
@font-face{font-family:'Selecta';src:url(../fonts/Selecta-Medium.otf) format('opentype');font-weight:500;font-display:swap}

:root{
  --ink:#090909;
  --ink-58:#636363;
  --ink-34:rgba(9,9,9,.34);
  --paper:#fafafa;
  --tile:#fafafa;
  --row:rgba(147,147,147,.08);
  --sm:24;                       /* the Figma radius token, in points */
  --ease:cubic-bezier(.22,1,.36,1);
  --spring:cubic-bezier(.34,1.42,.64,1);
  --sheet:cubic-bezier(.32,.72,0,1);
  /* elevation/3, straight off the Figma effect style */
  --e3:0 0 0 1px rgba(0,0,0,.02), 0 calc(var(--pt)*2) calc(var(--pt)*16) rgba(0,0,0,.04), 0 calc(var(--pt)*8) calc(var(--pt)*24) rgba(0,0,0,.10);
  --e2:0 0 0 1px rgba(0,0,0,.02), 0 calc(var(--pt)*2) calc(var(--pt)*6) rgba(0,0,0,.04), 0 calc(var(--pt)*4) calc(var(--pt)*8) rgba(0,0,0,.10);
  /* the exported artwork. ⚠ a url() in a real stylesheet resolves against the
     STYLESHEET, which is what we want; the trap is a url() inside a stylesheet
     built in JS, which resolves against the document. */
  --sheen:url(../img/orb.webp);
  --mag:url(../img/ui/search.svg);
  --plus:url(../img/ui/plus.svg);
}

*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{
  background:#101010;
  font-family:'Selecta',ui-sans-serif,system-ui,-apple-system,sans-serif;
  color:var(--ink);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overscroll-behavior:none;
}
button,textarea,input{font:inherit;color:inherit;border:0;background:none}
button{cursor:pointer}
[hidden]{display:none!important}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* ── the desk ─────────────────────────────────────────────────────────────
   Desktop only. `body.bare` is the same app with the hardware and the rail
   taken off, and a real phone is ALWAYS bare — the frame is a class, and
   js/app.js gates the class on matchMedia('(pointer:fine)') rather than a
   media query, because a media query cannot promise a class is absent. */
#desk{
  position:fixed;inset:0;display:flex;align-items:center;justify-content:center;
  gap:56px;
  background:radial-gradient(120% 90% at 50% 0%,#1b1b1b 0%,#0b0b0b 74%);
}
#device{
  position:relative;flex:none;width:402px;height:874px;
  container-type:size;container-name:app;
  border-radius:56px;overflow:hidden;isolation:isolate;
  background:var(--paper);
  box-shadow:
    0 0 0 12px #16161a, 0 0 0 13px #3a3a40, 0 0 0 15px #0d0d10,
    0 60px 120px -40px rgba(0,0,0,.9), 0 10px 40px -12px rgba(0,0,0,.6);
}
body.bare #desk{background:var(--paper);gap:0}
body.bare #device{width:100%;height:100%;border-radius:0;box-shadow:none}
body.bare #rail{display:none}
.island,.homebar{position:absolute;left:50%;transform:translateX(-50%);z-index:60;pointer-events:none}
.island{top:11px;width:125px;height:36px;border-radius:20px;background:#0a0a0a}
.homebar{bottom:8px;width:139px;height:5px;border-radius:3px;background:rgba(9,9,9,.32)}
body.bare .island,body.bare .homebar{display:none}

/* ── the reviewer's rail ───────────────────────────────────────────────── */
#rail{
  flex:none;width:268px;color:rgba(255,255,255,.9);
  display:flex;flex-direction:column;gap:18px;
}
.rail-hd b{display:block;font-weight:500;font-size:17px;letter-spacing:-.02em}
.rail-hd span{display:block;margin-top:4px;font-size:13px;color:rgba(255,255,255,.42)}
#people-rail{display:flex;flex-direction:column;gap:6px}
.pcard{
  display:flex;align-items:center;gap:11px;width:100%;text-align:left;
  padding:9px 11px;border-radius:15px;
  background:rgba(255,255,255,.05);
  transition:background .2s var(--ease);
}
.pcard:hover{background:rgba(255,255,255,.10)}
.pcard[aria-pressed=true]{background:rgba(255,255,255,.16);box-shadow:inset 0 0 0 1px rgba(255,255,255,.16)}
.pcard .orb{width:30px;height:30px;flex:none}
.pcard b{display:block;font-weight:500;font-size:14px;letter-spacing:-.015em}
.pcard span{display:block;font-size:12px;color:rgba(255,255,255,.44);letter-spacing:-.01em}
.pcard kbd{
  margin-left:auto;font:inherit;font-size:11px;color:rgba(255,255,255,.3);
  padding:2px 6px;border-radius:5px;background:rgba(255,255,255,.06);
}
.rail-ft{margin-top:2px;display:flex;flex-direction:column;gap:9px;align-items:flex-start}
#tolib,#vtoggle{
  font-size:13px;color:rgba(255,255,255,.66);text-decoration:none;
  padding:8px 13px;border-radius:999px;background:rgba(255,255,255,.07);
}
#tolib:hover,#vtoggle:hover{color:#fff;background:rgba(255,255,255,.13)}
.rail-note{font-size:11.5px;line-height:1.45;color:rgba(255,255,255,.3);max-width:236px}
body.bare #vtoggle{
  display:block;position:fixed;right:18px;top:18px;z-index:90;
  background:rgba(9,9,9,.07);color:var(--ink-58);
}

/* ── the app ──────────────────────────────────────────────────────────────
   --pt is 1/402 of the device's own width. --top and --bot are the phone's
   safe areas: real insets on a phone, the drawn island and home bar in the
   frame, so the layout is under the same constraint either way. */
#stage{
  position:absolute;inset:0;overflow:hidden;isolation:isolate;
  --pt:calc(100cqw / 402);
  --top:calc(var(--pt)*59);
  --bot:calc(var(--pt)*34);
  --gut:calc(var(--pt)*20);
  /* ⚠ 54 DESIGN POINTS IS 43 REAL PIXELS ON A 320pt PHONE. The one measurement
     that must not scale is the one about a thumb. */
  --dock:max(48px, calc(var(--pt)*54));
}
body.bare #stage{
  --top:max(calc(var(--pt)*20), env(safe-area-inset-top));
  --bot:max(calc(var(--pt)*16), env(safe-area-inset-bottom));
}
#wash{position:absolute;inset:0;z-index:0;pointer-events:none;background:#fafafa}

/* ── the top rail ─────────────────────────────────────────────────────────
   126pt tall, a gradient from the neutral ground to nothing, so the widgets
   dissolve INTO it as they scroll under rather than being sliced by an edge. */
#top{
  position:absolute;left:0;right:0;top:0;z-index:40;
  height:calc(var(--top) + var(--pt)*67);
  padding-top:var(--top);
  background:linear-gradient(#f2f2f2 0%, #f2f2f2 58%, rgba(250,250,250,0) 100%);
  -webkit-backdrop-filter:blur(calc(var(--pt)*8));backdrop-filter:blur(calc(var(--pt)*8));
  pointer-events:none;
}
#top>*{pointer-events:auto}
#top .status{
  position:absolute;left:0;right:0;top:calc(var(--pt)*21);height:calc(var(--pt)*22);
  display:flex;align-items:center;justify-content:space-between;
  padding:0 calc(var(--pt)*16);
}
body.bare #top .status{display:none}
#top .clock{font-weight:500;font-size:calc(var(--pt)*17);letter-spacing:-.01em}
#top .levels{display:flex;align-items:center;gap:calc(var(--pt)*7)}
#top .levels img{display:block;height:calc(var(--pt)*12)}
#top .tool{
  position:absolute;left:var(--gut);right:var(--gut);bottom:calc(var(--pt)*9);
  height:calc(var(--pt)*44);display:flex;align-items:center;justify-content:space-between;
}
#top .logo{display:block;width:calc(var(--pt)*112);color:var(--ink)}
#top .logo svg{display:block;width:100%;height:auto}
#top .me{
  width:max(44px, calc(var(--pt)*44));height:max(44px, calc(var(--pt)*44));
  display:grid;place-items:center;border-radius:999px;
  transition:transform .3s var(--spring);
}
#top .me:active{transform:scale(.93)}
#top .me .orb{width:calc(var(--pt)*44);height:calc(var(--pt)*44)}

/* the orb: a coloured ground with the mark's own specular screened over it —
   the Figma component exactly, including the 120.21% / -9.96% / -9% that push
   the plate's white margin outside the circle. */
.orb{
  position:relative;display:block;border-radius:50%;overflow:hidden;flex:none;
  background:radial-gradient(120% 120% at 30% 18%, var(--o1,#8ab) 0%, var(--o2,#248) 78%);
  box-shadow:0 0 0 1.5px #fff, 0 0 0 2.5px rgba(0,0,0,.02),
             0 calc(var(--pt)*3) calc(var(--pt)*7) rgba(0,0,0,.16);
}
.orb::after{
  content:'';position:absolute;left:-9.96%;top:-9%;width:120.21%;height:120.21%;
  background:var(--sheen) center/contain no-repeat;
  mix-blend-mode:screen;pointer-events:none;
}

/* ── the scroller ─────────────────────────────────────────────────────── */
#scroll{
  position:absolute;inset:0;z-index:10;
  overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  scrollbar-width:none;
}
#scroll::-webkit-scrollbar{display:none}
#page{
  padding-top:calc(var(--top) + var(--pt)*67);
  /* the dock floats over the list, so the list has to end above it */
  padding-bottom:calc(var(--bot) + var(--dock) + var(--pt)*40);
}

/* ── the widgets ──────────────────────────────────────────────────────────
   ⚠ A MOUSE CANNOT SWIPE `overflow-x`. It scrolls under a finger and a wheel
     and not at all under a mouse drag, so on the one machine this gets reviewed
     on the row would be dead. js/app.js drags scrollLeft by hand, with NO
     pointer capture — capturing on a scroller retargets the following `click`
     and every widget here is a button. */
.widgets{
  display:flex;gap:calc(var(--pt)*13);
  padding:calc(var(--pt)*4) var(--gut) calc(var(--pt)*18);
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
  scroll-snap-type:x proximity;scroll-padding-left:var(--gut);
  -webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;
}
.widgets::-webkit-scrollbar{display:none}
.cell{
  flex:none;position:relative;display:block;padding:0;
  width:calc(var(--pt)*140);height:calc(var(--pt)*140);
  scroll-snap-align:start;
  transition:transform .42s var(--spring);
  will-change:transform;
}
.cell:active{transform:scale(.965)}
.cell .field{
  position:absolute;inset:0;display:block;overflow:hidden;
  border-radius:calc(var(--pt)*var(--sm));
  background:var(--tile);isolation:isolate;
  /* 1.5px white border + elevation/3, both the artwork's own */
  box-shadow:0 0 0 1.5px #fff, var(--e3);
}
.widgets.drag{cursor:grabbing}
.widgets.drag .cell{pointer-events:none}

/* ── the list ─────────────────────────────────────────────────────────── */
.list{display:flex;flex-direction:column;gap:calc(var(--pt)*8);padding:0 var(--gut)}
.rowc{
  position:relative;display:flex;align-items:center;justify-content:space-between;
  gap:calc(var(--pt)*12);width:100%;text-align:left;
  padding:calc(var(--pt)*16);
  border-radius:calc(var(--pt)*var(--sm));
  background:var(--row);
  transition:transform .3s var(--spring), background .2s var(--ease);
}
.rowc:first-child{box-shadow:inset 0 0 0 1.5px #fff}
.rowc:active{transform:scale(.985);background:rgba(147,147,147,.14)}
.rowc .ic{flex:none;width:calc(var(--pt)*56);height:calc(var(--pt)*56);position:relative}
/* an app's icon is the widget itself, laid out at ITS own size and scaled —
   a photograph of the app running, not a redraw of it */
.rowc .ic .field{
  position:absolute;left:0;top:0;transform-origin:0 0;overflow:hidden;
  border-radius:calc(var(--pt)*20);background:var(--tile);
  box-shadow:0 0 0 1.5px #fff, var(--e2);
}
.rowc .txt{flex:1;min-width:0}
.rowc .txt b{
  display:block;font-weight:400;font-size:calc(var(--pt)*16);line-height:calc(var(--pt)*18);
  color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.rowc .txt span{
  display:block;margin-top:calc(var(--pt)*2);
  font-size:calc(var(--pt)*14);line-height:calc(var(--pt)*16);
  color:var(--ink-58);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.rowc.new .txt span{font-weight:500;color:var(--ink)}
.rowc .when{
  flex:none;display:flex;align-items:center;gap:calc(var(--pt)*8);
  font-size:calc(var(--pt)*14);line-height:calc(var(--pt)*16);color:var(--ink-58);opacity:.7;
}
.rowc .when i{width:calc(var(--pt)*6);height:calc(var(--pt)*6);border-radius:50%;background:#2f6bff}
.credit{
  padding:calc(var(--pt)*22) var(--gut) 0;
  font-size:calc(var(--pt)*11.5);line-height:1.5;color:var(--ink-34);text-align:center;
}

/* ── the dock ─────────────────────────────────────────────────────────────
   Two pieces of glass floating over the list: the search, and the one way to
   make something new. Geometry is the artwork's: 282x54 and 54 square, 14
   apart, radius 60, and the glass-1 inner shadows. */
#dock{
  position:absolute;left:50%;bottom:calc(var(--bot) + var(--pt)*12);z-index:45;
  transform:translateX(-50%);
  display:flex;align-items:center;gap:calc(var(--pt)*14);
}
#dock .pill,#dock .plus{
  height:var(--dock);border-radius:calc(var(--pt)*60);
  background:rgba(244,244,244,.3);
  -webkit-backdrop-filter:blur(calc(var(--pt)*18)) saturate(1.6);
  backdrop-filter:blur(calc(var(--pt)*18)) saturate(1.6);
  box-shadow:
    inset -1px -1px 2px 0 rgba(255,255,255,.32),
    inset 1px 1px 1px 0 rgba(255,255,255,.12),
    0 calc(var(--pt)*6) calc(var(--pt)*18) rgba(0,0,0,.10);
}
#dock .pill{
  width:calc(var(--pt)*282);display:flex;align-items:center;gap:calc(var(--pt)*11);
  padding:0 calc(var(--pt)*23);
}
#dock .mag{
  width:calc(var(--pt)*18);height:calc(var(--pt)*18);flex:none;
  background:var(--mag) center/contain no-repeat;opacity:.4;
}
#dock input{
  flex:1;min-width:0;height:100%;
  font-size:calc(var(--pt)*16);line-height:calc(var(--pt)*16);color:var(--ink);
}
#dock input::placeholder{color:rgba(0,0,0,.3)}
#dock input::-webkit-search-cancel-button{display:none}
#dock .plus{
  width:var(--dock);flex:none;display:grid;place-items:center;
  transition:transform .3s var(--spring);
}
#dock .plus:active{transform:scale(.93)}
#dock .pl{
  width:calc(var(--pt)*28);height:calc(var(--pt)*28);display:block;
  background:var(--plus) center/contain no-repeat;
}
body.searching #dock .plus{display:none}
body.searching #dock .pill{width:calc(var(--pt)*350)}

/* ── the app, opened ──────────────────────────────────────────────────────
   Tapping a widget OPENS it. The tile flies up and becomes the thing itself at
   the width of the phone — the same object, the same sim, not a screenshot —
   and the one verb under it is how you get your own. */
#open{
  position:absolute;inset:0;z-index:55;display:flex;flex-direction:column;
  background:#fafafa;
  padding:calc(var(--top) + var(--pt)*10) var(--gut) calc(var(--bot) + var(--pt)*18);
}
#open.in{animation:openin .42s var(--ease) both}
@keyframes openin{from{opacity:0}to{opacity:1}}
#open .oh{display:flex;align-items:center;gap:calc(var(--pt)*12);height:max(44px, calc(var(--pt)*44))}
#open .back{
  width:max(44px, calc(var(--pt)*44));height:max(44px, calc(var(--pt)*44));
  margin-left:calc(var(--pt)*-10);
  display:grid;place-items:center;border-radius:999px;position:relative;
}
#open .back::before{
  content:'';width:calc(var(--pt)*11);height:calc(var(--pt)*11);
  border-left:calc(var(--pt)*2) solid var(--ink);
  border-bottom:calc(var(--pt)*2) solid var(--ink);
  transform:rotate(45deg);border-radius:1px;
}
#open .who{font-size:calc(var(--pt)*15);color:var(--ink-58)}
#open .big{
  margin-top:calc(var(--pt)*10);
  width:100%;aspect-ratio:1;position:relative;
}
#open .big .field{
  position:absolute;inset:0;display:block;overflow:hidden;isolation:isolate;
  border-radius:calc(var(--pt)*34);background:var(--tile);
  box-shadow:0 0 0 1.5px #fff, var(--e3);
}
/* ── the variants, under the app ────────────────────────────────────────── */
/* ⚠ EIGHTEEN CHIPS DO NOT FIT ON A PHONE, so the row scrolls and snaps — and
   it is inset by the gutter with `scroll-padding` to match, or a `start` snap
   ignores the padding and pins the first chip flush to the screen edge. */
#open .ovs{
  display:flex;gap:calc(var(--pt)*7);margin:calc(var(--pt)*16) calc(var(--gut)*-1) 0;
  padding:0 var(--gut);overflow-x:auto;scroll-snap-type:x proximity;
  scroll-padding-left:var(--gut);scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
#open .ovs::-webkit-scrollbar{display:none}
#open .ovs[hidden]{display:none}
#open .ov{
  flex:none;scroll-snap-align:start;white-space:nowrap;cursor:pointer;
  height:max(34px, calc(var(--pt)*34));padding:0 calc(var(--pt)*14);
  border-radius:999px;border:1px solid var(--line);background:rgba(255,255,255,.62);
  backdrop-filter:blur(14px) saturate(1.4);-webkit-backdrop-filter:blur(14px) saturate(1.4);
  font:inherit;font-size:calc(var(--pt)*14);letter-spacing:-.012em;color:var(--ink-58);
}
#open .ov[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:#fff;font-weight:500}
#open .ot{margin-top:calc(var(--pt)*16)}
#open .ot b{display:block;font-weight:500;font-size:calc(var(--pt)*28);letter-spacing:-.034em}
#open .ot p{
  margin-top:calc(var(--pt)*8);
  font-size:calc(var(--pt)*16);line-height:1.42;letter-spacing:-.012em;color:var(--ink-58);
  text-wrap:pretty;
}
#open .obody{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding-bottom:calc(var(--pt)*10);
  scrollbar-width:none;-webkit-mask:linear-gradient(#000 calc(100% - 30px),transparent)}
#open .obody::-webkit-scrollbar{display:none}
#open .oa{margin-top:calc(var(--pt)*14);display:flex;flex:none}
#open .oa .btn{flex:1}

/* ── whose phone is this ──────────────────────────────────────────────── */
#people{position:absolute;inset:0;z-index:72}
#people::before{
  content:'';position:absolute;inset:0;background:rgba(18,18,17,.42);
  -webkit-backdrop-filter:blur(calc(var(--pt)*4));backdrop-filter:blur(calc(var(--pt)*4));
  animation:fadein .34s var(--ease) both;
}
#people .sh{
  position:absolute;left:0;right:0;bottom:0;
  padding:calc(var(--pt)*10) calc(var(--pt)*18) calc(var(--bot) + var(--pt)*18);
  border-radius:calc(var(--pt)*30) calc(var(--pt)*30) 0 0;
  background:#fbfbfa;
  box-shadow:0 calc(var(--pt)*-10) calc(var(--pt)*40) rgba(0,0,0,.30);
  animation:up .46s var(--sheet) both;
}
#people .k{
  font-weight:500;font-size:calc(var(--pt)*15);letter-spacing:-.016em;color:var(--ink-58);
  padding:0 calc(var(--pt)*4) calc(var(--pt)*12);
}
.who-list{display:flex;flex-direction:column;gap:calc(var(--pt)*4)}
.who-row{
  display:flex;align-items:center;gap:calc(var(--pt)*12);width:100%;text-align:left;
  padding:calc(var(--pt)*10) calc(var(--pt)*12);border-radius:calc(var(--pt)*18);
  min-height:max(44px, calc(var(--pt)*60));
}
.who-row[aria-pressed=true]{background:rgba(147,147,147,.12)}
.who-row .orb{width:calc(var(--pt)*40);height:calc(var(--pt)*40)}
.who-row b{display:block;font-weight:500;font-size:calc(var(--pt)*16);letter-spacing:-.015em}
.who-row span{display:block;font-size:calc(var(--pt)*14);color:var(--ink-58)}
#people .tiny{margin-top:calc(var(--pt)*14)}

/* ── the way in ───────────────────────────────────────────────────────────
   The widgets deal themselves along the row, then the list arrives under them.
   ⚠ IT PLAYS ONCE. Replaying it every time you switch person is an animation
     between two screens somebody is deliberately moving between. */
body.boot .cell{animation:dealx .62s var(--ease) both;animation-delay:calc(var(--i,0)*64ms + 40ms)}
body.boot .rowc{animation:rise .6s var(--ease) both;animation-delay:calc(var(--i,0)*44ms + 220ms)}
@keyframes dealx{from{opacity:0;transform:translateX(calc(var(--pt)*26)) scale(.94)}to{opacity:1;transform:none}}
@keyframes rise{from{opacity:0;transform:translateY(calc(var(--pt)*16))}to{opacity:1;transform:none}}
/* switching person is not a boot: the contents cross-fade in place */
body.swap .widgets,body.swap .list{animation:swap .46s var(--ease) both}
@keyframes swap{
  0%{opacity:1;transform:none}
  38%{opacity:0;transform:translateY(calc(var(--pt)*6))}
  100%{opacity:1;transform:none}
}

/* ── the chip ──────────────────────────────────────────────────────────────
   ⚠ A 38pt WIDGET IS MUD. Laid out at 38pt the scope's screen inset is two
     pixels and its labels are two pixels tall, so the chip came out as a black
     square — a thumbnail of nothing. Everything inside a widget is `cqw` of the
     tile, so the fix is to lay the art out at ITS OWN 171pt and then SCALE the
     whole thing down: a true miniature of the tile, still live, still the same
     object. Photograph, not redraw. */
.chip{
  position:relative;flex:none;
  width:calc(var(--pt)*56);height:calc(var(--pt)*56);
  border-radius:calc(var(--pt)*14);overflow:hidden;
  background:var(--tile);
  box-shadow:0 0 0 1px rgba(0,0,0,.06),0 calc(var(--pt)*3) calc(var(--pt)*8) rgba(0,0,0,.14);
}
.chip .field{
  position:absolute;left:0;top:0;
  transform-origin:0 0;
  border-radius:calc(var(--pt)*47);box-shadow:none;background:var(--tile);
}
.chip.in{animation:chipin .44s var(--spring) both}
@keyframes chipin{from{opacity:0;transform:scale(.5)}to{opacity:1;transform:none}}

/* ── the morph ─────────────────────────────────────────────────────────────
   The tile you tapped travels into the bar and becomes the chip. A cross-fade
   here would be the single most common motion defect in the book: the sentence
   has to come from somewhere, and it comes from the thing you touched. */
#ghost{
  position:absolute;z-index:55;pointer-events:none;
  border-radius:calc(var(--pt)*15);overflow:hidden;background:var(--tile);
  box-shadow:var(--e3);
  transform-origin:0 0;
}
#ghost .field{position:absolute;inset:0;box-shadow:none;border-radius:inherit}

/* the widget the sentence came from stays marked, so the loop closes */
.cell.picked .field{
  box-shadow:
    0 0 0 calc(var(--pt)*2) rgba(25,25,25,.86),
    0 calc(var(--pt)*4) calc(var(--pt)*8) rgba(0,0,0,.10),
    0 calc(var(--pt)*14) calc(var(--pt)*32) rgba(0,0,0,.20);
}
.cell .field{transition:box-shadow .34s var(--ease)}

/* ── the sheet: the composer ──────────────────────────────────────────────
   A tap opens this. It carries the tile you tapped (still running), the
   sentence that tile wrote, its own three refinements, and the one verb. There
   is no text field: in Wabi the field is the host's, and this hands the prompt
   to it. */
#sheetup{position:absolute;inset:0;z-index:70}
#sheetup::before{
  content:'';position:absolute;inset:0;background:rgba(18,18,17,.42);
  backdrop-filter:blur(calc(var(--pt)*4));
  -webkit-backdrop-filter:blur(calc(var(--pt)*4));
  animation:fadein .34s var(--ease) both;
}
#sheetup .sh{
  position:absolute;left:0;right:0;bottom:0;
  padding:calc(var(--pt)*10) calc(var(--pt)*22) calc(var(--bot) + var(--pt)*20);
  border-radius:calc(var(--pt)*30) calc(var(--pt)*30) 0 0;
  background:#fbfbfa;
  box-shadow:0 calc(var(--pt)*-10) calc(var(--pt)*40) rgba(0,0,0,.30);
  animation:up .46s var(--sheet) both;
}
/* ⚠ one measurement is taken while the sheet is sliding: `.still` parks it so
   the chip's rect is where it is GOING, not where it is. */
#sheetup.still .sh,#sheetup.still::before{animation:none;transform:none}
@keyframes fadein{from{opacity:0}to{opacity:1}}
@keyframes up{from{transform:translateY(100%)}to{transform:none}}
#sheetup .grip{width:calc(var(--pt)*38);height:calc(var(--pt)*5);border-radius:999px;background:rgba(25,25,25,.10);margin:0 auto calc(var(--pt)*16)}

#sheetup .shhead{display:flex;align-items:center;gap:calc(var(--pt)*11);margin-bottom:calc(var(--pt)*14)}
#sheetup .k{
  font-weight:500;font-size:calc(var(--pt)*15);letter-spacing:-.016em;color:var(--ink-58);
}
#sheetup .p{
  font-size:calc(var(--pt)*20);line-height:1.3;letter-spacing:-.022em;text-wrap:pretty;
  min-height:calc(var(--pt)*78);
}
#sheetup .row{display:flex;gap:calc(var(--pt)*10);margin-top:calc(var(--pt)*20)}
/* ⚠ 44 REAL PIXELS, not 44 design points. --pt scales with the screen, so on a
   320pt phone a button sized in points came out 38 tall — the one measurement
   that must not scale is the one about a thumb. */
.btn{
  flex:1;min-height:max(46px, calc(var(--pt)*48));
  padding:calc(var(--pt)*15) calc(var(--pt)*16);border-radius:999px;
  font-weight:500;font-size:calc(var(--pt)*15.5);letter-spacing:-.016em;
  background:var(--ink);color:#fff;
  box-shadow:0 calc(var(--pt)*6) calc(var(--pt)*14) calc(var(--pt)*-8) rgba(0,0,0,.5);
  transition:transform .2s var(--ease);
}
.btn.ghost{flex:0 0 auto;padding-inline:calc(var(--pt)*20);background:rgba(25,25,25,.06);color:var(--ink-58);box-shadow:none}
.btn:active{transform:scale(.98)}
#sheetup .tiny{margin-top:calc(var(--pt)*13);font-size:calc(var(--pt)*11.5);color:var(--ink-34);text-align:center}
#sheetup code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}

/* the refinements: this widget's own three. Deliberately NOT tiles — a tile is
   a thing you could have, a pill is a way to change the thing you just chose. */
#pills{display:flex;flex-wrap:wrap;gap:calc(var(--pt)*7);margin-top:calc(var(--pt)*4)}
.pill{
  min-height:max(38px, calc(var(--pt)*38));
  padding:calc(var(--pt)*10) calc(var(--pt)*14) calc(var(--pt)*11);
  border-radius:999px;
  font-size:calc(var(--pt)*13.5);letter-spacing:-.014em;color:var(--ink-58);
  background:rgba(25,25,25,.05);
  box-shadow:inset 0 0 0 1px rgba(25,25,25,.05);
  transition:transform .3s var(--spring),background .2s var(--ease),color .2s var(--ease);
  animation:pillin .46s var(--ease) both;animation-delay:calc(var(--i,0)*52ms);
}
@keyframes pillin{from{opacity:0;transform:translateY(calc(var(--pt)*8)) scale(.94)}to{opacity:1;transform:none}}
.pill:active{transform:scale(.96)}
.pill.on{background:var(--ink);color:#fff;box-shadow:none}

/* ── reduced motion: nothing moves unasked. The widgets stop too — they are
      ambient by definition, and ambient motion is the first thing this
      setting is about. ─────────────────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  body.boot .cell,body.boot .rowc{animation:none}
  body.swap .widgets,body.swap .list{animation:none}
  #open.in{animation-duration:.01s}
  #sheetup .sh,#sheetup::before{animation-duration:.01s}
}

/* ── a short phone ────────────────────────────────────────────────────────
   On a 568pt screen the greeting was taking nearly half of it and only two
   tiles were above the dock. The board is the content, so the header gives way
   — measured against the DEVICE's own box (a container query), not the viewport,
   because inside the drawn frame the viewport is the desk. */
@container app (max-height: 700px){
  /* a short phone: the widgets give up a little height so a row and a half of
     the list is still under them */
  .cell{width:calc(var(--pt)*124);height:calc(var(--pt)*124)}
  .widgets{padding-bottom:calc(var(--pt)*14)}
  #open .ot b{font-size:calc(var(--pt)*24)}
}


/* ── what you would ask for next ─────────────────────────────────────────────
   ⚠ A THIRD OF THE OPEN SCREEN WAS EMPTY and every widget already carried the
   thing that belongs in it. These are not settings and must not look like
   chips: they are the next sentence you would say about the app you are
   looking at, so they are SENTENCES with a hairline between them, left-aligned
   with the prompt above and reading down the page rather than across it. */
#open .oadds{padding:calc(var(--pt)*14) 0 0}
#open .oal{
  display:block;font-size:calc(var(--pt)*12);letter-spacing:.09em;text-transform:uppercase;
  color:rgba(25,25,25,.34);margin-bottom:calc(var(--pt)*6);
}
#open .oarow{display:flex;flex-direction:column}
#open .oadd{
  appearance:none;border:0;background:none;cursor:pointer;text-align:left;
  padding:calc(var(--pt)*10) 0;font:inherit;
  font-size:calc(var(--pt)*17);letter-spacing:-.012em;color:rgba(25,25,25,.72);
  border-bottom:1px solid rgba(25,25,25,.08);
  transition:color .2s var(--ease-wabi), transform .3s var(--spring);
}
#open .oadd:last-child{border-bottom:0}
#open .oadd::before{content:'+ ';color:rgba(25,25,25,.28)}
#open .oadd:hover{color:var(--ink)}
#open .oadd:active{transform:scale(.985)}


/* ── the way to the library, from a phone ────────────────────────────────────
   ⚠ THE LINK LIVES IN THE DESKTOP RAIL, which is the one piece of chrome a
   phone does not get — so on a phone the ninety widgets were unreachable from
   the app that is made of them. It sits at the foot of the profile sheet, in
   the same row shape the six people use, with the library's own five-orb mark
   where their orb goes. */
.who-row.tolib{
  text-decoration:none;color:inherit;margin-top:calc(var(--pt)*6);
  border-top:1px solid rgba(25,25,25,.08);border-radius:0;
  padding-top:calc(var(--pt)*16);
}
.who-row.tolib .t{flex:1;min-width:0}
.who-row.tolib .libmark{
  width:calc(var(--pt)*40);height:calc(var(--pt)*40);flex:none;border-radius:50%;
  background:rgba(147,147,147,.14);
  display:grid;place-items:center;position:relative;
}
/* the app icon's own five orbs, half an orb apart, every other one dropped */
.who-row.tolib .libmark::after{
  content:'';width:calc(var(--pt)*20);height:calc(var(--pt)*12);
  background:
    radial-gradient(circle at 50% 50%, var(--ink) 49%, transparent 50%) 0 0/calc(var(--pt)*8) calc(var(--pt)*8) no-repeat,
    radial-gradient(circle at 50% 50%, var(--ink) 49%, transparent 50%) calc(var(--pt)*4) calc(var(--pt)*3.6)/calc(var(--pt)*8) calc(var(--pt)*8) no-repeat,
    radial-gradient(circle at 50% 50%, var(--ink) 49%, transparent 50%) calc(var(--pt)*8) 0/calc(var(--pt)*8) calc(var(--pt)*8) no-repeat,
    radial-gradient(circle at 50% 50%, var(--ink) 49%, transparent 50%) calc(var(--pt)*12) calc(var(--pt)*3.6)/calc(var(--pt)*8) calc(var(--pt)*8) no-repeat;
}
.who-row.tolib .chev{
  width:calc(var(--pt)*9);height:calc(var(--pt)*9);flex:none;
  border-right:2px solid rgba(25,25,25,.28);border-top:2px solid rgba(25,25,25,.28);
  transform:rotate(45deg);
}
.who-row.tolib:active{background:rgba(147,147,147,.10)}
