/* The overlay's own surfaces: the left margin (the day's tide line), the island
   (⌘K bar ⇄ list ⇄ card), the sidebar, the greeting, tooltips, toasts and the
   cards they hold. Lifted verbatim from the inline <style> of the vanilla
   overlay.html so the React port renders pixel-identically.

   Three things were deliberately NOT carried over:
   - Everything above the margin section (the @font-face pair, the :root tokens,
     the reset, the veil, the ambient canvas, the cursor). kyra-theme.css already
     defines all of it, byte for byte; a second copy would mean re-embedding the
     ~340 kB base64 font in every bundle and having two places to change one
     colour.
   - The `.behind` / `.doc` / `.chrome` block, which drew a fake browser tab to
     sit behind the glass. It is mockup-only scaffolding: the real overlay is a
     transparent WKWebView with the actual desktop showing through.
   - The `body.onboarding` rules that hid every product surface. Onboarding got
     its own window in Phase 1, so this page no longer has a mode where it has
     to pretend not to exist. */

  /* ================= LEFT MARGIN — the day's tide line ================= */
  .margin{position:fixed;left:0;top:0;bottom:0;width:76px;z-index:6;pointer-events:none;
    opacity:1;transition:opacity .4s var(--spring),transform .45s var(--spring)}
  body.docked .margin{opacity:0;transform:translateX(-16px)}
  .m-line{position:absolute;left:38px;top:96px;bottom:96px;width:2px;border-radius:1px;
    background:linear-gradient(180deg,transparent,rgba(255,255,255,.26) 8%,rgba(255,255,255,.26) 92%,transparent)}
    .m-htick{position:absolute;left:31px;width:16px;height:2px;border-radius:1px;
    background:rgba(255,255,255,.38);transform:translateY(-50%)}
  .m-mtick{position:absolute;left:35px;width:8px;height:1.5px;border-radius:1px;
    background:rgba(255,255,255,.16);transform:translateY(-50%)}
  .mtime{position:absolute;left:calc(100% - 2px);top:50%;transform:translateY(-50%);
    font-size:10px;font-weight:650;color:rgba(235,235,240,.36);letter-spacing:.2px;
    font-variant-numeric:tabular-nums;pointer-events:none;transition:color .2s;white-space:nowrap;
    font-family:var(--font)}
  .margin.peek .mtime{color:rgba(235,235,240,.62)}
  .mark:hover .mtime{color:rgba(255,255,255,.95)}
  /* It reads the time now ("2:12 PM"), not the word NOW, so it is set like a
     time: tabular figures so the digits don't shuffle the label sideways on
     every tick, and none of the letterspacing that a four-letter all-caps word
     wanted. `left` clears the widened dot. */
  .m-nowlab{position:absolute;left:54px;transform:translateY(-50%);font-size:12.5px;font-weight:800;
    color:rgba(255,255,255,.72);letter-spacing:.1px;font-family:var(--font);
    font-variant-numeric:tabular-nums;white-space:nowrap}
  .m-rail{position:absolute;left:0;right:0;top:96px;bottom:96px}
  .m-hour{position:absolute;left:0;width:26px;text-align:right;font-size:12.5px;font-weight:650;
    color:rgba(235,235,240,.68);transform:translateY(-50%);letter-spacing:.2px;
    font-variant-numeric:tabular-nums}
  /* "You are here" — green, and a shade larger than the meeting bars so the
     live marker outranks the day drawn around it. Centred on .m-line's 39px
     (left = 39 - width/2), which is what keeps it ON the rail rather than
     beside it.

     It does NOT pulse. The dot used to breathe on a 2.6s loop, which is motion
     that never stops on a surface summoned to be read: in the corner of the eye
     a repeating pulse reads as something asking to be dealt with, and the
     current time is not asking for anything. A steady dot with a soft glow says
     the same thing once. The glow is a static box-shadow now, so the old
     `nowpulse` keyframes are gone with it. */
  .m-now{position:absolute;left:33.5px;width:11px;height:11px;border-radius:50%;
    transform:translateY(-50%);background:var(--green);opacity:1;
    box-shadow:0 0 12px -1px rgba(111,179,136,.75)}

  /* MEETINGS — the chosen day's calendar, lying ON the rail rather than beside
     it. Same x as .m-line, two pixels wider each side, so a meeting reads as
     the day's own line thickening for as long as it runs. Height is the real
     duration as a share of the day; min-height keeps a 15-minute slot visible
     at a rail that is only ~800px tall for 24 hours.

     The rail is one colour now: a lighter wash of the green NOW is drawn in,
     rather than the old --teal (which is a purple, whatever its name says) and
     a blue for the live one. Three hues down one 6px line made the day look
     categorised when nothing about it is — a meeting is a meeting. Lighter than
     --green so the dot and the meeting you are in still sit on top of it. */
  .m-ev{position:absolute;left:36px;width:6px;min-height:5px;border-radius:3px;
    background:#95CFAC;box-shadow:0 0 10px -2px rgba(149,207,172,.8);
    pointer-events:auto;cursor:default;
    animation:evIn .5s var(--spring) backwards;animation-delay:var(--d,0s)}
  @keyframes evIn{from{opacity:0;transform:translateX(-7px) scaleY(.4)}
    to{opacity:1;transform:none}}
  /* The one happening right now takes NOW's own green at full strength — the
     two marks agree, and the meeting you are in is the one the eye should land
     on. It is the same family as the rest, one step deeper. */
  .m-ev.now{background:var(--green);box-shadow:0 0 14px -1px rgba(111,179,136,.9)}

  /* The label rides at the segment's TOP, level with its start time, so the
     text lines up with the hour that made it. Capped and clipped: it lives
     inside the 215px band that triggers the margin's peek, and a long title
     must not run out across the glass. */
  .m-evlab{position:absolute;left:14px;top:0;transform:translateY(-3px);
    max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    font-family:var(--font);font-size:10.5px;font-weight:560;letter-spacing:.1px;
    color:rgba(235,235,240,.44);pointer-events:none;transition:color .2s}
  .m-evlab b{font-weight:700;font-variant-numeric:tabular-nums;margin-right:5px}
  .margin.peek .m-evlab{color:rgba(235,235,240,.78)}
  .m-ev:hover .m-evlab{color:rgba(255,255,255,.98)}

  /* nodes ON the line — delivery-tracker grammar. Shape, color, motion; zero text. */
  .mark{position:absolute;left:16px;width:44px;height:36px;transform:translateY(-50%);
    background:none;border:none;padding:0;cursor:pointer;pointer-events:auto;
    display:flex;align-items:center;justify-content:center;
    animation:markPop .55s var(--spring) backwards;animation-delay:var(--d,0s)}
  @keyframes markPop{from{transform:translateY(-50%) scale(0);opacity:0}to{transform:translateY(-50%) scale(1);opacity:1}}
  .mark i{position:relative;display:block;width:var(--s,13px);height:var(--s,13px);border-radius:50%;
    background:currentColor;
    box-shadow:0 0 12px -1px currentColor,0 0 0 3px rgba(10,10,16,.22);
    transition:filter .2s,box-shadow .25s,transform .3s var(--spring)}
  .mark:focus{outline:none}
  .mark:hover i{transform:scale(1.35);filter:brightness(1.15)}
  .margin.peek .mark i{filter:brightness(1.12)}

  /* done — filled stop on the route */
  .mark.done{color:var(--green)}
  .mark.done i::after{content:"✓";position:absolute;inset:0;display:flex;align-items:center;
    justify-content:center;font-size:8.5px;font-weight:800;color:rgba(18,26,16,.78);
    font-family:var(--font)}

  /* needs-you — open loop, radiating for attention */
  .mark.need{color:var(--blue)}
  .mark.need i{background:transparent;border:2.5px solid currentColor;
    animation:needbreathe 2.2s ease-in-out infinite}
  @keyframes needbreathe{0%,100%{opacity:1}50%{opacity:.55}}
  .mark.need i::after{content:"";position:absolute;inset:-9px;border-radius:50%;
    border:1.5px solid currentColor;animation:radiate 2.2s ease-out infinite}
  @keyframes radiate{0%{transform:scale(.55);opacity:.7}70%{transform:scale(1.25);opacity:0}100%{transform:scale(1.25);opacity:0}}

  /* couldn't-do-it — caution diamond (road-sign shape) */
  .mark.fail{color:var(--amber)}
  .mark.fail i{border-radius:3px;transform:rotate(45deg) scale(.92)}
  .mark.fail i::after{content:"!";position:absolute;inset:0;display:flex;align-items:center;
    justify-content:center;font-size:9px;font-weight:800;color:rgba(32,20,12,.82);
    font-family:var(--font);transform:rotate(-45deg)}
  .mark.fail:hover i{transform:rotate(45deg) scale(1.25)}

  /* in-progress — orbiting arc, the universal "working" */
  .mark.progress{color:var(--teal)}
  .mark.progress i{background:transparent;border:2px solid rgba(156,143,203,.32);box-shadow:none}
  .mark.progress i::before{content:"";position:absolute;inset:-2px;border-radius:50%;
    border:2px solid transparent;border-top-color:var(--teal);animation:orbit 1s linear infinite}
  @keyframes orbit{to{transform:rotate(360deg)}}

  /* undone — hollow, receded */
  .mark.undone{color:rgba(235,235,240,.28)}
  .mark.undone i{background:transparent;border:2px solid currentColor;box-shadow:none}

  .mark.active i{box-shadow:0 0 16px 0 currentColor,0 0 0 3px rgba(10,10,16,.22);transform:scale(1.3)}
  .mark.fail.active i{transform:rotate(45deg) scale(1.3)}

  /* greeting — editorial column: serif line, prose summary. The kicker that
     opened it carried the date, which now reads in the top-right clock. */
  .greet{position:fixed;left:50%;transform:translateX(-50%);z-index:8;
    text-align:center;pointer-events:none;transition:opacity .35s,transform .4s var(--spring);white-space:nowrap}
  /* The greeting proper: Kyra's mark, then the part of the day and the owner's
     first name. Instrument Serif at the display size the type scale asks for —
     this line is Kyra speaking, which is the one place the serif belongs.
     The mark is optically a touch smaller than the cap height it sits beside,
     because a ring reads larger than a letter of the same measure. */
  .g-hero{display:flex;align-items:center;justify-content:center;gap:12px;
    font-family:'Instrument Serif','Iowan Old Style',Georgia,serif;
    font-size:34px;font-weight:400;line-height:1.15;letter-spacing:-.2px;
    color:var(--label);margin-bottom:0}
  /* The "N waiting on you" line that used to close this block is gone — it
     reads in the top-right corner now (.ov-wait). What follows .g-hero today is
     the brief, which is Kyra talking rather than a count. */
  .g-logo{width:46px;height:46px;object-fit:contain;flex-shrink:0;
    user-select:none;filter:drop-shadow(0 1px 8px rgba(0,0,0,.38))}
  /* The day brief under the greeting: Kyra's sentence on what is outstanding.
     Sans, well down the type scale and at --label-2, so the block reads
     greeting → brief → bar in that order and the serif line above keeps the
     voice. Set in a measure rather than left to run the width of the screen —
     this is the one part of the overlay that is prose, and prose needs a
     column. `white-space:normal` undoes .greet's nowrap, which exists for the
     single greeting line and would otherwise push a wrapped brief off-screen.
     No bottom margin: GREET_GAP alone sets the gap down to the island. */
  .g-brief{margin:16px auto 0;max-width:44ch;white-space:normal;text-wrap:pretty;
    font-size:15px;line-height:1.55;letter-spacing:-.1px;color:var(--label-2);
    animation:g-brief-in .5s var(--spring) both}
  /* Re-keyed on the text, so a rewritten brief arrives the same way the first
     one did rather than swapping character-for-character under the eye. */
  @keyframes g-brief-in{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}

  /* sidebar */
  .sb-btn{position:fixed;top:18px;left:18px;z-index:8;width:38px;height:38px;border-radius:12px;
    border:none;background:var(--glass);backdrop-filter:blur(30px) saturate(170%);-webkit-backdrop-filter:blur(30px) saturate(170%);
    box-shadow:inset 0 0 0 0.5px var(--hairline);display:flex;align-items:center;justify-content:center;
    cursor:pointer;transition:background .2s,opacity .35s;color:var(--label-2)}
  .sb-btn:hover{background:var(--glass-heavy);color:var(--label)}
  body.docked .sb-btn{opacity:0;pointer-events:none}
  .sb-panel{position:fixed;top:64px;left:18px;z-index:8;width:216px;padding:8px;border-radius:18px;
    background:var(--glass-heavy);backdrop-filter:blur(50px) saturate(180%);-webkit-backdrop-filter:blur(50px) saturate(180%);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.08),inset 0 0 0 0.5px var(--hairline),0 24px 70px rgba(0,0,0,.5);
    opacity:0;transform:translateY(-6px) scale(.97);transform-origin:top left;pointer-events:none;
    transition:opacity .22s,transform .28s var(--spring);color:var(--label)}
  .sb-panel.open{opacity:1;transform:none;pointer-events:auto}
  .sb-item{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:12px;cursor:pointer;
    font-size:14px;font-weight:500;letter-spacing:-.2px;color:var(--label-2);transition:background .15s,color .15s}
  .sb-item:hover{background:rgba(255,255,255,.07);color:var(--label)}
  .sb-item.active{background:rgba(255,255,255,.10);color:var(--label)}
  .sb-item svg{width:16px;height:16px;flex-shrink:0;opacity:.75}
  .sb-item .sb-badge{margin-left:auto;font-size:10.5px;font-weight:650;color:var(--blue);
    background:rgba(228,228,231,.16);border-radius:999px;padding:2px 8px}
  .sb-glass{padding:11px 12px 9px;border-top:1px solid var(--sep);margin-top:4px}
  .sbg-head{display:flex;justify-content:space-between;font-size:10px;font-weight:700;
    letter-spacing:1.2px;color:var(--label-3);margin-bottom:9px}
  .sb-glass input[type=range]{width:100%}
  .sb-foot{display:flex;align-items:center;gap:9px;padding:11px 12px 6px;border-top:1px solid var(--sep)}
  .sb-ava{width:24px;height:24px;border-radius:50%;background:linear-gradient(135deg,#FAFAFA,#B9B9C0);flex-shrink:0}
  .sb-foot .sb-name{font-size:12.5px;font-weight:600;color:var(--label);letter-spacing:-.1px}
  .sb-foot .sb-plan{font-size:10.5px;color:var(--label-3)}

  /* view content inside island */
  .i-content.scrolly{max-height:56vh;overflow-y:auto;scrollbar-width:none}
  .i-content.scrolly::-webkit-scrollbar{width:0}
  /* No border-top: the rows are separated by their own padding, and a rule
     between every loop turned a short list into a table. */
  .lrow{display:flex;align-items:center;gap:13px;padding:12px 6px;
    cursor:pointer;border-radius:12px;transition:background .15s}
  .lrow:hover{background:rgba(255,255,255,.05)}
  .lnode{width:9px;height:9px;border-radius:50%;background:currentColor;flex-shrink:0;
    box-shadow:0 0 8px -1px currentColor}
  .lnode.need{background:transparent;border:2px solid currentColor;animation:needbreathe 2.2s infinite}
  .lnode.fail{border-radius:2px;transform:rotate(45deg)}
  .lnode.progress{opacity:.55}
  .lrow .l-main{flex:1;min-width:0}
  .lrow .l-t{font-size:14px;font-weight:560;letter-spacing:-.2px}
  .lrow .l-s{font-size:12px;color:var(--label-3);margin-top:1px;letter-spacing:-.1px}
  .lrow .l-ch{color:var(--label-3);font-size:15px}
  .mem-line{display:flex;align-items:flex-start;gap:10px;padding:9px 4px;border-top:1px solid var(--sep);font-size:13.5px;
    line-height:1.5;letter-spacing:-.15px;color:var(--label)}
  .mem-line:first-of-type{border-top:none}
  .mem-line .m-why{color:var(--label-3);font-size:12px;display:block;margin-top:1px}
  .mem-x{margin-left:auto;flex-shrink:0;background:none;border:none;color:var(--label-3);cursor:pointer;
    width:22px;height:22px;border-radius:50%;font-size:11px;line-height:1}
  .mem-x:hover{background:var(--fill);color:var(--label)}
  .mem-line.forgot{opacity:.32;text-decoration:line-through}
  .sec-h{font-size:11px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:var(--label-3);
    margin:18px 0 6px}
  .sec-h:first-of-type{margin-top:14px}
  .frow{display:flex;align-items:center;gap:12px;padding:10px 4px;border-top:1px solid var(--sep);opacity:.62}
  .frow:first-of-type{border-top:none}
  .frow .f-t{flex:1;font-size:13.5px;letter-spacing:-.15px}
  .frow .f-n{font-size:12px;color:var(--label-3);font-variant-numeric:tabular-nums}

  /* onboarding tour — bare type + light, no cards */
  .halo{position:fixed;z-index:30;border-radius:26px;pointer-events:none;opacity:0;
    background:radial-gradient(closest-side,rgba(255,255,255,.08),transparent 78%);
    box-shadow:0 0 0 1px rgba(255,255,255,.10),0 0 70px 10px rgba(228,228,231,.10);
    transition:all .5s var(--spring)}
  .halo.show{opacity:1}
  body.touring .veil{background:linear-gradient(180deg,rgba(8,20,11,.64),rgba(6,16,9,.72))}
  body.tour-margin .margin{filter:brightness(1.65)}
  body.tour-island .island{filter:brightness(1.32)}
  .margin{transition:opacity .4s var(--spring),transform .45s var(--spring),filter .45s}
  .coach{position:fixed;z-index:31;width:340px;padding:0;color:var(--label);
    opacity:0;transform:translateY(10px);pointer-events:none;
    transition:opacity .35s,transform .45s var(--spring),left .45s var(--spring),top .45s var(--spring)}
  .coach.show{opacity:1;transform:none;pointer-events:auto}
  .coach.centered.show{transform:translate(-50%,-50%);text-align:center}
  .coach.centerx.show{transform:translateX(-50%);text-align:center}
  .coach h3{font-family:"Instrument Serif","Iowan Old Style",Georgia,serif;
    font-size:33px;font-weight:400;letter-spacing:.2px;color:#fff;
    text-shadow:0 2px 22px rgba(0,0,0,.6)}
  .coach h3 .k-serif{font-style:italic}
  .coach p{font-size:14px;color:rgba(240,240,248,.78);line-height:1.65;margin-top:9px;letter-spacing:-.1px;
    text-shadow:0 1px 12px rgba(0,0,0,.5)}
  .coach .legend{display:flex;flex-direction:column;gap:10px;margin-top:15px}
  .coach.centered .legend,.coach.centerx .legend{align-items:center}
  .coach .leg{display:flex;align-items:center;gap:12px;font-size:13px;color:rgba(240,240,248,.8);
    letter-spacing:-.1px;text-shadow:0 1px 10px rgba(0,0,0,.5)}
  .coach .leg .n{width:10px;height:10px;border-radius:50%;flex-shrink:0;position:relative}
  .coach .leg .n.spin::before{content:"";position:absolute;inset:-2px;border:2px solid transparent;
    border-top-color:var(--teal);border-radius:50%;animation:orbit 1s linear infinite}
  .coach .c-row{display:flex;gap:16px;margin-top:16px;align-items:center}
  .coach.centered .c-row,.coach.centerx .c-row{justify-content:center}
  .t-link{background:none;border:none;font-family:var(--font);font-size:14.5px;font-weight:600;
    color:var(--blue);cursor:pointer;padding:4px 0;letter-spacing:-.2px;
    text-shadow:0 1px 10px rgba(0,0,0,.45);transition:opacity .15s}
  .t-link:hover{opacity:.75}
  .t-link.dim{color:rgba(235,235,240,.45);font-weight:500}
  .t-btn{background:#ECECEF;border:none;font-family:var(--font);font-size:14px;font-weight:650;
    color:#131316;cursor:pointer;padding:10px 22px;border-radius:999px;letter-spacing:-.2px;
    box-shadow:0 5px 18px rgba(0,0,0,.4),inset 0 -1px 0 rgba(0,0,0,.08);
    transition:transform .2s var(--spring),filter .15s}
  .t-btn:hover{filter:brightness(1.05);transform:translateY(-1px)}
  .t-btn:active{transform:translateY(0);filter:brightness(.92)}
  .coach .tdots{margin-left:auto;display:flex;gap:5px}
  .coach.centered .tdots,.coach.centerx .tdots{margin-left:4px}
  .coach .tdot{width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,.22);transition:background .2s}
  .coach .tdot.on{background:var(--blue)}
  .help-btn{position:fixed;bottom:18px;right:18px;z-index:8;width:34px;height:34px;border-radius:50%;
    border:none;background:var(--glass);backdrop-filter:blur(30px);-webkit-backdrop-filter:blur(30px);
    box-shadow:inset 0 0 0 0.5px var(--hairline);color:var(--label-3);font-size:14px;font-weight:600;
    cursor:pointer;transition:all .2s}
  .help-btn:hover{color:var(--label);background:var(--glass-heavy)}
  body.docked .help-btn{opacity:0;pointer-events:none}

  /* proactive: the island wakes over your work */
  body.docked .island.alert{width:min(560px,92vw);border-radius:24px;background:var(--glass-heavy);cursor:default}
  body.docked .island.alert .i-body{grid-template-rows:1fr !important}
  .island.alert{animation:alertGlow 2.2s ease-in-out infinite}
  @keyframes alertGlow{
    0%,100%{box-shadow:inset 0 1px 0 rgba(255,255,255,.10),inset 0 0 0 0.5px var(--hairline),0 30px 90px rgba(0,0,0,.5),0 0 0 0 rgba(228,228,231,0)}
    50%{box-shadow:inset 0 1px 0 rgba(255,255,255,.10),inset 0 0 0 0.5px var(--hairline),0 30px 90px rgba(0,0,0,.5),0 0 38px 2px rgba(228,228,231,.30)}
  }
  .alert-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--blue);
    margin-right:9px;vertical-align:1px;animation:needbreathe 1.4s ease-in-out infinite}
  .cd-wrap{display:flex;align-items:center;gap:16px;margin-top:12px}
  .cd-ring{width:46px;height:46px;flex-shrink:0}
  .cd-ring circle{fill:none;stroke-width:3}
  .cd-ring .cdbg{stroke:rgba(122,122,130,.32)}
  .cd-ring .cdfg{stroke:var(--blue);stroke-linecap:round;transform:rotate(-90deg);transform-origin:center;
    transition:stroke-dashoffset 1s linear}
  .alert-hero{font-size:25px;font-weight:700;letter-spacing:-.8px;font-variant-numeric:tabular-nums}
  .alert-sub{font-size:12.5px;color:var(--label-2);margin-top:2px;letter-spacing:-.1px}

  /* the thread — a mark visibly becomes its card */
  .thread{position:fixed;inset:0;width:100vw;height:100vh;z-index:6;pointer-events:none}
  .thread path{fill:none;stroke:rgba(255,255,255,.34);stroke-width:1.5;
    stroke-dasharray:4 7;stroke-linecap:round;transition:opacity .3s}

  /* margin tooltip */
  .mtip{position:fixed;z-index:8;max-width:280px;padding:10px 14px;border-radius:14px;
    background:var(--glass-heavy);backdrop-filter:blur(40px) saturate(180%);-webkit-backdrop-filter:blur(40px) saturate(180%);
    box-shadow:inset 0 0 0 0.5px var(--hairline),0 12px 40px rgba(0,0,0,.45);
    opacity:0;transform:translateX(-6px);transition:opacity .18s,transform .22s var(--spring);pointer-events:none}
  .mtip.show{opacity:1;transform:none}
  .mtip .mt-t{font-size:13px;font-weight:600;color:var(--label);letter-spacing:-.2px}
  .mtip .mt-s{font-size:12px;color:var(--label-2);margin-top:3px;line-height:1.45;letter-spacing:-.1px}
  .mtip .mt-time{font-size:10.5px;color:var(--label-3);margin-top:5px;font-weight:600}

  /* ================= THE ISLAND ================= */
  .island{position:fixed;left:50%;top:50%;z-index:7;width:560px;max-width:92vw;
    color:var(--label);
    transform:translateX(-50%) translateY(-50%);
    background:var(--glass);
    backdrop-filter:blur(50px) saturate(190%);
    -webkit-backdrop-filter:blur(50px) saturate(190%);
    border-radius:28px;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.10),inset 0 0 0 0.5px var(--hairline),0 30px 90px rgba(0,0,0,.5);
    transition:transform .55s var(--spring),border-radius .5s var(--spring),
      background .4s,left .5s var(--spring),top .5s var(--spring);
    overflow:hidden}
  .island.dragging{transition:none;box-shadow:inset 0 1px 0 rgba(255,255,255,.10),inset 0 0 0 0.5px var(--hairline),0 40px 110px rgba(0,0,0,.55)}
  .island.card-mode{width:640px;border-radius:26px;background:var(--glass-heavy)}
  body.docked .island{top:auto;bottom:22px;width:420px;border-radius:999px;
    transform:translateX(-50%);cursor:pointer;background:var(--glass-heavy)}
  body.docked .island:hover{transform:translateX(-50%) translateY(-2px)}

  /* PADDING SNAPS. It used to transition over .4s, and card mode drops it from
     16px to 13px — 6px of island height that does not exist yet at the moment
     useMorph measures.
     useMorph reads offsetHeight in a layout effect (after React mutates the DOM,
     before paint) and animates the box to that number with fill:none. Any CSS
     transition on a property that changes the island's height therefore makes it
     animate to a stale target and jump to the real one when the animation
     releases: over-expand then correct on the way open, under-collapse then
     correct on the way back — 6px each way, in opposite directions, exactly as
     the padding differs.
     THE INVARIANT: nothing inside the island may transition a property that
     affects its height. useMorph owns that animation. */
  .i-head{display:flex;align-items:center;gap:13px;padding:16px 20px}
  .island.card-mode .i-head{padding:13px 20px}
  .i-head .glyph-search{width:20px;height:20px;flex-shrink:0;opacity:.55;transition:opacity .3s}
  /* Selectable, explicitly. styles.css turns user-select off globally (a drag
     across the glass otherwise paints the heading with the system highlight)
     and opts `input` back in — but the island sits under several nested
     none-inheriting ancestors, and being explicit here is cheaper than relying
     on cascade order holding.

     `cursor:text` needs !important to land at all: kyra-theme.css hides the
     system cursor everywhere with `*{cursor:none !important}` because the page
     draws its own cursor dot, and a plain declaration loses to that no matter
     how specific it is. The drawn cursor hides itself over text fields (see
     `cur-text` in kyra-ambient.js) so only one cursor is ever visible. */
  .i-input{user-select:text;-webkit-user-select:text;cursor:text !important;
    flex:1;background:none;border:none;outline:none;font-family:var(--font);
    font-size:20px;font-weight:400;letter-spacing:-.35px;color:var(--label);caret-color:var(--blue);min-width:0}
  .i-input::placeholder{color:var(--label-3)}
  /* CARD MODE HIDES THE INPUT. A card is a result, not a query — leaving the
     search field on top of it invited typing into something that was no longer
     listening. The ESC chip stays, because it is the way back out.
     `display:none` rather than opacity: this must not leave an invisible box
     holding the head's height open. The magnifier goes with it for the same
     reason — a search glyph with nothing to search reads as broken. */
  .island.card-mode .i-input,
  .island.card-mode .glyph-search{display:none}
  /* ESC SHARES THE TITLE'S LINE. In card mode the head holds nothing but the
     chip, so as a flow row it was an empty 46px band pushing "Open loops" down
     and stranding the chip on a line of its own. Lifting the head out of flow
     lets the card start at the top of the island; the matching padding below
     puts the title's centre where the chip already is.
     No transition on either property — the head still contributes to the
     island's height model, and useMorph measures that in a layout effect. */
  .island.card-mode .i-head{position:absolute;top:0;right:0;padding:20px;
    pointer-events:none;z-index:2}
  .island.card-mode .i-esc{pointer-events:auto}
  .island.card-mode .i-content{padding-top:21px}
  .i-esc{font-size:10.5px;font-weight:700;color:var(--label-3);background:rgba(255,255,255,.08);
    border-radius:5px;padding:3px 7px;flex-shrink:0;letter-spacing:.3px}
  .i-dockmsg{display:none;flex:1;font-size:13px;font-weight:500;color:var(--label-2);letter-spacing:-.1px;
    white-space:nowrap;overflow:hidden}
  .i-dockmsg b{color:var(--green);font-weight:650}
  .i-dockmsg .need-n{color:var(--blue);font-weight:650}
  .dockdots{display:none;align-items:center;gap:6px;flex-shrink:0;margin-right:2px}
  .ddot{width:6px;height:6px;border-radius:50%;background:currentColor;box-shadow:0 0 6px -1px currentColor}
  .ddot.done{color:var(--green)}
  .ddot.need{color:var(--blue);animation:needbreathe 2s ease-in-out infinite}
  .ddot.fail{color:var(--amber);border-radius:1.5px;transform:rotate(45deg)}
  .ddot.progress{color:var(--teal);opacity:.6}
  .ddot.undone{color:rgba(235,235,240,.22);box-shadow:none}
  .i-dockkbd{display:none;font-size:10.5px;font-weight:700;color:var(--label-3);
    background:rgba(255,255,255,.08);border-radius:5px;padding:3px 7px;flex-shrink:0;letter-spacing:.3px}
  body.docked .i-input,body.docked .i-esc{display:none}
  body.docked .i-dockmsg{display:block}
  body.docked .dockdots{display:flex}
  body.docked .i-dockkbd{display:block}
  body.docked .i-head{padding:11px 18px}
  body.docked .i-head .glyph-search{width:17px;height:17px}
  body.docked .island.alert .dockdots,body.docked .island.alert .i-dockkbd{display:none}

  /* body of island — grid height morph */
  /* NO transition on grid-template-rows, deliberately. useMorph animates the
     island's height itself, and it measures that height in a layout effect —
     i.e. after React mutates the DOM but before paint. A transition here means
     the row track is still at its OLD value at that moment, so useMorph reads a
     stale height, animates towards the wrong target, and the CSS transition
     then drags the box to the real one. That is the "expands then shrinks"
     (and "shrinks then expands") that the transition was added to fix.
     The track snapping instantly is what makes useMorph's measurement true. */
  .i-body{display:grid;grid-template-rows:0fr}
  .island.open .i-body{grid-template-rows:1fr}
  body.docked .i-body{grid-template-rows:0fr !important}
  .i-inner{min-height:0;overflow:hidden}
  .i-content{padding:2px 20px 20px}

  /* result rows (spotlight list) */
  .rows{padding:2px 8px 10px}
  .row{display:flex;align-items:center;gap:13px;padding:10px 12px;border-radius:14px;cursor:pointer;
    font-size:15px;letter-spacing:-.2px;color:var(--label)}
  .row .r-ico{width:24px;text-align:center;font-size:15px}
  .row .r-hint{margin-left:auto;font-size:11px;color:var(--label-3);font-weight:600}
  .row.sel{background:rgba(255,255,255,.09)}
  .row .r-sub{font-size:12px;color:var(--label-3);margin-left:6px}

  /* card internals */
  .c-title{font-size:16px;font-weight:650;letter-spacing:-.3px}
  /* 8px, not 2px: the title is 16px/650 and the sub 13px, so at 2px they read
     as one wrapped block rather than a heading and its line. */
  .c-sub{font-size:13px;color:var(--label-2);margin-top:8px;line-height:1.5;letter-spacing:-.1px}
  .c-body{font-size:14px;color:var(--label);line-height:1.6;letter-spacing:-.15px;margin-top:10px}
  .c-why{font-size:12px;color:var(--label-3);margin-top:12px;line-height:1.5;letter-spacing:-.05px}
  .c-why b{color:var(--label-2);font-weight:600}
  .sep{height:1px;background:var(--hairline);margin:14px 0;opacity:.7}
  .kv{display:flex;justify-content:space-between;font-size:13.5px;padding:7px 0;letter-spacing:-.15px}
  .kv span:first-child{color:var(--label-2)}
  .kv b{font-weight:600;font-variant-numeric:tabular-nums}

  .btn{font-family:var(--font);font-size:14px;font-weight:590;border-radius:17px;padding:7px 16px;height:34px;
    cursor:pointer;border:none;background:var(--fill);color:var(--label);letter-spacing:-.2px;
    display:inline-flex;align-items:center;transition:background .15s,filter .15s}
  .btn:hover{background:var(--fill-2)}
  .btn:active{filter:brightness(.85)}
  .btn.primary{background:#E8E8EA;color:#111114}
  .btn.primary:hover{filter:brightness(1.1);background:var(--blue)}
  .btn.quiet{background:transparent;color:var(--blue)}
  .btn.quiet:hover{background:rgba(228,228,231,.14)}
  .btn.danger-quiet{background:transparent;color:var(--amber)}
  .btn.danger-quiet:hover{background:rgba(185,185,192,.12)}
  .btn-row{display:flex;gap:9px;margin-top:14px;align-items:center;flex-wrap:wrap}

  .chip{font-family:var(--font);font-size:13px;font-weight:500;color:var(--blue);background:transparent;
    box-shadow:inset 0 0 0 1px rgba(228,228,231,.5);border:none;border-radius:999px;padding:7px 14px;cursor:pointer;letter-spacing:-.1px}
  .chip:hover{background:rgba(228,228,231,.14)}

  .prov-row{display:flex;align-items:center;gap:6px;margin-top:16px;flex-wrap:wrap}
  .prov{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:500;color:var(--label-3);
    border-radius:999px;padding:4px 10px;background:rgba(122,122,130,.16)}
  .prov .pdot{width:6px;height:6px;border-radius:50%}
  .escape{margin-left:auto;font-size:12.5px;font-weight:500;color:var(--blue);cursor:pointer;
    padding:4px 8px;border-radius:8px;letter-spacing:-.1px}
  .escape:hover{background:rgba(228,228,231,.14)}

  .success-line{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--green);font-weight:590;margin-top:14px;letter-spacing:-.2px}

  /* flight slider */
  .slider-head{display:flex;justify-content:space-between;font-size:13px;color:var(--label-2);margin:14px 0 10px;letter-spacing:-.1px}
  .slider-head b{color:var(--label);font-weight:600}
  input[type=range]{width:100%;appearance:none;-webkit-appearance:none;height:4px;border-radius:2px;
    background:linear-gradient(to right,var(--blue) var(--pct,50%),var(--fill) var(--pct,50%));outline:none;cursor:grab}
  input[type=range]::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:20px;height:20px;border-radius:50%;
    background:#fff;border:none;box-shadow:0 1px 4px rgba(0,0,0,.4);cursor:grab}
  input[type=range]::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:#fff;border:none;
    box-shadow:0 1px 4px rgba(0,0,0,.4);cursor:grab}
  .price-strip{display:flex;justify-content:space-between;margin-top:10px}
  .price-tick{font-size:10.5px;color:var(--label-3);text-align:center;width:46px;padding:4px 0;border-radius:8px;transition:all .2s}
  .price-tick b{display:block;font-size:11px;color:var(--label-2);font-weight:600;margin-top:2px}
  .price-tick.cheapest b{color:var(--green)}
  .price-tick.current{background:var(--fill)}
  .price-tick.current b{color:var(--label)}

  /* chart */
  .chart{margin-top:14px}
  .chart .bars{display:flex;align-items:flex-end;gap:12px;height:84px}
  .chart .bcol{flex:1;display:flex;flex-direction:column;align-items:center;gap:7px;height:100%;justify-content:flex-end}
  .chart .bar{width:100%;max-width:48px;background:var(--blue);border-radius:5px 5px 2px 2px;opacity:.9;position:relative;transition:opacity .15s}
  .chart .bcol:hover .bar{opacity:1}
  .chart .bval{position:absolute;top:-19px;left:50%;transform:translateX(-50%);font-size:10.5px;font-weight:600;
    color:var(--label-2);opacity:0;transition:opacity .15s;white-space:nowrap;font-variant-numeric:tabular-nums}
  .chart .bcol:hover .bval{opacity:1}
  .chart .blabel{font-size:10.5px;color:var(--label-3)}
  .chart .baseline{height:1px;background:var(--hairline)}
  .hero-row{display:flex;align-items:baseline;gap:11px;margin-top:12px}
  .hero-num{font-size:32px;font-weight:700;letter-spacing:-1.2px;font-variant-numeric:tabular-nums}
  .delta{font-size:12.5px;font-weight:600;color:var(--green);background:rgba(201,201,206,.14);border-radius:999px;padding:3px 10px}

  /* message */
  .msg-bubble{background:var(--fill);border-radius:16px 16px 16px 4px;padding:10px 14px;font-size:14px;
    line-height:1.45;margin-top:12px;max-width:88%;letter-spacing:-.15px}
  .msg-meta{font-size:11.5px;color:var(--label-3);margin-top:6px;margin-left:3px}
  .reply-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
  .msg-input-row{display:flex;gap:9px;margin-top:12px}
  .msg-input{flex:1;background:var(--fill);border:none;border-radius:17px;padding:7px 15px;height:34px;
    font-family:var(--font);font-size:14px;color:var(--label);outline:none;letter-spacing:-.15px}
  .msg-input::placeholder{color:var(--label-3)}
  .msg-input:focus{box-shadow:0 0 0 3px rgba(228,228,231,.35)}

  /* timeline (day card) */
  .tl{margin-top:12px;position:relative;padding-left:20px}
  .tl::before{content:"";position:absolute;left:5px;top:8px;bottom:8px;width:2px;border-radius:1px;background:var(--hairline)}
  .tl-item{position:relative;padding:7px 0;font-size:14px;letter-spacing:-.15px}
  .tl-item::before{content:"";position:absolute;left:-19px;top:14px;width:8px;height:8px;border-radius:50%;background:var(--label-3)}
  .tl-item.now::before{background:var(--blue);box-shadow:0 0 0 4px rgba(228,228,231,.2)}
  .tl-time{color:var(--label-3);font-size:11.5px;font-weight:500;font-variant-numeric:tabular-nums}
  .tl-item.now .tl-time{color:var(--blue);font-weight:600}
  .tl-what{font-weight:590;margin-top:1px}
  .tl-sub{color:var(--label-2);font-size:12.5px;margin-top:1px}

  /* plan card steps */
  .plan-step{display:flex;align-items:flex-start;gap:11px;padding:9px 2px;border-top:1px solid var(--sep);
    font-size:13.5px;letter-spacing:-.15px;line-height:1.5}
  .plan-step:first-of-type{border-top:none;margin-top:4px}
  .plan-step .ps-n{flex-shrink:0;width:18px;height:18px;border-radius:50%;margin-top:1px;
    background:rgba(126,119,104,0.24);display:flex;align-items:center;justify-content:center;
    font-size:10px;font-weight:700;color:var(--label-2)}
  .plan-step .ps-t{color:var(--label)}
  .plan-when{display:flex;gap:8px;align-items:center;margin-top:4px;font-size:12.5px;color:var(--teal);font-weight:550}

  /* toast */
  .toast{position:fixed;top:26px;left:50%;transform:translateX(-50%) translateY(-14px);z-index:60;
    background:var(--glass-heavy);backdrop-filter:blur(40px) saturate(180%);-webkit-backdrop-filter:blur(40px) saturate(180%);
    border-radius:999px;padding:10px 20px;font-size:13px;font-weight:500;color:var(--label);
    opacity:0;transition:all .35s var(--spring);pointer-events:none;letter-spacing:-.1px;
    box-shadow:inset 0 0 0 0.5px var(--hairline),0 14px 44px rgba(0,0,0,.4)}
  .toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
  .toast b{font-weight:650}

  .fadein{animation:fin .4s var(--spring) both}
  #icontent>*{animation:cIn .38s cubic-bezier(.3,.8,.3,1) .06s both}
  @keyframes cIn{from{opacity:0;transform:translateY(7px) scale(.986);filter:blur(8px)}
    to{opacity:1;transform:none;filter:none}}
  @keyframes fin{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

  @media (max-width:700px){
    .island{width:92vw}
    .island.card-mode{width:92vw}
    /* Half a narrow window is not a column, it is a slot. Below this width the
       conversation takes the same 92vw every other mode does. */
    .island.chat-mode{width:92vw;min-width:0;max-width:92vw}
    .margin{width:60px}
    .m-line{left:30px}
    .mark{left:8px}
  }

  /* The ✕ that used to sit at top:18px;right:18px is gone, along with its
     rules. ESC and a click on the empty glass both put the surface away, and a
     close button is window chrome on a window that has none. */

  /* The top-right date and time ("Sat 25 Jul 1:06 PM") is gone, and .ov-clock
     with it. The margin's NOW marker names the hour where the hour actually
     means something — against the day it belongs to — so a second clock in the
     opposite corner was the same fact stated twice, the far copy of it carrying
     none of the context. The corner is empty on purpose. */

  /* The day picker, top-left — sitting directly
     above the rail it drives. A dropdown rather than four dates in a row: the
     corner states ONE fact (which day you are looking at) and the other three
     days are a choice you only need while making it. It clears the rail, which
     starts at 96px, so the open menu has room without covering the timeline it
     is about to change. Above the veil, so a click picks a day instead of
     dismissing the overlay. */
  .ov-day{position:fixed;top:18px;left:18px;z-index:40;
    display:flex;flex-direction:column;align-items:flex-start;
    pointer-events:auto;user-select:none}
  .ov-daybtn{appearance:none;-webkit-appearance:none;border:none;background:transparent;
    height:38px;display:flex;align-items:center;gap:7px;
    font-family:var(--font);font-size:15px;font-weight:600;letter-spacing:.1px;
    white-space:nowrap;color:var(--label-2);padding:0 12px;border-radius:11px;
    cursor:pointer;transition:background .18s,color .18s}
  .ov-daybtn:hover{color:var(--label);background:rgba(255,255,255,.08)}
  /* Open, the button stays lit so the menu reads as hanging off it rather than
     floating in the corner on its own. */
  .ov-daybtn.on{color:var(--label);background:rgba(255,255,255,.12)}
  .ov-daybtn:focus-visible{outline:1.5px solid rgba(255,255,255,.5);outline-offset:1px}
  /* The chevron turns over rather than swapping glyph — same mark, new state. */
  .dd-ch{opacity:.6;transition:transform .28s var(--spring),opacity .18s}
  .ov-daybtn.on .dd-ch{transform:rotate(180deg);opacity:.95}

  /* The menu. Glass, like every other panel Kyra puts on screen, and it drops
     from the top edge: scaled from its own top-left corner so it grows out of
     the button instead of fading in beside it. */
  .ov-daymenu{margin-top:6px;min-width:228px;padding:6px;border-radius:15px;
    display:flex;flex-direction:column;gap:1px;
    background:var(--glass-heavy);backdrop-filter:blur(40px) saturate(180%);
    -webkit-backdrop-filter:blur(40px) saturate(180%);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.07),inset 0 0 0 0.5px var(--hairline),
      0 16px 44px rgba(0,0,0,.44);
    opacity:0;transform:translateY(-6px) scale(.96);transform-origin:0 0;
    pointer-events:none;
    transition:opacity .2s ease,transform .3s var(--spring)}
  .ov-daymenu.open{opacity:1;transform:none;pointer-events:auto}

  .ov-dayitem{appearance:none;-webkit-appearance:none;border:none;background:transparent;
    width:100%;display:flex;align-items:baseline;justify-content:space-between;gap:14px;
    padding:8px 12px;border-radius:10px;cursor:pointer;text-align:left;
    font-family:var(--font);transition:background .15s}
  .ov-dayitem:hover{background:rgba(255,255,255,.09)}
  .ov-dayitem.on{background:rgba(255,255,255,.14)}
  .ov-dayitem:focus-visible{outline:1.5px solid rgba(255,255,255,.5);outline-offset:-1px}
  /* The date leads — it is what was asked for and what does not change meaning
     overnight. The relative word trails it, muted, as the gloss. */
  .di-date{font-size:14.5px;font-weight:600;letter-spacing:.1px;color:var(--label-2);
    font-variant-numeric:tabular-nums;white-space:nowrap}
  .di-rel{font-size:12.5px;font-weight:520;color:var(--label-3);white-space:nowrap}
  .ov-dayitem.on .di-date{color:var(--label)}
  .ov-dayitem:hover .di-date{color:var(--label)}
  body.docked .ov-day{opacity:0;pointer-events:none}

  /* The corner chip that read "waiting on you - 3" under the clock is gone.
     The count is what the right edge says on hover — see .edge-n — so the
     number is stated once, in the place the hand goes to act on it. */

  /* The right edge as a handle: the rightmost fifth of the window, invisible
     until the cursor is in it. Between the veil (5) and the island (7), so it
     takes the click off the glass without taking any from the island above it.
     min-width keeps it a real target on a narrow window; max-width stops it
     reaching the island on a very wide one. */
  .edge-pull{position:fixed;top:0;right:0;bottom:0;width:20vw;min-width:170px;max-width:420px;
    z-index:6;display:flex;align-items:center;justify-content:flex-end;gap:10px;
    padding:0 30px 0 0;margin:0;border:none;background:transparent;
    appearance:none;-webkit-appearance:none;cursor:pointer;pointer-events:auto}
  /* The shading, on a pseudo-element so the hit area itself stays untinted and
     the fade in and out is one property. Weighted to the outer edge — the glass
     darkens toward the border it is about to pull from, not in a slab. */
  .edge-pull::before{content:"";position:absolute;inset:0;pointer-events:none;
    background:linear-gradient(90deg,transparent,rgba(0,0,0,.09) 42%,rgba(0,0,0,.30));
    opacity:0;transition:opacity .28s ease}
  .edge-pull:hover::before{opacity:1}
  /* Faint by design: an invitation, not a control. It points inward, the way
     the cards travel. */
  .edge-ch{position:relative;color:rgba(255,255,255,.5);opacity:0;transform:translateX(16px);
    transition:opacity .28s ease,transform .4s var(--spring);
    filter:drop-shadow(0 2px 10px rgba(0,0,0,.5))}
  /* The count, and the whole reason to look over here. Large and light: it is
     a number written on the glass, not a badge. Tabular so 8 → 9 → 10 doesn't
     shuffle the arrow beside it.

     ALWAYS on screen, at about half size and half lit, so the edge answers
     "how many" before you go anywhere near it. Hover grows it to full.

     Sized once at 46px and scaled DOWN at rest rather than sized small and
     scaled up: font-size can't be animated on the compositor, so growing it
     that way reflows the flex row on every frame and lands the number a few
     pixels off from where it started. A transform moves no layout at all, and
     the 100% 50% origin pins the number's right edge and its centre line — so
     it grows leftward out of the edge it belongs to, into the space the arrow
     is arriving in, instead of drifting. */
  .edge-n{position:relative;font-family:var(--font);font-size:46px;font-weight:300;
    letter-spacing:-2px;line-height:1;color:rgba(255,255,255,.86);
    font-variant-numeric:tabular-nums;user-select:none;
    text-shadow:0 2px 16px rgba(0,0,0,.55);
    opacity:.46;transform:scale(.48);transform-origin:100% 50%;
    transition:opacity .3s ease,transform .46s var(--spring)}
  /* The number leads by a hair, the arrow follows it in — the pair reads as one
     gesture toward the middle of the screen rather than two things appearing. */
  .edge-pull:hover .edge-n{opacity:1;transform:none}
  .edge-pull:hover .edge-ch{opacity:1;transform:none;transition-delay:.05s}
  .edge-pull:active .edge-ch{transform:translateX(-6px)}
  .edge-pull:active .edge-n{opacity:.7}
  /* Open: the stack is the thing on the right now. The strip stays live as the
     click that puts it away, but stops drawing itself under it. */
  .edge-pull.open::before,.edge-pull.open .edge-ch,.edge-pull.open .edge-n{opacity:0}
  body.docked .edge-pull{display:none}

  /* The stack itself — a column down the right edge, the way macOS shows
     notifications. Each row carries its own delay (set inline, see WaitDrawer)
     so they fan out in sequence on open and fold back in reverse on close.
     Transparent, and it has to stay that way: what looked like a panel behind
     this column was never an element, it was the rows' own frosted glass and
     drop shadows overlapping at a 9px gap. */
  .wait-drawer{position:fixed;top:100px;right:18px;z-index:39;
    width:340px;max-height:calc(100vh - 128px);overflow-y:auto;overflow-x:hidden;
    display:flex;flex-direction:column;gap:1px;padding:2px 2px 20px;
    pointer-events:none;scrollbar-width:none}
  .wait-drawer::-webkit-scrollbar{display:none}
  .wait-drawer.open{pointer-events:auto}
  .wd-head{font-family:var(--font);font-size:11px;font-weight:640;letter-spacing:.7px;
    text-transform:uppercase;color:var(--label-3);margin-bottom:5px;
    display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:0 6px}
  /* The undo offer, in the head because a ticked row leaves no place to put it.
     Sentence case against the head's caps so it reads as a thing to press
     rather than a second label. */
  .wd-undo{font-family:var(--font);font-size:11px;font-weight:560;letter-spacing:.2px;
    text-transform:none;color:var(--label-3);background:none;border:none;padding:0;margin:0;
    appearance:none;-webkit-appearance:none;cursor:pointer;white-space:nowrap;
    transition:color .16s ease}
  .wd-undo:hover{color:var(--label)}
  .wd-undo:focus-visible{outline:1.5px solid rgba(255,255,255,.5);outline-offset:2px;
    border-radius:3px}

  /* Closed: parked off the right edge, laid back a touch so the return reads as
     the row coming toward you rather than merely sliding. */
  .wd-head,.wn,.wd-rule{opacity:0;transform:translateX(calc(100% + 26px)) scale(.96);
    transition:transform .52s var(--spring),opacity .3s ease,background .18s ease}
  .wait-drawer.open .wd-head,.wait-drawer.open .wn,.wait-drawer.open .wd-rule{
    opacity:1;transform:none}

  /* What needs you, and what can wait. The priority dot is gone, so this line
     is what states urgency: above it is P0. Drawn only when there is something
     on both sides of it — see WaitDrawer.

     Deliberately NOT var(--hairline): at 10% white it is a seam between two
     surfaces, which is the wrong job. This line has to carry the meaning the
     priority dot used to, over live desktop showing through frosted glass, so
     it starts well above hairline weight and fades out to the right — a rule
     that ends rather than a box that closes. */
  .wd-rule{flex-shrink:0;height:1px;margin:9px 6px 10px;
    background:linear-gradient(90deg,rgba(255,255,255,.30),rgba(255,255,255,.04))}

  /* No card. Layout and a hover tint, nothing else: the fill arrives under the
     pointer and leaves with it, so the column at rest is text on the overlay's
     own glass. */
  .wn{display:flex;align-items:flex-start;gap:10px;padding:9px 6px 9px 6px;
    border-radius:10px;background:transparent;color:var(--label);cursor:default}
  .wn:hover{background:rgba(255,255,255,.055)}
  /* On its way out: struck through and sliding right, on its own fast timing —
     the .52s spring above is the entrance, and an exit that slow would still be
     moving when the row is already gone from the list. */
  .wn.going{opacity:.3;transform:translateX(18px);
    transition:transform .19s ease,opacity .19s ease}
  .wn.going .wn-t{text-decoration:line-through;text-decoration-thickness:1px}
  .wn.going .wn-tick{border-color:var(--green);color:var(--green);background:transparent}
  .wn-main{flex:1;min-width:0}
  .wn-t{display:block;font-size:13.5px;font-weight:570;letter-spacing:-.2px;line-height:1.35}
  .wn-s{display:block;font-size:12px;color:var(--label-3);margin-top:3px;letter-spacing:-.1px;
    line-height:1.4}

  /* The tick, in the slot the priority dot had. Empty at rest and all but
     invisible until the pointer is on the row — the drawer is for reading first
     and acting second, and a column of bright checkboxes reads as a form.
     margin-top lines the circle up with the title's cap height rather than its
     line box. */
  .wn-tick{flex-shrink:0;width:17px;height:17px;margin-top:2px;padding:0;
    border-radius:50%;border:1.25px solid rgba(255,255,255,.22);background:transparent;
    display:flex;align-items:center;justify-content:center;color:transparent;
    appearance:none;-webkit-appearance:none;cursor:pointer;
    transition:color .16s ease,border-color .16s ease,background .16s ease,transform .16s ease}
  .wn:hover .wn-tick{border-color:var(--label-3);color:rgba(255,255,255,.34)}
  /* The one moment green is worth spending here — it is the colour "done"
     already means everywhere else in Kyra (--green, the margin's vocabulary). */
  .wn-tick:hover{border-color:var(--green);color:var(--green);
    background:rgba(111,179,136,.14)}
  .wn-tick:active{transform:scale(.88)}
  .wn-tick:focus-visible{outline:1.5px solid rgba(255,255,255,.55);outline-offset:2px;
    color:rgba(255,255,255,.34)}

  /* Set while the pointer is over a text field: the system I-beam is showing
     there, so the drawn cursor stands down. */
  body.cur-text .cur-dot{opacity:0}

  /* ── the conversation ────────────────────────────────────────────────────
     Asking Kyra something turns the island into a transcript. The greeting
     above it stands down (.greet.gone): once she is answering in her own voice
     a few pixels below, a greeting and a standing brief overhead are two more
     voices on one screen. */
  .greet.gone{opacity:0;transform:translateX(-50%) translateY(-6px)}

  /* HALF THE SCREEN, still dead centre. A conversation needs a column wide
     enough for two-sided bubbles to read as two sides; the 560px search bar is
     not that, and the full width would put Kyra's voice at the far edges of a
     27-inch display. Width SNAPS rather than transitions: the island's height is
     animated by useMorph from a measurement taken in a layout effect, and a
     width that is still moving rewraps the text under it, so the height it
     measured is never the height that lands. */
  /* THE CARD DISSOLVES. In every other mode the island is a glass box, because
     a bar and a card are objects you summon. A conversation is not an object —
     it is Kyra talking over the desktop — so in chat the box gives up its
     background, its blur, its radius and its shadow, and what is left is the
     words on the veil. The only thing that keeps a surface is the composer,
     because a text field with no field is not a text field.

     BOTTOM-ANCHORED. `top:auto;bottom` rather than the centred default: the bar
     goes where a bar belongs and the conversation grows upward off it, which is
     what makes the newest turn sit just above the caret that produced it.
     useMorph animates width and height only, so the growth direction is a
     matter of which edge is pinned — nothing else has to know. */
  .island.chat-mode{width:50vw;min-width:520px;max-width:50vw;
    top:auto;bottom:7vh;transform:translateX(-50%);
    background:none;backdrop-filter:none;-webkit-backdrop-filter:none;
    box-shadow:none;border-radius:0;overflow:visible;
    /* The transcript paints above the composer while the input stays the FIRST
       child, so focus order, the ESC chip and everything reading .i-head are
       untouched — only the painting order is reversed. */
    display:flex;flex-direction:column-reverse}

  /* The composer, and nothing else, keeps glass. No hairline on it: a border is
     the thing that would make it read as a box sitting on the desktop rather
     than as part of the same surface. */
  .island.chat-mode .i-head{border-top:none;padding:15px 20px;
    background:var(--glass);border-radius:21px;
    backdrop-filter:blur(40px) saturate(180%);
    -webkit-backdrop-filter:blur(40px) saturate(180%);
    box-shadow:0 18px 50px rgba(0,0,0,.34)}

  /* The conversation itself has no container: no padding box, no fill.
     NO TOP FADE either. A mask was tried here to soften a long transcript's
     upper edge, but it dims by position rather than by age — so the very first
     thing you say, sitting at the top of a two-line conversation, was the most
     faded thing on screen. The oldest message is not the least important one. */
  .island.chat-mode .i-content{padding:0 6px 16px}
  /* Words on the desktop rather than on a panel, so they carry their own
     legibility the way the coach copy does. */
  .island.chat-mode .ch-a{text-shadow:0 1px 16px rgba(0,0,0,.5)}
  .island.chat-mode .ch-q{border:none;background:rgba(255,255,255,.13);
    box-shadow:0 6px 20px rgba(0,0,0,.22)}
  .island.chat-mode .ch-chip{border:none;background:rgba(255,255,255,.09)}

  .ch-wrap{padding-top:6px;max-height:56vh;display:flex;flex-direction:column;gap:18px}
  .ch-turn{display:flex;flex-direction:column;gap:12px}

  /* YOURS, on the right. A filled bubble, sans, at reading size — it is a thing
     you said, not a heading over her answer. It arrives from the right edge,
     which is the direction it was sent in. */
  .ch-q{align-self:flex-end;max-width:74%;padding:9px 14px;border-radius:17px 17px 5px 17px;
    background:rgba(255,255,255,.11);border:1px solid var(--hairline);
    font-size:14.5px;line-height:1.45;letter-spacing:-.15px;color:var(--label);
    text-wrap:pretty;animation:ch-mine .34s var(--spring) both}
  @keyframes ch-mine{from{opacity:0;transform:translate(16px,4px) scale(.97)}
    to{opacity:1;transform:none}}

  /* HERS, on the left: the answer and everything hanging off it, in one column
     so the chips and the undo line up under the words they belong to. */
  .ch-k{align-self:flex-start;max-width:86%;display:flex;flex-direction:column;
    align-items:flex-start;gap:9px}
  /* No bubble on Kyra's side, on purpose. The serif IS her — the same face the
     greeting speaks in — and boxing it would make her another participant in a
     messaging app rather than the surface itself talking. */
  .ch-a{font-family:'Instrument Serif','Iowan Old Style',Georgia,serif;
    font-size:20.5px;line-height:1.42;letter-spacing:-.1px;color:var(--label);
    text-wrap:pretty;animation:ch-hers .4s var(--spring) both}
  @keyframes ch-hers{from{opacity:0;transform:translate(-10px,4px)}to{opacity:1;transform:none}}

  /* Three dots on her side of the room while she reads. */
  .ch-wait{display:flex;gap:5px;padding:6px 2px;animation:ch-hers .3s var(--spring) both}
  .ch-wait i{width:6px;height:6px;border-radius:50%;background:var(--label-3);
    animation:chpulse 1.3s ease-in-out infinite}
  .ch-wait i:nth-child(2){animation-delay:.16s}
  .ch-wait i:nth-child(3){animation-delay:.32s}
  @keyframes chpulse{0%,100%{opacity:.28;transform:scale(.85)}50%{opacity:.9;transform:none}}
  .ch-err{font-size:13.5px;color:var(--amber);letter-spacing:-.1px}

  /* What the answer rests on. Sans and small, deliberately below the serif:
     receipts, not speech. A chip opens in place — the island IS the card, so a
     popover over it would be a second surface saying the same thing. */
  .ch-cites{display:flex;flex-wrap:wrap;gap:6px;margin-top:1px}
  .ch-cite{display:inline-flex;align-items:baseline;gap:7px;max-width:100%}
  .ch-chip{font-family:var(--font);font-size:11.5px;font-weight:560;letter-spacing:-.05px;
    color:var(--label-2);background:rgba(255,255,255,.06);border:1px solid var(--hairline);
    border-radius:9px;padding:4px 9px;cursor:pointer;max-width:34ch;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap;
    transition:background .16s ease,color .16s ease}
  .ch-chip:hover{background:rgba(255,255,255,.10);color:var(--label)}
  .ch-cite.open .ch-chip{background:rgba(255,255,255,.11);color:var(--label)}
  .ch-icon{margin-right:5px;color:var(--label-3);font-size:11px}
  /* The evidence itself, once asked for: the message as it was written. */
  .ch-ev{flex-basis:100%;margin-top:5px;font-size:12.5px;line-height:1.5;
    color:var(--label-2);letter-spacing:-.1px;text-wrap:pretty;
    border-left:1.5px solid var(--hairline);padding-left:9px;
    animation:fin .3s var(--spring) both}

  /* What the turn changed, and the five seconds in which it can be unchanged. */
  .ch-did{display:flex;align-items:center;gap:10px;
    font-size:12.5px;color:var(--green);letter-spacing:-.1px}
  .ch-did-undone{color:var(--label-3);text-decoration:line-through}
  .ch-undo{font-family:var(--font);font-size:11.5px;font-weight:640;letter-spacing:.2px;
    color:var(--blue);background:rgba(124,166,221,.12);border:none;border-radius:8px;
    padding:3px 9px;cursor:pointer;transition:background .16s ease}
  .ch-undo:hover{background:rgba(124,166,221,.22)}
  .ch-more{color:var(--label-3);background:transparent}
