diff mrjunejune/src/jrpg/jrpg.css @ 264:04fee26ecce0

add authenticated JRPG conversation platform Add reusable auth/session storage, owned conversation recovery, guest quotas, admin workflows, URL-routed conversation UI, mobile frame support, and parallel browser acceptance. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 07:34:12 -0700
parents ee04e4e69fed
children 41a49c29a28f
line wrap: on
line diff
--- a/mrjunejune/src/jrpg/jrpg.css	Thu Aug 06 11:31:30 2026 -0700
+++ b/mrjunejune/src/jrpg/jrpg.css	Fri Aug 07 07:34:12 2026 -0700
@@ -105,8 +105,8 @@
   --mjj-frame-user-value-inline: 32.5%;
   --mjj-frame-status-value-inline: 60.5%;
   --mjj-frame-uptime-value-inline: 88%;
-  --mjj-frame-dog-bar-block-end: 4%;
-  --mjj-frame-dog-bar-height: 31%;
+  --mjj-frame-dog-bar-block-end: 0%;
+  --mjj-frame-dog-bar-height: 100%;
   box-sizing: border-box;
   display: grid;
   place-items: center;
@@ -354,7 +354,7 @@
   background-image: var(--mjj-jrpg-art);
   background-position: center;
   background-repeat: no-repeat;
-  background-size: 100% 100%;
+  background-size: cover;
   content: "";
   image-rendering: pixelated;
   pointer-events: none;
@@ -416,7 +416,6 @@
   border-bottom: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
 }
 
-.jrpg-preview-kicker,
 .jrpg-menu-label,
 .jrpg-brand > p,
 .jrpg-dialog-heading p {
@@ -559,6 +558,18 @@
   gap: 0;
   padding: var(--zenbu-sys-padding-md);
   background: var(--mjj-jrpg-surface);
+  overflow: hidden;
+}
+
+.jrpg-utility > mjj-jrpg-preview,
+.jrpg-utility > mjj-conversation-archive {
+  box-sizing: border-box;
+  grid-column: 1;
+  grid-row: 1;
+  width: 100%;
+  height: 100%;
+  min-height: 0;
+  min-width: 0;
 }
 
 .jrpg-brand {
@@ -613,7 +624,7 @@
 
 .jrpg-preview-panel {
   display: grid;
-  grid-template-rows: auto auto auto minmax(0, 1fr) auto;
+  grid-template-rows: auto auto minmax(0, 1fr) auto;
   gap: var(--zenbu-sys-space-group);
   height: 100%;
   padding: var(--zenbu-sys-padding-lg);
@@ -637,7 +648,7 @@
   color: var(--mjj-jrpg-primary);
 }
 
-.jrpg-preview-panel > p:not(.jrpg-preview-kicker) {
+.jrpg-preview-panel > p {
   color: var(--mjj-jrpg-text);
 }
 
@@ -1507,7 +1518,8 @@
   mjj-jrpg-menu
 ),
 .jrpg-scene > mjj-jrpg-chat,
-.jrpg-utility > mjj-jrpg-preview > .jrpg-preview-panel {
+.jrpg-utility > mjj-jrpg-preview > .jrpg-preview-panel,
+.jrpg-utility > mjj-conversation-archive {
   border: 0;
   background-color: transparent;
   box-shadow: none;
@@ -1642,6 +1654,7 @@
 
   .jrpg-utility {
     min-height: 27rem;
+    overflow: hidden;
   }
 
   mjj-jrpg-menu nav {
@@ -1653,7 +1666,7 @@
   }
 
   mjj-jrpg-menu ul {
-    grid-template-columns: repeat(3, minmax(0, 1fr));
+    grid-template-columns: repeat(2, minmax(0, 1fr));
   }
 }
 
@@ -1784,7 +1797,7 @@
   }
 
   mjj-jrpg-menu ul {
-    grid-template-columns: 1fr;
+    grid-template-columns: repeat(2, minmax(0, 1fr));
   }
 
   .jrpg-preview-dialog dialog {
@@ -1830,6 +1843,361 @@
   display: none;
 }
 
+/* ================================================================
+   Archive component — placed in utility panel (top-right)
+   ================================================================ */
+
+mjj-jrpg-chat {
+  grid-column: 2;
+  grid-row: 1;
+}
+
+mjj-conversation-archive {
+  position: relative;
+  z-index: 1;
+  display: grid;
+  grid-template-rows: auto auto minmax(0, 1fr) auto auto;
+  align-self: stretch;
+  min-height: 0;
+  padding: var(--zenbu-sys-padding-md);
+  overflow: hidden;
+  background: var(--mjj-jrpg-panel-strong);
+  box-shadow: inset 0 0 0 var(--zenbu-sys-stroke-width) var(--mjj-jrpg-info);
+}
+
+mjj-conversation-archive[hidden] {
+  display: none;
+}
+
+.jrpg-utility > mjj-conversation-archive {
+  border: 0;
+  box-shadow: inset 0 0 0 var(--zenbu-sys-stroke-width) var(--mjj-jrpg-info);
+}
+
+.jrpg-archive-heading {
+  display: flex;
+  align-items: baseline;
+  justify-content: space-between;
+  gap: var(--zenbu-sys-space-group);
+  padding-bottom: var(--zenbu-sys-padding-sm);
+  border-bottom: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
+}
+
+.jrpg-archive-heading h2 {
+  margin: 0;
+  color: var(--mjj-jrpg-text);
+  font-size: var(--zenbu-sys-font-size-lg);
+}
+
+.jrpg-archive-heading zen-button {
+  flex-shrink: 0;
+}
+
+.jrpg-archive-heading zen-button > button {
+  border: 0;
+  border-radius: 0;
+  background: transparent;
+  color: var(--mjj-jrpg-text-muted);
+  cursor: pointer;
+}
+
+.jrpg-archive-actions {
+  display: flex;
+  gap: var(--zenbu-sys-space-control);
+  padding-block: var(--zenbu-sys-padding-sm);
+  border-bottom: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
+}
+
+.jrpg-archive-actions zen-button,
+.jrpg-archive-actions button {
+  width: 100%;
+}
+
+.jrpg-archive-actions button {
+  border: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
+  border-radius: 0;
+  background: var(--mjj-jrpg-panel);
+  color: var(--mjj-jrpg-primary);
+  cursor: pointer;
+}
+
+.jrpg-archive-actions button:hover {
+  border-color: var(--mjj-jrpg-accent);
+  background: var(--mjj-jrpg-surface-raised);
+}
+
+.jrpg-archive-list {
+  display: grid;
+  align-content: start;
+  gap: var(--zenbu-sys-space-icon-label);
+  min-height: 0;
+  margin: 0;
+  padding: var(--zenbu-sys-padding-sm) 0;
+  overflow-y: auto;
+  list-style: none;
+  scrollbar-color: var(--mjj-jrpg-frame) transparent;
+}
+
+.jrpg-archive-list [data-conv-item] {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) auto;
+  align-items: center;
+  gap: var(--zenbu-sys-space-icon-label);
+  padding: var(--zenbu-sys-padding-sm);
+  border: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
+  background: var(--mjj-jrpg-panel);
+}
+
+.jrpg-archive-list [data-conv-open] {
+  display: grid;
+  gap: 0.1em;
+  min-width: 0;
+  border: 0;
+  border-radius: 0;
+  background: transparent;
+  color: var(--mjj-jrpg-primary);
+  cursor: pointer;
+  text-align: left;
+}
+
+.jrpg-archive-list [data-conv-open][aria-current="true"] {
+  color: var(--mjj-jrpg-highlight);
+}
+
+.jrpg-archive-list [data-conv-item]:has([data-conv-open][aria-current="true"]) {
+  border-color: var(--mjj-jrpg-accent);
+  background: var(--mjj-jrpg-surface-raised);
+}
+
+.jrpg-archive-list [data-conv-item]:hover {
+  border-color: var(--mjj-jrpg-frame);
+  background: var(--mjj-jrpg-surface-raised);
+}
+
+.jrpg-archive-list [data-conv-title] {
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  font-size: var(--zenbu-sys-font-size-sm);
+}
+
+.jrpg-archive-list [data-conv-meta] {
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  color: var(--mjj-jrpg-text-muted);
+  font-size: var(--zenbu-sys-font-size-xs);
+}
+
+.jrpg-archive-item-actions {
+  display: flex;
+  gap: var(--zenbu-sys-space-icon-label);
+  flex-shrink: 0;
+}
+
+.jrpg-archive-item-actions button {
+  border: 0;
+  border-radius: 0;
+  background: transparent;
+  color: var(--mjj-jrpg-text-muted);
+  cursor: pointer;
+  font-size: var(--zenbu-sys-font-size-xs);
+}
+
+.jrpg-archive-item-actions button:hover {
+  color: var(--mjj-jrpg-accent);
+}
+
+[data-archive-load-more-owner] {
+  padding-block: var(--zenbu-sys-padding-sm);
+}
+
+[data-archive-load-more-owner][hidden] {
+  display: none;
+}
+
+[data-archive-load-more-owner] > button {
+  width: 100%;
+  border: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
+  border-radius: 0;
+  background: var(--mjj-jrpg-panel);
+  color: var(--mjj-jrpg-text-muted);
+  cursor: pointer;
+}
+
+[data-archive-load-more-owner] > button:hover {
+  border-color: var(--mjj-jrpg-frame);
+  color: var(--mjj-jrpg-primary);
+}
+
+.jrpg-archive-status {
+  margin: 0;
+  padding: var(--zenbu-sys-padding-sm) 0;
+  color: var(--mjj-jrpg-text-muted);
+  font-size: var(--zenbu-sys-font-size-xs);
+}
+
+.jrpg-archive-status[hidden] {
+  display: none;
+}
+
+.jrpg-archive-status[data-state="error"] {
+  color: var(--mjj-jrpg-accent);
+}
+
+.jrpg-archive-status button {
+  border: 0;
+  border-radius: 0;
+  background: transparent;
+  color: var(--mjj-jrpg-info);
+  cursor: pointer;
+  font-size: inherit;
+  text-decoration: underline;
+}
+
+/* Archive dialogs */
+
+.jrpg-archive-dialog {
+  box-sizing: border-box;
+  min-width: min(22rem, calc(100vw - var(--zenbu-sys-space-content)));
+  max-width: min(26rem, calc(100vw - var(--zenbu-sys-space-content)));
+  padding: var(--zenbu-sys-padding-lg);
+  border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
+  border-radius: 0;
+  background: var(--mjj-jrpg-surface-raised);
+  color: var(--mjj-jrpg-text);
+  box-shadow:
+    inset 0 0 0 var(--zenbu-sys-stroke-width) var(--mjj-jrpg-accent),
+    var(--zenbu-sys-space-control) var(--zenbu-sys-space-control) 0 var(--mjj-jrpg-accent);
+}
+
+.jrpg-archive-dialog::backdrop {
+  background: color-mix(in srgb, var(--mjj-jrpg-canvas) 84%, transparent);
+}
+
+.jrpg-archive-dialog[open] {
+  display: grid;
+  grid-template-rows: auto auto auto;
+  gap: var(--zenbu-sys-space-group);
+  animation: mjj-jrpg-dialog-open var(--zenbu-sys-motion-duration-layout)
+    var(--zenbu-sys-motion-ease-enter);
+}
+
+.jrpg-archive-dialog-title {
+  margin: 0;
+  color: var(--mjj-jrpg-primary);
+  font-size: var(--zenbu-sys-font-size-md);
+}
+
+.jrpg-archive-dialog-subtitle {
+  margin: 0;
+  color: var(--mjj-jrpg-text-muted);
+  font-size: var(--zenbu-sys-font-size-xs);
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+.jrpg-archive-dialog-actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: var(--zenbu-sys-space-control);
+}
+
+.jrpg-archive-dialog zen-button > button {
+  border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
+  border-radius: 0;
+  background: var(--mjj-jrpg-surface);
+  color: var(--mjj-jrpg-text);
+  cursor: pointer;
+}
+
+.jrpg-archive-dialog zen-button > button:hover {
+  border-color: var(--mjj-jrpg-accent);
+  background: var(--mjj-jrpg-surface-raised);
+}
+
+.jrpg-archive-dialog zen-field[appearance="plain"] {
+  display: grid;
+  gap: var(--zenbu-sys-space-icon-label);
+}
+
+.jrpg-archive-dialog input {
+  box-sizing: border-box;
+  width: 100%;
+  min-height: var(--zenbu-control-height);
+  padding:
+    var(--zenbu-control-padding-block)
+    var(--zenbu-control-padding-inline);
+  border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
+  border-radius: 0;
+  background: var(--mjj-jrpg-surface-sunken);
+  color: var(--mjj-jrpg-text);
+  font: inherit;
+}
+
+/* Account slot — telemetry child 2 */
+
+[data-frame-account] a,
+[data-frame-account] button,
+[data-frame-account] span[data-account-user] {
+  color: var(--mjj-jrpg-primary);
+  font-size: inherit;
+}
+
+[data-frame-account] a {
+  text-decoration: none;
+}
+
+[data-frame-account] a:hover {
+  text-decoration: underline;
+  text-decoration-color: var(--mjj-jrpg-accent);
+}
+
+[data-frame-account] button {
+  border: 0;
+  background: transparent;
+  cursor: pointer;
+  padding: 0;
+  font: inherit;
+}
+
+[data-frame-account] button:hover {
+  color: var(--mjj-jrpg-accent);
+}
+
+/* Quota display in composer */
+
+.jrpg-composer-quota {
+  grid-column: 1 / -1;
+  margin: 0;
+  color: var(--mjj-jrpg-text-muted);
+  font-size: var(--zenbu-sys-font-size-xs);
+}
+
+.jrpg-composer-quota[data-state="warning"] {
+  color: var(--mjj-jrpg-highlight);
+}
+
+.jrpg-composer-quota[data-state="exhausted"] {
+  color: var(--mjj-jrpg-accent);
+}
+
+.jrpg-composer-quota[hidden] {
+  display: none;
+}
+
+/* Archive + chat grid in mobile single-column layout */
+
+@media (max-width: 34rem) {
+  mjj-jrpg-chat,
+  mjj-conversation-archive {
+    grid-column: 1;
+    grid-row: 2;
+  }
+}
+
+
 @media (forced-colors: active) {
   .jrpg-workspace,
   .jrpg-scene,
@@ -1837,3 +2205,576 @@
     background-image: none;
   }
 }
+
+/* ================================================================
+   Mobile hamburger button — hidden on desktop, used in portrait
+   ================================================================ */
+
+.jrpg-mobile-menu-btn {
+  display: none;
+}
+
+/* ================================================================
+   Mobile portrait frame layout (≤52rem + portrait)
+   Overrides the generic stacked grid from the 52rem breakpoint.
+   All geometry custom properties are centralised in .jrpg-shell.
+   ================================================================ */
+
+@media (max-width: 52rem) and (orientation: portrait) {
+  .jrpg-shell {
+    /* ── Aperture geometry: (inline=left%, block=top%, width%, height%) ── */
+
+    /* Main conversation */
+    --mjj-mobile-scene-inline:  4.5%;
+    --mjj-mobile-scene-block:   7.5%;
+    --mjj-mobile-scene-width:  91%;
+    --mjj-mobile-scene-height: 45.5%;
+
+    /* Preview / utility */
+    --mjj-mobile-utility-inline:  4.5%;
+    --mjj-mobile-utility-block:  54.7%;
+    --mjj-mobile-utility-width:  91%;
+    --mjj-mobile-utility-height: 17.1%;
+
+    /* Composer */
+    --mjj-mobile-composer-inline:  4.5%;
+    --mjj-mobile-composer-block:  72.8%;
+    --mjj-mobile-composer-width:  60.3%;
+    --mjj-mobile-composer-height: 19.2%;
+
+    /* Menu */
+    --mjj-mobile-menu-inline:  66.5%;
+    --mjj-mobile-menu-block:   72.8%;
+    --mjj-mobile-menu-width:   29%;
+    --mjj-mobile-menu-height:  19.2%;
+
+    /* Brand / SYS-01 cover */
+    --mjj-mobile-brand-inline:  11%;
+    --mjj-mobile-brand-block:    2.4%;
+    --mjj-mobile-brand-width:   10%;
+    --mjj-mobile-brand-height:   3.5%;
+
+    /* Baked hamburger overlay */
+    --mjj-mobile-hamburger-inline: 89.5%;
+    --mjj-mobile-hamburger-block:   2%;
+    --mjj-mobile-hamburger-width:   7%;
+    --mjj-mobile-hamburger-height:  4%;
+
+    /* Telemetry value absolute positions (x = left-center, y = top-center) */
+    --mjj-mobile-telemetry-temp-x:   22%;
+    --mjj-mobile-telemetry-temp-y:   94.7%;
+    --mjj-mobile-telemetry-user-x:   45%;
+    --mjj-mobile-telemetry-user-y:   94.7%;
+    --mjj-mobile-telemetry-status-x: 73%;
+    --mjj-mobile-telemetry-status-y: 94.7%;
+    --mjj-mobile-telemetry-uptime-x: 22%;
+    --mjj-mobile-telemetry-uptime-y: 97.5%;
+
+    height: 100dvh;
+    min-height: 0;
+  }
+
+  .jrpg-page {
+    overflow: hidden;
+  }
+
+  .jrpg-main {
+    height: 100dvh;
+    min-height: 0;
+    padding: 0;
+  }
+
+  /* Workspace: switch from stacked grid back to absolute-positioned frame */
+  .jrpg-workspace {
+    display: block;
+    position: relative;
+    width: 100%;
+    height: 100%;
+    min-height: 0;
+    overflow: hidden;
+    background-image: url("/public/jrpg/background-frame-mobile.webp");
+    background-position: top left;
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+  }
+
+  /* Desktop window controls are irrelevant on mobile portrait */
+  .jrpg-workspace > .jrpg-frame-controls {
+    display: none;
+  }
+
+  /* Restore absolute positioning for all aperture elements */
+  .jrpg-workspace > .jrpg-scene,
+  .jrpg-workspace > .jrpg-utility,
+  .jrpg-workspace > mjj-jrpg-composer,
+  .jrpg-workspace > mjj-jrpg-menu,
+  .jrpg-workspace > .jrpg-brand {
+    position: absolute;
+    width: auto;
+    height: auto;
+  }
+
+  /* Scene aperture */
+  .jrpg-workspace > .jrpg-scene {
+    inset:
+      var(--mjj-mobile-scene-block)
+      auto
+      auto
+      var(--mjj-mobile-scene-inline);
+    width: var(--mjj-mobile-scene-width);
+    height: var(--mjj-mobile-scene-height);
+    min-height: 0;
+    font-size: clamp(
+      var(--zenbu-sys-font-size-xs),
+      2.8vw,
+      var(--zenbu-sys-font-size-sm)
+    );
+  }
+
+  /* Utility / preview aperture */
+  .jrpg-workspace > .jrpg-utility {
+    inset:
+      var(--mjj-mobile-utility-block)
+      auto
+      auto
+      var(--mjj-mobile-utility-inline);
+    width: var(--mjj-mobile-utility-width);
+    height: var(--mjj-mobile-utility-height);
+    min-height: 0;
+    overflow: hidden;
+    font-size: clamp(
+      var(--zenbu-sys-font-size-xs),
+      2.8vw,
+      var(--zenbu-sys-font-size-sm)
+    );
+  }
+
+  /* Composer aperture */
+  .jrpg-workspace > mjj-jrpg-composer {
+    inset:
+      var(--mjj-mobile-composer-block)
+      auto
+      auto
+      var(--mjj-mobile-composer-inline);
+    width: var(--mjj-mobile-composer-width);
+    height: var(--mjj-mobile-composer-height);
+    font-size: clamp(
+      var(--zenbu-sys-font-size-xs),
+      2.8vw,
+      var(--zenbu-sys-font-size-sm)
+    );
+  }
+
+  /* Menu aperture */
+  .jrpg-workspace > mjj-jrpg-menu {
+    inset:
+      var(--mjj-mobile-menu-block)
+      auto
+      auto
+      var(--mjj-mobile-menu-inline);
+    width: var(--mjj-mobile-menu-width);
+    height: var(--mjj-mobile-menu-height);
+    overflow: hidden;
+    font-size: clamp(
+      var(--zenbu-sys-font-size-xs),
+      2.5vw,
+      var(--zenbu-sys-font-size-sm)
+    );
+  }
+
+  /* Brand cover (covers baked SYS-01 label) */
+  .jrpg-workspace > .jrpg-brand {
+    inset:
+      var(--mjj-mobile-brand-block)
+      auto
+      auto
+      var(--mjj-mobile-brand-inline);
+    width: var(--mjj-mobile-brand-width);
+    height: var(--mjj-mobile-brand-height);
+    background: var(--mjj-jrpg-canvas);
+    padding: 0;
+    box-shadow: none;
+  }
+
+  /* Hamburger button: transparent overlay over baked art */
+  .jrpg-workspace > .jrpg-mobile-menu-btn {
+    display: grid;
+    place-items: center;
+    position: absolute;
+    z-index: 5;
+    inset:
+      var(--mjj-mobile-hamburger-block)
+      auto
+      auto
+      var(--mjj-mobile-hamburger-inline);
+    width: var(--mjj-mobile-hamburger-width);
+    height: var(--mjj-mobile-hamburger-height);
+  }
+
+  .jrpg-mobile-menu-btn > button {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+    border: 0;
+    border-radius: 0;
+    background: transparent;
+    color: transparent;
+    cursor: pointer;
+  }
+
+  .jrpg-mobile-menu-btn zen-icon {
+    opacity: 0;
+  }
+
+  .jrpg-mobile-menu-btn > button:focus-visible {
+    outline-color: var(--mjj-jrpg-focus);
+    outline-style: solid;
+    outline-width: 2px;
+    outline-offset: 2px;
+    color: var(--mjj-jrpg-primary);
+  }
+
+  .jrpg-mobile-menu-btn > button:focus-visible zen-icon {
+    opacity: 0.5;
+  }
+
+  /* Telemetry: full-workspace container so children use workspace % coords */
+  .jrpg-workspace > .jrpg-frame-telemetry {
+    position: absolute;
+    inset: 0;
+    display: block;
+    width: 100%;
+    height: 100%;
+    background: transparent;
+    pointer-events: none;
+    font-size: clamp(
+      var(--zenbu-sys-font-size-xs),
+      2.5vw,
+      var(--zenbu-sys-font-size-sm)
+    );
+  }
+
+  .jrpg-frame-telemetry > :nth-child(1) {
+    position: absolute;
+    left: var(--mjj-mobile-telemetry-temp-x);
+    top: var(--mjj-mobile-telemetry-temp-y);
+    transform: translate(-50%, -50%);
+    background: transparent;
+    padding-inline: 0;
+    pointer-events: auto;
+    white-space: nowrap;
+  }
+
+  .jrpg-frame-telemetry > :nth-child(2) {
+    position: absolute;
+    left: var(--mjj-mobile-telemetry-user-x);
+    top: var(--mjj-mobile-telemetry-user-y);
+    transform: translate(-50%, -50%);
+    background: transparent;
+    padding-inline: 0;
+    pointer-events: auto;
+    white-space: nowrap;
+  }
+
+  .jrpg-frame-telemetry > :nth-child(3) {
+    position: absolute;
+    left: var(--mjj-mobile-telemetry-status-x);
+    top: var(--mjj-mobile-telemetry-status-y);
+    transform: translate(-50%, -50%);
+    background: transparent;
+    padding-inline: 0;
+    pointer-events: auto;
+    white-space: nowrap;
+  }
+
+  .jrpg-frame-telemetry > :nth-child(4) {
+    position: absolute;
+    left: var(--mjj-mobile-telemetry-uptime-x);
+    top: var(--mjj-mobile-telemetry-uptime-y);
+    transform: translate(-50%, -50%);
+    background: transparent;
+    padding-inline: 0;
+    pointer-events: auto;
+    white-space: nowrap;
+  }
+
+  /* Compact the brand header text for the narrow cover area */
+  .jrpg-workspace > .jrpg-brand header h1 {
+    font-size: clamp(
+      var(--zenbu-sys-font-size-xs),
+      2vw,
+      var(--zenbu-sys-font-size-xs)
+    );
+  }
+
+  /* Compact scene internals for mobile aperture */
+  .jrpg-scene {
+    grid-template-columns: minmax(0, 1fr);
+    grid-template-rows: minmax(0, 1fr);
+    align-items: stretch;
+    gap: var(--zenbu-sys-space-icon-label);
+    padding: var(--zenbu-sys-padding-sm);
+  }
+
+  .jrpg-scene > mjj-jrpg-character {
+    display: none;
+  }
+
+  mjj-jrpg-chat {
+    grid-column: 1;
+    grid-row: 1;
+    width: 100%;
+    height: 100%;
+    max-height: 100%;
+    overflow: hidden;
+    padding: var(--zenbu-sys-padding-sm);
+  }
+
+  .jrpg-utility > mjj-conversation-archive {
+    width: 100%;
+    height: 100%;
+    max-height: 100%;
+    overflow: auto;
+  }
+
+  /* Utility compact padding */
+  .jrpg-utility {
+    padding: var(--zenbu-sys-padding-sm);
+  }
+
+  /* Composer: compact single-row within aperture */
+  .jrpg-composer {
+    gap: var(--zenbu-sys-space-icon-label);
+    padding: var(--zenbu-sys-padding-sm);
+  }
+
+  .jrpg-composer-hint {
+    display: none;
+  }
+
+  /* Menu compact: single column stacking */
+  .jrpg-workspace > mjj-jrpg-menu {
+    padding: var(--zenbu-sys-padding-xs, var(--zenbu-sys-padding-sm));
+    overflow-y: auto;
+    scrollbar-width: thin;
+  }
+
+  mjj-jrpg-menu nav {
+    height: 100%;
+    grid-template-columns: 1fr;
+  }
+
+  mjj-jrpg-menu .jrpg-menu-label {
+    display: none;
+  }
+
+  mjj-jrpg-menu ul {
+    grid-template-columns: minmax(0, 1fr);
+    gap: 0;
+  }
+
+  mjj-jrpg-menu button {
+    min-height: var(--zenbu-control-height);
+    padding-block: 0;
+    padding-inline: var(--zenbu-control-padding-inline);
+    font-size: var(--zenbu-sys-font-size-xs);
+  }
+
+  mjj-jrpg-menu[data-mobile-menu-collapsed] {
+    overflow: hidden;
+  }
+
+  mjj-jrpg-menu[data-mobile-menu-collapsed] nav {
+    display: grid;
+    place-items: center;
+  }
+
+  mjj-jrpg-menu[data-mobile-menu-collapsed] .jrpg-menu-label {
+    display: block;
+    writing-mode: initial;
+  }
+
+  mjj-jrpg-menu[data-mobile-menu-collapsed] ul {
+    display: none;
+  }
+
+  /* Preview panel compact for narrow utility aperture */
+  .jrpg-preview-panel {
+    gap: var(--zenbu-sys-space-icon-label);
+    padding: var(--zenbu-sys-padding-sm);
+    overflow-y: auto;
+  }
+
+  .jrpg-preview-panel h2 {
+    font-size: var(--zenbu-sys-font-size-sm);
+  }
+
+  .jrpg-preview-panel > p {
+    font-size: var(--zenbu-sys-font-size-xs);
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    overflow: hidden;
+  }
+
+  .jrpg-work-showcase {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+    gap: var(--zenbu-sys-space-icon-label);
+  }
+
+  .jrpg-work-showcase a {
+    padding: var(--zenbu-sys-padding-xs, var(--zenbu-sys-padding-sm));
+    font-size: var(--zenbu-sys-font-size-xs);
+  }
+
+  /* Archive fits within scene aperture */
+  mjj-conversation-archive {
+    padding: var(--zenbu-sys-padding-sm);
+  }
+
+  /* Scrollable message viewport fills aperture */
+  zen-message-scroller > .jrpg-message-viewport {
+    scrollbar-width: thin;
+  }
+}
+
+/* ================================================================
+   Login modal dialog
+   ================================================================ */
+
+.jrpg-login-dialog-owner {
+  display: contents;
+}
+
+.jrpg-login-dialog {
+  box-sizing: border-box;
+  width: min(24rem, calc(100vw - var(--zenbu-sys-space-content)));
+  padding: var(--zenbu-sys-padding-xl);
+  border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
+  border-radius: 0;
+  background: var(--mjj-jrpg-surface-raised);
+  color: var(--mjj-jrpg-text);
+  box-shadow:
+    inset 0 0 0 var(--zenbu-sys-stroke-width) var(--mjj-jrpg-accent),
+    var(--zenbu-sys-space-control) var(--zenbu-sys-space-control) 0
+      var(--mjj-jrpg-accent);
+}
+
+.jrpg-login-dialog::backdrop {
+  background: color-mix(in srgb, var(--mjj-jrpg-canvas) 84%, transparent);
+}
+
+.jrpg-login-dialog[open] {
+  display: grid;
+  grid-template-rows: auto auto minmax(0, 1fr);
+  gap: var(--zenbu-sys-space-group);
+  animation: mjj-jrpg-dialog-open var(--zenbu-sys-motion-duration-layout)
+    var(--zenbu-sys-motion-ease-enter);
+}
+
+.jrpg-login-dialog-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: var(--zenbu-sys-space-group);
+  padding-bottom: var(--zenbu-sys-padding-md);
+  border-bottom: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
+}
+
+.jrpg-login-dialog-header h2 {
+  margin: 0;
+  color: var(--mjj-jrpg-primary);
+  font-size: var(--zenbu-sys-font-size-lg);
+  letter-spacing: 0.08em;
+}
+
+.jrpg-login-dialog-header zen-button > button {
+  width: var(--zenbu-control-height);
+  padding: 0;
+  border: 0;
+  border-radius: 0;
+  background: transparent;
+  color: var(--mjj-jrpg-text-muted);
+  cursor: pointer;
+}
+
+.jrpg-login-dialog [data-login-error] {
+  padding: var(--zenbu-sys-padding-sm);
+  border-left: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-accent);
+  background: color-mix(in srgb, var(--mjj-jrpg-accent) 10%, transparent);
+  color: var(--mjj-jrpg-accent);
+  font-size: var(--zenbu-sys-font-size-sm);
+}
+
+.jrpg-login-dialog [data-login-error][hidden] {
+  display: none;
+}
+
+.jrpg-login-dialog form {
+  display: grid;
+  gap: var(--zenbu-sys-space-group);
+}
+
+.jrpg-login-dialog zen-field[appearance="plain"] {
+  display: grid;
+  gap: var(--zenbu-sys-space-icon-label);
+}
+
+.jrpg-login-dialog input {
+  box-sizing: border-box;
+  width: 100%;
+  min-height: var(--zenbu-control-height);
+  padding:
+    var(--zenbu-control-padding-block)
+    var(--zenbu-control-padding-inline);
+  border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
+  border-radius: 0;
+  background: var(--mjj-jrpg-surface-sunken);
+  color: var(--mjj-jrpg-text);
+  font: inherit;
+}
+
+.jrpg-login-dialog input::placeholder {
+  color: var(--mjj-jrpg-text-muted);
+}
+
+.jrpg-login-dialog-actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: var(--zenbu-sys-space-control);
+}
+
+.jrpg-login-dialog zen-button > button {
+  border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
+  border-radius: 0;
+  background: var(--mjj-jrpg-surface);
+  color: var(--mjj-jrpg-text);
+  cursor: pointer;
+}
+
+.jrpg-login-dialog zen-button > button:hover {
+  border-color: var(--mjj-jrpg-accent);
+  background: var(--mjj-jrpg-surface-raised);
+}
+
+.jrpg-login-dialog [data-login-submit] {
+  border-color: var(--mjj-jrpg-primary);
+  background: var(--mjj-jrpg-primary);
+  color: var(--mjj-jrpg-primary-foreground);
+}
+
+.jrpg-login-dialog [data-login-submit]:hover {
+  border-color: var(--mjj-jrpg-primary-hover);
+  background: var(--mjj-jrpg-primary-hover);
+}
+
+.jrpg-login-dialog zen-button > button:disabled {
+  opacity: var(--zenbu-sys-opacity-disabled);
+  cursor: not-allowed;
+}
+
+@media (prefers-reduced-motion: reduce) {
+  .jrpg-login-dialog[open] {
+    animation: none;
+  }
+}