/* ============================================================
   THE DRAWER — the phone's whole navigation, and nothing above
   700px can see any of it.

   The phone used to be navigated by a floating pill of three words
   at the foot of the screen. Three words is all it could ever be,
   and the site is bigger than three words: the case studies, the
   resume, the mailbox and the four profiles have been listed in the
   desktop rail since the shell was built and had no way onto a phone
   at all. On the case pages the bar was worse than empty — its links
   still pointed at the about.html / work.html / play.html redirect
   stubs, and it marked the wrong one as the current page.

   So the rail comes to the phone, in the shape a phone reads: one
   button in the top-left corner, a panel that slides out from under
   it, and the page pushed aside behind it. Same TREE (js/shell.js),
   regrouped for a thumb — see js/drawer.js for what moves where and
   why.

   NOT a re-skin of .shell-side. That column is sticky, is as wide as
   a remembered localStorage number, carries a resize grip and a
   collapse toggle and a globe, and — fatally — its letterhead is
   driven by wireAskReveal(), which on a phone reads the hero at 100%
   of the screen, writes --ask-p: 0, and sets `inert` on the name.
   Every one of those would have to be undone here. This is a panel.

   Loaded on all five documents. Every rule is inside the one media
   query; js/drawer.js does its own matchMedia guard.
   ============================================================ */
@media (max-width: 700px) {

  /* THE WHOLE SCREEN. It was 81% — the reference's share, keeping a
     strip of the page visible so you could see it was still there —
     and a strip you cannot read is not reassurance, it is 74px of a
     390px screen spent on a rumour of the page behind. Given all of
     it, the navigation gets room to be laid out rather than fitted in.

     What tells you the page is still there is the button in the corner,
     which never moved and is the way back. That was always the stronger
     signal; the strip was the weaker one standing next to it. */
  :root {
    --m-drawer-w: 100%;
    --m-btn: 38px;               /* both corner buttons, one number */
    --m-btn-top: 12px;
    --m-btn-side: 14px;
    /* one left edge for the whole column: the mark, the labels and every
       glyph hang off this, so nothing in the panel is a pixel out */
    --m-inset: 24px;
  }

  /* ============================================================
     (GONE: THE PUSH — .shell travelling right and scaling to 0.88
     behind the panel, with rounded corners, which was the gesture taken
     whole from the reference.

     It went with the strip. At 81% there was a page behind the drawer to
     push; at 100% there is nothing to see, so the transform was
     compositing an entire nine-thousand-pixel document into one layer to
     move it somewhere no one could look. This site has twice stopped
     drawing over exactly that kind of layer (css/styles.css's frost
     incident, js/case-overlay.js's iframe measurement), and this one was
     not even buying a picture.

     Its two preconditions STAY, on their own merits: the case studies'
     .read-progress is appended to <body> (js/vicino.js and siblings)
     because a fixed bar has no business inside a transformable ancestor
     either way, and .globe-card is out of the phone document below
     because there is no hover here to open it. Neither is load-bearing
     for anything now — but if a push ever comes back, they are what
     makes it safe.)
     ============================================================ */

  /* js/globe.js builds its card at parse time on EVERY page and
     appends it into #shell, and there is no hover on a phone to ever
     open it. It is already [hidden]; this also stops it being a fixed
     descendant of the element the push transforms. */
  .globe-card { display: none !important; }

  /* ============================================================
     THE PANEL
     ============================================================ */
  .m-drawer {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 70;
    width: var(--m-drawer-w);
    display: flex;
    flex-direction: column;
    /* the rail's own material. --shell-surface (--g-100) against the
       card's --bg is the one considered step the whole frame is built
       on, and the drawer IS the rail — it should not invent a third
       surface to say so. */
    background: var(--shell-surface);
    /* no border-right: at full width there is no edge for a seam to sit
       on, and a hairline against the screen's own edge is a line for
       nothing */
    padding: calc(var(--m-btn-top) + var(--m-btn) + 18px) 0
             calc(24px + env(safe-area-inset-bottom, 0px));
    translate: -100% 0;
    /* visibility, not display: a display:none panel cannot transition,
       and a panel that is merely translated off-screen is still in the
       tab order. This is the pair that answers both. */
    visibility: hidden;
    overscroll-behavior: contain;
    transition: translate var(--t-lift) var(--ease-lift),
                visibility var(--t-lift);
  }
  html.m-open .m-drawer { translate: 0 0; visibility: visible; }
  /* while a finger is on it the panel must track the pointer exactly —
     a transition here puts the panel on elastic (js/drawer.js) */
  html.m-dragging .m-drawer { transition: none; }

  /* ---- the scrim, and it is the SCROLL LOCK.

     It covers every pixel of the page, so every touch meant for the
     page lands here instead — and `touch-action: none` means the
     browser will not pan from it. That is the whole lock: no
     overflow:hidden on <html> (iOS honours it unevenly, and it would
     fight the pager's own per-screen scroll bank in js/mobile.js), no
     position:fixed body swap, no scrollY bookkeeping to get wrong.
     The panel's own overscroll-behavior closes the only other hole,
     and html { overscroll-behavior-y: none } (css/shell.css) already
     closed the rubber-band one.

     A <button>, not a <div>: it is the drawer's screen-reader-
     reachable way out, and it costs nothing to make it one. ---- */
  .m-scrim {
    position: fixed;
    inset: 0;
    z-index: 65;
    margin: 0;
    padding: 0;
    border: 0;
    background: rgba(var(--ink-rgb), 0.32);
    opacity: 0;
    visibility: hidden;
    touch-action: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: opacity var(--t-lift) var(--ease-lift),
                visibility var(--t-lift);
  }
  html.m-open .m-scrim { opacity: 1; visibility: visible; }

  /* ============================================================
     THE BUTTON IN THE CORNER — and it does not move.

     It wears G.rail, the same mark the desktop rail's own toggle and
     .rail-open both wear, and it obeys the rule js/shell.js states
     about them: open or closed, the toggle is in the top-left corner
     of the frame and does not move; only the surface behind it
     changes. So the panel slides out from UNDERNEATH it. Focus never
     leaves the button, which means there is nothing to restore on
     close and no second control to keep in step.

     A <body> child, outside .shell — where it has to be to sit OVER the
     panel at full width, and where the push (now retired, see above)
     needed it too.

     NO backdrop-filter, and .case-x's comment is the reason verbatim:
     a filter here would re-blur its own circle on every scrolled
     frame beneath it, for the whole length of a case-study read.
     Near-solid does the same job for nothing.
     ============================================================ */
  .m-menu {
    position: fixed;
    top: var(--m-btn-top);
    left: var(--m-btn-side);
    z-index: 80;                    /* over the panel (70) and .read-progress (45) */
    width: var(--m-btn);
    height: var(--m-btn);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0;
    /* opaque. The chat's transcript runs underneath this button now
       (css/mobile.css --scroll-top), and at 94% the words showed through
       it — see the same note on .ai-reset. */
    background: var(--bg);
    border: 1px solid var(--shell-line);
    border-radius: 50%;
    color: var(--g-550);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    opacity: 0;
    transition: opacity var(--t-fade) ease,
                color var(--t-micro) ease,
                background-color var(--t-micro) ease;
  }
  /* ---- …except on the home screen, where it is placed at a document
     coordinate instead, for the reason js/mobile.js sets out at length:
     `position: fixed` is anchored to something browsers disagree about
     while a keyboard is up, and the home screen is the only one here that
     ever raises one. It is fixed to the top of the layout viewport and
     given nothing that changes, so it does not move for a keyboard at
     all — which is the point.

     It rides the same curve as the hero (css/mobile.css) because it is
     answering the same event, and the hero carries #ai-reset — so all
     three move as one thing or none of them moves at all. ---- */
  html.is-phone[data-m-screen="home"] .m-menu {
    /* The hero's coordinate exactly (css/mobile.css) — absolute, at the
       document y of the top of the visible window. Not fixed: on iOS a
       fixed box is anchored to the layout viewport, which is itself
       displaced while a keyboard is open, and that is how this button
       ended up above the top of the screen.

       No transform and no transition on it — the coordinate already puts
       it where the window is, and easing a position that IS the answer
       would draw it somewhere the window is not.

       It used to translate by visualViewport.offsetTop to stay on the
       window's top line when the browser shoved it. Correct on paper and a
       flinch in practice: the shove is answered a frame late, and traced
       off a recording this button wandered ±13px over four hundred
       milliseconds every time a keyboard arrived.

       The hero is fixed at the same origin and only its HEIGHT changes, so
       its top edge never moves either — which means this button and
       #ai-reset (an absolute child of that box) sit on one line and stay
       there because neither of them has anything to react to. The shove
       is prevented upstream instead; see js/mobile.js. */
    position: absolute;
    top: calc(var(--doc-top, 0px) + var(--m-btn-top));
  }

  .m-menu.is-lit { opacity: 1; }
  .m-menu svg { display: block; width: 20px; height: 20px; }
  .m-menu:active { background: var(--wash-solid); color: var(--ink); }
  html.m-open .m-menu { color: var(--ink); }

  /* the opening owns the corner. On the home page the button waits for
     the name to finish typing, exactly as .rail-open does above this
     width; js/typewriter.js drops the class. On the other four pages
     the class is never set and js/drawer.js lights it a frame in. */
  html.intro-pending .m-menu { opacity: 0; pointer-events: none; }

  /* ?embed=1 is a bare frame with no chrome at all (js/shell.js) */
  html.is-embed .m-menu,
  html.is-embed .m-drawer,
  html.is-embed .m-scrim { display: none; }

  /* ============================================================
     THE LETTERHEAD — a mark, a name and a role.

     The rail's own #ask-chip could not be reused and it is worth
     writing down why: wireAskReveal() runs unguarded at this width,
     reads the hero as 100% of the reading area, writes --ask-p: 0 and
     sets `inert`. The rail's letterhead is deliberately invisible on
     a phone. This is a fresh one, with the same two lines and the
     same href, which is the one thing a wordmark in a top-left corner
     has always meant.

     The mark is darkcircle.png — already the <link rel="icon"> on all
     five pages, so it is in cache before this is parsed. NOT the
     hedcut: js/portrait.js records that the rail's small face was
     replaced by a drawn mark for being illegible at that size, and
     the drawn mark has since gone too. Twice retired is enough.
     ============================================================ */
  .m-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 var(--m-inset) 20px;
    text-decoration: none;
    color: inherit;
    -webkit-tap-highlight-color: transparent;
  }
  .m-head-mark {
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 50%;
    display: block;
  }
  .m-head-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .m-head-name {
    font-size: 16px;
    line-height: 20px;
    letter-spacing: -0.015em;
    color: var(--ink);
  }
  .m-head-role {
    font-size: 12px;
    line-height: 15px;
  }

  /* ============================================================
     THE ROWS

     46px, not the rail's 30. That is the whole argument for new class
     names rather than .side-row: every number in css/shell.css's row
     block was drawn for a 14px label under a pointer, and a thumb
     wants a target it can hit without looking.
     ============================================================ */
  /* the hairline lives HERE rather than under .m-head, so it runs the
     full width of the screen instead of stopping at the letterhead's
     inset: it divides identity from navigation, and that is a division
     of the whole panel, not of one padded box inside it. */
  .m-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    border-top: 1px solid var(--shell-line);
    padding: 12px 0 8px;
  }

  /* ---- THE RHYTHM, which is the whole of what makes this read as
     organised rather than as a list that happens to have headings.

     A label owns the rows UNDER it, so the air above it is large and the
     air below it is small — 28 and 6. Get that pair the wrong way round,
     or make them equal (the same mistake, more politely), and every label
     floats between two groups belonging to neither: the eye then has to
     READ the words to find the seams instead of seeing them.

     And there are exactly two vertical edges in the panel. --m-inset
     carries the mark, both labels and every glyph, so a line drawn down
     the screen touches all of them; the row TEXT sits on a second edge of
     its own, past the glyph column. Nothing is on a third. ---- */
  .m-group + .m-group { margin-top: 28px; }
  /* ============================================================
     ONE INK.

     The rail differentiates hard — the current row wears the accent,
     its ancestors a half-step of it, the rest sit back in --g-700 with
     their glyphs a further step back in --g-400 — because the rail is
     a persistent map you read WHILE you are somewhere, and it has to
     answer "where am I" without being asked.

     A drawer is not that. It is shut except in the moment you opened
     it to go somewhere, you already know where you are because you
     were just looking at it, and every gradient of grey in here was
     answering a question nobody was asking. So the labels, the rows,
     the glyphs and the status lines are all one colour, and the only
     thing that varies down the column is the type size.

     The current row still carries aria-current — that mark is for a
     reader who genuinely cannot see the page behind the panel, and it
     costs nothing to keep saying it.
     ============================================================ */
  .m-drawer,
  .m-drawer .m-label,
  .m-drawer .m-row,
  .m-drawer .m-ico,
  .m-drawer .m-head-name,
  .m-drawer .m-head-role { color: var(--ink); }

  .m-label {
    margin: 0 0 6px;
    padding: 0 var(--m-inset);
    font-size: 11px;
    font-weight: 400;
    /* the label register: small, spaced, lowercase. Size and tracking do
       the work a second colour would have done — see ONE INK above. */
    letter-spacing: 0.1em;
    text-transform: lowercase;
  }
  .m-row {
    display: flex;
    align-items: center;
    gap: 14px;
    height: 52px;
    padding: 0 var(--m-inset);
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: background-color var(--t-micro) ease;
  }
  .m-ico {
    flex: none;
    /* a fixed box, not the glyph's own size: the marks are drawn on a 26
       grid and do not all fill it, so without this the word after a narrow
       one (Goodreads' g) would start a pixel or two left of the word after
       a wide one. The COLUMN is the thing being aligned, not the drawing. */
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .m-ico svg { display: block; width: 22px; height: 22px; }
  .m-text {
    font-size: 17px;
    line-height: 22px;
    letter-spacing: -0.015em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .m-row:active { background: rgba(var(--ink-rgb), 0.05); }

  /* (GONE: `.m-row.is-current`, `.is-current .m-ico` and `.is-trail`,
     which painted the current row in the accent and its ancestors a
     step down from it. See ONE INK above — the classes are still set by
     js/drawer.js and still carry aria-current; nothing paints them.) */

  /* (GONE: `.m-foot` and everything in it — statusHTML()'s "now" section
     and, before that, a black "new chat" pill beneath it.

     The rail's own argument for a weighted floor is an argument about a
     RAIL: a persistent column with nav above it should not end in a long
     fall to nothing. A drawer has no long fall — it is shut except in the
     second you opened it to go somewhere — so the floor was holding down
     a column that was never falling, and spending a third of a phone
     screen to do it. The status lines still live on About, in the letter,
     where someone is actually asking.

     The pill went for its own reason: the site has one conversation, and
     the way to clear it is already in the corner of the screen the pill
     led to. Two doors to one action, and the quieter one was in the wrong
     room.) */
}

/* ---- no travel for a visitor who does not want any. The panel is
   simply there, cross-faded at the micro duration so the change is
   still legible AS a change, and the page does not move at all. ---- */
@media (max-width: 700px) and (prefers-reduced-motion: reduce) {
  .m-drawer {
    translate: none;
    opacity: 0;
    transition: opacity var(--t-micro) ease, visibility var(--t-micro);
  }
  html.m-open .m-drawer { translate: none; opacity: 1; }
  .m-scrim {
    transition: opacity var(--t-micro) ease, visibility var(--t-micro);
  }
}
