/* widgets/portal — THE PORTAL ENGINE (Craig ruling 7/31 10:02a: "clicks replace the entire
   view — same screen, no scrolling"). A room is a FULL VIEW SWAP, not a modal: the floor
   fades out, the room fades in, ~250ms, native CSS only (no animation libs — flex law).

   LAYERING: 2000 sits above the app's own chrome (sidebar 100, mobile overlay 1000) and
   well below every TRANSIENT overlay (spotlight 10006, toasts/qc 10050+). That ordering is
   deliberate and load-bearing — a room is the base surface an overlay opens OVER, so Esc
   closes the overlay first and the room second. (The 8999 slot was the lane-screen stream's;
   it retired 8/7 and the gap is left rather than reused, so nothing lands mid-stack.) */

#fg-portal{
  position:fixed; inset:0; z-index:2000;
  display:none;
  background:var(--bg, #f7f8f7);
  opacity:0;
  transition:opacity 250ms ease;
}
#fg-portal.fgp-shown{ display:block; }
#fg-portal.fgp-open{ opacity:1; }

/* The floor (the app itself) — fades only. NO transform: this subtree is ~2MB of DOM and
   transforming it makes a containing block for all of it, which is where jank comes from. */
.fgp-floor{ transition:opacity 250ms ease; }
body.fgp-portal-open .fgp-floor{ opacity:0; pointer-events:none; }
/* The floor stays laid out (opacity-only hide, see comment above) so it still occupies its
   full natural height in the document flow. Locking overflow on body ALONE does not stop the
   page from scrolling: with no explicit height on html/body, html is the element that actually
   grows to the floor's full content height and becomes the scrolling box, so the lock has to
   land on both (Craig's "no-scroll law" — the glass is a fixed-frame surface, room or no room). */
html.fgp-portal-open, body.fgp-portal-open{ overflow:hidden; height:100%; }

/* A room owns the whole viewport and never scrolls itself — Craig's "no scrolling" is about
   the SWAP, so room CONTENT that needs to scroll declares its own scroll container inside. */
.fgp-room{
  position:absolute; inset:0;
  display:none;
  flex-direction:column;
  overflow:hidden;
  outline:none;
  transform:translateY(6px);
  transition:transform 250ms ease;
}
.fgp-room.fgp-room-active{ display:flex; }
#fg-portal.fgp-open .fgp-room.fgp-room-active{ transform:none; }

/* ── The home control — the engine's exit, and the ONLY thing it draws on top of a room.
   Rooms are position:absolute so they paint over their earlier siblings; this needs the
   z-index to stay reachable. It reserves the top-left 128x52 of every room by contract. */
#fg-portal-home{
  position:absolute; left:14px; top:10px; z-index:3;
  display:flex; align-items:center; justify-content:center;
  height:32px; max-width:126px; padding:0 12px;
  border:0; border-radius:7px; cursor:pointer;
  /* The app's brand mark is a WHITE logo drawn for the dark canopy sidebar — on a light room
     it vanishes (caught in QA screenshots). The chip carries its own canopy so the mark keeps
     the background it was designed against, whatever the white-label brand swaps in. */
  background:var(--canopy, #1e3b2f);
  opacity:.82; transition:opacity 150ms ease;
}
#fg-portal-home:hover, #fg-portal-home:focus-visible{ opacity:1; }
#fg-portal-home:focus-visible{ outline:2px solid var(--action, #15a850); outline-offset:2px; }
#fg-portal-home img{ max-height:26px; max-width:102px; width:auto; height:auto; display:block; }
/* no brand image available (white-label build mid-swap) — the exit still has to exist */
#fg-portal-home.fgp-home-bare::before{
  content:'←'; font-size:17px; line-height:1; color:#fff;
}

/* ── Stub room — what engineer/toolsmith replace. Calm and deliberate, never a broken screen. */
.fgp-stub{
  flex:1; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:10px;
  color:var(--ink-3, #6b7a72); text-align:center; padding:40px;
}
.fgp-stub-mark{
  width:34px; height:34px; border-radius:50%;
  border:2px solid var(--canopy-line, #2c4f3e); opacity:.35;
}
.fgp-stub-title{
  font-size:var(--fs-label, 11px); font-weight:600;
  letter-spacing:.08em; text-transform:uppercase;
  color:var(--canopy, #1e3b2f);
}
.fgp-stub-note{ font-size:var(--fs-body, 13.5px); max-width:34ch; line-height:1.45; }
.fgp-stub-esc{ font-size:var(--fs-micro, 10px); letter-spacing:.06em; opacity:.7; }

/* Calm means calm. Reduced motion gets the swap with no travel and near-zero fade. */
@media (prefers-reduced-motion:reduce){
  #fg-portal, .fgp-floor, .fgp-room{ transition-duration:1ms; }
  .fgp-room{ transform:none; }
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   THE SHARED ROOM CHROME — `.fgr-*` (builder2, 7/31 night).

   Craig's parity ask: "the peek/expand + launch affordance must behave identically across
   Study, Projects, Close, Completed — same peek interaction, same launch button, same chrome."
   Four rooms grown from four seams had four headers, four filter idioms and four expand
   behaviours. The chrome cannot live in any one room's stylesheet without the next room
   copying it and drifting again, so it lives HERE, on the engine, and rooms opt in by class.

   Layout contract, inherited from the engine: a room is a flex column that NEVER scrolls.
   `.fgr-body` is the one scroll container. The head reserves the engine's top-left 128×52.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
.fgr-head{
  flex:0 0 auto; display:flex; align-items:center; gap:14px;
  padding:13px 22px 12px 150px;      /* 150 = the engine's reserved 128 + breathing room */
  border-bottom:1px solid var(--line, #e6e9e6); background:var(--card, #fff);
}
.fgr-title{ font-size:16px; font-weight:650; color:var(--canopy, #1e3b2f); letter-spacing:-.01em; }
.fgr-sub{ font-size:var(--fs-micro, 10.5px); color:var(--ink-3, #6b7a72); letter-spacing:.04em; }
.fgr-count{
  display:inline-flex; align-items:center; height:20px; padding:0 8px; border-radius:10px;
  background:#f4ecd8; border:1px solid #ecdfc2; color:#8a5a0f;
  font-size:11.5px; font-weight:700;
}
.fgr-spacer{ flex:1 }

/* Chips / sort / find — one idiom, three rooms. Matches the .abw-fchip geometry the Study
   already uses so nothing on the glass reads as a sixth control style. */
.fgr-chips{ display:flex; gap:6px; flex-wrap:wrap }
.fgr-chip{
  height:26px; padding:0 11px; border-radius:13px; cursor:pointer;
  border:1px solid var(--line, #e6e9e6); background:var(--card, #fff);
  color:var(--ink-2, #46564d); font-size:12px; font-weight:600;
  display:inline-flex; align-items:center; gap:5px;
}
.fgr-chip:hover{ border-color:#cfd8d2 }
.fgr-chip.on{ background:var(--canopy, #1e3b2f); border-color:var(--canopy, #1e3b2f); color:#fff }
.fgr-chip b{ font-weight:700; opacity:.75 }
.fgr-sel, .fgr-find{
  height:26px; border-radius:7px; border:1px solid var(--line, #e6e9e6);
  background:var(--card, #fff); color:var(--ink-2, #46564d); font-size:12px; padding:0 8px;
}
.fgr-find{ width:170px }
.fgr-find:focus, .fgr-sel:focus{ outline:2px solid var(--action, #15a850); outline-offset:1px }

.fgr-body{ flex:1; min-height:0; overflow:auto; padding:16px 22px 22px }
.fgr-empty{
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:8px; padding:60px 20px; color:var(--ink-3, #6b7a72); text-align:center;
}

/* ── THE PEEK, and it is the same peek in every room ──────────────────────────────────────
   Craig's law is "eyes never move": a row expands IN PLACE over its own room. It is not a
   drawer, not a navigation, not a second portal. Esc closes the peek and leaves the room
   standing (the engine's Esc honours _opsEscDone, so exactly one thing closes per key). */
.fgr-peek{
  position:absolute; inset:0; z-index:12;
  display:flex; align-items:center; justify-content:center;
  background:rgba(24,34,29,.30); padding:40px;
}
.fgr-peek-card{
  width:min(680px, 100%); max-height:100%; overflow:auto;
  background:var(--card, #fff); border:1px solid var(--line, #e6e9e6);
  border-radius:14px; box-shadow:0 18px 48px rgba(20,32,26,.20);
  padding:20px 22px 18px;
}
.fgr-peek-hd{ display:flex; align-items:flex-start; gap:12px; margin-bottom:10px }
.fgr-peek-t{ font-size:15.5px; font-weight:650; color:var(--canopy, #1e3b2f); flex:1; line-height:1.3 }
.fgr-peek-x{
  border:0; background:transparent; cursor:pointer; font-size:18px; line-height:1;
  color:var(--ink-3, #6b7a72); padding:2px 4px;
}
.fgr-peek-sec{ margin-top:12px }
.fgr-peek-lb{
  font-size:var(--fs-micro, 10px); letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-3, #6b7a72); font-weight:700; margin-bottom:4px;
}
.fgr-peek-v{ font-size:var(--fs-body, 13.5px); color:var(--ink-1, #24332c); line-height:1.5 }

/* THE LAUNCH BUTTON — the one affordance that turns a peek into work. Same shape, same words'
   weight, same place (bottom-right of the peek card) in every room. A room with nothing to
   launch renders no button rather than a dead one (a control that cannot act must not look
   like it can). */
.fgr-peek-act{ display:flex; gap:8px; justify-content:flex-end; align-items:center; margin-top:16px }
.fgr-launch{
  height:32px; padding:0 15px; border-radius:8px; cursor:pointer;
  border:1px solid var(--action, #15a850); background:var(--action, #15a850); color:#fff;
  font-size:12.5px; font-weight:650; display:inline-flex; align-items:center; gap:6px;
}
.fgr-launch:hover{ filter:brightness(1.06) }
.fgr-launch:focus-visible{ outline:2px solid var(--canopy, #1e3b2f); outline-offset:2px }
.fgr-launch.ghost{ background:transparent; color:var(--ink-2, #46564d); border-color:var(--line, #e6e9e6) }
