/* ---------- TITAN AI'S LEFT RAIL, AND ITS PROJECTS CANVAS ----------
   THE LEFT SUB-LANE OWNS THIS FILE (LANE4-PLAN.md). It is the geometry the
   rail's markup (public/rooms/titan-rail.js, titan-fly.js, titan-projects.js)
   stands in: house-shell.js draws titanRail() whole in place of the ordinary
   .house-left column for this room, so .titan-rail carries the column's own
   width, flex and edge, the same numbers .house-left carries for every other
   room (house-shell.css), rather than a content box sitting inside one.

   EVERY VALUE HERE IS A TOKEN, read off public/styles/tokens.css, the same
   law titan.css's own header states: no raw colour, no hand-picked size, and
   no room markup in this lane carries a style attribute. .titan-side,
   .titan-row and .titan-win are titan.css's own rules already and are
   unchanged by this file; what is added here is the head, the toolbar, the
   flyout, the kickers, the cap and the canvas.

   NO MONO, NO PILLS, NO FILLED BLUE IN THE COLUMN. A kicker is uppercase and
   letter spaced in the HOUSE BODY FACE (--font-ui, which is what everything
   below inherits), never --font-mono. The accent appears on exactly two
   things, the open project's row and the open chat's row, and both wear it as
   INK rather than as a fill: a filled row would be a pill, and this column is
   a list of rows. tools/titan/eyes.mjs measures both rules off computed
   style, so a rule added here that quietly grows one goes red there. */

/* POSITION:RELATIVE IS LOAD BEARING and not decoration. The flyout below is
   absolute and its containing block is the nearest POSITIONED ancestor: the
   panel lives inside .titan-burger, which is a sibling of .titan-rail-mid
   rather than a child of it, so without this line the browser walked past
   the whole column and laid the panel out against the viewport. That is what
   drew a full-page dark sheet over the banner and the stage on the first
   eyes run (tools/titan/titan-rail.png, 2026-09-03). The flyout covers the
   rail column and nothing else. */
.titan-rail{
  position:relative;
  width:var(--house-lw); flex:none; min-width:0; min-height:0;
  display:flex; flex-direction:column;
  background:var(--panel); border-right:var(--bd) solid var(--edge);
}

/* ---------- THE HEAD ----------
   The house's own .house-tabs track, unchanged: the segmented control in this
   room is the same control at the same height as the one in every other room.
   This rule only pins the two segments to equal widths, because the house's
   track is built for one wide segment plus a door icon and this one has no
   door and two equal names. */
.titan-rail-head .house-tab{flex:1;}

/* ---------- THE TOOLBAR STRIP ----------
   THE STRIP IS THE FLYOUT'S ANCHOR, which is why it carries position:relative
   and a height of its own rather than letting its buttons decide one. The
   panel hangs off the BOTTOM of this box (top:100% below), so the one number
   the flyout needs is the strip's own height and nothing has to add the head's
   up by hand. --titan-rt-h is that height, declared once and read twice. */
.titan-rt{
  --titan-rt-h:30px;
  position:relative; z-index:6;
  display:flex; align-items:center; gap:2px; flex:none; height:var(--titan-rt-h);
  margin:0 var(--panel-pad) var(--s2);
}
.titan-rt-gap{flex:1;}
.titan-rt-btn{
  width:30px; height:30px; flex:none; display:grid; place-items:center;
  border:0; border-radius:var(--r-sm); background:transparent; color:var(--muted);
  cursor:pointer;
}
.titan-rt-btn:hover:not(:disabled){background:var(--sel); color:var(--text);}
/* THE ON-STATE IS INK, NOT A FILL. The magnifier lit while the search panel
   is up is the one toolbar button that carries a state, and it carries it the
   way every row in this column does. */
.titan-rt-btn.on{color:var(--accent);}
/* Disabled at the ends of the history, and it looks disabled: an arrow that
   answered nothing while looking live is an arrow somebody presses twice. */
.titan-rt-btn:disabled{opacity:.32; cursor:default;}

/* ---------- THE HAMBURGER'S OWN BOX ----------
   It holds the button and nothing else now. The drill-down used to live inside
   it, which is what made the hover work with no listener; it lives in the
   middle instead (rooms/titan-fly.js says why, and the .titan-fly rule below
   says what went wrong when it did not). The hover is still CSS and still has
   no listener: the rule further down opens the panel when EITHER this box or
   the panel itself is hovered, so crossing the gap between them can never
   close the thing the cursor is moving into. */
.titan-burger{position:static; display:inline-flex;}

/* ---------- THE MIDDLE, AND WHAT LIES OVER IT ---------- */
.titan-rail-mid{
  position:relative; flex:1; min-height:0; display:flex; flex-direction:column;
  overflow:hidden;
}
.titan-rail-mid > .titan-side,
.titan-rail-mid > .house-list{flex:1; min-height:0; overflow:auto;}

/* THE FLYOUT COVERS THE MIDDLE and does not push it down: a panel that moved
   the rows would move the very row somebody is reaching for.

   IT IS A CHILD OF THE MIDDLE, which is the whole of its geometry: the middle
   is already exactly the region under the toolbar strip and over the account
   foot, and it already carries position:relative, so the panel's four edges
   are the middle's own and this sheet states no height, no offset and no
   number of its own.

   IT USED TO LIVE INSIDE .titan-burger, WHICH WAS POSITIONED BY NOBODY, and
   the browser did what position:absolute with no positioned ancestor means: it
   laid the panel out against the VIEWPORT and drew a full-page dark sheet over
   the banner, the stage and the right column (tools/titan/titan-rail.png from
   the first eyes run, 2026-09-03). The check that would have caught it
   measures this panel's box against the rail's and against the strip's, in
   tools/titan/walk-rail.mjs. */
.titan-fly{
  position:absolute; inset:0; z-index:5;
  background:var(--panel); display:flex; flex-direction:column;
}
.titan-fly-body{flex:1; min-height:0; overflow:auto; padding:var(--s4) var(--s3);}
.titan-fly-menu{
  padding-bottom:var(--s3); margin-bottom:var(--s1);
  border-bottom:var(--bd) solid var(--edge);
}
.titan-fly-label{margin-top:var(--s6);}

/* THE MENU TWIN IS ALWAYS IN THE MARKUP and hidden until the hamburger is
   hovered, until the panel ITSELF is hovered, or until something inside
   either takes KEYBOARD focus. Three triggers rather than one, and the middle
   one is what replaced nesting the panel inside the button's box: the cursor
   leaves the hamburger to reach the rows and the panel keeps itself open the
   moment it is under the pointer, so the gap between them can never shut the
   thing somebody is moving into.

   THE KEYBOARD TRIGGER IS :focus-visible AND NOT :focus-within, and that is
   the whole of Mark's second-click finding (2026-09-04). A mouse click
   FOCUSES the hamburger, so :focus-within matched from the first press
   onward: the click that unfolded New chat and Projects dropped the flyout
   straight over the rows it had just revealed, and the second click folded
   them under a panel that stayed until focus left the column. The hamburger
   read as a dead button. Home Bid Pros opens its own flyout on hover and on
   :focus-visible only, never on a mouse click, and this is that rule written
   in CSS: :focus-visible is the browser's own reading of "arrived here by
   keyboard", so tabbing to the hamburger still opens the panel, tabbing INTO
   the panel keeps it open, and a mouse click opens nothing at all. Chromium
   and Edge, which is what this house runs, support :has() and :focus-visible.

   AND :has() IS NEVER NESTED INSIDE :has(), which cost this lane a red walk
   and is worth the line. The first draft wrote
   .titan-rail:has(.titan-burger:has(:focus-visible)), which is INVALID CSS:
   :has() may not appear inside a :has(). One invalid selector in a comma list
   drops the WHOLE RULE, so the hover trigger sitting beside it stopped
   working too and the drill-down could not be opened at all. Nothing errored
   and nothing looked wrong in the source; the eyes walk found it by reading
   the panel's computed visibility with a real cursor on the button, and the
   diagnostic said :has(.titan-burger:hover) matched while the panel was still
   hidden, which is only possible if the rule was never parsed. The button is
   named directly instead. .titan-fly-menu-panel:has(:focus-visible) is fine:
   it is one :has() with a plain selector inside it.

   THE CLOSE IS DELAYED, the way HBP's timer delays it, because the cursor has
   a few pixels of gap to cross and a zero delay would snap it shut mid-move.
   Opening is immediate; only the leaving is held. */
.titan-fly-menu-panel{
  visibility:hidden; opacity:0;
  transition:visibility 0s linear .22s, opacity .12s ease .22s;
}
.titan-rail:has(.titan-burger:hover) .titan-fly-menu-panel,
.titan-rail:has(.titan-burger .titan-rt-btn:focus-visible) .titan-fly-menu-panel,
.titan-fly-menu-panel:hover,
.titan-fly-menu-panel:has(:focus-visible){
  visibility:visible; opacity:1;
  transition:visibility 0s linear 0s, opacity .12s ease 0s;
}
/* ONE PANEL OVER THE COLUMN, NEVER TWO. While the search panel is up the
   menu twin is held shut whatever the cursor is doing, and every trigger
   above is overruled by name rather than by order. */
.titan-fly-held,
.titan-rail:has(.titan-burger:hover) .titan-fly-held,
.titan-rail:has(.titan-burger .titan-rt-btn:focus-visible) .titan-fly-held,
.titan-fly-held:hover,
.titan-fly-held:has(:focus-visible){visibility:hidden; opacity:0;}
.titan-fly-on{visibility:visible; opacity:1;}

/* ---------- THE SEARCH BOX ---------- */
.titan-fly-bar{
  display:flex; align-items:center; gap:var(--s3);
  padding:var(--s2) var(--s4); margin-bottom:var(--s3);
  border:var(--bd) solid var(--edge); border-radius:var(--r-sm);
  background:var(--inset);
}
.titan-fly-bar:focus-within{border-color:var(--accent-line);}
.titan-fly-ic{display:inline-flex; flex:none; color:var(--muted);}
.titan-fly-input{
  flex:1; min-width:0; border:0; background:transparent; color:var(--text);
  font-family:inherit; font-size:var(--t-small); padding:2px 0;
}
.titan-fly-input:focus{outline:none;}
.titan-fly-results{display:flex; flex-direction:column;}

/* ---------- THE PINNED ROWS ---------- */
.titan-menu{
  display:flex; flex-direction:column;
  padding-bottom:var(--s3); margin-bottom:var(--s1);
  border-bottom:var(--bd) solid var(--edge);
}
.titan-menu-row{
  display:flex; align-items:center; gap:var(--s4); width:100%; text-align:left;
  padding:var(--s3) var(--s4); border:0; border-radius:var(--r-sm);
  background:transparent; cursor:pointer;
  font-family:inherit; font-size:var(--t-small); font-weight:var(--w-med);
  color:var(--ink2);
}
.titan-menu-row:hover{background:var(--sel); color:var(--text);}
.titan-menu-ic{display:inline-flex; flex:none; color:var(--muted);}
.titan-menu-row.on{color:var(--accent);}
.titan-menu-row.on .titan-menu-ic{color:var(--accent);}
.titan-menu-label{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}

/* ---------- THE KICKERS ----------
   Uppercase, letter spaced, muted, in the house body face. --ls-label is the
   house's own kicker spacing and --t-label its own size, so a kicker here is
   a kicker anywhere. The row at the far end ("+ New", "Cancel") is a bare
   press with no border and no fill, because a button in a heading is a
   heading with a button in it and not a control in its own right. */
.titan-kicker{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  margin:var(--s7) var(--s2) var(--s2);
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--ls-label); text-transform:uppercase; color:var(--muted);
}
.titan-kicker:first-child{margin-top:var(--s2);}
.titan-kicker-act{
  display:inline-flex; align-items:center; gap:var(--s1);
  padding:0; border:0; background:none; cursor:pointer;
  font-family:inherit; font-size:var(--t-tiny); font-weight:var(--w-semi);
  letter-spacing:0; text-transform:none; color:var(--muted); white-space:nowrap;
}
.titan-kicker-act:hover{color:var(--accent);}
.titan-kicker-act svg{width:12px; height:12px;}

/* ---------- THE CASCADE ----------
   The indent plus the guide line is what says these chats belong to the row
   above, which is the whole reason they moved out of a group of their own. */
.titan-cascade{
  margin:var(--s1) 0 var(--s2) var(--s6);
  padding-left:var(--s4);
  border-left:var(--bd) solid var(--edge);
}
.titan-cascade .titan-row{font-size:var(--t-tiny);}
.titan-cascade .titan-side-quiet{padding:var(--s1) var(--s3);}

/* ---------- THE FOUR-ROW CAP AND ITS FADE ----------
   The HEIGHT is measured live in the arm (actions/titan-rail.js), top of row
   one to bottom of row four, because row height moves with the face and one
   hard-coded max-height would show three and a half rows on one machine and
   five on another. This rule only carries the LOOK of the cap: the fifth row
   bleeding off under a fade that says there is more below.

   THE FADE IS A MASK, NOT AN OVERLAY, so it works over any wall the shell
   happens to be hanging behind the panel: an overlay painted in --panel would
   be a grey bar over a picture. It goes once the list is scrolled to the end,
   because a fade that stayed would be claiming there is more when there is
   not, and .titan-cap-end is what the arm's own scroll listener adds. */
.titan-cap{overflow:auto; scrollbar-width:none;}
.titan-cap::-webkit-scrollbar{display:none;}
.titan-cap-more{
  -webkit-mask-image:linear-gradient(to bottom, currentColor calc(100% - 28px), transparent 100%);
  mask-image:linear-gradient(to bottom, currentColor calc(100% - 28px), transparent 100%);
}
.titan-cap-end{-webkit-mask-image:none; mask-image:none;}

/* ---------- SELECTING CHATS ----------
   The bar sits outside the scrolling list so the count and the press stay put
   while the rows move under them. "Delete forever" is the one place in this
   column with a fill, and it earns it: it is the destructive press and it is
   only ever on screen while somebody is deliberately choosing what to lose. */
.titan-selbar{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  padding:0 var(--s2) var(--s3);
}
.titan-selcount{font-size:var(--t-tiny); color:var(--muted);}
.titan-seldel{
  border:0; border-radius:var(--r-sm); padding:var(--s2) var(--s5);
  font-family:inherit; font-size:var(--t-tiny); font-weight:var(--w-semi);
  background:var(--danger); color:var(--onAccent); cursor:pointer;
}
.titan-seldel:disabled{opacity:.4; cursor:default;}
/* A picked row is marked by its own edge rather than by a fill, so the list
   still reads as a list while a range is chosen. */
.titan-row-sel{box-shadow:inset 2px 0 0 var(--accent);}

/* ---------- THE PROJECTS CANVAS ---------- */
.titan-projects{
  padding:var(--s8) var(--s8) var(--s8);
  max-width:900px; margin:0 auto; min-height:0; overflow:auto;
}
.titan-projects-head{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s5);
  margin-bottom:var(--s7);
}
.titan-projects-title{
  margin:0; font-size:var(--t-display); font-weight:var(--w-semi);
  letter-spacing:var(--ls-head); color:var(--text);
}
.titan-projects-new{
  display:inline-flex; align-items:center; gap:var(--s2);
  padding:var(--s3) var(--s6); border:var(--bd) solid var(--edge);
  border-radius:var(--r-sm); background:var(--panel); color:var(--ink2);
  font-family:inherit; font-size:var(--t-small); font-weight:var(--w-semi);
  cursor:pointer;
}
.titan-projects-new:hover{border-color:var(--accent-line); color:var(--accent);}
.titan-projects-sec{margin:0 0 var(--s3);}
.titan-projects-lead{
  margin:0 0 var(--s6); font-size:var(--t-small); line-height:var(--lh-read);
  color:var(--ink3); max-width:62ch;
}

/* GENERAL LEADS AS ITS OWN BLOCK, not a tile: it is the neutral state and a
   tile in the grid taught that you pick it the way you pick a project. */
.titan-home-face{
  display:flex; flex-direction:column; gap:var(--s2); width:100%; text-align:left;
  padding:var(--s7) var(--s7); margin-bottom:var(--s8);
  border:var(--bd) solid var(--edge); border-radius:var(--r-md);
  background:var(--inset); cursor:pointer; font-family:inherit; color:var(--text);
}
.titan-home-face:hover{border-color:var(--accent-line);}
.titan-home-name{font-size:var(--t-lead); font-weight:var(--w-semi);}
.titan-home-lead{font-size:var(--t-small); line-height:var(--lh-read); color:var(--ink3);}

.titan-card-grid{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(260px, 1fr));
  gap:var(--s6);
}
.titan-card{
  position:relative; border:var(--bd) solid var(--edge); border-radius:var(--r-md);
  background:var(--panel);
}
.titan-card:hover{border-color:var(--accent-line);}
.titan-card-pinned{border-color:var(--accent-line);}
.titan-card-face{
  display:flex; flex-direction:column; gap:var(--s2); width:100%; text-align:left;
  padding:var(--s6) 76px var(--s5) var(--s6);
  border:0; border-radius:var(--r-md); background:transparent; cursor:pointer;
  font-family:inherit; color:var(--text);
}
.titan-card-name{
  font-size:var(--t-lead); font-weight:var(--w-semi); letter-spacing:var(--ls-head);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.titan-card-kind{font-size:var(--t-tiny); color:var(--muted);}
.titan-card-foot{font-size:var(--t-label); color:var(--muted);}
/* The two acts sit ON the card rather than in its face, so the face can be
   one press covering the whole tile. */
.titan-card-act{
  position:absolute; top:var(--s4); width:28px; height:28px;
  display:grid; place-items:center; border:0; border-radius:var(--r-sm);
  background:transparent; color:var(--muted); cursor:pointer; opacity:.55;
}
.titan-card:hover .titan-card-act{opacity:.9;}
.titan-card-act:hover,.titan-card-act:focus-visible{background:var(--sel); opacity:1;}
.titan-card-pin{right:var(--s4);}
.titan-card-pin.on{color:var(--accent); opacity:1;}
.titan-card-del{right:42px;}
.titan-card-del:hover,.titan-card-del:focus-visible{color:var(--danger);}
