:root{
    --bg:#f4f4f3; --panel:#fff; --panel-hi:#fafafa; --ink:#1c1c1f; --muted:#67676f;
    --line:rgba(0,0,0,.09); --accent:#3b6ef5; --code-bg:#f1f1f0; --ok:#1a7f4b;
    --shadow:0 1px 2px rgba(0,0,0,.04), 0 2px 10px rgba(0,0,0,.04);
    --shadow-hi:0 1px 2px rgba(0,0,0,.06), 0 4px 16px rgba(0,0,0,.07);
  }
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){
      /* Tuned toward what Dark Reader produces: not pure black, and borders carried by
         low-alpha white rather than a hard grey line -- that is what reads as "smoother". */
      --bg:#181a1b; --panel:#1e2021; --panel-hi:#25282a; --ink:#e8e6e3; --muted:#9d9891;
      --line:rgba(255,255,255,.07); --accent:#7aa2ff; --code-bg:#141617; --ok:#4ade80;
      --shadow:0 1px 2px rgba(0,0,0,.28), 0 2px 10px rgba(0,0,0,.16);
      --shadow-hi:0 1px 3px rgba(0,0,0,.34), 0 6px 20px rgba(0,0,0,.24);
    }
  }
  *{box-sizing:border-box}
  /* Reserve the scrollbar gutter always. Opening the panel changes the page height, and a
     scrollbar appearing or vanishing changes the viewport width -- which resizes the grid
     columns, which resizes the terminal, after it has already drawn. */
  html{scrollbar-gutter:stable}
  body{
    margin:0; background:var(--bg); color:var(--ink);
    font:16px/1.65 ui-sans-serif,-apple-system,"Segoe UI",Roboto,sans-serif;
    -webkit-font-smoothing:antialiased; padding:32px 20px;
  }
  .wrap{max-width:860px;margin:0 auto}
  .card{
    width:100%; max-width:680px; margin:0 auto; background:var(--panel);
    border:1px solid var(--line); border-radius:16px; padding:34px; box-shadow:var(--shadow);
  }
  body.center{display:flex;align-items:center;justify-content:center;min-height:100vh;padding:24px}
  header{margin-bottom:28px}
  h1{margin:0 0 3px;font-size:1.55rem;letter-spacing:-.021em;font-weight:650}
  .sub{color:var(--muted);font-size:.885rem}
  .badge{display:inline-block;font-size:.68rem;padding:3px 9px;border-radius:99px;
    background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok);
    border:1px solid color-mix(in srgb,var(--ok) 28%,transparent);margin-left:9px;vertical-align:3px;
    font-weight:500;letter-spacing:.01em}
  h2{font-size:.735rem;text-transform:uppercase;letter-spacing:.095em;color:var(--muted);
    margin:32px 0 12px;font-weight:600}
  .card h2:first-of-type{margin-top:0}
  .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(212px,1fr));gap:11px}
  a.tile{
    display:block;background:var(--panel);border:1px solid var(--line);border-radius:12px;
    padding:14px 16px;text-decoration:none;color:var(--ink);box-shadow:var(--shadow);
    transition:background .18s ease, box-shadow .18s ease, transform .18s ease;
  }
  a.tile:hover{background:var(--panel-hi);box-shadow:var(--shadow-hi);transform:translateY(-1px)}
  .tile .n{font-weight:600;font-size:.925rem;letter-spacing:-.005em}
  .tile .d{color:var(--muted);font-size:.755rem;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
    margin-top:4px;word-break:break-all}
  .cmd{position:relative;background:var(--code-bg);border:1px solid var(--line);
    border-radius:11px;padding:15px 48px 15px 15px;overflow-x:auto}
  code{font:13px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre;color:var(--ink)}
  button{
    position:absolute;top:9px;right:9px;background:var(--panel);color:var(--muted);
    border:1px solid var(--line);border-radius:7px;padding:4px 10px;font-size:11px;
    cursor:pointer;font-family:inherit;
    transition:color .16s ease, border-color .16s ease, background .16s ease;
  }
  button:hover{color:var(--ink);border-color:color-mix(in srgb,var(--accent) 45%,transparent);
    background:var(--panel-hi)}
  button.done{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent)}
  .note{font-size:.83rem;color:var(--muted);margin-top:12px}
  .steps{font-size:.87rem;color:var(--muted);margin:11px 0 0;padding-left:20px}
  .steps li{margin:5px 0}
  footer{margin-top:34px;padding-top:17px;border-top:1px solid var(--line);
    font-size:.765rem;color:var(--muted)}

  /* --- browser shell panel -----------------------------------------------------
     One card, not a tile, because it is a control rather than a link -- and it has
     to read as clearly "on" or "off" from across the room. State lives on
     .shell[data-on], so JS flips one attribute and every colour follows. */
  .shell{
    background:var(--panel);border:1px solid var(--line);border-radius:12px;
    padding:14px 16px;box-shadow:var(--shadow);
  }
  .shell.busy{opacity:.55;pointer-events:none}
  .shell-row{display:flex;align-items:center;gap:12px}
  .shell-row.actions{margin-top:13px;padding-top:13px;border-top:1px solid var(--line);gap:8px}
  .shell .dot{
    width:9px;height:9px;border-radius:50%;flex:0 0 auto;
    background:var(--muted);box-shadow:none;transition:background .2s ease,box-shadow .2s ease;
  }
  .shell[data-on="1"] .dot{
    background:var(--ok);box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 20%,transparent);
  }
  .shell-txt{min-width:0;flex:1}
  .shell .n{font-weight:600;font-size:.925rem;letter-spacing:-.005em}
  .shell .state{
    font-size:.68rem;font-weight:600;text-transform:uppercase;letter-spacing:.07em;
    color:var(--muted);margin-left:7px;vertical-align:1px;
  }
  .shell[data-on="1"] .state{color:var(--ok)}
  .shell .d{color:var(--muted);font-size:.755rem;
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;margin-top:4px}

  /* .btn is static-position on purpose: the bare `button` rule above is absolutely
     positioned for the copy-token button and would fling these into the corner. */
  .btn{
    position:static;display:inline-block;background:var(--panel);color:var(--muted);
    border:1px solid var(--line);border-radius:8px;padding:6px 13px;font-size:.79rem;
    font-family:inherit;text-decoration:none;cursor:pointer;
    transition:color .16s ease,border-color .16s ease,background .16s ease;
  }
  .btn:hover{color:var(--ink);background:var(--panel-hi);
    border-color:color-mix(in srgb,var(--accent) 45%,transparent)}
  .btn.go:hover{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 50%,transparent)}
  .btn.stop:hover{color:#e05a5a;border-color:color-mix(in srgb,#e05a5a 50%,transparent)}
  /* Only offer the action that changes something: the shell is either on or off. */
  .shell[data-on="1"] .btn.go,
  .shell[data-on="1"] #shell-mins,
  .shell[data-on="0"] .btn.stop,
  .shell[data-on="0"] .btn.open{display:none}
  .shell #shell-mins{
    background:var(--panel);color:var(--muted);border:1px solid var(--line);
    border-radius:8px;padding:6px 9px;font:inherit;font-size:.79rem;cursor:pointer;
  }

  /* --- /drop -------------------------------------------------------------------
     A phone-first page: one big target, thumbs big enough to identify a screenshot
     at arm's length, and the path always visible because copying it is the point. */
  .drop-wrap{max-width:720px}
  .badge.off{background:color-mix(in srgb,var(--muted) 14%,transparent);color:var(--muted);
    border-color:color-mix(in srgb,var(--muted) 28%,transparent)}
  .pane{background:var(--panel);border:1px solid var(--line);border-radius:12px;
    padding:16px;box-shadow:var(--shadow)}
  .note-pane{color:var(--muted);font-size:.855rem}
  .dz{
    border:1px dashed color-mix(in srgb,var(--muted) 45%,transparent);text-align:center;
    padding:30px 18px;transition:border-color .18s ease,background .18s ease;
  }
  .dz.over{border-color:var(--accent);background:var(--panel-hi)}
  .dz.busy{opacity:.5;pointer-events:none}
  .dz:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
  .dz-main{font-weight:600;font-size:.95rem}
  .dz-sub{color:var(--muted);font-size:.775rem;margin-top:5px}
  .dz .btn{margin-top:14px}
  .dz{border-radius:11px}
  /* The error hangs off a data attribute so a failure needs no extra element and
     vanishes the moment the next attempt clears it. */
  .dz[data-err]:not([data-err=""])::after{
    content:attr(data-err);display:block;margin-top:12px;font-size:.8rem;color:#e05a5a;
  }
  .say{margin-top:16px}
  .say-l{font-size:.735rem;text-transform:uppercase;letter-spacing:.095em;
    color:var(--muted);margin-bottom:8px;font-weight:600}
  .f{display:flex;align-items:center;gap:13px;background:var(--panel);
    border:1px solid var(--line);border-radius:12px;padding:11px 13px;
    box-shadow:var(--shadow);margin-bottom:9px}
  .thumb{flex:0 0 auto;width:62px;height:48px;border-radius:8px;overflow:hidden;
    background:var(--code-bg);border:1px solid var(--line);display:block}
  .thumb img{width:100%;height:100%;object-fit:cover;display:block}
  .f-txt{min-width:0;flex:1}
  .f-txt code{font-size:12px;word-break:break-all;white-space:normal}
  .f-meta{color:var(--muted);font-size:.735rem;margin-top:3px}
  /* The path is the thing you actually read here, so wrap it instead of inheriting
     .cmd's horizontal scroll — on a phone that hid the end of the filename behind
     the copy button, which is exactly the half you need. */
  .say .cmd{padding-right:15px;overflow-x:visible}
  .say .cmd code{white-space:pre-wrap;word-break:break-all;display:block;padding-right:52px}

  /* --- back-home link + view switch ---------------------------------------------
     Both are fixed rather than in flow: the public branch of the hub page centres a
     card in the viewport with flex, and an in-flow element there becomes a flex item
     and shoves the card off-centre. */
  /* Opaque, not translucent-with-blur. backdrop-filter on fixed elements forces the
     compositor to re-blur the page behind them on every paint, and with three of them on a
     long page that is a visible hitch on first load. Nothing sits under these anyway. */
  .home,.viewsw{
    position:fixed;top:12px;z-index:20;font-size:.75rem;
    background:var(--panel);
    border:1px solid var(--line);border-radius:99px;box-shadow:var(--shadow);
  }
  .home{left:12px;padding:5px 12px;color:var(--muted);text-decoration:none;
    transition:color .16s ease,border-color .16s ease}
  .home:hover{color:var(--ink);border-color:color-mix(in srgb,var(--accent) 45%,transparent)}
  .viewsw{right:12px;display:flex;align-items:center;gap:2px;padding:4px 5px 4px 11px}
  .viewsw-l{color:var(--muted);font-size:.68rem;text-transform:uppercase;
    letter-spacing:.07em;margin-right:5px}
  .viewsw a{color:var(--muted);text-decoration:none;padding:3px 9px;border-radius:99px;
    transition:color .16s ease,background .16s ease}
  .viewsw a:hover{color:var(--ink)}
  .viewsw a.sel{background:var(--panel-hi);color:var(--ink);
    box-shadow:inset 0 0 0 1px var(--line)}
  /* Unmissable while previewing: the point is to see the public page, not to forget
     you are on it and think the hub broke. */
  .viewsw.on{border-color:color-mix(in srgb,var(--accent) 55%,transparent)}
  @media (max-width:520px){ .viewsw-l{display:none} }

  /* --- drop, as a collapsible cell ----------------------------------------------
     <details>, so open/closed needs no JS and survives a failed script. The summary row
     is the compact form he asked for: dot, count, and a choose button that works without
     expanding. */
  .drop{background:var(--panel);border:1px solid var(--line);border-radius:12px;
    box-shadow:var(--shadow);overflow:hidden}
  .drop.over{border-color:var(--accent);background:var(--panel-hi)}
  .drop>summary{
    display:flex;align-items:center;gap:12px;padding:14px 16px;cursor:pointer;
    list-style:none;user-select:none;
  }
  .drop>summary::-webkit-details-marker{display:none}
  .drop>summary::after{
    content:"";width:7px;height:7px;flex:0 0 auto;margin-left:2px;
    border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
    transform:rotate(45deg) translate(-2px,-2px);transition:transform .18s ease;
  }
  .drop[open]>summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
  .drop>summary:hover{background:var(--panel-hi)}
  .drop .dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;background:var(--muted)}
  .drop[data-armed="1"] .dot{background:var(--ok);
    box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 20%,transparent)}
  .drop-sum{min-width:0;flex:1}
  .drop-sum .n{font-weight:600;font-size:.925rem;letter-spacing:-.005em;display:block}
  .drop-sum .count{color:var(--muted);font-weight:400}
  .drop-sum .d{color:var(--muted);font-size:.755rem;
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;margin-top:3px;display:block}
  .drop-body{padding:0 16px 16px;border-top:1px solid var(--line);padding-top:15px}
  .drop .note{font-size:.755rem}
  .drop video.thumb{object-fit:cover}

  /* The public page's shell row. Same shape as the trusted cell, minus every control:
     from out there the only useful actions are "go in" and "send a screenshot". */
  .pubshell{display:flex;align-items:center;gap:12px;background:var(--panel);
    border:1px solid var(--line);border-radius:12px;padding:13px 15px;box-shadow:var(--shadow)}
  .pubshell .dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;background:var(--ok);
    box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 20%,transparent)}
  .pubshell-txt{min-width:0;flex:1}
  .pubshell .n{font-weight:600;font-size:.9rem}
  .pubshell .d{color:var(--muted);font-size:.75rem;margin-top:2px}
  /* Both pills are position:fixed, so they sit ON TOP of the first heading at narrow
     widths -- "← thorsp.net" landed across the drop page's h1 on a phone. Push the page
     down only when one is actually present. */
  body:has(> .home), body:has(> .viewsw){padding-top:58px}
  @media (max-width:520px){ body:has(> .viewsw){padding-top:58px} }

  /* --- the slide-out terminal ---------------------------------------------------
     Closed, this is EXACTLY the old page: one centred column, nothing else on screen.
     Open, the viewport splits in two and each half centres its own content.

     grid-template-columns is the animated property -- `1fr 0fr` -> `1fr 1fr` interpolates
     (both sides are <flex> values), which flex-basis on two children does not do as
     cleanly. margin-inline:auto inside each column is what keeps both halves centred
     rather than jammed against the divider. */
  .cols{display:block}
  .cols>.wrap{max-width:860px;margin-inline:auto}

  @media (min-width:1180px){
    body:has(.cols){padding-left:24px;padding-right:24px}
    .cols{
      display:grid;grid-template-columns:1fr 0fr;gap:0;align-items:start;
      max-width:1800px;margin:0 auto;
      transition:grid-template-columns .48s cubic-bezier(.4,0,.2,1), gap .48s cubic-bezier(.4,0,.2,1);
    }
    /* The gap has to be wider than the handle (44px) or the handle sits ON both columns
       with no breathing room -- 26px left it crowded against the card on one side and the
       terminal on the other. 76px gives it 16px of clear space either side, symmetric by
       construction rather than by nudging `left`. */
    .cols.open{grid-template-columns:1fr 1fr;gap:76px}
    .cols>.wrap{width:100%}
    /* overflow:hidden matters while closed: the column is 0 wide but the terminal inside
       still has intrinsic width, and without this it spills across the page mid-animation. */
    .cols>.term{
      /* Same max-width as .wrap, deliberately. Both columns centre their content, so
         unequal caps give them unequal slack -- and the handle, which sits at the centre of
         the GRID gap, then looks off against the two visible boxes. At 1920 the 860/840
         split put 35px on its left and 45px on its right. Equal caps make the grid gap and
         the visual gap the same thing. */
      display:flex;width:100%;max-width:860px;margin-inline:auto;min-width:0;overflow:hidden;
      contain:paint;
      opacity:0;visibility:hidden;
      transition:opacity .3s ease, visibility 0s linear .48s;
    }
    .cols.open>.term{
      opacity:1;visibility:visible;
      transition:opacity .34s ease .14s, visibility 0s;
      position:sticky;top:24px;height:calc(100vh - 60px);max-height:940px;
    }
    /* The handle. Fixed, vertically centred, and it MOVES: parked in the empty space to the
       right of the centred page when closed, sliding to the divider as the page opens. */
    .termtoggle{
      position:fixed;top:50%;z-index:25;
      /* Centred in the empty space beside the page, not just tucked against it: the gap
         runs from 50%+430px to 100%, so its midpoint is 75%+215px. */
      left:min(calc(75% + 198px), calc(100% - 54px));
      transform:translateY(-50%);
      display:flex;align-items:center;justify-content:center;
      width:44px;height:44px;padding:0;cursor:pointer;color:var(--muted);
      background:var(--panel);
      border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);
      /* Only `left` animates, and promoting it up front stops the first click from
         triggering a layer-creation hitch mid-slide. */
      will-change:left;
      transition:left .48s cubic-bezier(.4,0,.2,1), color .16s ease,
                 background .16s ease, border-color .16s ease, box-shadow .16s ease;
    }
    .cols.open ~ .termtoggle, .termtoggle.open{left:calc(50% - 22px)}
    .termtoggle:hover{color:var(--ink);background:var(--panel-hi);
      border-color:color-mix(in srgb,var(--accent) 45%,transparent);box-shadow:var(--shadow-hi)}
    .termtoggle>svg{width:21px;height:21px;display:block}
    /* Open, it is a "close" affordance, so the tile reads as active rather than inviting. */
    .termtoggle.open{color:var(--accent);
      border-color:color-mix(in srgb,var(--accent) 45%,transparent)}
  }
  /* Below the breakpoint there is no split and no handle: a 400px terminal is not a
     terminal, and /shell/ already covers being on a phone. */
  @media (max-width:1179px){ .termtoggle{display:none} }

  /* --- the terminal panel -------------------------------------------------------
     Hidden entirely on narrow screens: a 400px-wide terminal is not a terminal, and the
     emergency /shell/ already covers "I am on my phone". */
  .term{
    display:none;flex-direction:column;background:var(--panel);
    border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);overflow:hidden;
  }
  .term-bar{display:flex;align-items:stretch;gap:4px;padding:7px 7px 0;overflow-x:auto}
  .term-tabs{display:flex;gap:4px;min-width:0}
  .term-tab{
    position:static;display:flex;align-items:center;gap:7px;white-space:nowrap;
    background:transparent;border:1px solid transparent;border-radius:8px 8px 0 0;
    padding:6px 11px;font:inherit;font-size:.78rem;color:var(--muted);cursor:pointer;
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  }
  .term-tab:hover{color:var(--ink);background:var(--panel-hi)}
  .term-tab.sel{color:var(--ink);background:var(--code-bg);
    border-color:var(--line);border-bottom-color:transparent}
  .term-tab .x{opacity:.45;font-size:14px;line-height:1}
  .term-tab .x:hover{opacity:1;color:#e05a5a}
  .term-ico{
    position:static;background:transparent;border:1px solid transparent;border-radius:8px;
    color:var(--muted);font-size:15px;line-height:1;padding:4px 9px;cursor:pointer;
  }
  .term-ico:hover{color:var(--ink);background:var(--panel-hi)}
  .term-ctl{display:flex;align-items:center;gap:6px;padding:8px 10px;
    border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
  .term-ctl select{
    flex:1;min-width:0;background:var(--panel);color:var(--ink);border:1px solid var(--line);
    border-radius:8px;padding:5px 8px;font:inherit;font-size:.76rem;cursor:pointer;
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  }
  .term-ctl .btn{padding:5px 11px;font-size:.76rem}
  .term-frames{flex:1;min-height:0;background:#141617;position:relative}
  .term-frames iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
  .term-frames iframe[hidden]{display:none}

  /* --- enrolment OS / profile picker -------------------------------------------
     Segmented rows rather than <select>s: two choices that change one visible line of
     text read better as buttons you can see the state of at a glance. */
  .pick{display:flex;flex-direction:column;gap:7px;margin-bottom:11px}
  .pick-row{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
  .pick-l{font-size:.68rem;text-transform:uppercase;letter-spacing:.08em;
    color:var(--muted);font-weight:600;width:72px;flex:0 0 auto}
  .pick-b{
    position:static;background:var(--panel);color:var(--muted);border:1px solid var(--line);
    border-radius:99px;padding:4px 12px;font:inherit;font-size:.76rem;cursor:pointer;
    transition:color .16s ease,background .16s ease,border-color .16s ease;
  }
  .pick-b:hover{color:var(--ink);background:var(--panel-hi)}
  .pick-b.sel{color:var(--ink);background:var(--panel-hi);
    border-color:color-mix(in srgb,var(--accent) 50%,transparent)}
  @media (max-width:520px){ .pick-l{width:100%} }
  /* The copy button sat at top:9px while the command line beside it is vertically centred
     in the box -- fine when .cmd was exactly one line tall, visibly off once the enrolment
     note and the wrapped drop paths made it taller. Centre it against whatever height the
     box ends up. */
  .cmd button{top:50%;transform:translateY(-50%)}
