/* =========================================================================
 * THE SHELL. What every screen in this platform is drawn inside.
 *
 * Extracted from index.html on 27 September 2026 -- step 3b of document 39 --
 * because Chris decided the Calendar gets its own page and asked that the
 * pages that follow look like the landing page:
 *
 *   "The screens do not stay within the plan's shell. They will have their own
 *    pages and I would hope they exist in the landing page shell." -- and
 *   "basically, I would like the landing page to be the style of all the pages
 *    that follow."
 *
 * EXTRACTED RATHER THAN COPIED. Chris allowed either; this codebase has a rule
 * about it, written beside linkgeom.js:
 *
 *   A MODULE THAT IS SHARED BY BEING COPIED IS NOT SHARED. IT IS TWO MODULES
 *   THAT AGREE TODAY.
 *
 * One copy is cheap. The fourth screen is where it stops being cheap, and by
 * then three of them disagree about what the rail looks like.
 *
 * ------------------------------------------------------------ what is here --
 * The palette and the type scale, the stage, the two-track .app grid, the rail
 * and its buttons, the avatar and its account popover, the project list in the
 * rail, the narrow (phone) shape, the "Loading..." boot state, AND THE SIGN-IN
 * FORM -- which auth.js renders on every page that uses this shell, so every
 * page that uses it gets a styled sign-in rather than a browser-default one.
 *
 * WHAT IS NOT HERE is anything belonging to one screen. The landing page keeps
 * its composer, its greeting, its suggestion chips and its scripted answer in
 * its own <style> block, and the split was made rule by rule rather than by
 * cutting the file in half -- the two were interleaved, including inside the
 * reduced-motion media query.
 *
 *   A STYLESHEET SPLIT BY LINE NUMBER IS A STYLESHEET SPLIT BY WHERE SOMEBODY
 *   HAPPENED TO TYPE.
 *
 * app.css IS DELIBERATELY NOT IMPORTED, and index.html has said why since it
 * was written: importing it would bring the older look with it. app.css still
 * dresses the Registry, the plan, the chart and the print view, and converting
 * those two screens to this shell is its own step, with Chris looking at it --
 * not a change riding inside a module split.
 * ========================================================================= */

/* THE SAME TWO FAMILIES api/public/app.css NAMES, and neither is fetched --
   used if the reader has them, fallen back through if not. Declared here
   rather than by importing app.css, because importing it would bring the
   plan screen's whole cascade into a page with its own layout. Two
   screens agreeing on a value is not the same as one depending on the
   other. */
:root{
  --sans:"IBM Plex Sans",system-ui,-apple-system,Segoe UI,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
}


:root{
  color-scheme: light;
  --paper:#f4f6f5; --surface:#ffffff; --surface2:#eceff0; --hair:#e0e6e5;
  --ink:#141d1c; --ink2:#4c5b59; --ink3:#8b9a97;
  --brand:#b4530a; --sys:#0f6e6a; --sysSoft:#e2efee;
  --wait:#a86a00; --waitSoft:#f8ecd4;
  /* ---- ADDED 28 SEPTEMBER 2026, step 3c. Six tokens the plan, the chart and the
     print view need and this shell had never had a name for, plus five that were
     being USED with no definition anywhere -- `var(--line, #ccc)` and four like
     it, where the fallback was doing all the work and therefore never changed in
     dark mode. A VAR() WITH A FALLBACK CANNOT FAIL, WHICH IS WHY NOBODY EVER
     FINDS OUT THAT IT IS THE FALLBACK DOING THE WORK. */
  --edge:#c4cdc9;                      /* a hairline with more weight than --hair */
  --sysInk:#0a554a; --waitInk:#8a5600;  /* the ink versions of --sys and --wait */
  --bar:#0f6e6a; --barDone:#00332b; --weekend:#e9edeb;  /* the Gantt's own */
  --ring:rgba(15,110,106,.14);
  --shadow:0 1px 2px rgba(18,32,30,.05), 0 18px 40px -26px rgba(18,32,30,.30);
  /* ---- ADDED 6 OCTOBER 2026, 02 s6.1 (068). A FILL a person put on a grid
     cell, a row or a column: the value is written per cell by plan.js and
     print-ui.js as an inline --fill, and this is its resting state. The same
     in dark mode -- a chosen colour is the chosen colour. */
  --fill:transparent;
  /* ---- ADDED 12 OCTOBER 2026, 02 s6.1 (077). A TEXT COLOUR a person put on a
     cell, a row or a column, written per cell the same way; at rest it is the
     ink, so a cell with none reads as every other cell. */
  --ftext:currentColor;
}

@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    color-scheme: dark;
    --paper:#0d1413; --surface:#141d1c; --surface2:#1a2523; --hair:#243130;
    --ink:#e8efee; --ink2:#a3b4b1; --ink3:#718683;
    --brand:#e08636; --sys:#49bcb0; --sysSoft:#102826;
    --wait:#deab4b; --waitSoft:#2b2411;
    --edge:#3a443f;
    --sysInk:#6fd6bf; --waitInk:#f0c68a;
    --bar:#49bcb0; --barDone:#c9fbee; --weekend:#1a2523;
    --ring:rgba(73,188,176,.16);
    --shadow:0 1px 2px rgba(0,0,0,.5), 0 20px 48px -30px rgba(0,0,0,.9);
  }}

:root[data-theme="dark"]{
  color-scheme: dark;
  --paper:#0d1413; --surface:#141d1c; --surface2:#1a2523; --hair:#243130;
  --ink:#e8efee; --ink2:#a3b4b1; --ink3:#718683;
  --brand:#e08636; --sys:#49bcb0; --sysSoft:#102826;
  --wait:#deab4b; --waitSoft:#2b2411;
  --edge:#3a443f;
  --sysInk:#6fd6bf; --waitInk:#f0c68a;
  --bar:#49bcb0; --barDone:#c9fbee; --weekend:#1a2523;
  --ring:rgba(73,188,176,.16);
  --shadow:0 1px 2px rgba(0,0,0,.5), 0 20px 48px -30px rgba(0,0,0,.9);
}

*{box-sizing:border-box}

html,body{height:100%}

body{
  margin:0; background:var(--paper); color:var(--ink);
  font-family:var(--sans,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif); font-size:0.9375rem; line-height:1.5;
  -webkit-font-smoothing:antialiased;
}

/* THE RESET REACHES THE CHROME AND NOT THE PAGE, and it said `.app button`
   until 28 September 2026.

   `.app button` is one class and one element -- more specific than `.btn`, which
   is the class app.css styles every button on the plan and the Registry with. So
   the moment plan.html and registry.html gained `class="app"`, the shell
   stripped the background, border and padding off every button on both screens:
   "New project" rendered as a line of plain text, and Share, Copy and Delete on
   each project row disappeared into the row.

     A RESET WRITTEN FOR A COMPONENT'S OWN CHILDREN MATCHES EVERY DESCENDANT,
     AND WHATEVER THE PAGE PUTS INSIDE IT IS A DESCENDANT.

   So the four places the chrome actually has buttons are named -- INSIDE
   `:where()`, WHICH CONTRIBUTES NOTHING TO SPECIFICITY. The first attempt at
   this wrote them out plainly, `.app .rail button, .app .who button, ...`, and
   that is TWO classes and an element: it then beat `.app .avatar`, which is two
   classes, and the account avatar lost the gradient it is drawn with.

     NARROWING A SELECTOR BY ADDING ANCESTORS MAKES IT MORE SPECIFIC, NOT LESS.
     THE FIX FOR A RULE THAT REACHES TOO FAR IS NOT A LONGER SELECTOR.

   `:where()` is how you say WHERE without saying HOW MUCH: this rule matches
   exactly the chrome and still weighs one class and one element, which is what
   `.app button` weighed. The room is the page's, and nothing in this file
   reaches into it -- the same boundary `.room` already draws for layout, now
   drawn for style as well. */
.app :where(.rail,.who,.pop,.topask) button{
  font:inherit; cursor:pointer; background:none; border:0; color:inherit; padding:0;
}

.app :where(.rail,.who,.pop,.topask) button:focus-visible{
  outline:2px solid var(--sys); outline-offset:3px; border-radius:8px;
}


/* ============================================================ the shell */
.stage{height:100%; display:flex; align-items:center; justify-content:center}

.stage.phone{padding:1.5rem; background:var(--surface2)}

/* SHAPE B, chosen by Chris on 28 September 2026 from two shapes drawn against
   this very stylesheet in proto/shell/index.html.

   THE RAIL RUNS FULL HEIGHT AND KEEPS THE CORNER; the bar covers only the work
   area. In Shape A the bar spanned everything and the rail started below it,
   which read as a second-level control -- the rail stopped being the frame.

   Two columns, two rows. The rail spans both rows in column one. The bar and
   the room stack in column two. `.who` stays absolutely positioned over the
   rail's top, which is what "keeps the corner" means in CSS. */
/* HEIGHT AND OVERFLOW ARRIVED HERE FROM app.css ON 28 SEPTEMBER 2026, with the
   argument that produced them. THE PAGE IS EXACTLY THE WINDOW: a minimum is not
   a size, and a flex or grid container with a minimum and no maximum grows
   instead of shrinking, which walked the bottom of the plan -- the horizontal
   scroll controls and the Dependencies pane -- off the bottom of a short window
   whenever a standing message was showing. Chris, 19 September 2026, on the live
   Beta: those "must be visible at all times without vertical scrolling."

     A MINIMUM IS NOT A SIZE. IF THE THING AT THE BOTTOM MUST ALWAYS BE VISIBLE,
     SOMETHING HAS TO BE FORBIDDEN FROM GROWING.

   TWO UNITS, DELIBERATELY: `dvh` is the visible viewport on a phone, where `vh`
   includes the strip the address bar sits over. A browser that has never heard
   of `dvh` discards the second declaration and keeps the first.

   `overflow:hidden` CLIPS NOTHING ANYBODY CAN REACH: every screen inside carries
   its own scroller -- .room, the plan and chart panes, .plist, .view -- and
   dialogs are position:fixed. The rule for anything added here later is one line
   long: give it a scroller of its own. */
.app{
  position:relative; width:100%;
  height:100vh; height:100dvh;
  display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto 1fr;
  background:var(--paper); overflow:hidden;
}
/* The phone frame on the prototype stage sizes itself; it is not the window. */
.stage.phone .app{height:812px}
.app .rail{grid-column:1; grid-row:1 / -1}
.app .topask{grid-column:2; grid-row:1}
.app .room{grid-column:2; grid-row:2}

/* ------------------------------------------------------------- the Ask bar -- */
.app .topask{
  display:flex; align-items:center; gap:0.75rem; min-width:0;
  padding:0.5625rem 0.875rem; border-bottom:1px solid var(--hair);
  background:var(--surface);
}
.app .topask .brandmark{
  flex:0 0 auto; font-size:0.7812rem; font-weight:700; letter-spacing:.08em;
  color:var(--ink3);
}
.app .topask .askbox{
  flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:0.5rem;
  height:34px; padding:0 0.25rem 0 0.6875rem; border-radius:999px;
  border:1px solid var(--hair); background:var(--paper);
}
.app .topask .askbox:focus-within{
  border-color:var(--sys); box-shadow:0 0 0 3px var(--sysSoft);
}
.app .topask .askbox > svg{width:17px; height:17px; flex:0 0 auto; color:var(--ink3)}
.app .topask .askbox input{
  flex:1 1 auto; min-width:0; border:0; background:none; outline:none;
  font:inherit; font-size:0.8125rem; color:var(--ink);
}
.app .topask .askbox input::placeholder{color:var(--ink3)}
.app .topask .askgo{
  flex:0 0 auto; width:26px; height:26px; padding:0; border:0; border-radius:50%;
  background:var(--sys); color:#fff; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
}
.app .topask .askgo svg{width:15px; height:15px}
.app .topask .right{flex:0 0 auto; display:flex; align-items:center; gap:0.5rem; min-width:0}
.app .topask .pname{
  font-size:0.7812rem; color:var(--ink2); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; max-width:26ch;
}
.app .topask .pname:empty{display:none}
/* The bar's example (D76, section 6): quiet, beside the box, a button only
   so that a click puts the sentence in; it never looks like typed text. */
.app .topask .asktry{font:inherit; font-size:0.75rem; color:var(--ink2); background:transparent; border:0; padding:0 0.25rem;
  cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:28rem}
.app .topask .asktry:hover{color:var(--sysInk); text-decoration:underline}
.app .topask .asktry[hidden]{display:none}
/* A document with the sentence (02 s10.16, 12 October 2026): the clip, the chip. */
.app .topask .askclip{flex:0 0 auto; width:26px; height:26px; padding:0; border:0; border-radius:50%; background:transparent; color:var(--ink3); cursor:pointer;
  display:flex; align-items:center; justify-content:center}
.app .topask .askclip:hover{color:var(--sysInk); background:var(--sysSoft)}
.app .topask .askclip svg{width:15px; height:15px}
.app .topask .askclip[hidden]{display:none}
.app .topask .askdoc{flex:0 0 auto; display:inline-flex; align-items:center; gap:0.375rem; max-width:18rem; padding:0 0.25rem 0 0.5rem; height:24px;
  border-radius:999px; background:var(--sysSoft); color:var(--sysInk); font-size:0.75rem}
.app .topask .askdoc[hidden]{display:none}
.app .topask .askdocname{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:12rem}
.app .topask .askdocn{color:var(--ink2); white-space:nowrap}
.app .topask .askdocx{border:0; background:transparent; color:var(--ink2); font-size:0.9rem; line-height:1; width:18px; height:18px; padding:0; border-radius:50%; cursor:pointer}
.app .topask .askdocx:hover{background:var(--surface); color:var(--ink)}
.app .topask.dropping .askbox{border-color:var(--sys); box-shadow:0 0 0 3px var(--sysSoft)}
.app .askdrawer .askdoc{margin:0.25rem 0 0.5rem; font-size:0.8125rem}
.app .askdrawer .askdoc summary{cursor:pointer}
.app .askdrawer .askdoctext{white-space:pre-wrap; font:inherit; font-size:0.75rem; color:var(--ink2); max-height:10rem; overflow:auto; margin:0.25rem 0 0; padding:0.375rem 0.5rem; background:var(--paper); border-radius:6px}

.stage.phone .app{
  height:812px; max-height:100%; width:388px;
  border-radius:34px; border:1px solid var(--hair); box-shadow:var(--shadow);
}


.app .rail{
  width:60px; flex:0 0 60px;
  display:flex; flex-direction:column; align-items:center; gap:0.25rem;
  padding:0.875rem 0 1rem; padding-top:calc(14px + env(safe-area-inset-top,0px));
  border-right:1px solid var(--hair); background:var(--surface);
  transition:width .18s ease;
}

.app.open .rail{width:224px; align-items:stretch; padding-left:0.75rem; padding-right:0.75rem}

@media (prefers-reduced-motion:reduce){.app .rail{transition:none}}


.app .avatar{
  width:34px; height:34px; border-radius:50%; flex:0 0 auto;
  background:linear-gradient(145deg,var(--brand),#7d3a06);
  color:#fff; font-size:0.8125rem; font-weight:600; letter-spacing:.02em;
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 0 0 2px var(--surface), 0 0 0 3px var(--hair);
}

.app .who{position:absolute; top:13px; left:13px; z-index:18; display:flex; align-items:center; gap:0.625rem}

.app .rail{padding-top:calc(60px + env(safe-area-inset-top,0px))}

.app .who .nm{display:none; min-width:0}

.app.open .who .nm{display:block}

.app .who .nm b{display:block; font-size:0.8438rem; font-weight:600; line-height:1.25}

.app .who .nm span{display:block; font-size:0.7188rem; color:var(--ink3)}


/* A FLEX COLUMN THAT RUNS OUT OF ROOM DOES NOT OVERFLOW. IT SHRINKS WHAT IS IN
   IT, AND THAT IS THE ONE FAILURE A SCREENSHOT AT YOUR OWN WINDOW SIZE WILL
   NEVER SHOW YOU.

   MEASURED 28 September 2026 at 1280 wide, by injecting buttons into the live
   rail: eight items squash at 440px and eleven squash at 560px -- the icons and
   their hit areas get smaller, nothing clips, nothing scrolls, and no scrollbar
   appears to say so. `flex-shrink` defaults to 1 and `.railbtn` never said
   otherwise.

   Two declarations. The first stops the shrinking; the second gives the column
   somewhere to put what no longer fits, which is section 2's standing rule
   since 25 August -- compress it, scroll it, summarise it, or say why it is not
   shown, but never leave somebody looking for something that was there a moment
   ago.

   Measured after: 36px at every height from 560 down to 400, and it scrolls.

   AND THE FLYOUTS ARE NOT IN HERE, WHICH IS WHY THIS IS SAFE. `overflow-y` on a
   box clips absolutely-positioned descendants, so a submenu parked inside the
   rail would have been cut off at the rail's edge by the very fix that lets the
   rail scroll. They are children of `.app` instead -- see `.fly` below. */
.app .railbtn,.app .railsep,.app .avatar{flex:0 0 auto}

.app .rail{overflow-y:auto; overflow-x:hidden; scrollbar-width:thin}

.app.narrow .rail{overflow:visible}

.app .railbtn{
  display:flex; align-items:center; gap:0.75rem; width:36px; height:36px;
  border-radius:9px; color:var(--ink3); justify-content:center; position:relative;
}

.app.open .railbtn{width:100%; justify-content:flex-start; padding:0 0.625rem}

.app .railbtn:hover{background:var(--surface2); color:var(--ink)}

.app .railbtn.here{color:var(--sys); background:var(--sysSoft)}

/* About is the one rail item that is a link rather than a scope's button
   (02 s3.4 item 4; n77): it must not look like one. */
.app a.railbtn{text-decoration:none}

.app .railbtn svg{width:19px; height:19px; flex:0 0 auto}

.app .railbtn .lb{display:none; font-size:0.8438rem; font-weight:500; white-space:nowrap}

.app.open .railbtn .lb{display:block}

.app .railbtn .ct{
  position:absolute; top:5px; right:5px; min-width:15px; height:15px; padding:0 0.25rem;
  border-radius:8px; background:var(--wait); color:#fff; font-size:0.625rem; font-weight:700;
  display:flex; align-items:center; justify-content:center;
}

.app.open .railbtn .ct{position:static; margin-left:auto}

/* AND IT HAS TO SAY SO TWICE, WHICH IS THE DEFECT THIS FOUND -- 28 September
   2026, while building the scope rail.

   `button()` has written `<span class="ct" hidden>` since the shell was
   extracted, and `drawWaiting` unhides it only when the count is non-zero:
   "hidden when it is nought: a standing badge reading 0 is furniture."

   MEASURED: `ct.hidden === true` and `getComputedStyle(ct).display === 'flex'`.
   The rule above sets `display`, and any author rule that sets `display` beats
   the `hidden` attribute, which is only a user-agent default. So the badge has
   been on every screen with a rail since the day it shipped -- an empty amber
   pill, no number in it, saying nothing.

     AN ELEMENT'S `hidden` ATTRIBUTE IS A DEFAULT, NOT A DECISION. ANY AUTHOR
     RULE THAT SETS `display` OVERRULES IT SILENTLY, AND THE CODE THAT SET THE
     ATTRIBUTE GOES ON READING AS THOUGH IT WORKED.

   The same shape as 3c-i's `var()` with a fallback: the JavaScript is correct,
   the stylesheet quietly wins, and nothing looks broken enough to investigate.
   This is the third time this product has found it and the first in a
   stylesheet the same commit was already editing. */
.app .railbtn .ct[hidden]{display:none}

.app .grow{flex:1 1 auto}

.app .railsep{height:1px; background:var(--hair); width:22px; margin:0.5rem 0}

.app.open .railsep{width:100%}


/* ------------------------------------------------------------- the flyout --
   SHAPE A, chosen by Chris on 28 September 2026 from two drawn against this
   stylesheet: a panel beside the rail, over the work area.

     "The rail should only contain a few items: Account, Portfolio (when built),
      Projects, Enterprise, Recent. When one of the above is clicked then a
      submenu appears. This is already working for accounts and recent."

   HALF OF THAT LAST SENTENCE WAS TRUE AND IT IS THE HALF THAT MATTERS. Account
   is a real popover -- `.pop`, below, unchanged. `Recent` was never a submenu:
   it was an inline block that only existed while the rail was wide and vanished
   altogether on a phone. So the shape Chris named already existed once, and
   this makes it the mechanism for all of them.

   ONE ELEMENT, NOT ONE PER SCOPE. It is a child of `.app` rather than of the
   rail, for the clipping reason recorded above, and it is filled and moved on
   open -- so the rail stays 60px whether or not anything is open, the scopes
   never move, and the work area never resizes. A submenu may be any length;
   Enterprise has seven rows today and will have more. */
.app .fly{
  position:absolute; left:68px; top:0; z-index:22; width:252px; max-height:70vh;
  overflow:auto; background:var(--surface); border:1px solid var(--hair);
  border-radius:12px; box-shadow:var(--shadow); padding:0.375rem; display:none;
}

.app.open .fly{left:232px}

.app .fly.on{display:block}

.app .fly h4{
  font-size:0.6562rem; letter-spacing:.1em; text-transform:uppercase; color:var(--ink3);
  font-weight:600; margin:0; padding:0.4375rem 0.625rem 0.5rem;
}

.app .fly a,.app .fly button{
  display:flex; align-items:center; gap:0.625rem; width:100%; text-align:left;
  padding:0.4375rem 0.625rem; border-radius:8px; font-size:0.8438rem; color:var(--ink2);
  text-decoration:none; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

.app .fly a:hover,.app .fly button:not([disabled]):hover{background:var(--surface2); color:var(--ink)}

.app .fly a.here{color:var(--sys); background:var(--sysSoft)}

.app .fly button[disabled]{opacity:.55; cursor:default}

/* THE HINT IS WHAT THE ROW IS HONEST ABOUT -- "not built", "the Registry", a
   count. It sits right, in the reader's colour for quiet things, and it is the
   difference between a menu of promises and a menu of facts. */
.app .fly .hint{margin-left:auto; font-size:0.6875rem; color:var(--ink3); flex:0 0 auto}

.app .fly .sep{height:1px; background:var(--hair); margin:0.3125rem 0.5rem}

.app .fly .none{display:block; padding:0.4375rem 0.625rem; font-size:0.8125rem; color:var(--ink3)}

/* ON A PHONE THE RAIL IS A BAR AT THE BOTTOM, so a panel beside it has nowhere
   to be. It becomes a sheet above the bar, full width, which is the one place
   that does not cover the thing the person was reading. */
.app.narrow .fly{
  left:8px; right:8px; width:auto; top:auto;
  bottom:calc(68px + env(safe-area-inset-bottom,0px)); max-height:60vh;
}


.app .pop{
  position:absolute; top:46px; left:0; z-index:20; width:230px;
  background:var(--surface); border:1px solid var(--hair); border-radius:12px;
  box-shadow:var(--shadow); padding:0.375rem; display:none;
}

.app .pop.on{display:block}

.app .pop .hd{padding:0.5625rem 0.625rem 0.625rem; border-bottom:1px solid var(--hair); margin-bottom:0.3125rem}

.app .pop .hd b{display:block; font-size:0.8438rem}

.app .pop .hd span{display:block; font-size:0.7188rem; color:var(--ink3)}

/* The menu's items are links to pages and one button (Sign out), drawn alike
   -- 16 October 2026 (02 s3.1i). */
.app .pop button, .app .pop a[role="menuitem"]{display:block; width:100%; box-sizing:border-box; margin:0; text-align:left; padding:0.5rem 0.625rem; border-radius:8px; color:var(--ink2); text-decoration:none; font:inherit; font-size:0.8438rem; background:transparent; border:0; cursor:pointer}

.app .pop button:hover, .app .pop a[role="menuitem"]:hover{background:var(--surface2); color:var(--ink)}
.app .pop a[role="menuitem"][hidden]{display:none}


.app .room{ position:relative; display:flex; flex-direction:column; min-width:0; overflow:auto; }


/* ---------------------------------------------------------- phone shape */
/* ONE COLUMN, AND THE RAIL LEAVES THE GRID ENTIRELY -- it is position:fixed at
   the bottom of the window below. So the bar and the room are the only two
   things the grid still places, and they take the two rows. */
.app.narrow{grid-template-columns:1fr}
.app.narrow .topask{grid-column:1; grid-row:1}
.app.narrow .room{grid-column:1; grid-row:2}
.app.narrow .topask .brandmark,.app.narrow .topask .pname{display:none}

.app.narrow .rail{
  position:fixed; inset:auto 0 0 0; flex-direction:row; width:auto; height:60px;
  border-right:0; border-top:1px solid var(--hair);
  padding:0 0.5rem calc(0px + env(safe-area-inset-bottom,0px)); gap:0;
  justify-content:space-around; align-items:center; z-index:15;
}

.stage.phone .app.narrow .rail{position:absolute}

.app.narrow .rail{padding-top:0}

.app.narrow .grow,.app.narrow .railsep{display:none}

.app.narrow .railbtn{flex-direction:column; gap:3px; width:56px; height:44px}

.app.narrow .railbtn .lb{display:block; font-size:0.5938rem; font-weight:500}

/* NO TOP PADDING ANY MORE: the 64px was clearing the absolutely-positioned
   `.who`, and the bar is a real grid row that already occupies that space. The
   bottom padding stays -- the rail really is floating over the room down there.

   AND `.who` HAS TO MOVE, because on a phone the rail is at the bottom and the
   corner it used to sit in is now the bar's left end. It goes to the right of
   the bar, which is where Shape A put the avatar and is the one place in this
   layout nothing else claims. */
.app.narrow .room{padding-bottom:5.25rem}
.app.narrow .who{top:9px; left:auto; right:14px}
.app.narrow .who .nm{display:none}

/* `#recentList` IS NOW A FLYOUT'S BODY RATHER THAN A BLOCK IN THE WIDE RAIL,
   and it keeps its id because browser-landing.js grips it. The rows take
   `.fly a` above; the empty case keeps its own quiet line. */
.app #recentList a{display:flex}


.app .boot{
  grid-column:1/-1; align-self:center; justify-self:center;
  color:var(--ink3); font-size:0.8125rem; letter-spacing:.02em;
}

.app .signin{
  grid-column:1/-1; min-height:0; overflow:auto;
  display:flex; align-items:center; justify-content:center; padding:1.5rem;
}

.app .signin-box{width:100%; max-width:320px; display:flex; flex-direction:column; gap:0.375rem}

.app .signin-box h1{margin:0 0 1.125rem; font-size:1.25rem; letter-spacing:.08em; color:var(--ink)}

.app .signin-box label{font-size:0.75rem; color:var(--ink2); margin-top:0.5rem}

.app .signin-box input{
  font:inherit; padding:0.5rem 0.625rem; border:1px solid var(--hair); border-radius:6px;
  background:var(--surface); color:var(--ink);
}

.app .signin-box input:focus{outline:2px solid var(--sys); outline-offset:1px}

.app .signin-box button{
  margin-top:1.125rem; font:inherit; font-size:0.8125rem; font-weight:600; padding:0.5rem 0.75rem;
  border-radius:6px; border:1px solid var(--brand); background:var(--brand);
  color:#fff; cursor:pointer;
}

.app .signin-box button[disabled]{opacity:.6; cursor:default}

.app .signin-msg{min-height:1.2em; margin:0.625rem 0 0; font-size:0.8125rem; color:#b00020}

.app .signin-note{margin:0.25rem 0 0; font-size:0.75rem; color:var(--ink2)}

.app .signin-note code{font-family:var(--mono); font-size:0.6875rem}

/* ============================================== the "?" in a dialog header ===
   02 s2 "Dialogs": the title and the choice stay visible; why, and what each
   option costs, sits behind the "?" -- closed until asked, per dialog. The
   button is a child of the heading (which on the plan screen is also the
   dialog's drag handle; the handle already refuses a drag that starts on
   anything but the heading itself). help-ui.js draws it on five screens, so
   the one stylesheet they all share is where it is styled. */
.modal h3 .qhelp{display:inline-flex; align-items:center; justify-content:center; width:18px; height:18px;
   margin-left:0.5rem; padding:0; border:1px solid var(--edge); border-radius:50%; background:transparent;
   color:var(--ink2); font:inherit; font-size:0.6875rem; font-weight:600; line-height:1; vertical-align:middle;
   cursor:help}
.modal h3 .qhelp::before{content:'?'}
.modal h3 .qhelp:hover, .modal h3 .qhelp[aria-expanded="true"]{background:var(--sys); border-color:var(--sys); color:#fff}
.modal .qhelptext{margin:-.2rem 0 .8rem; padding:0.5rem 0.625rem; border-left:3px solid var(--sys);
   background:var(--surface2); color:var(--ink2); font-size:0.7812rem; line-height:1.45}
.modal .qhelptext[hidden]{display:none}

/* The mark is a link home since 4 October 2026 (D63): a link that looks
   exactly like the mark it replaced, and says so on hover. */
.app .topask a.brandmark{text-decoration:none; color:inherit; cursor:pointer}
.app .topask a.brandmark:hover{text-decoration:underline}

/* ============================ THE ASK PANE ON EVERY PAGE -- 4 OCTOBER 2026 ===
   ask-ui.js; 02 s10.11. In the room's grid cell, over the top of the room,
   so a page redrawing its room cannot wipe it. */
.app .askdrawer{grid-column:2; grid-row:2; align-self:start; z-index:12; margin:0.5rem 1rem 0 1rem;
  background:var(--surface); border:1px solid var(--hair); border-radius:8px; box-shadow:0 8px 24px rgba(0,0,0,.12);
  max-height:70%; display:flex; flex-direction:column; min-width:0}
.app.narrow .askdrawer{grid-column:1; grid-row:2}
.askdrawer[hidden]{display:none}
.askdrawer-hd{display:flex; align-items:center; gap:0.5rem; padding:0.5rem 0.75rem; border-bottom:1px solid var(--hair)}
.askdrawer-t{font-size:0.6875rem; letter-spacing:.06em; text-transform:uppercase; color:var(--ink2); font-weight:600}
.askdrawer-body{padding:0.5rem 0.75rem 0.75rem; overflow:auto; min-height:0}
.askdrawer-q{margin:0 0 0.5rem; font-size:0.9375rem; color:var(--ink)}
.askdrawer .askread{margin:0 0 0.5rem; font-size:0.8125rem; color:var(--ink2)}
.askdrawer .askread.wait{font-style:italic}
.askdrawer .askother{margin-left:0.5rem; color:var(--sysInk)}
.askdrawer .askchoices{margin:0 0 0.5rem; display:flex; flex-wrap:wrap; gap:0.375rem}
.askdrawer .asksent{margin:0.25rem 0 0.5rem; font-size:0.75rem; max-width:70rem; color:var(--ink2)}
.askdrawer .askanswer{font-size:0.9375rem; line-height:1.5; white-space:pre-wrap; max-width:70rem; padding:0.5rem 0.75rem;
  background:var(--paper); border:1px solid var(--hair); border-radius:6px}
.askdrawer .askanswer[data-live]::after{content:'\258F'; color:var(--sys); animation:askblink 1s steps(2) infinite}
@keyframes askblink{to{visibility:hidden}}
.askdrawer .askrec{font-family:var(--mono); font-size:0.875em; color:var(--sysInk); text-decoration:none; border-bottom:1px dotted var(--sys); padding:0 1px}
.askdrawer .askrec:hover{background:var(--sysSoft)}
.askdrawer .err{color:var(--waitInk); margin:0.25rem 0 0.5rem; font-size:0.875rem}
.askdrawer .btn.mini{font-size:0.6875rem; padding:2px 0.4375rem}
/* The pane's own buttons, so a page that loads only shell.css (the front
   door) draws them the way app.css does everywhere else. */
.askdrawer .btn{font:inherit; font-size:0.8125rem; padding:0.3125rem 0.6875rem; border-radius:4px; border:1px solid var(--sys);
  background:var(--sys); color:#fff; cursor:pointer}
.askdrawer .btn.ghost{background:transparent; color:var(--sysInk); border-color:var(--hair)}
/* A SEQUENCE'S STEPS (02 s10.11 section 3): the list before anything runs,
   a field the person may correct, Go, and each step marked as it lands. */
.askdrawer .askfields{display:flex; flex-wrap:wrap; gap:0.5rem 1rem; margin:0 0 0.5rem}
.askdrawer .askfield{display:flex; align-items:center; gap:0.5rem; font-size:0.8125rem; color:var(--ink2)}
.askdrawer .askfield input{font:inherit; font-size:0.875rem; color:var(--ink); background:var(--surface); border:1px solid var(--edge);
  border-radius:4px; padding:0.25rem 0.5rem; min-width:18rem}
.askdrawer .askfield input:focus{outline:none; border-color:var(--sys); box-shadow:0 0 0 3px var(--ring)}
/* The few words a route accepts, as a select (n3) -- the same box as a field. */
.askdrawer .askfield select{font:inherit; font-size:0.875rem; color:var(--ink); background:var(--surface); border:1px solid var(--edge);
  border-radius:4px; padding:0.25rem 0.5rem}
.askdrawer .askfield select:focus{outline:none; border-color:var(--sys); box-shadow:0 0 0 3px var(--ring)}
/* A STEP THAT LACKS SOMETHING ASKS FOR IT (02 s10.12, D76, 7 October 2026):
   a blank the walk is waiting for is marked down its left edge in the
   waiting colour -- the same amber a field not yet saved wears on the plan
   -- and the question stands as its label. The mark goes the moment it is
   filled; the Go button is disabled, not hidden, so what it waits for is
   in view. */
.askdrawer .askfield.needed input, .askdrawer .askfield.needed select{border-left:3px solid var(--wait)}
.askdrawer .askneeds{margin:-0.25rem 0 0.5rem; font-size:0.8125rem; color:var(--waitInk)}
.askdrawer .askgo .btn:disabled{opacity:0.55; cursor:default}
/* Each "Did you mean" choice with the sentence that would have gone straight
   there, in small type beneath (section 6). */
.askdrawer .askchoice{display:inline-flex; flex-direction:column; align-items:flex-start; gap:2px}
.askdrawer .askeg{font-size:0.6875rem; color:var(--ink2)}
/* "None of these -- tell Santan what you meant" (D68 decision 3): under the
   nearest few, one quiet button; then a line to type and the sentence that
   says where it goes. */
.askdrawer .askmeant{margin:0 0 0.5rem}
.askdrawer div.askmeant{display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem}
.askdrawer div.askmeant .quiet{flex-basis:100%; margin:0}
.askdrawer .askmeantdone{color:var(--sysInk)}
.askdrawer .asksteps{margin:0 0 0.5rem; padding-left:1.5rem; font-size:0.875rem; line-height:1.6; max-width:70rem}
.askdrawer .askstep.doing{font-style:italic}
.askdrawer .askstep.done{color:var(--ink2)}
.askdrawer .askstep.done::marker{color:var(--sysInk)}
.askdrawer .askstep.fail{color:var(--waitInk)}
.askdrawer .askstep.fail::marker{color:var(--waitInk)}
.askdrawer .askgo{margin:0 0 0.5rem}

/* THE FOLLOW-UP TURN -- 02 s10.15, 11 October 2026. The box that is waiting
   for an answer says so in the system colour; the reply line in the pane
   carries its two ways back. */
.app .topask .askbox input.answering::placeholder, .app .box textarea.answering::placeholder{color:var(--sysInk); font-style:italic}
.askdrawer .askreplied{margin:0 0 0.5rem; font-size:0.8125rem; color:var(--ink)}
.askdrawer .askreplied .btn{margin-left:0.25rem}

/* FORGOT PASSWORD AND CHOOSE A NEW ONE -- 02 s3.1e s11, 9 October 2026.
   A quiet link-shaped button under the form. The rule above makes every
   button in the box the primary one; this one is a way out, not an action,
   so it is drawn as text and sits on the left. Same specificity plus a class,
   so it wins wherever the primary rule would. */
.app .signin-box .signin-link{
  align-self:flex-start; margin-top:0.75rem; padding:0; border:0; background:none;
  color:var(--brand); font:inherit; font-size:0.8125rem; font-weight:400; cursor:pointer;
  text-decoration:underline; text-underline-offset:2px;
}
.app .signin-box .signin-link:focus-visible{outline:2px solid var(--sys); outline-offset:2px}
/* A success line, not the red one: "an email is on its way", "your password
   is changed". Empty, it takes no room. */
.app .signin-box .signin-ok{color:var(--ink); font-size:0.8125rem; margin:0.5rem 0 0}
.app .signin-box .signin-ok:empty{display:none}

/* =========================== THE RAIL ON THE RIGHT -- 22 OCTOBER 2026 ===
   02 s3.4 item 8 (D122; n78). Chris: "Ok, left and right for now." The
   person's choice on the Account page (settings.js rail.side), applied by
   shell.js as `.railright` on the shell. The two columns swap; the rail's
   hairline moves to its other edge; the avatar keeps the rail's corner, now
   the top right; and every panel the rail opens -- the scopes' flyouts and
   the avatar's menu -- opens toward the work area, which is now to the left.
   A PHONE-WIDTH SCREEN IS UNTOUCHED (`:not(.narrow)`): there the rail is a
   row along the bottom, and a side has no meaning. */
.app.railright:not(.narrow){grid-template-columns:1fr auto}
.app.railright:not(.narrow) .rail{grid-column:2; border-right:0; border-left:1px solid var(--hair)}
.app.railright:not(.narrow) .topask,
.app.railright:not(.narrow) .room,
.app.railright:not(.narrow) .askdrawer{grid-column:1}
.app.railright:not(.narrow) .who{left:auto; right:13px}
.app.railright.open:not(.narrow) .who{right:auto; left:calc(100% - 211px)}
.app.railright:not(.narrow) .pop{left:auto; right:0}
.app.railright:not(.narrow) .fly{left:auto; right:68px}
.app.railright.open:not(.narrow) .fly{left:auto; right:232px}

/* The bar's microphone (02 s10.17 A3, D127): the front door's sentence on
   how to dictate, under the bar, until the next click or Escape. */
.app .topask{position:relative}
.app .topask .askdictate{position:absolute; top:calc(100% - 2px); left:3.5rem; right:3.5rem; z-index:40; margin:0;
  padding:0.5rem 0.75rem; font-size:0.75rem; line-height:1.5; color:var(--ink2); background:var(--paper);
  border:1px solid var(--hair); border-radius:8px; box-shadow:0 4px 14px rgba(0,0,0,0.08); max-width:38rem}
.app .topask .askdictate[hidden]{display:none}
