/* Z_HIS_ONE_STYLESHEET_2026-09-18 (root seat, Opus 5)
   HIS ORDER 2026-09-18 02:31 EST: "FUFKCING DELETE EVERY SINGLE STYLEHSEET THATS NOT THE
   MAIN FUCKGIN ONE!!!!!!!!!!" and "THE UFCKING ELEMETNS ALL LOAD WITH THE ATRTRIBUTES AND
   THEIR FUCKNIG STYLES !!!!"
   HIS LAW: "I FUCKNIG SAID THE TOP RULES IS THAT ONLY FUCKNIG ONE STYLESHEEET... MULTIPLE
   STYLESHEETS SHOULD NEEEEVER EXIST!!!!!"
   His sign-in styles, his colour settings and his settings styles are folded in here in the
   exact order they used to load, so nothing he can see changes. The outside Google font
   fetch is gone - his own copy of the same typeface is already served from this file.
   UNDO THIS PART ALONE: restore shell.css from the backup beside it, put the two link lines
   back in face/home/deploy/index.html and the settings line back in app.js. */

/* ---- his sign-in styles (was /shared/access-lock.css) ---- */
/* Z_SITE_IDENTITY_FONT_2026-07-19 (Claude2, founder-direct instruction: "save
   that font to site identity too, and point both of them to it"). Genuinely
   :root-scoped (unlike --access-lock-font below, which only cascades inside
   .access-lock-overlay/.access-lock-panel/.access-lock-key/.access-lock-input
   descendants) so any element anywhere in the document -- including the Chat
   sidebar, which lives outside the access-lock DOM tree -- can reference the
   same canonical identity typeface. Value is identical to --access-lock-font
   on purpose: this is the one worker-terminal blocky lock font already
   approved site-wide (see the comment on --access-lock-font just below); this
   token exists so future non-lock UI (sidebar identity, etc.) has a real
   global var to point at instead of duplicating the literal font stack. */
:root {
  --z-site-identity-font: "Z JetBrains Mono", monospace;
}
.access-lock-overlay,
.access-lock-panel,
.access-lock-key,
.access-lock-input {
  /*
   * Owner live edit 2026-04-29: the worker terminal blocky lock font is the
   * approved standard for every lock/passcode/account gate. Keep the typeface
   * centralized here so chat, worker, engineer, login, passkey, and passcode
   * screens do not drift into page-specific fonts again.
   */
  --access-lock-font: "Z JetBrains Mono", monospace;
  /*
   * Owner live correction 2026-04-29: every shared "Enter your/the
   * 4-digit access code" lock must render the instruction copy smaller.
   * Keep this as the single shared token source so chat, worker, engineer,
   * demo owner website, passkey, and passcode gates cannot drift by route.
   */
  --access-lock-body-font-size: 11px;
  --access-lock-body-line-height: 1.18;
  --access-lock-code-slot-font-size: 13px;
  --access-lock-key-font-size: 15px;
  --access-lock-key-number-font-size: 16px;
  --access-lock-key-letter-font-size: 9px;
  --access-lock-delete-font-size: 14px;
  --access-lock-keypad-max-width: 292px;
  font-family: var(--access-lock-font);
}

.access-lock-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding:
    calc(24px + env(safe-area-inset-top))
    max(18px, env(safe-area-inset-right))
    calc(24px + env(safe-area-inset-bottom))
    max(18px, env(safe-area-inset-left));
  box-sizing: border-box;
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  z-index: 1200;
}

/* P0 unlock-stuck-text fix (2026-04-26): when JS sets hidden=true or adds the
 * .hidden class after a successful /api/access/unlock, the overlay must
 * actually disappear. Without this rule the .access-lock-overlay's
 * display:flex above wins over the user-agent [hidden] {display:none}. */
.access-lock-overlay[hidden],
.access-lock-overlay.hidden {
  display: none !important;
}

.access-lock-panel {
  width: min(400px, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  text-align: center;
}

.access-lock-logo {
  /* Z_HALO_IDENTICAL_2026-05-13: lockscreen Z is in the identical-halo
   * family with message-bar / loading-Z / big Live-Z.
   * LOCKPAD_TEXT_REMOVED_2026-05-13: only the separate title/body under the
   * logo are hidden. The neon Z inside the logo stays visible. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(84px, 27vw, 128px);
  height: clamp(84px, 27vw, 128px);
  margin: 0 auto 19px !important;
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(40, 25, 70, 0.52),
    rgba(10, 6, 22, 0.38) 66%,
    transparent 100%
  );
  box-shadow:
    0 0 12px rgba(140, 100, 255, 0.42),
    0 0 22px rgba(140, 100, 255, 0.22);
  pointer-events: none;
  /* CYAN_RADAR_RING (2026-07-14 Claude-A, A3): needed so the new ::before/::after ring
     layers below can be absolutely positioned around the existing Z mark without moving
     it. Purely additive — logo itself is untouched. */
  position: relative;
}

/* DO NOT REMOVE, STRONG FOUNDER DO-NOT-REMOVE, can only be evolved by
   Z/ZActions -- Z_HOME_BIG_LOGO_MENU_CLICKABLE_2026-07-17 (Claude/Sonnet5,
   founder-requested). Z_HOME_BIG_LOGO_MENU_2026-07-17 in
   chat-critical-bundle.js wires a click handler onto this exact element
   (role="button", gated on accessState.locked === false) so the big Home Z
   opens the Live Z menu once authenticated -- but the base rule above sets
   pointer-events:none unconditionally, so the click event never reached the
   element and the JS handler never fired. The JS gate (locked !== false)
   already restricts this to the authenticated state, so it's safe to
   restore pointer-events here unconditionally rather than trying to key
   this CSS rule off the same auth state. */
.access-lock-logo[role="button"] {
  pointer-events: auto;
  cursor: pointer;
}

.access-lock-logo .z-logo {
  width: 100%;
  height: 100%;
}

/* TEMPORARILY DISABLED — HOME/LOCKSCREEN RADAR WEDGE/SWEEP
 * This is the original common lockscreen radar source. It is intentionally
 * commented out for every Z Home state, including grid and login/search, so
 * neither desktop nor mobile Home can render the blue/purple wedge or beam.
 * The active copy immediately below is constrained to non-Home lock surfaces.
.access-lock-logo::before {
  content: "";
  position: absolute;
  inset: -16%;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    rgba(143, 230, 244, 0) 0deg,
    rgba(143, 230, 244, 0.85) 16deg,
    rgba(143, 230, 244, 0) 46deg,
    rgba(143, 230, 244, 0) 360deg
  );
  pointer-events: none;
  mix-blend-mode: screen;
  animation: zLogoRadarSweep 3400ms linear infinite;
  z-index: 0;
}
*/

/* ==========================================================================
 * Z_THE_RADAR_IS_GONE_FOR_GOOD_2026-08-31
 * FOUNDER, verbatim, 2026-08-31: "aslo FUCKING REMOVE THE RADAR FROM THE ORB.
 * I REMVOED IT A WHILE AGO, SOMEONE FUCKNIG PUT IT BACK. MAKE SURE THEY DONT
 * PUT IT BACK EITHER"
 *
 * The sweeping cyan wedge that used to live here is DELETED, not scoped and not
 * commented out. It kept coming back because the old rule was only *scoped*
 * away from Home with `:not([data-z-home-view])` -- and the moment the overlay
 * stopped carrying data-z-home-view (measured live 2026-08-31: the attribute is
 * absent), that guard inverted and the radar returned to the Home orb.
 *
 * DO NOT RE-ADD. Not scoped, not behind a flag, not "only for non-Home".
 * REMOVE MEANS REMOVE. The blocker below makes it inert even if the wedge is
 * re-pasted anywhere by anyone.
 * ========================================================================== */
.access-lock-logo::before,
.access-lock-overlay .access-lock-logo::before,
.access-lock-overlay:not([data-z-home-view]) .access-lock-logo::before {
  background: none !important;
  animation: none !important;
  content: none !important;
}

/* Static always-visible cyan ring (the "energy ring" itself) so it reads clearly at any
   animation frame, not just when the sweep/pulse layers happen to be bright. */
.access-lock-logo::after {
  content: "";
  position: absolute;
  inset: -16%;
  border-radius: 50%;
  border: 2px solid rgba(143, 230, 244, 0.78);
  box-shadow:
    0 0 14px rgba(143, 230, 244, 0.55),
    0 0 26px rgba(143, 230, 244, 0.28),
    inset 0 0 12px rgba(143, 230, 244, 0.18);
  pointer-events: none;
  animation: zLogoRadarPulse 2800ms ease-in-out infinite;
  z-index: 0;
}

.access-lock-logo .z-logo {
  position: relative;
  z-index: 1;
}

@keyframes zLogoRadarSweep {
  to {
    transform: rotate(360deg);
  }
}

/* 2026-07-21 FOUNDER: "fade the radar-style pinging pulse to 50% (but keep
   the recently added pulsating)". The expanding radar ping's peak opacity is
   halved (0.85 -> 0.42); its motion/timing is untouched, and the separate
   purple-backdrop breathing pulses claude2 added stay as-is. */
@keyframes zLogoRadarPulse {
  0% {
    transform: scale(0.9);
    opacity: 0.42;
  }
  70% {
    transform: scale(1.22);
    opacity: 0;
  }
  100% {
    transform: scale(1.22);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .access-lock-logo::before,
  .access-lock-logo::after {
    animation: none;
    opacity: 0.5;
  }
}

/* Z_HALO_IDENTICAL_2026-05-13: needs the z-blood-tri-mark attribute in
 * the selector to out-specify the embed-overrides rule
 * (`z-blood-tri-mark[data-z-blood-tri-mark="1"] .z-composed { 88% !important }`).
 * The lockscreen mark is the approved recipe for the large loading/Live-Z
 * variants: same Z visible, same flower, same hidden disk/hourglass core. */
.access-lock-logo z-blood-tri-mark[data-z-blood-tri-mark="1"] .z-composed,
.access-lock-logo z-blood-tri-mark[data-z-top-mark="1"] .z-composed,
.access-lock-logo z-blood-tri-mark[data-z-btn-mark="1"] .z-composed,
.access-lock-logo z-blood-tri-mark[data-z-popup-mark="1"] .z-composed {
  width: 62% !important;
  height: 62% !important;
}

.access-lock-title {
  /* LOCKPAD_NO_EXTRA_LETTERS_2026-05-13: lockscreen should be logo + keypad
   * only. Keep keypad digits/letters, but hide title/body copy. */
  display: none !important;
  margin: 0;
  font-family: var(--access-lock-font);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.access-lock-panel .access-lock-body,
.access-lock-body.unlock-copy,
.access-lock-body {
  display: none !important;
  visibility: hidden !important;
  width: 0 !important;
  height: 0 !important;
  margin: 0;
  color: rgba(255, 242, 222, 0.8);
  /* Owner lock-subtitle one-line rule (Pass 73): the access-code
     instruction line must never wrap. Title may still wrap to two
     lines. nowrap + clamp font-size keeps the line readable on
     every viewport without overflowing the panel. The previous
     34ch max-width was forcing wrap on narrow phones. */
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--access-lock-font);
  font-size: clamp(10px, 3.2vw, var(--access-lock-body-font-size));
  line-height: var(--access-lock-body-line-height);
}

.access-lock-auth-options,
.access-lock-auth-status,
.access-lock-error,
.access-lock-passkey {
  display: none !important;
  visibility: hidden !important;
}

.access-lock-user-selector {
  width: min(340px, 100%);
  display: grid;
  gap: 10px;
  margin: 0 auto;
  color: rgba(245, 247, 255, 0.95);
}

.access-lock-user-search-area {
  display: grid;
  gap: 8px;
}

.access-lock-user-search-input {
  width: 100%;
  height: 42px;
  box-sizing: border-box;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 12px;
  padding: 0 13px;
  background: rgba(7, 10, 18, 0.62);
  color: rgba(245, 247, 255, 0.96);
  font: 700 14px/1 var(--access-lock-font);
  letter-spacing: 0;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

.access-lock-user-search-input::placeholder {
  color: rgba(245, 247, 255, 0.48);
}

.access-lock-user-search-input:focus {
  border-color: rgba(105, 203, 255, 0.68);
  box-shadow: 0 0 0 3px rgba(105, 203, 255, 0.12);
}

/* Z_BUSINESS_VISIBLE_PASSWORD_FIELD_2026-09-29: the Business typed-login
   screen uses the same existing credential selector as the other locks, but
   its Password control must be a real visible field with a placeholder and
   caret, like Username.  The shared password style remains hidden only for
   the post-passcode dot renderer; this selector is scoped to the Business
   login box. */
.z-access-login-password-box .access-lock-password-input {
  position: relative !important;
  inset: auto !important;
  z-index: 1 !important;
  display: block !important;
  width: 100% !important;
  height: 40px !important;
  min-height: 40px !important;
  box-sizing: border-box !important;
  margin: 0 !important;
  padding: 0 13px !important;
  border: 0 !important;
  border-radius: 12px !important;
  outline: none !important;
  background: transparent !important;
  color: rgba(245, 247, 255, 0.96) !important;
  caret-color: rgba(216, 180, 254, 0.98) !important;
  font: 700 14px/1 var(--access-lock-font) !important;
  letter-spacing: 0 !important;
  text-align: center !important;
  opacity: 1 !important;
  -webkit-appearance: none !important;
  appearance: none !important;
}

.z-access-login-password-box .access-lock-password-input::placeholder {
  color: rgba(245, 247, 255, 0.48) !important;
  opacity: 1 !important;
}

.z-access-login-password-box .access-lock-password-input:focus {
  outline: none !important;
  box-shadow: 0 0 0 3px rgba(105, 203, 255, 0.12) !important;
}

.access-lock-user-list {
  display: grid;
  gap: 7px;
  max-height: min(246px, 34vh);
  overflow: auto;
  overscroll-behavior: contain;
  padding: 2px;
  scrollbar-width: thin;
}

.access-lock-user-option {
  width: 100%;
  min-height: 44px;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 12px;
  padding: 6px 9px;
  background: rgba(255, 255, 255, 0.07);
  color: rgba(245, 247, 255, 0.96);
  text-align: left;
  cursor: pointer;
  font: 800 13px/1.15 var(--access-lock-font);
  letter-spacing: 0;
}

.access-lock-user-option:hover,
.access-lock-user-option:focus {
  border-color: rgba(105, 203, 255, 0.56);
  background: rgba(105, 203, 255, 0.11);
  outline: none;
}

/* Z_BUSINESS_POPUP_FIELDS_SHARE_PASSWORD_WIDTH_2026-09-30 (Codex196):
   Business and the dock sheet load this shell stylesheet as their live
   shared surface. The password field is capped at 336px, so keep Username in
   that same field column instead of letting the borrowed selector stretch to
   the full wide modal. */
.z-access-username-password-area {
  width: min(336px, 100%) !important;
  max-width: min(336px, 100%) !important;
}

.access-lock-user-avatar {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(105, 203, 255, 0.16);
  color: rgba(245, 247, 255, 0.96);
  font: 900 11px/1 var(--access-lock-font);
}

.access-lock-user-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.access-lock-user-empty {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  padding: 12px;
  color: rgba(245, 247, 255, 0.58);
  font: 700 12px/1.2 var(--access-lock-font);
}

.access-lock-selected-user {
  width: 100%;
  min-height: 42px;
  box-sizing: border-box;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  border: 1px solid rgba(105, 203, 255, 0.42);
  border-radius: 12px;
  padding: 7px 9px 7px 12px;
  background: rgba(7, 10, 18, 0.52);
}

.access-lock-selected-user[hidden],
.access-lock-user-search-area[hidden] {
  display: none !important;
}

.access-lock-selected-user-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: rgba(245, 247, 255, 0.96);
  font: 900 13px/1.2 var(--access-lock-font);
}

.access-lock-user-change {
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 10px;
  padding: 8px 10px;
  background: rgba(255, 255, 255, 0.08);
  color: rgba(245, 247, 255, 0.88);
  font: 900 11px/1 var(--access-lock-font);
  cursor: pointer;
}

.access-lock-user-change:focus,
.access-lock-user-change:hover {
  border-color: rgba(105, 203, 255, 0.56);
  outline: none;
}

.access-lock-panel.access-lock-user-search-enabled:not(.access-lock-user-selected) .access-lock-display,
.access-lock-panel.access-lock-user-search-enabled:not(.access-lock-user-selected) .access-lock-keypad {
  display: none !important;
}

.access-lock-display {
  position: relative;
  display: grid;
  /* VISUAL_LOCKED_SURFACE_GUARD: passcode display is always six visible
     slots. Do not reduce this fallback or derive visible slots from the
     selected user's passcode length without express founder approval. */
  grid-template-columns: repeat(var(--access-lock-slot-count, 4), minmax(0, 1fr));
  gap: clamp(8px, 2.8vw, 12px);
  width: 100%;
  max-width: min(336px, calc(var(--access-lock-slot-count, 4) * 48px + 48px));
  justify-items: center;
  align-items: center;
  margin-inline: auto;
}

.access-lock-dot {
  width: clamp(32px, 9vw, 38px);
  height: clamp(32px, 9vw, 38px);
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.24);
  background: rgba(255, 255, 255, 0.08);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 242, 222, 0.96);
  font-size: clamp(15px, 4.8vw, 20px);
  font-weight: 800;
  letter-spacing: 0;
  line-height: 1;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
  transition:
    transform 0.12s ease,
    background 0.12s ease,
    border-color 0.12s ease,
    box-shadow 0.12s ease;
  -webkit-text-security: disc;
  overflow: hidden;
}

.access-lock-dot[data-state="filled"] {
  background:
    radial-gradient(circle at 50% 34%, rgba(236, 231, 255, 0.48) 0 15%, rgba(140, 100, 255, 0.38) 44%, rgba(40, 25, 70, 0.5) 100%);
  border-color: rgba(178, 154, 255, 0.48);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.12),
    inset 0 -8px 15px rgba(18, 11, 32, 0.22),
    0 0 0 4px rgba(140, 100, 255, 0.07),
    0 0 16px rgba(140, 100, 255, 0.18);
  transform: scale(1.06);
}

.access-lock-dot[data-state="revealed"],
.access-lock-dot[data-state="confirmed"] {
  background:
    radial-gradient(circle at 50% 34%, rgba(236, 231, 255, 0.42) 0 15%, rgba(140, 100, 255, 0.32) 44%, rgba(40, 25, 70, 0.44) 100%);
  border-color: rgba(178, 154, 255, 0.42);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.1),
    inset 0 -8px 15px rgba(18, 11, 32, 0.18),
    0 0 0 4px rgba(140, 100, 255, 0.06),
    0 0 16px rgba(140, 100, 255, 0.14);
}

.access-lock-error {
  min-height: 20px;
  color: #ff8d8d;
  font-size: 0.92em;
}

.access-lock-panel {
  position: relative;
}

/*
  Do not remove keypad input focusability. Mobile keyboard auto-popup depends on
  this input remaining focusable, enabled, measurable, and pointer-safe. The
  six visible slots are the only visible code-entry surface; this real input
  must stay visually hidden, not display:none/visibility:hidden/disabled/readonly.
*/
.access-lock-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
  padding: 0;
  opacity: 0.01;
  pointer-events: auto;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  font-size: var(--access-lock-key-font-size);
  font-weight: 700;
  letter-spacing: 0;
  text-align: center;
  transform: none;
  z-index: 3;
  -webkit-text-security: disc;
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  outline: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
}

.access-lock-input::placeholder {
  color: transparent;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  -webkit-text-security: none;
}

.access-lock-input:focus {
  outline: none;
}

.access-lock-panel:focus-within .access-lock-dot {
  border-color: rgba(178, 154, 255, 0.46);
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.18),
    0 0 0 3px rgba(140, 100, 255, 0.08);
}

.access-lock-input::selection,
.access-lock-input::-moz-selection {
  background: transparent;
  color: transparent;
}

.access-lock-keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  width: 100%;
  max-width: var(--access-lock-keypad-max-width);
  box-sizing: border-box;
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 0.18s ease,
    transform 0.18s ease;
}

.access-lock-keypad.access-lock-keypad-pending:not(.access-lock-keypad-ready) {
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
}

.access-lock-keypad.access-lock-keypad-ready {
  opacity: 1 !important;
  transform: translateY(0) !important;
  pointer-events: auto !important;
}

.access-lock-key {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 54px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.07);
  color: inherit;
  font-size: var(--access-lock-key-number-font-size);
  font-weight: 500;
  cursor: pointer;
  touch-action: manipulation;
  transition:
    background 0.08s ease,
    border-color 0.08s ease,
    transform 0.08s ease;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}

.access-lock-key-number {
  font-size: var(--access-lock-key-number-font-size);
  font-weight: 600;
  line-height: 1;
}

.access-lock-key-letters {
  display: block;
  min-height: 9px;
  margin-top: 3px;
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--access-lock-key-letter-font-size);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.08em;
  text-align: center;
}

.access-lock-key:hover:not(:disabled) {
  background: rgba(140, 100, 255, 0.12);
}

.access-lock-key:active:not(:disabled),
.access-lock-key.pressed:not(:disabled) {
  background: rgba(140, 100, 255, 0.18);
  border-color: rgba(178, 154, 255, 0.36);
  transform: scale(0.94);
}

.access-lock-key-del {
  font-size: var(--access-lock-delete-font-size);
}

.access-lock-key-spacer {
  visibility: hidden;
  pointer-events: none;
}

.access-lock-keypad.submitting .access-lock-key {
  opacity: 0.35;
  pointer-events: none;
}

.access-lock-auth-options {
  width: 100%;
  max-width: var(--access-lock-keypad-max-width);
  display: grid;
  gap: 8px;
  margin-top: 2px;
  font-family: var(--access-lock-font);
}

.access-lock-passkey {
  border: 1px solid rgba(255, 231, 190, 0.28);
  border-radius: 12px;
  padding: 9px 12px;
  background: rgba(255, 255, 255, 0.08);
  color: inherit;
  font: 800 11px/1.2 var(--access-lock-font);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
}
.access-lock-panel :where(button, [role="button"], input[type="submit"]) {
  white-space: nowrap;
}

.access-lock-passkey:disabled {
  cursor: default;
  opacity: 0.62;
}

.access-lock-auth-status {
  min-height: 16px;
  margin: 0;
  color: rgba(255, 242, 222, 0.68);
  font-size: 11px;
  line-height: 1.25;
}

/* P0 2026-06-28 white-boot regression guard:
 * when chat is locked, the lockscreen must never rely on a transparent
 * app shell or late JS style injection. Keep the approved lockscreen
 * gradient visible on first load; language controls belong in Tools only. */
/* SEAMLESS_SHARED_BG (2026-07-14 founder full-screen fix): the homepage/
   lockscreen must show the SAME seamless chat background as the real chat
   (IMG_9192) with NO top line and NO bottom line. Previously the lockscreen
   painted its OWN separate compound gradient box on html/body/#app/app-shell
   PLUS a second gradient on the overlay PLUS a dark ::before tint — those
   stacked boxes did not blend to the very top (thick top line) and did not
   cover the full dynamic viewport (bottom seam). Fix: paint ONE chat gradient
   at the html level, fixed to the viewport so it covers the ENTIRE dynamic
   viewport (incl. the top status area and the bottom safe area — no seam), and
   make every element above it transparent so there is no separate lockscreen
   background box. Color/look is the exact chat purple/blue->black fade; no new
   cyberpunk layers/overlays are added (founder rejected those). First-paint
   safety is preserved because html is painted synchronously (also inline in
   index.html <head>), never a transparent shell. Admin lock (no access-locked
   home view) reaches this ONLY via .app-shell.access-locked, same as before. */
html:has(.app-shell.access-locked),
html:has(.app-shell.z-authenticated-home-open) {
  /* RED_GLOW_ONLY (2026-07-14 founder, STEER-05, supersedes STEER-04): locked home shares
     the EXACT same single html painter as chat — a FLAT #0d0617 base (no top line, no blue
     bottom seam) PLUS ONLY the canonical red center glow. One clean painter, both views. */
  background:
    radial-gradient(circle at 48% 46%, rgba(255, 45, 85, 0.19), transparent 44%),
    #0d0617 !important;
  background-color: #0d0617 !important;
  background-repeat: no-repeat !important;
  background-size: cover !important;
  /* FULLBLEED (STEER-07): drop background-attachment:fixed (mobile-Safari full-bleed
     killer that mis-sizes/doesn't repaint on pinch-zoom, exposing boxes). Default scroll
     lets the root paint span the whole document box at every zoom. */
  background-attachment: scroll !important;
  background-position: center top !important;
  min-height: 100vh !important;
  min-height: -webkit-fill-available !important;
  min-height: 100dvh !important;
}
/* BLEED_FIX_FIXED_LAYER (2026-07-14 Claude-A, A2): same fixed backstop layer as the
   inline first-paint painter in index.html <head>, mirrored here so the locked-home
   view is covered even if this stylesheet loads/overrides after first paint. Additive;
   does not replace the html:has(...) rule above. */
html:has(.app-shell.access-locked)::before,
html:has(.app-shell.z-authenticated-home-open)::before {
  content: "" !important;
  position: fixed !important;
  inset: 0 !important;
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  width: 100vw !important;
  height: 100dvh !important;
  min-height: 100svh !important;
  min-height: -webkit-fill-available !important;
  margin: 0 !important;
  padding: 0 !important;
  z-index: -1 !important;
  pointer-events: none !important;
  background:
    radial-gradient(circle at 48% 46%, rgba(255, 45, 85, 0.19), transparent 44%),
    #0d0617 !important;
  background-repeat: no-repeat !important;
  background-size: cover !important;
  background-position: center top !important;
}
body:has(.app-shell.access-locked),
body:has(.app-shell.access-locked) #app,
body .app-shell.access-locked,
body .app-shell.access-locked .access-lock-overlay,
body:has(.app-shell.z-authenticated-home-open),
body:has(.app-shell.z-authenticated-home-open) #app,
body .app-shell.z-authenticated-home-open,
body .app-shell.z-authenticated-home-open .access-lock-overlay {
  background: transparent !important;
  background-color: transparent !important;
}
body .app-shell.access-locked .access-lock-overlay,
body .app-shell.z-authenticated-home-open .access-lock-overlay {
  color: #f8fafc !important;
}
body .app-shell.access-locked .access-lock-overlay::before,
body .app-shell.z-authenticated-home-open .access-lock-overlay::before {
  background: transparent !important;
}

@media (max-width: 760px) {
  .access-lock-panel {
    gap: 12px;
    background: transparent;
    box-shadow: none;
  }

  .access-lock-display,
  .access-lock-keypad {
    max-width: 100%;
  }
}

/* ============================================================================
   Z_HOME_LOCKSCREEN_SURFACES (2026-07-13): the main CHAT lockscreen shows the
   twelve Z World app surfaces first; tapping Chat reveals the existing
   user-list + passcode. Every rule below is scoped to
   .access-lock-overlay[data-z-home-view=...], an attribute set ONLY by the
   chat-surface code. The netbics/tiktoke admin lock never receives this
   attribute, so admin login (admin list) is completely unaffected.
   ========================================================================== */
.z-home-grid { display: none; }
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(3.5px, 0.8vh, 6.5px) clamp(4px, 2.2vw, 16px);
  justify-items: center;
  align-content: center;
  width: min(360px, 100%);
  /* TAGLINE_GAP_HALF_3 (2026-07-14 founder GO): tightened a bit more for a compact,
     balanced block (was clamp(2.5px,0.75vh,5.5px)). */
  margin: clamp(1px, 0.45vh, 3.5px) auto 0;
}
/* In grid view, hide the login controls (revealed on Chat tap). */
.access-lock-overlay[data-z-home-view="grid"] .access-lock-title,
.access-lock-overlay[data-z-home-view="grid"] .access-lock-body,
.access-lock-overlay[data-z-home-view="grid"] .access-lock-display,
.access-lock-overlay[data-z-home-view="grid"] .access-lock-keypad,
.access-lock-overlay[data-z-home-view="grid"] .access-lock-input,
.access-lock-overlay[data-z-home-view="grid"] [data-access-lock-user-selector] {
  display: none !important;
}
.z-home-grid .z-surface {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* LABEL_GAP_ZERO (2026-07-14 founder, STEER-03): founder says still too far —
     label must sit RIGHT under the icon, near touching. Flex-column gap dropped to
     0 (was clamp(1px,0.17vh,1.5px) -> before that ~1/3 -> ~1/2 originally). */
  gap: 0px;
  min-width: 0;
  color: #eef0f6;
  /* ICON_GLOW_NO_BOX (2026-07-14): the icon button is a bare, container-less,
     transparent, overflow-visible click target — no card/box/border/radius/
     shadow/fill/clip/mask can crop the PNG's baked transparent glow bleed. */
  background: none;
  background-color: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  overflow: visible;
  clip-path: none;
  -webkit-mask: none;
  mask: none;
  cursor: pointer;
  font: inherit;
  -webkit-tap-highlight-color: transparent;
}
.z-home-grid .z-surface-glyph {
  font-size: clamp(40px, 7.5vh, 66px);
  line-height: 1;
  /* GLOW_NO_HARD_EDGE (2026-07-14 founder): the earlier tight
     drop-shadow(0 0 12px) added a hard-ish cyan ring that stopped abruptly.
     The PNG already carries its OWN wide, soft glow that fades to nothing
     (alpha 0 at the canvas edge), so we drop the CSS shadow and let ONLY the
     PNG glow show — it fades smoothly to nothing on all four sides, no hard
     line. object-fit:contain renders the full soft-glow PNG. */
  filter: none;
  transition: transform 0.12s ease;
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  overflow: visible;
  clip-path: none;
  -webkit-mask: none;
  mask: none;
}
/* ==========================================================================
   Z_HIS_DESIGN_APP_MATCHES_THE_OTHERS_2026-09-11   (Agent 6F)
   ==========================================================================
   HIS WORDS: "update z design on all apps so its purple backgound like the other apps"
   HIS WORDS: "THE FUCKING CORNERED EDGES APP"
   HIS WORDS: "THEY ALLL HAVE CUREED FUCKING EDGES!!! FIXTHE MALLL NOW TO USE THE PROPER SIZE ALR USED"

   MEASURED, NOT GUESSED. I opened his own icon pictures side by side. Every other app is
   painted purple artwork with soft edges. Z Design alone is a flat blue line drawing with
   hard square corners and nothing behind it. That is the cornered-edges app he is pointing at.
   Both pictures are see-through behind the drawing, so a colour placed behind Z Design shows
   through and nothing is covered up.

   NOTHING HERE IS A NUMBER I CHOSE. The purple is his own purple. The corner is his own
   large-icon corner. Both are read from his own design so they can never drift from the
   rest of his site.

   THIS TOUCHES ONE APP AND NOTHING ELSE. It is tied to the design tile by name, so every
   other tile on every one of his names is byte-for-byte what it was. The soft-glow rule
   above is untouched for them - only this one, which has no glow to protect, is clipped
   so its corners can actually curve.

   PER-PART UNDO: delete this one block. Z Design goes straight back to how it looks now.
   ========================================================================== */
/* HIS NEWEST WORDS, and they beat the block above:
   "OMFGGG PRURLE HAS THE SAME FUCKING EDGES!!!!! !!S SETTTT EHHOMPAGE ICON EDGES NOWWWW"
   MEASURED FIRST, on his live home page, both sizes: all fifteen icons came back with NO
   curve at all - dead square. So this is not one app, it is every app, and the corner goes
   on every homepage icon. The size is HIS OWN large-icon corner, read from his own design.
   Z Design additionally gets his own purple behind it, which is his separate order:
   "update z design on all apps so its purple backgound like the other apps" */
/* MEASURED AGAIN WITH A PICTURE I OPENED: putting the corner on the drawing changed nothing,
   because the purple box he is pointing at is the TILE ITSELF, not the drawing inside it. The
   tile is what carries the purple and the square edges. So the corner goes on the tile. */
/* HIS LAW: "ALLL TEXT ON HOMEPAGES MUST BE FUCKING VISIBLE". MEASURED IN A PHONE PICTURE I
   OPENED: hiding what spills out of the tile was cutting the app names off. The curve does not
   need it - the tile's own colour curves on its own. So the hiding is gone and every name shows. */
.z-home-grid .z-surface {
  border-radius: var(--z-radius-icon-lg, 10px) !important;
}
.z-home-grid .z-surface-glyph {
  border-radius: var(--z-radius-icon-lg, 10px) !important;
}
/* THE ONE THAT ACTUALLY SHOWS. I opened his page and listed every layer inside one app:
   the purple square he sees IS THE PICTURE ITSELF, and the picture was the only thing still
   square. The boxes around it were already curved, which is why nothing looked different.
   His own icon corner goes on the picture. */
/* Z_HOME_APPS_ROUNDED_LIKE_THE_LAUNCHER_2026-09-23 (3/C other agent, Opus 5.5)
   HIS-WORDS 2026-09-23 1:5x PM EST:"make the ones on the home page match the corner rounding of the ones on the app on the launcher"
   and "Make it so they're all rounded the same way as the other ones" - on Z Home, Z World and Z Business, phone and computer.
   MEASURED LIVE 2:02-2:06 PM EST, signed in: launcher apps 10px on a 38px tile = 26.3 % of the tile (vector ones 27.8 %);
   dock apps 9px on 33px = 27.3 %; home apps 10px on a 109-112px picture = 8.9-9.2 % - the same 10px on a picture three times bigger.
   So the home picture takes the launcher tile's own share: his --z-radius-icon-lg (10px) over the 38px launcher tile, both read out of
   this file (the icon corner lines and .z-apptile--lg). A share, so it curves like a launcher app at every size, on every screen.
   FUCKUP-CHECK:"F01 F02 F03 - no new look, only this one corner; F17 - kept !important so his older rules cannot beat it;
   F27 F28 F30 - live pictures on phone and computer opened before any done; F33 - times read off a clock; F37 - only the corner he named"
   UNDO THIS PART ALONE: put "var(--z-radius-icon-lg, 10px)" back as the corner below and delete this comment. */
.z-home-grid .z-surface-glyph img,
.z-home-grid img.z-home-surface-img {
  border-radius: calc(100% * 10 / 38) !important;
  overflow: hidden !important;
}
/* Z_HIS_PURPLE_ICONS_TAKE_THE_OLD_SPACE_AND_ZOOM_LIKE_THE_DOCK_2026-09-13 (Fable 5.1) - WIDE SCREENS.
   The same rule as the phone block further down (same HIS-WORDS, same measurement: the old icons' drawing filled
   0.885 of its box; the dock grows 1.08 on hover). MEASURED live at 1280 wide before this: every icon read
   transform "none" - the earlier line lived only inside the phone-width block, so the desktop kept drawing the
   purple art edge to edge, right up against the app names. One size for every app, per the dock law (6F).
   UNDO THIS PART ALONE: delete this block. */
.z-home-grid .z-surface .z-home-surface-img {
  transform: scale(0.819) !important;
  transform-origin: center center !important;
  transition: transform var(--z-dur, 160ms) var(--z-ease, ease) !important;
}
.z-home-grid .z-surface:hover .z-home-surface-img,
.z-home-grid .z-surface:focus-visible .z-home-surface-img { transform: scale(0.885) !important; }
.z-home-grid .z-surface:active .z-home-surface-img { transform: scale(0.832) !important; }
/* Z_HIS_PURPLE_DESIGN_ICON_2026-09-13 (Fable 20x). HIS-WORDS:"LOOK AT THE DOCK ITEMS! THEYRE MADE BY USING A PURPLE BACKGROUND THAT GOT FADED. THEY WERE ALL JUST ICONS! MAKE THE PURPLE APP ICON FOR THE ZDSEISN. LOOK AT IT COMPARED TO THE OTHER ONES". Design now has a real purple icon (icons/purple/design.png, made the same way as the other fifteen), so every design-only number below now equals the shared ones (0.819 rest / 0.885 hover / 0.832 pressed) and its painted plate is transparent. UNDO THIS PART ALONE: restore _backups-claude/access-lock.css.before-fable20x-designicon-* */
.z-home-grid .z-surface[data-surface="design"] .z-surface-glyph img.z-home-surface-img,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"] .z-surface-glyph img.z-home-surface-img {
  transform: scale(0.819) !important;
  transition: transform var(--z-dur, 160ms) var(--z-ease, ease) !important;
}
.z-home-grid .z-surface[data-surface="design"]:hover .z-surface-glyph img.z-home-surface-img,
.z-home-grid .z-surface[data-surface="design"]:focus-visible .z-surface-glyph img.z-home-surface-img,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"]:hover .z-surface-glyph img.z-home-surface-img { transform: scale(0.885) !important; }
.z-home-grid .z-surface[data-surface="design"]:active .z-surface-glyph img.z-home-surface-img,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"]:active .z-surface-glyph img.z-home-surface-img { transform: scale(0.832) !important; }
/* Z_DESIGN_IS_AN_APP_LIKE_THE_OTHER_FIFTEEN_2026-09-11 (Agent 6F)
   HIS WORDS: "Z INDSUTRIES DOES NOT AHVE Z DESIGN IN A FUCKING APPP. ROUNDED EDGE ...
   ALLLL MEANS FUCKING ALLLLLL".
   WHY IT WAS NOT AN APP, MEASURED, NOT GUESSED: his own app-icon set has fifteen
   pictures and no Design. The other fifteen carry his plate baked into the picture, so
   they read as app icons. Design falls back to a plain line drawing with see-through
   corners, so it had no plate and no edge at all.
   MY EARLIER ATTEMPT PAINTED NOTHING: it asked for a colour name that is empty on his
   live page, which makes the whole line invalid, so the plate never appeared.
   THE COLOURS BELOW WERE READ OFF HIS OWN FOUR APP PICTURES, pixel by pixel, and were
   identical on all four. Nothing here is invented.
   THE SIZE IS HIS DOCK OWN SHARE: the plate is the same box as every other app, and the
   drawing sits inside it at the same share his dock uses. */
.z-home-grid .z-surface[data-surface="design"] .z-surface-glyph {
  background: transparent !important; /* the plate is baked into design.png now */
  border-radius: var(--z-radius-icon-lg, 10px) !important;
  overflow: hidden !important;
}
.z-home-grid .z-surface[data-surface="design"] .z-surface-glyph img.z-home-surface-img,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"] .z-surface-glyph img.z-home-surface-img {
  transform: scale(0.819) !important; /* Z_HIS_PURPLE_ICONS_TAKE_THE_OLD_SPACE_AND_ZOOM_LIKE_THE_DOCK_2026-09-13: rest = 0.60 / 1.08; hover is 0.60 (6F dock share). UNDO: 0.60 */
  transition: transform var(--z-dur, 160ms) var(--z-ease, ease) !important;
}
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"] .z-surface-glyph {
  background: transparent !important; /* the plate is baked into design.png now */
  border-radius: var(--z-radius-icon-lg, 10px) !important;
  overflow: hidden !important;
}

.z-home-grid .z-surface-label {
  font-size: clamp(12px, 1.9vh, 15px);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-align: center;
  white-space: nowrap;
  /* Desktop retains the original neutral label position. The tightened mobile
     icon-to-label spacing is applied only in the mobile breakpoint below. */
  line-height: 1;
  margin: 0;
  padding: 0;
}
.z-home-grid .z-surface[data-state="on"]:hover .z-surface-glyph { transform: scale(1.08); }
/* DISABLED_MODULES_CLICKABLE_EVERYWHERE (2026-07-15 founder: "disabled must be
   able to show popups everywhere, home page especially"). data-state="off" is
   the DISABLED state — keep it visually dimmed as the not-built cue, but it must
   still be tappable everywhere (lockscreen AND authenticated Home) so its popup
   fires. Only pointer-events + cursor change; the 0.28 dim stays. */
.z-home-grid .z-surface[data-state="off"] { opacity: 0.28; pointer-events: auto; cursor: pointer; }
.z-home-grid .z-surface[data-state="off"] .z-surface-glyph { filter: grayscale(0.7); }

/* AUTHENTICATED_HOME_OVERLAY_FORCE_VISIBLE (2026-07-15 founder: "tap Home while
   logged in and everything goes blank"). Verified via real login: tapping Home
   detaches Chat, but a stray async lock-sync inline-sets the overlay to
   display:none / visibility:hidden / z-index:-1 even though the authenticated-home
   class stays ON — leaving a blank page with 12 zero-size modules. The class is
   the correct "show Home" signal, so force the overlay + its panel + the module
   grid visible whenever it is present. The inline hide is NOT !important, so this
   wins. Logged-out lockscreen has no such class and is untouched. */
html body .app-shell.z-authenticated-home-open .access-lock-overlay,
html body .app-shell.z-authenticated-home-open .access-lock-overlay[hidden],
html body .app-shell.z-authenticated-home-open .access-lock-overlay.hidden {
  display: flex !important;
  visibility: visible !important;
  opacity: 1 !important;
  z-index: 2147482300 !important;
  pointer-events: auto !important;
}
.app-shell.z-authenticated-home-open .access-lock-overlay .access-lock-panel {
  display: flex !important;
  visibility: visible !important;
}
.app-shell.z-authenticated-home-open .access-lock-overlay[data-z-home-view="grid"] .z-home-grid {
  display: grid !important;
  visibility: visible !important;
}

/* Z-home intro: the orb identity block belongs to the Home grid state only.
 * Z_HOME_INTRO_GRID_ONLY_2026-07-27 (Claude/Sonnet5, founder-direct: the orb
 * + "I'm Z..." tagline are homepage elements and must never render on the
 * plain sign-in ("login") state reached from /chat, /voice, or any other
 * module route — founder caught this live). This selector used to match ANY
 * data-z-home-view presence (both "grid" and "login"), which is exactly why
 * the intro kept leaking onto the login/search screen for non-home routes.
 * Do not widen this back to a bare [data-z-home-view] presence check. */
.z-home-intro { display: none; }
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro {
  display: block;
  --z-home-copy-title-font-size: clamp(12px, 4vw, 17px);
  --z-home-copy-subtitle-font-size: clamp(10px, 2.5vw, 13px);
  text-align: center;
  /* COMPACT_BALANCE (2026-07-14 founder GO): tighten leading gap above the intro so the
     whole block is more compact/balanced (was 2px). */
  margin: 1px auto 0;
  max-width: 32ch;
}
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro-title {
  white-space: nowrap;
  font-size: var(--z-home-copy-title-font-size);
  font-weight: 700;
  letter-spacing: 0.2px;
  color: #f8fafc;
  font-family: var(--z-site-identity-font);
}
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro-body {
  margin-top: 2px;
  white-space: nowrap;
  font-size: var(--z-home-copy-subtitle-font-size);
  line-height: 1.3;
  color: rgba(224, 230, 244, 0.62);
  font-family: var(--access-lock-font);
}

/* Z_HOME_COPY_TRUE_CENTER_2026_07_17: the Home intro lines were text-aligned
   center but still drifted right on tablet/desktop because the shared intro
   wrapper stayed capped at 32ch while both nowrap lines were wider than that
   box. The text paint rect overflowed the centered box, so the text itself was
   not centered to the viewport even though the parent was. Fix the root cause
   by letting the shared intro size to its real content width (bounded by the
   viewport) and centering that block itself. Also neutralize the stale inline
   login duplicate's relative left/translate centering so, if that path is ever
   visible, it centers via the same symmetric layout rules at every width. */
/* Z_HOME_COPY_ENGINE_PROOF_CENTER_2026_07_17: fit-content + margin-inline/justify-self
   centered in Chromium but DRIFTED right in WebKit/Safari. Root-cause fix: full-width
   blocks + text-align:center only. text-align is rendered identically by every engine,
   so the copy is perfectly, symmetrically centered at every width in Safari too. */
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro {
  display: block !important;
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  margin-left: auto !important;
  margin-right: auto !important;
  padding-left: 12px;
  padding-right: 12px;
  text-align: center !important;
  box-sizing: border-box;
}
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro-title,
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro-body {
  display: block !important;
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  text-align: center !important;
  /* Z_HOME_COPY_SINGLE_LINE_FIT_2026_07_17: root cause of the ink-offset drift
     was NOT wrapping vs nowrap -- it was that the panel is fixed-width (~400px)
     below the 820px desktop breakpoint while the font-size clamp saturates at
     its max well before 820px, so single-line ink became wider than its box
     from ~500-819px viewport. Fix: keep nowrap (one line, per founder) and
     shrink the clamp MAX (below) so the longest single line always fits the
     narrowest pre-820 box with margin. */
  white-space: nowrap !important;
}
/* MOBILE_ONE_LINE_CENTER_2026-07-19 (founder: sub-tagline must stay ONE line, NEVER
   wrap to 2, centered with EQUAL distance to both screen edges). Keep nowrap; scale the
   font by viewport so the whole line always fits with margin; center it as a full-width,
   symmetric block so left/right gaps are always equal at every width. */
.access-lock-overlay[data-z-home-view="grid"] .z-home-intro-body {
  white-space: nowrap !important;
  width: 100% !important;
  max-width: 100% !important;
  margin-left: auto !important;
  margin-right: auto !important;
  text-align: center !important;
  font-size: clamp(6px, 2.15vw, 11px) !important;
  letter-spacing: 0 !important;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-z-tagline,
.access-lock-overlay[data-z-home-view="login"] .access-lock-z-subtagline {
  position: static !important;
  left: auto !important;
  right: auto !important;
  transform: none !important;
  display: block !important;
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  text-align: center !important;
}

/* The persistent copy keeps its established position; only the module region
 * below it swaps between the 12-surface grid and login/search content. */
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid {
  margin-top: 0;
}

/* Flatscreen-TV inline SVG glyph for the Watch surface. */
.z-home-grid .z-surface-glyph svg {
  display: block;
  width: 1em;
  height: 1em;
  color: #8fe6f4;
}

/* Mockup-sourced holographic PNG glyphs (2026-07-14).
   EQUAL_ORIGINAL_SIZE (2026-07-14 founder fix): every one of the 12 surface
   icons renders at ONE uniform square dimension (width == height, driven by the
   shared glyph em so it is identical for all 12 at each breakpoint). object-fit
   contain letterboxes each 1024x1024 PNG inside that square, so the full icon +
   its baked transparent glow bleed is always shown on all four sides and NEVER
   cropped, while all 12 stay exactly the same size (no per-icon variance, no
   grid shrink). Restored larger than the prior 1.32em shrink. overflow visible
   so the drop-shadow glow is never clipped. */
.z-home-grid .z-surface-glyph img.z-home-surface-img {
  display: block;
  width: auto;
  height: auto;
  min-width: 0;
  min-height: 0;
  max-width: none;
  max-height: none;
  flex: none;
  object-fit: contain;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  overflow: visible;
  clip-path: none;
  -webkit-mask: none;
  mask: none;
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none;
  /* HOME_ICON_FADE_IN (2026-07-14 Claude-A, founder pop-in fix): the slot is already a
     fixed 1.7em box (reserved above -> zero layout shift whether or not the PNG has
     loaded), so late-arriving icons never move the grid. This adds a short graceful
     fade so any icon that still finishes loading after paint fades in smoothly instead
     of hard-popping. Runs once on mount; opacity settles at 1. Reduced-motion honored
     below by disabling the animation (icon shows instantly at full opacity). */
  animation: zHomeIconFadeIn 180ms ease-out both;
}
@keyframes zHomeIconFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .z-home-grid .z-surface-glyph img.z-home-surface-img {
    animation: none;
    opacity: 1;
  }
}
/* DO NOT REMOVE, STRONG FOUNDER DO-NOT-REMOVE, can only be evolved by
   Z/ZActions -- Z_ANIMATIONS_SETTING_2026-07-17: the Settings > General >
   Animations toggle also covers this pre-existing Home icon fade, not just
   the new lockscreen one below -- it is a general animations kill switch. */
html.z-animations-disabled .z-home-grid .z-surface-glyph img.z-home-surface-img,
body.z-animations-disabled .z-home-grid .z-surface-glyph img.z-home-surface-img {
  animation: none;
  opacity: 1;
}
/* DO NOT REMOVE, STRONG FOUNDER DO-NOT-REMOVE, can only be evolved by
   Z/ZActions -- Z_LOCKSCREEN_FADE_IN_2026-07-17 (Claude/Sonnet5,
   founder-requested: "there's a light animation when I hit the back button
   from the lock (the modules fade in) -- put that similar one on the
   lockscreen when it comes in"). Same shape as zHomeIconFadeIn above
   (180ms ease-out, opacity 0->1) applied to the LOGIN/keypad panel instead
   of the Home grid icons, which already have their own fade. Scoped to
   data-z-home-view="login" only so it never double-fires alongside the
   Home grid's per-icon fade. Gated on .z-animations-disabled (the
   Settings > General > Animations toggle, chat-critical-bundle.js
   Z_ANIMATIONS_SETTING_2026-07-17) in addition to prefers-reduced-motion --
   both must be respected, do not drop either check. */
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel {
  animation: zLockscreenFadeIn 180ms ease-out both;
}
@keyframes zLockscreenFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
html.z-animations-disabled .access-lock-overlay[data-z-home-view="login"] .access-lock-panel,
body.z-animations-disabled .access-lock-overlay[data-z-home-view="login"] .access-lock-panel {
  animation: none;
  opacity: 1;
}
/* Defensive: guarantee overflow:visible on the ENTIRE icon ancestor chain so it
   is impossible for any ancestor to clip the glow (BUG 1). Additive; changes no
   layout/order. */
.access-lock-overlay[data-z-home-view="grid"],
.access-lock-overlay[data-z-home-view="grid"] .access-lock-panel,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface {
  overflow: visible;
}
/* GLOW_UNCLIP_APPSHELL (2026-07-14): the app shell + content shell set
   overflow:hidden in the chat style canon; on the lockscreen home view that
   was the REAL clipper of the icon glow (a fixed-descendant clip via the
   overlay's backdrop-filter containing block). Scope overflow:visible to the
   locked home shell ONLY so the glow can never be cut; chat/admin untouched. */
body .app-shell.access-locked,
body .app-shell.access-locked .app-content-shell,
body .app-shell.access-locked .access-lock-overlay,
body .app-shell.z-authenticated-home-open,
body .app-shell.z-authenticated-home-open .app-content-shell,
body .app-shell.z-authenticated-home-open .access-lock-overlay {
  overflow: visible !important;
}

/* TRUE_EQUAL_VISUAL_SIZE (2026-07-14 founder): a fixed em box does NOT make the
   12 icons look the same size because each PNG has a different content bounding
   box inside its 1024x1024 canvas (e.g. Mail's glyph is short/wide, Calendar's
   is tall). We normalize the VISIBLE glyph to an equal size by scaling each icon
   by the ratio of the median sqrt(INK pixels) to its own (STEER-06: perceived
   size tracks ink coverage, not bbox — mail is a sparse wireframe so it needs a
   bigger scale than the dense calendar). Pure transform:scale on the <img> (centered),
   no PNG bytes changed, no layout/order/color change. Applied to the <img> so
   the scaled result still object-fit:contains and the soft glow scales with it. */
@media (max-width: 819px) {
  /* Z_HIS_APP_NAMES_MUST_BE_READABLE_2026-09-11 (Agent 6F)
     HIS WORDS: "CANT SEE ANY TEXT". HIS OWN PHONE PICTURE showed every app name hidden
     behind the row of apps below it. The name was pulled UP into the picture above it by a
     negative top margin. It now sits under its own picture where it can be read. */
  /* Z_HOME_APPS_TAKE_THE_OLD_SPACE_AGAIN_2026-09-23 (3/C, Opus 5.5, session a5a29577)
     HIS-WORDS (2026-09-23, about 2:50 PM EST): "go find an old screenshot of the homepage from 1-2 months ago. find out
     exactly How many pixels in space at the old icon used to take up before I put the purple background on it? And make
     the purple app icons the exact same space" and (3:19 PM EST): "when these icons got bigger, it pushed the Z orb upwards".
     MEASURED off his own old screenshots, 1 Aug (390x844) and 11 Aug (430x932): the app rows sat 95 and 103 px apart, and
     on 2026-09-23 they sit 111 and 121 px apart. The old space per row was the picture box (1.65em) with the name pulled
     up by clamp(-16px, -1.8vh, -10px) - the 31 Aug rules in _backups-claude/access-lock.css.before-20260831-radarout -
     which gives exactly 95 and 103 on those two screens. The name's +4px (6F, above) made every row taller, and the
     taller block pushed the orb and the I'm Z line up the screen.
     NOW: the same space again. The pull-up is split, half on the picture and half on the name, so the name keeps a clear
     gap under the purple square and stays readable (his "CANT SEE ANY TEXT", 6F above). Half of clamp(-16px,-1.8vh,-10px)
     is clamp(-8px, -0.9vh, -5px), on each of the two.
     UNDO THIS PART ALONE: margin back to 4px 0 0 on the name, and drop the margin-top line from the picture. */
  .z-home-grid .z-surface-label {
    margin: clamp(-8px, -0.9vh, -5px) 0 0;
  }
  .z-home-grid .z-surface-glyph img.z-home-surface-img {
    width: 1.65em;
    height: 1.65em;
    min-width: 1.65em;
    min-height: 1.65em;
    margin-top: clamp(-8px, -0.9vh, -5px);
  }
  /* Z_HIS_DOCK_WAY_ALL_APPS_EQUAL_2026-09-11 (Agent 6F)
     HIS WORDS: "ALLLL APPS MUST BE EQUAL FFUCKNGIN SIZES / CHECK THE APP DOCKER AND
     FIND OUT HOW ALL ARE DONE THRE". MEASURED ON HIS OWN DOCK, LIVE: every dock app is
     one box, one corner, and the picture inside is the same share of that box for all
     of them. So every app here is ONE size too. The old per-app sizes are gone. */
  /* Z_HIS_PURPLE_ICONS_TAKE_THE_OLD_SPACE_AND_ZOOM_LIKE_THE_DOCK_2026-09-13 (Fable 5.1)
     HIS-WORDS: "finding the OLD SIZE OF THE ICONS ON THE HOMEPAGE, AND MAKING THE PURPLE CONS TAKE UP THAT SAME
     SPACE. THERYE WAY TOO CLSOE TO TEXT AND SHIT" and "MAKE SURE HOMEPAGEAPPS GET ZOOM IN LIKE DOCKS" and "the
     hover size becomes the normal size, the normal becomes slightly smaller by the same amount the dock grows on
     hover ... the exact same dock effect".
     MEASURED 2026-09-13 00:5x EST off his own picture files, not guessed: the old icons' drawing filled on average
     0.885 of its box (15 apps, 0.80 to 0.99); the purple ones fill 1.00 of it. One size for every app, per his dock
     law above (Agent 6F): the purple drawing at 0.885 of the box IS the old space. His dock grows 1.08 on hover
     (shell.css .z-dock__btn:hover) and presses to .94, so: rest 0.819 (= 0.885 / 1.08), hover and keyboard focus
     0.885, press 0.832 (= 0.885 x .94), with the dock's own timing. Design keeps its own 0.60 drawing (6F) and
     gets the same zoom on top of it.
     UNDO THIS PART ALONE: put back  .z-home-grid .z-surface .z-home-surface-img { transform: none !important; }  */
  /* Z_HOME_APPS_TAKE_THE_OLD_SPACE_AGAIN_2026-09-23 (3/C, Opus 5.5) - THE PURPLE SQUARE'S SIZE ON PHONES.
     MEASURED off the same two old screenshots: the old drawings were 60-69 px across on the 390 screen and 64-69 px on the
     430 screen (brightness 45 and 60), about 0.705 of the picture box as it shows there. The purple squares showed 73 and
     80 px at rest. His dock rule stays exactly as Fable 5.1 wrote it above ("the hover size becomes the normal size, the
     normal becomes slightly smaller by the same amount the dock grows on hover"): hover and keyboard focus 0.705 = the
     old drawing, rest 0.653 (= 0.705 / 1.08), press 0.663 (= 0.705 x .94). Design gets the same three numbers.
     UNDO THIS PART ALONE: in this phone block put 0.819, 0.885 and 0.832 back for 0.653, 0.705 and 0.663. */
  .z-home-grid .z-surface .z-home-surface-img {
    transform: scale(0.653) !important;
    transform-origin: center center !important;
    transition: transform var(--z-dur, 160ms) var(--z-ease, ease) !important;
  }
  .z-home-grid .z-surface:hover .z-home-surface-img,
  .z-home-grid .z-surface:focus-visible .z-home-surface-img { transform: scale(0.705) !important; }
  .z-home-grid .z-surface:active .z-home-surface-img { transform: scale(0.663) !important; }
  .z-home-grid .z-surface[data-surface="design"] .z-surface-glyph img.z-home-surface-img,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"] .z-surface-glyph img.z-home-surface-img {
    transform: scale(0.653) !important;
    transition: transform var(--z-dur, 160ms) var(--z-ease, ease) !important;
  }
  .z-home-grid .z-surface[data-surface="design"]:hover .z-surface-glyph img.z-home-surface-img,
  .z-home-grid .z-surface[data-surface="design"]:focus-visible .z-surface-glyph img.z-home-surface-img,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"]:hover .z-surface-glyph img.z-home-surface-img { transform: scale(0.705) !important; }
  .z-home-grid .z-surface[data-surface="design"]:active .z-surface-glyph img.z-home-surface-img,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="design"]:active .z-surface-glyph img.z-home-surface-img { transform: scale(0.663) !important; }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-state="off"] {
    opacity: 0.28;
  }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-state="off"] .z-surface-glyph {
    filter: grayscale(0.7);
  }
}

/* Z_HOME_APP_COLUMNS_AS_FAR_APART_AS_THE_ROWS_2026-09-23 (3/C other agent, Opus 5.5, session 5c5f5ae3), his order of 2026-09-23 4:02 PM EST:
   HIS-WORDS:"move the apps a little closer like the row the columns on the homepage move them so they They have the same distance apart from each other, width-wise, as they do height-wise. So it looks cleaner."
   HIS-WORDS:"But first, just move them together. And I'll see how it looks."
   MEASURED live before, signed in, his 15-app homepage on phones (apps apart across / down): 390 wide 103 / 95 ·
   414 wide 103 / 98 · 430 wide 111 / 103 · 360 wide 95 / 73.
   One row of apps is the picture box (1.65 of the drawing size) + the two half pull-ups + the name + the row gap -
   the same four numbers the phone rules above use. The grid is now three of those wide, less one column gap, so each
   column sits exactly one row apart on every phone. Nothing moves up or down.
   STYLE-SOURCE:"shared/z-shell/shell.css line 874 (drawing size), 1314 (picture box 1.65em), 1311 and 1318 (the two pull-ups), 1010 (name size), 829 (row gap and column gap)"
   Only his 15-app homepage (a grid holding 7 or more apps): Z World and Z Business set their own row gap and keep theirs.
   FUCKUP-CHECK:"F03 F22 F27 F30 - the spacing uses his own numbers, read off the lines above; pictures opened on four phone sizes before any claim"
   UNDO THIS PART ALONE: delete this block. */
@media (max-width: 760px) {
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid:has(> .z-surface:nth-child(7)) {
    width: min(100%, calc(3 * (1.65 * clamp(40px, 7.5vh, 66px) + 2 * clamp(-8px, -0.9vh, -5px) + clamp(12px, 1.9vh, 15px) + clamp(3.5px, 0.8vh, 6.5px)) - clamp(4px, 2.2vw, 16px)));
  }
}

/* Desktop remains centered. The requested recent downward adjustment belongs
   only to the mobile Home composition. */
.access-lock-overlay[data-z-home-view="grid"] .access-lock-panel {
  transform-origin: top center;
  transform: translateY(0);
}
/* Z_PUBLIC_ORB_MATCHES_ZHOME_MEASURED_2026-09-30 (Codex199): after the
   direct live revert showed the old public orb clipped at the viewport edge,
   restore the measured static offsets that place both public home orbs at the
   same visible level as Z Home on desktop and phone. */
/* Z_PUBLIC_ORB_FOLLOWS_ZHOME_AT_EVERY_HEIGHT_2026-09-30 (6/F as 3/C Controller, seat-cbc1b9ef).
   HIS WORDS: "the positions on homepage arent the same . I want you to go look at how the positions of the
   home page for the Z, uh, Z orb are set and then make sure it's positioned at the right place".
   MEASURED in private windows: Z Home centres its block, so its top moves with the window height
   (17 at 670 tall, 84 at 900, 174 at 1080); the fixed 66 matched Z Home at 900 tall alone.
   This follows Z Home's own top: proven equal at 1000x670, 1280x720, 1440x900, 1000x1000, 1920x1080, 1440x1200.
   UNDO: put back  transform: translateY(66px);  */
@media (min-width: 820px) {
  .access-lock-overlay[data-z-home-view="grid"][data-z-public-home="world"] .access-lock-panel,
  .access-lock-overlay[data-z-home-view="grid"][data-z-public-home="business"] .access-lock-panel {
    transform: translateY(calc(max((100vh - 733px) / 2, 27vh - 164px) - 20px));
  }
}
@media (max-width: 819px) {
  .access-lock-overlay[data-z-home-view="grid"] .access-lock-panel {
    transform: translateY(clamp(40px, 6vh, 60px));
  }
  .access-lock-overlay[data-z-home-view="grid"][data-z-public-home="world"] .access-lock-panel,
  .access-lock-overlay[data-z-home-view="grid"][data-z-public-home="business"] .access-lock-panel {
    transform: translateY(calc(clamp(40px, 6vh, 60px) - 10px));
  }
}
@media (max-width: 819px) and (max-height: 900px) {
  .access-lock-overlay[data-z-home-view="grid"] .access-lock-panel {
    transform: translateY(clamp(40px, 6vh, 60px)) scale(0.95);
  }
  .access-lock-overlay[data-z-home-view="grid"][data-z-public-home="world"] .access-lock-panel,
  .access-lock-overlay[data-z-home-view="grid"][data-z-public-home="business"] .access-lock-panel {
    transform: translateY(calc(clamp(40px, 6vh, 60px) - 10px)) scale(0.95);
  }
}

/* Back button under the user list — login view only. */
.z-home-back { display: none; }
.access-lock-overlay[data-z-home-view="login"] .z-home-back {
  display: inline-block;
  margin: 16px auto 0;
  border: 1px solid rgba(196, 181, 253, 0.35);
  border-radius: 10px;
  background: transparent;
  color: #cbd5e1;
  padding: 11px;
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
}
.access-lock-overlay[data-z-home-view="login"] .z-home-back:hover,
.access-lock-overlay[data-z-home-view="login"] .z-home-back:focus-visible {
  border-color: rgba(196, 181, 253, 0.6);
  outline: none;
}

/* Z_LOGIN_ACTIONS_MATCH_NODE_POPUP_2026-09-30 (Codex196): centered login
   actions reuse the Connect Device popup button family and keypad width. */
.access-lock-login-actions {
  display: flex;
  grid-column: 1 / -1;
  width: min(100%, 248px);
  gap: 9px;
  margin: 9px auto 0;
  box-sizing: border-box;
  align-self: center;
  justify-content: center;
}
.access-lock-login-actions button {
  min-width: 0;
  flex: 1 1 0;
  margin: 0;
}
.access-lock-login-back,
.access-lock-login-enter {
  text-align: center;
}
/* Z_LOGIN_PASSWORD_BUTTONS_UNDER_FIELD_2026-09-30 (Codex196): keep the dock
   Enter button and the page Back/Enter row directly beneath the password box. */
.access-lock-password-actions {
  display: flex;
  order: 3;
}
/* Z_BUSINESS_DOCK_SHARED_BACK_2026-09-30 (Codex199): the Business dock's
   Username + Password screen uses the same Back control as Z Home. */
[data-z-login-picker] .z-business-credential-actions .access-lock-login-back {
  display: inline-flex !important;
}
.access-lock-overlay[data-z-home-view="login"] [data-z-password-step="1"] ~ .z-home-back,
[data-z-login-picker] [data-z-password-step="1"] ~ .z-home-back,
[data-z-login-picker][data-z-password-step="true"] .z-home-back {
  display: none !important;
}

/* Desktop View A (5/4/3) on wide screens; the grid takes ~60% of the page. */
/* Z_HOME_LOGIN_HEADER_CENTERING (2026-07-14): the login view (after tapping
   Chat -> inline user + passcode) must keep the Z mark + selected-user name bar
   above the code input horizontally centered at EVERY width during continuous
   desktop resize. Force symmetric centering so no intrinsic sizing or leaked
   width can push the header off-center. Scoped to the chat home login view only;
   admin locks (no data-z-home-view) are untouched. */
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel {
  margin-inline: auto;
  align-items: center;
  text-align: center;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > * {
  align-self: center;
  margin-inline: auto;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-user-selector,
.access-lock-overlay[data-z-home-view="login"] .access-lock-selected-user,
.access-lock-overlay[data-z-home-view="login"] .access-lock-display,
.access-lock-overlay[data-z-home-view="login"] .access-lock-keypad {
  margin-inline: auto;
  justify-self: center;
}

/* Z_HOME_LOGIN_PAD_BELOW_TITLE_2026_07_16 (founder lockscreen fix): the shared
 * panel's DOM SOURCE order appends the passcode display + custom keypad BEFORE
 * the two "I'm Z" identity title lines (.z-home-intro) and the injected user
 * search / selected-user bar (.access-lock-user-selector, inserted right after
 * .z-home-intro). In the login flex column that rendered the pad ABOVE those
 * lines, so the instant a name is tapped — before ANY passcode key — the title
 * lines and search bar dropped BELOW the pad in Y. Re-stack the login column
 * VISUALLY ONLY (no DOM move, no change to the pad/keypad/display/back internals,
 * geometry, widths, or the shared identity nodes) so the identity lines and the
 * search / selected-user bar hold their intended top-of-login Y above the pad,
 * fully visible. Because `order` is unconditional in the login view it also
 * survives once passcode typing opens the OS keyboard (the keyboard-open rules
 * above only make the overlay scroll from flex-start; the top-anchored copy +
 * search stay above the pad and above the keyboard). The passcode input is
 * position:absolute (out of flow) and the Home grid is display:none in login, so
 * neither needs an order. Scoped to the chat login view only; admin locks (no
 * data-z-home-view) and the Home grid view are untouched. */
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > .access-lock-logo {
  order: 0;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > .z-home-intro {
  order: 1;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > .access-lock-user-selector {
  order: 2;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > .access-lock-display {
  order: 3;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > .access-lock-keypad {
  order: 4;
}
.access-lock-overlay[data-z-home-view="login"] .access-lock-panel > .z-home-back {
  order: 5;
}

@media (min-width: 820px) {
  .access-lock-overlay[data-z-home-view="grid"] {
    align-items: center;
    justify-content: center;
  }
  /* Z_THE_PANEL_MUST_FIT_THE_HOME_BLOCK_2026-09-04 (Agent E)
     HIS OWN EYES, with a screenshot: "WHEN Z INDUSTRIES DESKTOP gets resized, it loks weirds
     and isnt centered."
     MEASURED LIVE AT SIX WIDTHS BEFORE ONE CHARACTER CHANGED, every picture opened:
       fine at 1920 / 1600 / 1440 / 1280 - BROKEN at 1100 and 1000.
       The home block - orb, WELCOME TO Z INDUSTRIES, the six tiles - is 700.8px wide at EVERY
       window size, because its heading is nowrap and can never shrink. This panel was a flat
       sixty percent of the window: 768px at 1280 so the block fits and centres, but only
       600px at 1000 so it does not. A child wider than its parent starts at the parent's LEFT
       edge, so it hung 101px off the RIGHT. That is the entire fault.
     THE CHANGE: the old sixty-percent is kept wherever it is already big enough, and simply
     never drops below the width of the block it has to hold. 1280 and wider come out
     byte-identical to before. Under 820px never reached this rule and still does not - he
     said DESKTOP, so phones keep exactly what they have (M-070: never change the half he did
     not name).
     THE FIX I ALMOST SHIPPED INSTEAD: capping the block at the panel's width. By the numbers
     it centres perfectly - my own check printed CENTRED - and THE PICTURE SHOWED IT CHOPPED
     THE HEADING: "Z INDUSTRIE", the S gone, and "intelligenc" cut. The picture beat the
     numbers. Never cap the block; give it the room.
     REVERT THIS PART ALONE: set both lines below back to sixty percent of the window and
     delete this note. */
  .access-lock-overlay[data-z-home-view="grid"] .access-lock-panel {
    width: min(96vw, max(60vw, 720px));
    max-width: min(96vw, max(60vw, 720px));
    margin-inline: auto;
    align-items: center;
    text-align: center;
  }
  .access-lock-overlay[data-z-home-view="grid"] .access-lock-panel > * {
    align-self: center;
    margin-inline: auto;
  }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro-title,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro-body {
    text-align: center;
    margin-inline: auto;
  }
  .access-lock-overlay[data-z-home-view] .access-lock-logo,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro {
    position: relative;
    top: -10px;
  }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid {
    width: 100%;
    max-width: 100%;
    grid-template-columns: repeat(10, minmax(0, 1fr));
    row-gap: clamp(8px, 2.25vh, 20px);
    column-gap: clamp(10px, 1.2vw, 20px);
    justify-content: center;
    justify-items: center;
  }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface-glyph img.z-home-surface-img {
    width: auto;
    height: min(1.7em, calc(12vw - 8px));
    min-width: 0;
    min-height: 0;
    transform: scale(0.819) !important; /* Z_HIS_PURPLE_ICONS_TAKE_THE_OLD_SPACE_AND_ZOOM_LIKE_THE_DOCK_2026-09-13 (Fable 5.1): this heavier wide-screen rule was the one winning on a desktop (measured live at 1280: every icon read none). Same measured size as the blocks above; the hover/press pair follows this block. UNDO: transform: none !important; */
    transition: transform var(--z-dur, 160ms) var(--z-ease, ease) !important;
  }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface:hover .z-surface-glyph img.z-home-surface-img,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface:focus-visible .z-surface-glyph img.z-home-surface-img { transform: scale(0.885) !important; }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface:active .z-surface-glyph img.z-home-surface-img { transform: scale(0.832) !important; }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-state="on"]:hover .z-surface-glyph {
    transform: none;
  }
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface { grid-column: auto / span 2; }
  /* NEW FINAL Desktop View A (2026-07-14): rows 5 / 4 / 3. DOM source order is
     reordered PER BREAKPOINT by JS (matchMedia) so DOM order == visual order ==
     a11y/tab order at every breakpoint (NO CSS `order` remap that would desync
     the screen reader / tab sequence). Explicit columns pin every row so the
     grid stays symmetric/centered at EVERY width (continuous resize).
       Row1: MAIL DRIVE CALENDAR MAPS HEALTH  (auto span-2 fills all 10 cols)
       Row2: FOOD PROJECTS DOCS/NOTES GALLERY  (cols 2-9, centered)
       Row3: CHAT VOICE WATCH                  (cols 3-8, centered) */
  /* 15 items / 3 rows = 5-per-row exactly (span-2 x5 = 10 cols), every row
     auto-fills edge-to-edge -- no explicit grid-column overrides needed. */
}

/* DESKTOP_VIEWPORT_CENTER_LOCK (2026-07-14 founder): keep the Home identity
   copy and the login user-search control centered against the browser viewport
   through continuous desktop resizing.  The overlay owns the full viewport;
   its grid/login panels and the two requested content blocks then use symmetric
   auto margins. A desktop window can be resized below the layout breakpoint,
   so fine-pointer/hover desktop input keeps this lock at every width. Coarse-
   pointer mobile remains on the existing mobile geometry. */
@media (min-width: 820px), (any-hover: hover) and (any-pointer: fine) {
  .access-lock-overlay[data-z-home-view="grid"],
  .access-lock-overlay[data-z-home-view="login"] {
    inset: 0 !important;
    width: 100vw !important;
    max-width: 100vw !important;
    margin: 0 !important;
    box-sizing: border-box;
    justify-content: center !important;
  }

  .access-lock-overlay[data-z-home-view="grid"] .access-lock-panel,
  .access-lock-overlay[data-z-home-view="login"] .access-lock-panel {
    left: auto !important;
    right: auto !important;
    margin-inline: auto !important;
  }

  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro {
    width: fit-content;
    min-width: 0;
    max-width: calc(100vw - 36px);
    margin-inline: auto !important;
    text-align: center;
  }

  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro-title,
  .access-lock-overlay[data-z-home-view="grid"] .z-home-intro-body {
    width: fit-content;
    min-width: 0;
    max-width: 100%;
    margin-inline: auto !important;
    text-align: center;
  }

  .access-lock-overlay[data-z-home-view="login"] .access-lock-user-selector {
    width: min(340px, calc(100vw - 36px));
    max-width: min(340px, calc(100vw - 36px));
    min-width: 0;
    margin-inline: auto !important;
    justify-self: center;
    align-self: center;
    text-align: center;
  }

  .access-lock-overlay[data-z-home-view="login"] .access-lock-user-search-area,
  .access-lock-overlay[data-z-home-view="login"] .access-lock-user-search-input {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    margin-inline: auto !important;
    box-sizing: border-box;
    justify-self: stretch;
  }

  .access-lock-overlay[data-z-home-view="login"] .access-lock-z-tagline,
  .access-lock-overlay[data-z-home-view="login"] .access-lock-z-subtagline {
    width: fit-content;
    min-width: 0;
    max-width: calc(100vw - 36px);
    margin-inline: auto !important;
    justify-self: center;
    text-align: center !important;
  }
}

/* MOBILE_HOME_USER_SEARCH_KEYBOARD_LOCK (2026-07-14 founder): the Home login
   search field and at least two complete user rows must stay inside the real
   visual viewport while the software keyboard is open. iOS keeps a larger
   layout viewport behind the reduced visual viewport, so generic fixed/flex
   centering can leave the search/results underneath the keyboard. The shared
   viewport owner already publishes --mobile-visual-vh / offset-top and toggles
   mobile-keyboard-open; consume that current truth here instead of guessing a
   keyboard height. This is login-only and mobile-only: Home grid geometry and
   continuous fine-pointer desktop centering are untouched. */
@media (max-width: 700px) {
  html.mobile-keyboard-open .access-lock-overlay[data-z-home-view="login"],
  body.mobile-keyboard-open .access-lock-overlay[data-z-home-view="login"] {
    inset: var(--spyder-viewport-offset-top, 0px) 0 auto 0 !important;
    width: var(--visual-vw, 100vw) !important;
    height: var(--mobile-visual-vh, var(--visual-vh, 100dvh)) !important;
    min-height: 0 !important;
    max-height: var(--mobile-visual-vh, var(--visual-vh, 100dvh)) !important;
    padding-top: max(32px, calc(env(safe-area-inset-top, 0px) + 20px)) !important;
    padding-bottom: 10px !important;
    align-items: flex-start !important;
    justify-content: center !important;
    overflow-x: hidden !important;
    overflow-y: auto !important;
    overflow-anchor: none !important;
    overscroll-behavior-y: contain;
    -webkit-overflow-scrolling: touch;
  }

  html.mobile-keyboard-open .access-lock-overlay[data-z-home-view="login"] .access-lock-panel,
  body.mobile-keyboard-open .access-lock-overlay[data-z-home-view="login"] .access-lock-panel {
    transform: none !important;
    margin-block: 0 !important;
    overflow-anchor: none !important;
  }

  html.mobile-keyboard-open .access-lock-overlay[data-z-home-view="login"] .access-lock-user-list,
  body.mobile-keyboard-open .access-lock-overlay[data-z-home-view="login"] .access-lock-user-list {
    max-height: clamp(106px, calc(var(--mobile-visual-vh, var(--visual-vh, 100dvh)) - 350px), 156px);
    scroll-padding-block: 2px;
  }
}

/* Move on focus immediately for real coarse-pointer phones, before the first
   visualViewport resize/class-toggle frame arrives. This prevents a visible
   down-then-up jump as the keyboard opens. */
@media (max-width: 700px) and (any-pointer: coarse) {
  .access-lock-overlay[data-z-home-view="login"]:has(.access-lock-user-search-input:focus) {
    inset: var(--spyder-viewport-offset-top, 0px) 0 auto 0 !important;
    width: var(--visual-vw, 100vw) !important;
    height: var(--mobile-visual-vh, var(--visual-vh, 100dvh)) !important;
    min-height: 0 !important;
    max-height: var(--mobile-visual-vh, var(--visual-vh, 100dvh)) !important;
    padding-top: max(32px, calc(env(safe-area-inset-top, 0px) + 20px)) !important;
    padding-bottom: 10px !important;
    align-items: flex-start !important;
    justify-content: center !important;
    overflow-x: hidden !important;
    overflow-y: auto !important;
    overflow-anchor: none !important;
    overscroll-behavior-y: contain;
    -webkit-overflow-scrolling: touch;
  }

  .access-lock-overlay[data-z-home-view="login"]:has(.access-lock-user-search-input:focus) .access-lock-panel {
    transform: none !important;
    margin-block: 0 !important;
    overflow-anchor: none !important;
  }

  .access-lock-overlay[data-z-home-view="login"]:has(.access-lock-user-search-input:focus) .access-lock-user-list {
    max-height: clamp(106px, calc(var(--mobile-visual-vh, var(--visual-vh, 100dvh)) - 350px), 156px);
    scroll-padding-block: 2px;
  }
}

/* =====================================================================
   SHARED DARK CYBERPUNK BACKGROUND (2026-07-14, R6 shared-bg task)
   ---------------------------------------------------------------------
   ONE shared background layer, loaded ONCE from the chat page shell via
   this stylesheet (linked from face/deploy/index.html). It sits behind
   the lockscreen homepage AND all 12 surfaces/modules — no per-module
   background duplication. Painted as a fixed #app::before at z-index:-1
   so it renders ABOVE #app's deep near-black base (#0d0617) but BEHIND
   every surface/module in normal flow. Additive only; removes nothing
   and touches no module logic.

   Visual oracle: reference/target-homepage-reference.png
     deep near-black base + subtle cyan holographic depth + faint panel
     seams + soft center glow / edge vignette.
   Static first: NO per-icon timers, NO animation. (Any future motion
   MUST honor prefers-reduced-motion and pause on hidden tab.)
   ===================================================================== */

/* HOME_MOTION_LIFECYCLE_OWNER_2026_07_15: scoped to the active public Home/lockscreen. */
html[data-z-home-surface-active][data-z-home-motion-paused] body *,
html[data-z-home-surface-active][data-z-home-motion-paused] body *::before,
html[data-z-home-surface-active][data-z-home-motion-paused] body *::after {
  animation-play-state: paused !important;
  transition: none !important;
}
html[data-z-home-surface-active][data-z-home-motion-paused] body,
html[data-z-home-surface-active][data-z-home-motion-paused] body::before,
html[data-z-home-surface-active][data-z-home-motion-paused] body::after {
  animation-play-state: paused !important;
  transition: none !important;
}
@media (prefers-reduced-motion: reduce) {
  html[data-z-home-surface-active] body,
  html[data-z-home-surface-active] body::before,
  html[data-z-home-surface-active] body::after,
  html[data-z-home-surface-active] body *,
  html[data-z-home-surface-active] body *::before,
  html[data-z-home-surface-active] body *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* HOME_MOBILE_VIEWPORT_COMPOSITION_2026_07_16:
 * Keep the Z and its two copy lines in their established parent geometry.
 * Only the 3x4 Home module grid gets a uniform visual 0.9 scale, anchored at
 * its existing top edge, so the Z/copy-to-grid distance is preserved while
 * short Chrome mobile viewports gain bottom clearance. No individual module,
 * icon equalization, order, label, or hit target changes here. */
@media (max-width: 819px) {
  .access-lock-overlay[data-z-home-view="grid"] .z-home-grid {
    transform: scale(0.9);
    transform-origin: top center;
  }
}

/* LOGIN_USER_TEXT_LEFT_ONLY (2026-07-16): do not move the user-list/card,
 * avatar, controls, hit area, spacing, or grid. This intentionally changes
 * only text alignment on the name node within login/search result rows. */
.access-lock-overlay[data-z-home-view="login"] .access-lock-user-list .access-lock-user-name {
  text-align: left;
}

.access-lock-overlay[data-z-home-view] .access-lock-logo::after {
  border-color: rgba(140, 100, 255, 0.78);
  box-shadow:
    0 0 14px rgba(140, 100, 255, 0.55),
    0 0 26px rgba(140, 100, 255, 0.28),
    inset 0 0 12px rgba(140, 100, 255, 0.18);
}

/* DO NOT REMOVE -- Z_HOME_LOGO_ALWAYS_SPIN_2026-07-17 (Claude/Sonnet5,
 * founder-reported, root-caused live, strong founder DO-NOT-REMOVE, can only
 * be evolved by Z). This block used to be `animation: none` on mobile,
 * killing the rotating triangle/iris layers on the big Home Z specifically
 * on narrow viewports (a 2026-07-16 battery/perf choice). Founder explicitly
 * overrode this 2026-07-17: "make it spin like all other Z logos" -- so the
 * mobile-only stop is removed. Do not reintroduce animation:none here
 * without a new explicit founder instruction (this is a deliberate reversal
 * of the 2026-07-16 behavior, not an oversight). */


/* Z_CHAT_ON_Z_HOME_IS_ALWAYS_ON_2026-09-11 (Agent 6F)
   HIS WORDS: "Chat on z home is always on: never dimmed". His own greying code stamps
   data-z-greyed on the tiles of his two public names, so this rule cannot touch those -
   they stay greyed exactly as he asked before. On Z Home, Chat is never dimmed. */
.z-home-grid .z-surface[data-surface="chat"]:not([data-z-greyed]),
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="chat"]:not([data-z-greyed]) {
  opacity: 1 !important;
}
.z-home-grid .z-surface[data-surface="chat"]:not([data-z-greyed]) .z-surface-glyph,
.access-lock-overlay[data-z-home-view="grid"] .z-home-grid .z-surface[data-surface="chat"]:not([data-z-greyed]) .z-surface-glyph {
  filter: none !important;
}

/* Z node connection flow: static geometry only. The modal is an overlay and
   never reserves space or moves the underlying page. */
.z-node-connect-popup {
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(2, 2, 6, 0.55);
}

.z-node-connect-popup.is-open {
  display: flex;
}

.z-node-modal {
  border: 1px solid rgba(196, 181, 253, 0.28);
  border-radius: 16px;
  background:
    linear-gradient(135deg, rgba(12, 10, 18, 0.98), rgba(20, 15, 34, 0.94)),
    linear-gradient(180deg, rgba(45, 225, 255, 0.06), rgba(255, 65, 221, 0.06));
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.04) inset,
    0 0 28px rgba(45, 225, 255, 0.16),
    0 22px 54px rgba(0, 0, 0, 0.58);
  color: #cbd5e1;
  max-width: 360px;
  width: calc(100% - 40px);
  max-height: calc(100% - 40px);
  overflow-y: auto;
  padding: 20px 18px;
}

.z-node-modal[hidden] {
  display: none !important;
}

.z-node-modal h2,
.z-node-modal h3,
.z-node-modal p {
  margin-top: 0;
}

.z-node-modal h2 {
  color: #f8fafc;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
  margin-bottom: 8px;
}

.z-node-modal p {
  color: #cbd5e1;
  font-size: 13px;
  line-height: 1.4;
  text-align: center;
  margin-bottom: 16px;
}

.z-node-choice-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  margin: 16px 0 0;
}

.z-node-choice {
  min-height: 92px;
  padding: 13px;
  border: 1px solid rgba(196, 181, 253, 0.28);
  border-radius: 10px;
  background: transparent;
  color: #cbd5e1;
  cursor: pointer;
  text-align: left;
}

.z-node-choice:hover,
.z-node-choice:focus-visible {
  border-color: rgba(196, 181, 253, 0.55);
  outline: none;
}

.z-node-choice.is-selected {
  border-color: #8b5cf6;
  background: rgba(139, 92, 246, 0.16);
  box-shadow: inset 0 0 0 1px rgba(139, 92, 246, 0.34);
}

.z-node-choice strong,
.z-node-choice small {
  display: block;
}

.z-node-choice small {
  margin-top: 7px;
  color: #cbd5e1;
  line-height: 1.35;
}

.z-node-modal-actions {
  display: flex;
  gap: 9px;
  margin-top: 16px;
}

.z-node-modal-actions button,
.z-node-secondary-action,
.z-node-connect-primary {
  border: 1px solid rgba(196, 181, 253, 0.35);
  background: transparent;
  color: #cbd5e1;
  cursor: pointer;
  flex: 1;
  padding: 11px;
  border-radius: 10px;
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
}

.z-node-modal-actions button:hover,
.z-node-modal-actions button:focus-visible,
.z-node-secondary-action:hover,
.z-node-secondary-action:focus-visible,
.z-node-connect-primary:hover,
.z-node-connect-primary:focus-visible {
  border-color: rgba(196, 181, 253, 0.6);
  outline: none;
}

/* the row rule above is stronger than a bare class, so the main button's own look never landed.
   Naming it inside the row makes the set family's filled main button actually show. */
.z-node-modal-actions button.z-node-connect-primary,
.z-node-connect-primary {
  border-color: #8b5cf6;
  background: #8b5cf6;
  color: #fff;
  font-weight: 600;
}

.z-node-device-select {
  width: 100%;
  min-height: 40px;
  margin-top: 7px;
  padding: 8px 10px;
  border: 1px solid rgba(196, 181, 253, 0.35);
  border-radius: 9px;
  background: rgba(12, 10, 18, 0.9);
  color: #cbd5e1;
  font: inherit;
}

@media (max-width: 520px) {
  .z-node-connect-popup {
    padding: 12px;
  }

  .z-node-modal {
    padding: 18px 16px;
  }

  .z-node-choice-grid {
    grid-template-columns: 1fr;
  }

  .z-node-modal-actions {
    flex-direction: column-reverse;
  }

  .z-node-modal-actions button {
    width: 100%;
  }
}

/* ---- his colour settings (was /shared/z-shell/tokens.css) ---- */
/* Z World Shell — design tokens
   Single source of truth. Every colour, radius, space, shadow, z-index and
   timing used by shell.css lives here. Override any of these on :root (or on
   [data-z-shell]) from the host page; nothing else needs patching.

   RADIUS SPEC
   -----------
   --z-radius        24px  universal — windows, dock slab, modals, popovers
   --z-radius-inner  16px  inner chrome — tiles, cards, list rows
   --z-radius-ctl    10px  controls — menu items, buttons, inputs
   --z-radius-chip    8px  smallest chrome — checkboxes, badges, ticks
   --z-radius-pill   999px pills only
   Nothing else. Do not introduce new radius values.
*/

:root {
  /* ---- Base palette ------------------------------------------------ */
  --z-bg:               #0d0617;
  --z-bg-deep:          #06040c;
  --z-bg-raise:         #111218;
  --z-bg-panel-a:       rgba(20, 14, 36, 0.97);
  --z-bg-panel-b:       rgba(10, 7, 20, 0.97);
  --z-bg-window:        rgba(17, 18, 24, 0.88);
  --z-bg-inset:         rgba(4, 6, 12, 0.70);
  --z-bg-scrim:         rgba(6, 4, 12, 0.60);

  --z-violet-900:       #4c1d95;
  --z-violet-700:       #6d28d9;
  --z-violet-600:       #7c3aed;
  --z-violet-500:       #a855f7;
  --z-violet-300:       #c4b5fd;
  --z-violet-200:       #e9d5ff;
  --z-cyan-300:         #7dd3fc;
  --z-cyan-400:         #2de1ff;

  --z-text:             #f8fafc;
  --z-text-2:           #e8e8ea;
  --z-text-3:           rgba(176, 198, 224, 0.68);
  --z-text-4:           rgba(176, 198, 224, 0.50);

  --z-line:             rgba(196, 181, 253, 0.16);
  --z-line-strong:      rgba(196, 181, 253, 0.40);
  --z-line-hairline:    rgba(255, 255, 255, 0.06);

  /* Traffic lights */
  --z-tl-close:         #ff5f57;
  --z-tl-min:           #febc2e;
  --z-tl-max:           #28c840;

  /* Z_HIS_BADGES_ARE_PURPLE_NOT_RED_2026-09-02 (Assistant A)
     HIS ROW, his words: "Homepage badges must be purple not red".
     It was #ff2d55, which is red. This file already has a house way of saying
     "make it purple" - --z-running and --z-suggest both point at the violet
     scale rather than naming a colour - so this follows that, and no new colour
     is invented. MEASURED FIRST: var(--z-badge) is used in exactly ONE place,
     .z-dock__badge in shell.css:383, so nothing else can change with it.
     REVERT THIS ALONE: put back  --z-badge:            #ff2d55; */
  --z-badge:            var(--z-violet-500);
  --z-running:          var(--z-violet-500);

  /* ---- Suggestion accent (the old #41f4a7) ------------------------- *
   * Ships violet. Green only appears if the host opts in with
   * <html data-z-flag-green="1">. #41f4a7 exists nowhere else.        */
  --z-suggest:          var(--z-violet-300);
  --z-suggest-bg:       rgba(196, 181, 253, 0.14);
  --z-suggest-border:   rgba(196, 181, 253, 0.42);

  /* ---- App-tile artwork shell -------------------------------------- */
  --z-tile-art:         linear-gradient(155deg, #a06bf5 0%, #7b3fe4 46%, #4c1d95 100%);
  --z-tile-art-inner:   inset 0 1px 0 rgba(255, 255, 255, 0.28),
                        inset 0 0 0 1px rgba(196, 181, 253, 0.22);

  /* ---- Surfaces / gradients ---------------------------------------- */
  --z-grad-dock:        linear-gradient(104deg, rgba(34,22,60,0.80) 0%, rgba(16,10,30,0.72) 62%, rgba(8,5,16,0.90) 100%);
  --z-grad-panel:       linear-gradient(180deg, var(--z-bg-panel-a), var(--z-bg-panel-b));
  --z-grad-titlebar:    linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0));
  --z-grad-hover:       linear-gradient(90deg, rgba(45,225,255,0.16), rgba(196,181,253,0.16));
  --z-grad-cta:         linear-gradient(90deg, rgba(124,58,237,0.50), rgba(168,85,247,0.40));

  /* ---- Radius (spec above) ----------------------------------------- */
  --z-radius:           24px;
  --z-radius-inner:     16px;
  --z-radius-ctl:       10px;
  --z-radius-chip:      8px;
  --z-radius-pill:      999px;
  /* Icon art corner: 26% of the icon box, per size */
  --z-radius-icon-lg:   10px;  /* 38px art */
  --z-radius-icon-md:    9px;  /* 33px art */
  --z-radius-icon-sm:    5px;  /* 19px art */

  /* ---- Spacing ----------------------------------------------------- */
  --z-space-1:          2px;
  --z-space-2:          4px;
  --z-space-3:          6px;
  --z-space-4:          8px;
  --z-space-5:          10px;
  --z-space-6:          12px;
  --z-space-7:          16px;
  --z-space-8:          20px;
  --z-space-9:          28px;
  --z-space-10:         40px;

  /* ---- Sizes ------------------------------------------------------- */
  --z-dock-slot:        40px;
  /* Z_HIS_ONE_GLOBAL_ICON_SIZE_2026-09-11 (Agent 6F). HIS WORDS: "make ALL app icons that
     size (dock, homepage, etc). ANYWHERE PURPLE ICONS EXIST, THEY ALLLL MATCH THAT SIZE ...
     1 GLOBAL ICON SIZE ... PUT IT OOOCNE IN OOOCNE PALCE, TEHN POITN ALLLLLLLL PLACES WHERE
     THEYRE USED TO IT" and "whcihevr ones closer to a multiple of 3/6/9".
   MEASURED on his own live pages first: dock 40 box holding 24 art, launcher big 38 holding
   23, launcher medium 33 holding 20, home app 82.5 holding 82.5. Of all of those 24 is the
   only clean multiple (3x8, 6x4), and 36 is the only nearby number that is 3 AND 6 AND 9.
   THIS IS THE ONE PLACE. Everywhere else points here.
   UNDO THIS PART ALONE: delete these two lines and put the old numbers back. */
  --z-app-icon-box:     36px;
  --z-app-icon-art:     24px;
  --z-dock-icon:        33px;
  --z-dock-gap:         9px;
  --z-dock-inset:       -22px;   /* slab bleeds off the right edge */
  --z-dock-hidden:      -96px;
  --z-hit:              44px;    /* minimum touch target */
  --z-tl:               13px;    /* traffic light diameter */
  --z-menubar-h:        39px;

  /* ---- Z_THE_SIZE_IS_IN_THE_PICTURES_NOW_2026-08-31 (Assistant C) --------
     FOUNDER: "You can edit the biggest icon files so theyre all identical
     sizes, and then regenerate the smaller sizes from that. That way no code or
     script does resizing matchinng" - and, asked directly on 2026-08-31, "Make
     the smaller ones BIGGER by editing the core files".
     DONE. The fifteen big picture files were edited so the drawing inside each
     one is the same size, and the small copies were rebuilt from them. Nothing
     was shrunk: Mail's drawing grew about 25 per cent, Learn 27, Voice 18, Game
     18, Office 16, Chat 15, and Calendar - already the biggest - was left
     untouched. Backup of all 283 files before the edit:
       core/swarm/evolve/_backups-claude/icons-before-normalise-20260831-102122
     SO THE FIFTEEN NUMBERS THAT USED TO LIVE HERE ARE GONE, and so is the rule
     in shell.css that applied them. No code resizes a picture any more, which
     is exactly what he asked for.
     THE ONE HONEST GAP: Mail and Voice are wide flat drawings that already
     nearly fill their own square, so they could not grow the whole way. Mail
     ends about 14 per cent short of Calendar and Voice about 13. Closing that
     needs the artwork redrawn taller, not code.
     REVERT: the backup above puts every picture back, and shell.css names the
     rule to restore. */

  /* ---- Shadows ----------------------------------------------------- */
  --z-shadow-window:    0 24px 80px rgba(10, 8, 18, 0.45);
  --z-shadow-panel:     0 22px 50px rgba(0, 0, 0, 0.62);
  --z-shadow-pop:       0 12px 30px rgba(0, 0, 0, 0.50);
  --z-shadow-dock:      0 0 0 1px rgba(255,255,255,0.05), -14px 14px 36px rgba(0,0,0,0.55);
  --z-shadow-icon:      drop-shadow(0 5px 12px rgba(0, 0, 0, 0.55));
  --z-glow-halo-lo:     0 0 12px rgba(140,100,255,0.42), 0 0 22px rgba(140,100,255,0.22);
  --z-glow-halo-hi:     0 0 22px rgba(140,100,255,0.62), 0 0 44px rgba(140,100,255,0.34);

  /* ---- Z-index ladder ---------------------------------------------- */
  --z-layer-desktop:    1;
  --z-layer-header:     40;
  /* Z_DOCK_SITS_ABOVE_APPS_2026-08-31 (Assistant C, founder-direct).
     FOUNDER: "keep the dock ONTOP of the apps (z-index) always".
     MEASURED: the dock was 46 and windows are 56 and can climb to 71, so every
     window sat OVER the dock - the opposite of his rule. 72 is the first free
     rung above the window ceiling and still below everything that must cover
     the dock: on-top windows, the menu bar, menus, scrims, popups and prompts.
     Nothing else on the ladder moves.
     REVERT: put --z-layer-dock back to 46. */
  --z-layer-dock:       72;
  --z-layer-window:     56;   /* + stack offset, max +15 */
  --z-layer-ontop:      74;
  --z-layer-menubar:    80;
  --z-layer-menu:       84;
  --z-layer-submenu:    86;
  /* Z_A_SLIDE_OVER_PANEL_HAS_ITS_OWN_RUNG_2026-09-01 (Assistant A). Founder:
     "the chat slideout goes UNDER the z-index of the top page. i TOLD u to use
     the zindex fucking leedger when building". The This-chat panel had a raw
     number and no rung here, which is exactly what the ledger exists to stop.
     A slide-over panel covers the page and everything an app draws on it,
     including the app's own menu bar, and sits below a modal's dim. */
  --z-layer-slideover:  98;
  --z-layer-scrim:      100;
  --z-layer-modal:      110;
  --z-layer-prompt:     142;

  /* =====================================================================
     THE ONE Z-INDEX LEDGER FOR THE WHOLE WEBSITE
     Z_ONE_LAYER_LEDGER_2026-08-31   (written by Assistant B on his order)
     =====================================================================
     FOUNDER, 2026-08-31, word for word:
       "For the website, make sure z index things have ONE ledger where they're
        all written ... Should contain everything from the pages, apps, windows,
        menus, keyboards, settings, etc. The layers should be known & understood,
        never butting heads or breakng the rule, and z indexes should never
        randomly be set. EVERY element gets one and EVERY elment gets a placing
        for z index, so its never randomly assigned."

     THE RULE, FOR EVERY AGENT AND EVERY FILE:
       1. No element gets a raw z-index number ever again. It uses a token below.
       2. If a thing has no token yet, its token is ADDED HERE FIRST, in the
          right place on the ladder, and only then used.
       3. Nothing is squeezed between two rungs with a decimal or a +1. If two
          things need to be apart, the ladder gets a new rung here.
       4. Read this before changing anything visual. It is the whole picture.

     WHY THERE ARE TWO FLOORS, AND WHY THAT IS NOT A CONTRADICTION.
     Layers only compete inside the same stacking context. The page lives inside
     #app, and the shell furniture lives inside #z-shell, which are siblings.
     A number on the page floor can never beat a number on the shell floor, no
     matter how big it is. That is why settings once lost to the dock at 72.
     So there are two ladders, and the floor is chosen first, the rung second.

     ---- FLOOR ONE: things drawn inside the page (#app) -------------------
       --z-layer-desktop    1     the page itself
       --z-layer-header    40     a page's own top bar
       --z-layer-window    56     an app window (+ its stack offset, max +15)
       --z-layer-dock      72     the dock, above every app window
       --z-layer-ontop     74     a window kept on top
       --z-layer-menubar   80     an app's menu bar
       --z-layer-menu      84     an open menu
       --z-layer-submenu   86     a menu inside a menu
       --z-layer-slideover 98     a panel that slides over the whole page
       --z-layer-scrim    100     the dim behind a modal
       --z-layer-modal    110     a modal
       --z-layer-prompt   142     a prompt on top of a modal

     ---- FLOOR TWO: the shell overlay, above the whole page --------------
     Everything here sits above every page. The numbers are large on purpose:
     they were chosen long ago to clear anything a page could ever use. */
  --z-shell-root:        2147481500;  /* #z-shell itself, and the dock inside it */
  --z-shell-page-over:   2147481600;  /* a page lifted over the shell on purpose */
  --z-shell-zdesign:     2147482000;  /* the two zDesign menus */
  --z-shell-keyboard-tray: 2147482700; /* the keyboard button and the gamepad */
  --z-shell-keyboard:    2147482800;  /* the on-screen keyboard itself */
  --z-shell-settings:    2147482900;  /* settings - ABOVE the dock and the
                                         keyboard and the gamepad tabs, on his
                                         direct order of 2026-08-31 */
  --z-shell-launcher:    2147482950;  /* the open / add to dock sheet */
  --z-shell-itemmenu:    2147482990;  /* the catcher behind a dock item menu */
  --z-shell-itemmenu-top: 2147482991; /* a dock item's own right-click menu */

  /* ---- WHAT IS STILL UNPLACED, so nobody guesses --------------------
     Nothing on this list may be given a number until it is added above.
     Everything measured on 2026-08-31 is placed. When a new part appears -
     a watch face, a tv screen, an ar layer - it gets its rung here first. */

  /* ---- Motion ------------------------------------------------------ */
  --z-dur-fast:         120ms;
  --z-dur:              180ms;
  --z-dur-slow:         240ms;
  --z-dur-genie-out:    300ms;
  --z-dur-genie-in:     340ms;
  --z-ease:             cubic-bezier(0.32, 0.72, 0, 1);
  --z-ease-out:         cubic-bezier(0.25, 1, 0.40, 1);
  --z-ease-in:          cubic-bezier(0.50, 0, 0.75, 0);
  --z-halo-cycle:       3.2s;

  /* ---- Type -------------------------------------------------------- */
  --z-font:             "Z Space Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --z-font-mono:        "Z JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --z-fs-body:          15px;
  --z-fs-ui:            12.5px;
  --z-fs-small:         11px;
  --z-fs-mono:          10.5px;
}

/* Opt-in green. Off by default — #41f4a7 does not ship unless this is set. */
[data-z-flag-green="1"] {
  --z-suggest:        #41f4a7;
  --z-suggest-bg:     rgba(65, 244, 167, 0.16);
  --z-suggest-border: rgba(65, 244, 167, 0.42);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --z-dur-fast: 1ms; --z-dur: 1ms; --z-dur-slow: 1ms;
    --z-dur-genie-out: 1ms; --z-dur-genie-in: 1ms;
  }
}

/* ---- the main one ---- */
/* ============================================================================
 * !!!!!  CHECK THE APPMENU, AND DETAILS+OPTIONS 3 DOTS ARE STILL WORKING
 *        PERFECTLY  !!!!!
 * ----------------------------------------------------------------------------
 * FOUNDER ORDER, 2026-09-03, word for word:
 *   "APPMENU, DETAILS + 3 DOTS OPTIONS ARE NOT THERE ONLOAD!!!!!!!! I TOLD YOU
 *    TO CONNECT IT FULLY TO THE DOCK & HOW IT LOADS... ITS FUCKING EASY TO CHECK
 *    THE WINDOW STATE (WINDOWED, FILL SCREEN, ETC) AND KEEEP IT LOCKED TO THE
 *    SIDE OF THE APP ALWAYS. INSIDE & OUT FIX THIS... DO NOT EVER LET IT GET
 *    BROKEN AGAIN."  and: "Fix it permanently. Permanently means fix it and dont
 *    fucking touch it again, and ANY / ALL things / files / parts that touch
 *    anything it's connected to gets a hard note on it."
 *
 * THIS FILE TOUCHES THAT CHAIN. BEFORE YOU EDIT IT, AND AGAIN AFTER:
 *   1. Cold-load the app's OWN address in a fresh private window, signed in.
 *   2. The app menu bar .z-bar[data-z-pagebar] must be on screen no later than
 *      the dock [data-z-dock].
 *   3. The options + 3 dots [data-z-chat-tabs] must be on screen no later than
 *      the dock, and pinned to THAT app's own side in EVERY window state
 *      (data-z-page-app-windowed / -minimised / data-z-pagebar-on).
 *   4. Open the picture from that same run and LOOK at it. No picture = UNVERIFIED.
 * One cause, three symptoms - they all read #z-shell data-z-server-auth.
 * He has said this 50+ times. It is one of the most consistent faults in the
 * project. If your change cannot prove all three above, DO NOT SHIP IT.
 * ========================================================================== */
/* Z_FONTS_NEVER_SWAP_IN_LATE_2026-08-31 (Assistant B)
   FOUNDER, 2026-08-31: "The fucking settings font in the app loaded with font and
   then the real one applied... NEVER EVER EEEVER LOAD FONTS. FONTS ARE
   PRELOADADED AT THE BEGINNING OF ENTERING THE WEBSITE AND ALL FONTS ADHERE TO
   THE RIGHT ONES."
   MEASURED, not guessed: both faces below said font-display: swap, which means
   "draw in some other font first, then change it once mine arrives" - that IS
   the change he saw. And the served page carried ZERO font preloads, so the file
   was only discovered after this stylesheet had been read.
   TWO PARTS: the head of the page now preloads both files (face/home/deploy/
   index.html), and swap becomes block, which means never draw the wrong font -
   wait the few milliseconds and draw the right one.
   REVERT THIS PART ALONE: put both back to font-display: swap and take the two
   preload lines out of the page head. */
/* Z World Shell — stylesheet
   Every value comes from tokens.css. No !important anywhere: the host page's
   own CSS can still win where it needs to. All selectors are namespaced .z-*
   or [data-z-*], so nothing leaks into host styles.
*/

/* ---------------------------------------------------------------- fonts */
@font-face {
  font-family: "Z Space Grotesk";
  src: url("fonts/space-grotesk-latin.woff2") format("woff2");
  font-weight: 300 700; font-style: normal; font-display: block;
}
@font-face {
  font-family: "Z JetBrains Mono";
  src: url("fonts/jetbrains-mono-latin.woff2") format("woff2");
  font-weight: 100 800; font-style: normal; font-display: block;
}

/* ------------------------------------------------------------- keyframes */
@keyframes z-halo {
  0%, 100% { box-shadow: var(--z-glow-halo-lo); }
  50%      { box-shadow: var(--z-glow-halo-hi); }
}
@keyframes z-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes z-drop {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes z-genie-out {
  0%   { opacity: 1;    transform: translate(0,0) scale(1) skewY(0deg); filter: blur(0); }
  55%  { opacity: .85;  transform: translate(calc(var(--z-gx) * .55), calc(var(--z-gy) * .55)) scale(.44,.3) skewY(4deg); filter: blur(.6px); }
  100% { opacity: 0;    transform: translate(var(--z-gx), var(--z-gy)) scale(.05,.02) skewY(9deg); filter: blur(2px); }
}
@keyframes z-genie-in {
  0%   { opacity: 0;   transform: translate(var(--z-gx), var(--z-gy)) scale(.05,.02) skewY(9deg); filter: blur(2px); }
  45%  { opacity: .9;  transform: translate(calc(var(--z-gx) * .45), calc(var(--z-gy) * .45)) scale(.5,.36) skewY(-3deg); filter: blur(.5px); }
  100% { opacity: 1;   transform: translate(0,0) scale(1) skewY(0deg); filter: blur(0); }
}

/* ----------------------------------------------------------------- shell */
/* ==========================================================================
   Z_THE_GLOW_MOVES_WITH_THE_PAGE_2026-09-02   (Assistant B)
   ==========================================================================
   FOUNDER, 2026-09-02: "the slide out menu from the left on every app is
   supposed to push the entire page, but it only pushes the element to the page
   because the background, it stays completely still... make sure that when all
   apps slide out, that it pushes the background as well"

   MEASURED, NOT GUESSED. The glow is centred at 48% of the WINDOW. With his
   side menu out on a 1280 wide screen the part he can actually see runs from
   320 to 1280, so 48% of THAT is 780.8 - while the glow sits at 48% of 1280,
   which is 614.4. 166px adrift, and it never moves because nothing told it to.

   HIS 48% IS UNTOUCHED. It is now measured against the area he can see instead
   of the whole window, which is what he asked for. The whole shift is
   0.52 x the menu's own width - that is arithmetic from his own number, not a
   number I picked: 320 + 0.48x(1280-320) minus 0.48x1280 = 0.52x320.

   NOTHING NEW WAS INVENTED FOR THE SELECTOR OR THE WIDTH EITHER. This copies the
   rule the chat runtime already uses to shift the live worker view by the same
   menu - same body:has(.sidebar:not(.z-sidebar-collapsed)), same
   min(320px, 80vw), same @media (min-width: 860px). That media query matters:
   below it the menu FLOATS OVER the page instead of pushing it, so the glow
   must not move there, and measuring the slide-out at phone width once had me
   reporting a defect that was really a different design.

   IT IS SET ON html AND body BOTH, because the guard in chat-runtime.js paints
   this gradient onto both of them inline, and a variable only reaches downwards.

   WHY ONE VARIABLE AND NOT FOUR EDITS: that same centre was written out in FOUR
   separate places - chat-runtime.js, this file, and his index.html twice. They
   now all read one variable, so they cannot drift apart again.

   REVERT THIS PART ALONE: delete this block. The variable falls back to 0px
   everywhere and the glow stops moving, exactly as it was.
   ========================================================================== */
@media (min-width: 860px) {
  html:has(.sidebar:not(.z-sidebar-collapsed)),
  body:has(.sidebar:not(.z-sidebar-collapsed)) {
    --z-glow-shift: calc(min(320px, 80vw) * 0.52);
  }
}

[data-z-shell] {
  position: relative;
  min-height: 100dvh;
  overflow: hidden;
  background: radial-gradient(circle at calc(48% + var(--z-glow-shift, 0px)) 46%, rgba(255,45,85,.19), transparent 44%), var(--z-bg);
  color: var(--z-text-2);
  font-family: var(--z-font);
  font-size: var(--z-fs-body);
  -webkit-font-smoothing: antialiased;
}
[data-z-shell] *, [data-z-shell] *::before, [data-z-shell] *::after { box-sizing: border-box; }



[data-z-shell] button { font-family: inherit; }
[data-z-shell] a { color: var(--z-violet-300); text-decoration: none; }
[data-z-shell] a:hover { color: var(--z-violet-200); }

.z-mono { font-family: var(--z-font-mono); }
.z-cap {
  font-family: var(--z-font-mono);
  font-size: 9px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--z-text-4);
}

/* --------------------------------------------------------------- desktop */
.z-desktop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 100dvh;
  padding: 56px var(--z-space-7) var(--z-space-9);
}
.z-desktop__inner {
  width: 60vw; max-width: 60vw;
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.z-orb {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: clamp(84px, min(27vw, 30vh), 300px);
  height: clamp(84px, min(27vw, 30vh), 300px);
  margin: 0 auto var(--z-space-1);
  border-radius: var(--z-radius-pill);
  background: radial-gradient(circle at 50% 50%, rgba(40,25,70,.52), rgba(10,6,22,.38) 66%, transparent);
  animation: z-halo var(--z-halo-cycle) cubic-bezier(.45,0,.55,1) infinite;
  pointer-events: none;
}
.z-orb img { display: block; width: 100%; height: 100%; object-fit: contain; }
.z-lede {
  font-family: var(--z-font-mono);
  font-size: clamp(12px, 4vw, 17px); font-weight: 700;
  color: var(--z-text); white-space: nowrap;
}
.z-sub {
  margin-top: var(--z-space-1);
  font-family: var(--z-font-mono);
  font-size: clamp(6px, 2.15vw, 11px); line-height: 1.3;
  color: rgba(224,230,244,.62); white-space: nowrap;
}
.z-grid {
  display: grid; grid-template-columns: repeat(10, minmax(0, 1fr));
  row-gap: clamp(8px, 2.25vh, 20px); column-gap: clamp(10px, 1.2vw, 20px);
  justify-items: center; width: 100%; margin-top: var(--z-space-2);
}
.z-tile {
  grid-column: auto / span 2;
  display: flex; flex-direction: column; align-items: center;
  min-width: 0; color: #eef0f6; background: none; border: 0; padding: 0;
  cursor: pointer;
}
.z-tile[data-z-ready="0"] { opacity: .28; }
.z-tile__art {
  display: block;
  width: min(1.7em, calc(12vw - 8px)); height: min(1.7em, calc(12vw - 8px));
  font-size: clamp(40px, 7.5vh, 66px);
  background-repeat: no-repeat; background-position: center; background-size: contain;
  animation: z-fade-in var(--z-dur) ease-out both;
}
.z-tile[data-z-ready="0"] .z-tile__art { filter: grayscale(.7); }
.z-tile__label {
  font-family: var(--z-font-mono);
  font-size: clamp(12px, 1.9vh, 15px); font-weight: 600; line-height: 1;
  white-space: nowrap;
}

/* ------------------------------------------------------------- app icons *
 * The artwork is a square raster. Rounding belongs on the ART, never on the
 * surrounding tile / button / cell.                                       */
/* Z_ONE_ICON_SET_2026-08-30 (Assistant C, founder-ordered).
   FOUNDER: "homepage is the icons. Dock is the icons ON the purple bg. The icons
   should be identical, and anywehre the icon appears onthe purple thing should all
   be identical ... Docks and everywhere PULL from the same set of icons"
   The picture is now the SAME one the homepage shows and the served page already
   preloads. The purple is drawn HERE, behind it, instead of being baked into a
   second shrunken copy. That is what makes the dock icon identical to the homepage
   icon and full size - his "the app icons look really fucking small" was the baked
   copies having the artwork shrunk inside their own padding.
   The treatment is the design's own --z-tile-art / --z-tile-art-inner from
   tokens.css, which were defined and had never been used anywhere.
   REVERT: delete this block and set Z_ONE_ICON_SET = false in shell.js. */
.z-appicon {
  display: block;
  object-fit: contain;
  border-radius: var(--z-radius-icon-lg);
  background: var(--z-tile-art);
  box-shadow: var(--z-tile-art-inner);
  filter: var(--z-shadow-icon);
}
.z-appicon--md { border-radius: var(--z-radius-icon-md); }
.z-appicon--md { width: var(--z-dock-icon); height: var(--z-dock-icon); border-radius: var(--z-radius-icon-md); }
.z-appicon--sm { width: 19px; height: 19px; border-radius: var(--z-radius-icon-sm); }
.z-appicon--lg { width: 38px; height: 38px; }

/* ==========================================================================
 * Z_ICON_SIZE_IS_ONE_NUMBER_2026-08-31  (Assistant C, founder-ordered)
 *
 * FOUNDER: "YOU STILL NEVER DID THE FUCKING ICON SIZES!!!!!! I TOLD U TO MFIX
 * THEM AT THE CORE LEVEL SO ITS EQUAL/CONSISTENT ACROSS THE BOARD"
 *
 * The drawing inside each square is a different size, so without a correction
 * Mail (a wide flat envelope, 210 x 122 inside a 256 square) reads much
 * smaller than Gallery (216 x 200). His own correction existed but only ever
 * reached the home grid - the dock, window title bars, the launcher, the menus
 * and Add to Dock all drew the raw picture. That is what "not consistent
 * across the board" was.
 *
 * NOW: mark any app picture with the app's name and it is corrected, wherever
 * it is, forever. The numbers live once, in tokens.css. Nothing is applied by
 * script any more.
 *
 * THE PURPLE TILE MOVED OFF THE PICTURE. It used to be painted on the picture
 * itself, so making the drawing bigger would have made the purple square
 * bigger with it and Mail's tile would have stuck out past its neighbours.
 * The tile is now its own holder, the same shape .z-appshell already uses for
 * the vector apps, so the drawing can be corrected without touching it.
 *
 * REVERT, THIS PART ALONE: delete this block and set Z_ICON_ONE_NUMBER = false
 * in shell.js. The pictures then draw uncorrected again, as they do today
 * everywhere except the home grid.
 * ======================================================================== */

.z-apptile {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  border-radius: var(--z-radius-icon-lg);
  background: var(--z-tile-art);
  box-shadow: var(--z-tile-art-inner);
  filter: var(--z-shadow-icon);
  overflow: visible;   /* a corrected drawing may sit a hair proud - never clip */
}
.z-apptile--lg { width: 38px; height: 38px; }
.z-apptile--md {
  width: var(--z-dock-icon); height: var(--z-dock-icon);
  border-radius: var(--z-radius-icon-md);
}
.z-apptile--sm { width: 19px; height: 19px; border-radius: var(--z-radius-icon-sm); }
.z-apptile > img.z-appicon {
  width: 100%; height: 100%;
  background: none; box-shadow: none; filter: none;
  border-radius: inherit;
}
/* Z_THE_SIZE_IS_IN_THE_PICTURES_NOW_2026-08-31: the scale that used to sit here,
   and the one on the home grid picture, are BOTH GONE. The drawings themselves
   were made the same size, so nothing in code resizes a picture any longer -
   his own instruction. data-z-app stays on the pictures because it is how any
   surface says which app it is drawing, and the purple holder stays because the
   purple is a tile and the drawing is a drawing; they were never the same
   thing. REVERT: put back
     .z-apptile > img.z-appicon { transform: scale(var(--z-art-fix,1)); }
     img.z-home-surface-img[data-z-app] { transform: scale(var(--z-art-fix,1)); }
   and the fifteen [data-z-app="..."] lines that set --z-art-fix. */

/* Vector Z apps sit in the same shell as the raster artwork, so both rows of
   the picker read identically. app-shell.png is the real artwork's purple
   field, reconstructed from the icon set. */
.z-appshell {
  display: inline-flex; align-items: center; justify-content: center;
  background: url("icons/app-shell.png") center / cover no-repeat;
  border-radius: var(--z-radius-icon-lg);
}
/*Z_POINTS_AT_HIS_ONE_ICON_SIZE_2026-09-11*/.z-appshell--lg { width: var(--z-app-icon-box); height: var(--z-app-icon-box); }
.z-appshell--lg > svg, .z-appshell--lg > img { display: block; width: var(--z-app-icon-art); height: var(--z-app-icon-art); }
.z-appshell--md {
  width: var(--z-dock-icon); height: var(--z-dock-icon);
  border-radius: var(--z-radius-icon-md);
  filter: var(--z-shadow-icon);
}
.z-appshell--md > svg, .z-appshell--md > img { display: block; width: var(--z-app-icon-art); height: var(--z-app-icon-art); }

/* ------------------------------------------------------------------ dock */
.z-dockwrap {
  position: absolute; inset: 0 0 0 auto; z-index: var(--z-layer-dock);
  display: flex; align-items: center; justify-content: flex-end;
  padding: 72px 0;
  pointer-events: none;
}
.z-dockwrap[data-z-align="start"] { align-items: flex-start; }
.z-dock-edge { position: absolute; inset: 0 0 0 auto; width: var(--z-space-7); pointer-events: auto; }
.z-dock {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: var(--z-dock-gap);
  margin-right: var(--z-dock-inset);
  padding: 11px 30px 13px 11px;
  transition: margin-right var(--z-dur-slow) var(--z-ease), opacity var(--z-dur) ease;
  pointer-events: auto;
}
.z-dock[data-z-hidden="1"] { margin-right: var(--z-dock-hidden); opacity: 0; }
.z-dock__slab {
  position: absolute; inset: -4px 0; z-index: -1;
  border-radius: 26px 0 0 26px;
  background: var(--z-grad-dock);
  box-shadow: var(--z-shadow-dock);
  backdrop-filter: blur(20px);
}
.z-dock__orb {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: var(--z-radius-pill);
  background: radial-gradient(circle at 50% 50%, rgba(58,34,104,.6), rgba(10,6,22,.2) 70%, transparent);
  animation: z-halo var(--z-halo-cycle) cubic-bezier(.45,0,.55,1) infinite;
}
.z-dock__orb img { display: block; width: 34px; height: 34px; object-fit: contain; }
.z-dock__sep { width: 24px; height: 1px; background: rgba(196,181,253,.22); }
.z-dock__slot { position: relative; display: flex; align-items: center; justify-content: center; width: var(--z-dock-slot); height: var(--z-dock-slot); }
.z-dock__btn {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; padding: 0; border: 0;
  background: transparent; cursor: pointer;
  transform-origin: right center;
  transition: transform var(--z-dur) var(--z-ease);
  touch-action: none; -webkit-tap-highlight-color: transparent;
}
.z-dock__btn:hover { transform: scale(1.08); }
.z-dock__btn:active { transform: scale(.94); }
.z-dock__btn[data-z-holding="1"] { transform: scale(.86); transition-duration: 420ms; }
/* =========================================================================
   Z_NON_OPEN_DOCK_APPS_ARE_HALF_DIM_2026-09-03   (Agent E)
   =========================================================================
   HIS SPEC, word for word, in #1 HOME & ORB, APPS, DOCK, DASHBOARD-DOCK-MENU.MD:
     "Non-open Dock apps are half-dim."
   and in the very same paragraph, the rule that decides HOW it may be done:
     "No fake count, badge, chip, device, controller, or slot attribute is allowed."

   SO IT READS REAL STATE AND NOTHING ELSE. shell.js renderDock adds .z-dock__run
   to a slot ONLY when there is a genuinely open window for that app
   (if (d.running || win)). A slot without that dot is genuinely not open. No new
   attribute is invented, no script writes anything, and nothing is faked - this is
   a stylesheet rule reading a mark his own renderer already puts there from truth.

   IT DIMS THE ICON, NOT THE SLOT, so the open dot and the minimised flag keep their
   full strength when they do appear, and it cannot fight the drag rule further down
   which dims the SLOT at 0.45.
   REVERT THIS PART ALONE: delete this block.
   ========================================================================= */
.z-dock__slot:not(:has(.z-dock__run)) .z-dock__btn { opacity: .5; }
.z-dock__slot:not(:has(.z-dock__run)) .z-dock__btn:hover { opacity: 1; }
/* Z_THE_OPEN_DOT_IS_UNDER_THE_APP_AND_NOTHING_CLIPS_IT_2026-09-01  (Assistant A)
   FOUNDER, 2026-09-01: "you still HAVE NOT FIXED THE PURPLE GLOW. I HAVE NEVER
   SEEN MY OPEN APPS SHOW IT. FIX IT PROPERLY FFS! UNDER THE FUKCING APP O N THE
   DOCK! IT SHOWS CLEARLY THAT 2 APPS ARE OPEN CUZ DRIVE IS DIMMED, BUT OPENED
   ONES DONT SHOW THE DOT GLOW."

   HE IS RIGHT, AND HE COULD NEVER HAVE SEEN IT. The dot used to sit at
   right:-6px, six pixels OUTSIDE the slot on the right. The rail was later made
   scrollable, and that block's own note says why this kills it:
       "A box that scrolls one way clips the other way too - the browser gives
        you no choice."
   Room was added on the LEFT (padding-left:14px, margin-left:-14px) for the
   hover zoom, and none on the right. So overflow-x:hidden sliced the dot off
   every single time. MEASURED LIVE 2026-09-01: the dot's own centre point
   reported the dock underneath it, not the dot -- nothing was painted there.

   AND THE DIMMING STILL WORKED, which is exactly the half he could see: the
   dim rule only asks whether the dot EXISTS in the page, and it did.

   NOW IT IS UNDER THE APP, WHERE HE ASKED FOR IT. bottom:-4px drops it into the
   9px gap between slots, which is on the scroll axis and already has 6px of
   padding, so no clipping can ever reach it again.
   REVERT THIS PART ALONE: put back right:-6px / top:50% / margin-top:-2.5px. */
/* Z_THE_OPEN_DOT_TOUCHES_THE_WALL_2026-09-01 (Assistant A)
   Founder, 2026-09-01: "the purple open button is supposed to be on the right
   side of the app icon, not underneath. Make that so the purple button for an
   open icon is touching the wall, not in between the apps."
   It sat underneath because the rail used to slice anything past the tile's
   right edge. The rail now makes room on the right, so the dot goes back where
   he wants it: beside the icon, hard against the edge of the screen.
   REVERT THIS ALONE: put back left:50%; bottom:-4px; transform:translateX(-50%). */
.z-dock__run {
  position: absolute; right: -12px; top: 50%; left: auto; bottom: auto;
  width: 5px; height: 5px; margin: 0; transform: translateY(-50%);
  border-radius: var(--z-radius-pill);
  background: var(--z-running); box-shadow: 0 0 8px 1px rgba(168,85,247,.95);
  pointer-events: none;
}
.z-dock__flag {
  position: absolute; right: -3px; bottom: -3px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: var(--z-radius-chip);
  background: rgba(9,5,18,.94); box-shadow: 0 0 0 1px rgba(196,181,253,.32);
  color: var(--z-violet-300); pointer-events: none;
}
.z-dock__badge {
  position: absolute; top: -4px; left: -5px;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 var(--z-space-2);
  border-radius: var(--z-radius-pill);
  background: var(--z-badge); box-shadow: 0 0 0 1.5px rgba(9,5,18,.9);
  font-size: 10px; font-weight: 800; line-height: 1; color: #fff;
  pointer-events: none;
}
.z-tip {
  position: absolute; right: 48px; top: 50%; transform: translateY(-50%);
  padding: 5px var(--z-space-4);
  border: 1px solid rgba(196,181,253,.24); border-radius: var(--z-radius-ctl);
  background: rgba(12,8,24,.96); box-shadow: var(--z-shadow-pop);
  font-family: var(--z-font-mono); font-size: var(--z-fs-mono); font-weight: 700;
  color: var(--z-text-2); white-space: nowrap; pointer-events: none;
  animation: z-fade-in var(--z-dur-fast) ease-out both;
}
.z-dock__add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0; border: 0;
  border-radius: var(--z-radius-pill);
  background: transparent; color: rgba(196,181,253,.72); cursor: pointer;
}
.z-dock__add:hover { color: var(--z-violet-200); background: rgba(196,181,253,.12); }
/* =========================================================================
   Z_HE_IS_TOLD_WHEN_THE_CONNECTION_GOES_2026-09-03   (Agent D)
   HIS LAW: "if it cannot be reached, the screen says so and shows nothing."
   HIS TEST MATRIX, item 8 of 18: "offline/reconnect".
   HIS 532 DEVICE RECORDS: every one carries an offlinePolicy.

   ⛔ THIS IS NOT AN OFFLINE COPY OF THE SITE. ⛔
   Founder, 2026-08-26: "I NEVER ASKED YOU TO KEEP AN OFFLINE COPY OF ITSELF.
   REMOVE THE OFFLINE COPY." That order stands and nothing here stores one byte.
   This only TELLS HIM the connection is gone, so a message he types does not
   vanish without him knowing. A cold load with no internet still shows the
   browser's own page, and that is correct.

   THE POSITION IS NOT INVENTED. It is the exact place his own stylesheet
   already puts a site message - the .z-toast rule directly below this one:
   right 82px, bottom var(--z-space-9), beside the dock. Same offsets, same
   tokens, same look. `fixed` instead of `absolute` only so it does not have to
   live inside the dock's own box and so it can touch NOTHING that is already
   on the page - it takes no space in the layout and cannot clip a neighbour.

   IT SHIPS HIDDEN AND ONLY A MARKER TURNS IT ON. No script ever creates it,
   sizes it or places it - his hard rule. The script flips one attribute, the
   same way the boot shell already uses data-stage.

   REVERT THIS PART ALONE: delete this block and the matching block in
   shell.js. Nothing else refers to it.
   ========================================================================= */
.z-offline-notice {
  position: fixed; right: 82px;
  /* ⛔ LIFTED CLEAR OF HIS MESSAGE BOX, 2026-09-03. ⛔
     The first version sat at the toast's own bottom offset and the picture from
     the live run showed it sitting ON TOP OF his message box. His rule: nothing
     may overlap, and nothing sits over the page's own words. When two of his
     rules collide the stricter one wins, so it moves.
     THE LIFT IS NOT INVENTED EITHER. It is the exact expression his own dock
     already uses to stay clear of the message box, a few hundred lines below
     this: env(safe-area-inset-bottom) + var(--composer-height, 118px) + 18px
     + var(--z-kb-tray-space, 0px). Same tokens, same fallbacks. On a page with
     no message box --composer-height is unset and the fallback keeps it in the
     same corner, clear of the dock. */
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--composer-height, 118px) + 18px + var(--z-kb-tray-space, 0px) + var(--z-space-3, 10px));
  display: none;
  z-index: 70;
  max-width: min(360px, calc(100vw - 120px));
  padding: 9px 13px;
  border: 1px solid rgba(196,181,253,.26); border-radius: var(--z-radius-ctl);
  background: rgba(12,8,24,.94); box-shadow: var(--z-shadow-pop);
  font-family: var(--z-font-mono); font-size: var(--z-fs-mono); font-weight: 700;
  color: var(--z-violet-200);
  pointer-events: none;
}
html[data-z-offline] .z-offline-notice { display: block; }

.z-toast {
  position: absolute; right: 82px; bottom: var(--z-space-9);
  padding: 7px 11px;
  border: 1px solid rgba(196,181,253,.26); border-radius: var(--z-radius-ctl);
  background: rgba(12,8,24,.94); box-shadow: var(--z-shadow-pop);
  font-family: var(--z-font-mono); font-size: var(--z-fs-mono); font-weight: 700;
  color: var(--z-violet-200); white-space: nowrap;
  animation: z-fade-in var(--z-dur-fast) ease-out both;
}

/* ------------------------------------------------------------ popovers */
.z-pop {
  display: flex; flex-direction: column;
  padding: var(--z-space-3);
  border: 1px solid rgba(196,181,253,.2); border-radius: var(--z-radius);
  background: var(--z-grad-panel); box-shadow: var(--z-shadow-panel);
  backdrop-filter: blur(20px);
  animation: z-drop var(--z-dur-fast) ease-out both;
}
.z-pop--dock {
  position: absolute; right: 50px; top: 50%; transform: translateY(-50%);
  z-index: 6; min-width: 190px;
}
.z-row {
  display: flex; align-items: center; gap: var(--z-space-5);
  width: 100%; padding: 7px var(--z-space-5);
  border: 0; border-radius: var(--z-radius-ctl);
  background: transparent; color: var(--z-text-2);
  font-size: var(--z-fs-ui); font-weight: 600; text-align: left;
  white-space: nowrap; cursor: pointer;
}
.z-row:hover { background: var(--z-grad-hover); box-shadow: inset 0 0 14px rgba(45,225,255,.18); }
.z-row__ico { display: inline-flex; justify-content: center; width: 16px; color: var(--z-violet-300); }
.z-row__end { margin-left: auto; padding-left: var(--z-space-7); display: inline-flex; align-items: center; gap: var(--z-space-4); }
.z-row__tick { display: inline-flex; color: var(--z-suggest); }
.z-row__more { color: rgba(232,232,234,.5); font-size: 14px; line-height: 1; }
.z-sep { height: 1px; margin: 5px var(--z-space-4); background: var(--z-line); }

/* -------------------------------------------------------------- windows */
.z-win {
  position: absolute; z-index: var(--z-layer-window);
  /* Z_WINDOW_BUTTONS_CAN_BE_PRESSED_2026-08-31 (Assistant C).
     FOUNDER: "Make sure minimize, expand and close work".
     MEASURED LIVE, not guessed: the layer windows sit in is set to ignore
     clicks, so clicks fall through it to the page underneath. Every other
     layer in this file that does that turns clicks back on for its own
     children - the dock edge does it, the menu bar does it. The window never
     did, so its Minimize, Expand and Close were impossible to press. Pressing
     Close did nothing at all, which is exactly what a frozen window looks
     like. This is the same one-line pattern the rest of the file already
     uses.
     REVERT: delete this one line. */
  pointer-events: auto;
  display: flex; flex-direction: column;
  border: 1px solid rgba(255,255,255,.08); border-radius: var(--z-radius);
  background: var(--z-bg-window); box-shadow: var(--z-shadow-window);
  backdrop-filter: blur(16px);
  transform-origin: 100% 50%;
  animation: z-drop var(--z-dur) ease-out both;
  will-change: transform, opacity;
}
.z-win[data-z-mode="full"] { border: 0; border-radius: 0; }
.z-win[data-z-anim="out"] { animation: z-genie-out var(--z-dur-genie-out) var(--z-ease-in) both; }
.z-win[data-z-anim="in"]  { animation: z-genie-in  var(--z-dur-genie-in)  var(--z-ease-out) both; }
.z-win[data-z-min="1"] { display: none; }

.z-grip { position: absolute; z-index: 4; }
.z-grip--n  { left: var(--z-space-6); right: var(--z-space-6); top: -4px; height: 9px; cursor: ns-resize; }
.z-grip--s  { left: var(--z-space-6); right: var(--z-space-6); bottom: -4px; height: 9px; cursor: ns-resize; }
.z-grip--w  { top: var(--z-space-6); bottom: var(--z-space-6); left: -4px; width: 9px; cursor: ew-resize; }
.z-grip--e  { top: var(--z-space-6); bottom: var(--z-space-6); right: -4px; width: 9px; cursor: ew-resize; }
.z-grip--nw { left: -4px;  top: -4px;    width: var(--z-space-7); height: var(--z-space-7); cursor: nwse-resize; }
.z-grip--ne { right: -4px; top: -4px;    width: var(--z-space-7); height: var(--z-space-7); cursor: nesw-resize; }
.z-grip--sw { left: -4px;  bottom: -4px; width: var(--z-space-7); height: var(--z-space-7); cursor: nesw-resize; }
.z-grip--se { right: -4px; bottom: -4px; width: var(--z-space-7); height: var(--z-space-7); cursor: nwse-resize; }
.z-win[data-z-mode="full"] .z-grip,
.z-win[data-z-mode="fill"] .z-grip { display: none; }

.z-bar {
  position: relative; z-index: 5;
  display: grid; grid-template-columns: minmax(0,1fr) auto minmax(0,1fr);
  align-items: center; gap: var(--z-space-3);
  min-height: var(--z-menubar-h); padding: 7px 11px;
  border-bottom: 1px solid var(--z-line-hairline);
  border-radius: 23px 23px 0 0;
  background: var(--z-grad-titlebar);
  cursor: grab;
}
.z-bar:active { cursor: grabbing; }
.z-win[data-z-mode="full"] > .z-bar { border-radius: 0; }
.z-bar__menus { grid-column: 1; justify-self: start; display: flex; align-items: center; gap: 1px; min-width: 0; }
.z-win[data-z-mode="split"] .z-bar__menus { grid-column: 2; justify-self: center; }
.z-bar__lights { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: var(--z-space-4); }

/* Z_THE_APP_MENU_ROW_SLIDES_IT_NEVER_RUNS_UNDER_THE_LIGHTS_2026-09-02 (Agent D)
   MEASURED, not guessed: at tablet width the app menu's words ran straight under
   the three window lights — his picture showed "Inse" with the yellow light on
   top of it and "Help" with the red one over it. His law is explicit on both
   halves: a row that does not fit SLIDES sideways, and nothing may sit over the
   page's own words.
   The row is a grid: words in their column, lights in the last one. The words
   column could shrink but its buttons could not, so they spilled across.
   NOW the words slide inside their own column, with no scrollbar drawn, and the
   lights hold their size and their place. Nothing overlaps at any width.
   REVERT THIS PART ALONE: delete this block. */
/* THE ACTUAL CAUSE, found by reading the grid rather than guessing twice:
   .z-bar is  grid-template-columns: minmax(0,1fr) auto minmax(0,1fr)  and in
   page-bar mode the words sit in that MIDDLE, AUTO track. An auto track grows to
   fit its content and refuses to shrink, so the words' track overran the lights'
   track — and the overflow below could never fire, because the element was never
   narrower than its own content. Making that one track shrinkable is the fix.
   REVERT THIS PART ALONE: delete the grid-template-columns line below. */
/* Z_THE_LIGHTS_TAKE_ONLY_WHAT_THEY_NEED_2026-09-03  (Agent A)
   FOUNDER, 2026-09-03: "APPMENU, DETAILS + 3 DOTS OPTIONS ARE NOT THERE ONLOAD...
   INSIDE & OUT FIX THIS." Measured live, signed in as Dare, on BOTH /chat and
   /office, and the picture agrees with the numbers:
     the bar          600-1160, 560 wide
     resolved tracks  261px / 0px / 261px
     the words        column 1, 261 wide, holding 389 on Notes and 344 on Chat
     the lights       column 3, 261 wide, holding 65
   So the LIGHTS' track was taking an equal 1fr share and wasting 196 pixels,
   while the words were cut off - the bar read "Office/Notes File Edit Format Vi"
   and stopped. Window and Help could not be reached at all, on either page. That
   is why a test could not even open the Window menu.
   Agent D's fix above is UNTOUCHED and still does its job: the words' track is
   still shrinkable and still slides, so nothing can ever run under the lights.
   The ONLY change is the third track, from an equal share to what the lights
   actually need. The lights do not move - they are justify-self:end, and 1148
   minus 65 puts them at the same 1082 they are at today. The words' track gains
   the 196 that was being thrown away.
   REVERT THIS PART ALONE: put the last track back to minmax(0,1fr). */
.z-bar[data-z-pagebar] { grid-template-columns: minmax(0,1fr) minmax(0,auto) minmax(0,auto); }
.z-bar[data-z-pagebar] .z-bar__menus {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  flex-wrap: nowrap;
}
.z-bar[data-z-pagebar] .z-bar__menus::-webkit-scrollbar { width: 0; height: 0; display: none; }
.z-bar[data-z-pagebar] .z-bar__lights {
  flex: 0 0 auto;
  position: relative;
  z-index: 1;
  padding-left: 10px;
}

.z-menu {
  min-height: 25px; padding: 0 var(--z-space-4);
  border: 0; border-radius: 9px;
  background: transparent; color: var(--z-text-2);
  font-size: 12px; font-weight: 600; white-space: nowrap; cursor: pointer;
}
.z-menu:hover, .z-menu[data-z-open="1"] { background: rgba(196,181,253,.12); }
.z-menu[data-z-open="1"] { font-weight: 750; }
.z-menu__host { position: relative; }
.z-menu__host[hidden] { display: none; }
.z-pop--menu {
  position: absolute; top: 30px; left: 0; z-index: var(--z-layer-menu);
  min-width: 258px;
}
.z-pop--sub {
  position: absolute; top: -6px; left: 100%; z-index: var(--z-layer-submenu);
  min-width: 216px; margin-left: var(--z-space-3);
  border-radius: var(--z-radius-inner);
  animation: z-fade-in 110ms ease-out both;
}

.z-light {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--z-tl); height: var(--z-tl); padding: 0; border: 0;
  border-radius: var(--z-radius-pill);
  box-shadow: inset 0 0 0 .5px rgba(0,0,0,.28), 0 1px 2px rgba(0,0,0,.35);
  color: rgba(0,0,0,.62); cursor: pointer;
}
.z-light:hover { filter: brightness(1.18); }
.z-light:active { filter: brightness(.9); }
.z-light--close { background: var(--z-tl-close); }
.z-light--min   { background: var(--z-tl-min); }
.z-light--max   { background: var(--z-tl-max); }
.z-light svg { width: 9px; height: 9px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

.z-win__body {
  display: grid; grid-template-columns: 158px minmax(0, 1fr);
  flex: 1; min-height: 0;
  border-radius: 0 0 23px 23px; overflow: hidden;
}
.z-win[data-z-mode="full"] .z-win__body { border-radius: 0; }
.z-win__side {
  display: flex; flex-direction: column; gap: var(--z-space-1);
  padding: var(--z-space-6) var(--z-space-5);
  border-right: 1px solid var(--z-line-hairline);
  overflow-y: auto;
}
.z-win__side > * {
  padding: 7px var(--z-space-5); border-radius: var(--z-radius-ctl);
  font-size: 12px; font-weight: 600; color: rgba(226,232,240,.78);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.z-win__side > *:hover { background: var(--z-grad-hover); }
.z-win__main { display: flex; flex-direction: column; min-height: 0; padding: var(--z-space-6) var(--z-space-7); overflow-y: auto; }
.z-win__row {
  display: grid; grid-template-columns: minmax(0,1fr) auto; gap: var(--z-space-5);
  padding: 11px var(--z-space-4);
  border-bottom: 1px solid rgba(255,255,255,.05); border-radius: var(--z-radius-ctl);
}
.z-win__row:hover { background: linear-gradient(90deg, rgba(45,225,255,.1), rgba(255,65,221,.07)); }
.z-win__row b { font-size: var(--z-fs-ui); font-weight: 700; color: #f1f5f9; }
.z-win__row span { font-size: var(--z-fs-small); line-height: 1.35; color: var(--z-text-3); }
.z-win__row i { font-family: var(--z-font-mono); font-size: var(--z-fs-mono); font-style: normal; color: var(--z-text-4); white-space: nowrap; }

/* ==========================================================================
   Z_HIS_MAIN_MENU_SITS_ON_ITS_OWN_RUNG_2026-09-02   (Assistant B)
   ==========================================================================
   FOUNDER, 2026-09-02: "when I hover my mouse towards the app menu, the app
   menu goes over the z menu and the fucking top menu z index. It should never
   go over them. It's sliding underneath... for a split second it goes over on
   top the top menu and the z. Fix that and don't ever let that fucking happen
   again."

   MEASURED, NOT GUESSED. His main menu row is .top-bar in the chat runtime and
   it is declared:  .top-bar { position: relative; ... }  with NO z-index at all,
   so it sits at z-index:auto. The app menu bar is position:fixed with z-index:5
   in all three of its states - resting, peeking, and menu-open. A positioned
   element with a real z-index always paints above a positioned element with
   auto, no matter which comes first in the page. So the app menu bar was ALWAYS
   in front of his main menu; it only LOOKED right at rest because the bar is
   clipped in half there. The moment it slides down and the clip comes off, it
   crosses over the main menu in full view. That is the split second he sees.

   Agent D had already moved the bar to sit before the main menu in the page so
   ordinary paint order would put it underneath. That was the right idea and it
   could not work on its own, because a z-index of 5 beats DOM order outright.

   NO INVENTED NUMBER: tokens.css:137 already names this exact rung -
   --z-layer-header: 40 "a page's own top bar". His main menu IS that. It now
   reads its own rung, so 40 beats the bar's 5 and the bar genuinely slides
   underneath in every state.

   WHY body .top-bar AND NOT .top-bar: the chat runtime injects its own style
   block at runtime, which lands after this stylesheet, so an equal-strength
   rule here would lose. One extra step of strength wins without !important.

   SAFE BY MEASUREMENT: this only changes how the main menu compares with things
   between auto and 40, and the only such thing is the app menu bar at 5.
   Everything meant to sit above it is far higher - open menus 84, the whole
   dock and its menus above 2147481500 - and none of them move.

   REVERT THIS PART ALONE: delete this block. The bar goes back over the row.
   ========================================================================== */
body .top-bar { z-index: var(--z-layer-header, 40); }

/* Page-level menu bar for mode="full" */
.z-menubar {
  position: absolute; left: 0; right: 0; top: var(--z-space-3);
  z-index: var(--z-layer-menubar);
  display: flex; align-items: center; justify-content: center; gap: var(--z-space-4);
  pointer-events: none;
}
.z-menubar > * { pointer-events: auto; }
.z-menubar__inner {
  display: flex; align-items: center; gap: var(--z-space-4);
  padding: 5px var(--z-space-5);
  border: 1px solid var(--z-line); border-radius: var(--z-radius);
  background: rgba(12,8,24,.86); backdrop-filter: blur(20px);
}

/* ---------------------------------------------------------------- modals */
.z-scrim {
  position: absolute; inset: 0; z-index: var(--z-layer-scrim);
  background: var(--z-bg-scrim);
  animation: z-fade-in var(--z-dur-fast) ease-out both;
}
.z-modal-layer {
  position: absolute; inset: 0; z-index: var(--z-layer-modal);
  display: flex; align-items: center; justify-content: center;
  padding: var(--z-space-7);
  pointer-events: none;
}
.z-modal {
  pointer-events: auto;
  display: flex; flex-direction: column;
  border: 1px solid var(--z-line); border-radius: var(--z-radius);
  background: linear-gradient(180deg, rgba(18,12,32,.98), rgba(9,6,18,.98));
  box-shadow: var(--z-shadow-window); backdrop-filter: blur(16px);
  animation: z-drop var(--z-dur) ease-out both;
}
.z-modal--picker { width: 60%; min-width: min(320px, 100%); max-width: 940px; max-height: min(74dvh, 620px); }
.z-modal__head {
  display: flex; align-items: center; gap: var(--z-space-5);
  padding: 15px var(--z-space-7) var(--z-space-6);
  border-bottom: 1px solid var(--z-line);
}
.z-modal__title { font-size: 14px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--z-text); }
.z-modal__sub { margin-top: 3px; font-size: 11.5px; line-height: 1.35; color: var(--z-text-3); }
.z-modal__x {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border: 0; border-radius: var(--z-radius-pill);
  background: transparent; color: rgba(196,181,253,.72); cursor: pointer;
}
.z-modal__x:hover { background: rgba(196,181,253,.12); color: var(--z-violet-200); }
.z-modal__body { display: flex; flex-direction: column; gap: var(--z-space-7); min-height: 0; padding: var(--z-space-7); overflow-y: auto; }
.z-modal__foot {
  display: flex; align-items: center; gap: var(--z-space-5);
  padding: var(--z-space-6) var(--z-space-7);
  border-top: 1px solid var(--z-line); background: rgba(10,7,18,.6);
}
.z-modal__hint { font-family: var(--z-font-mono); font-size: var(--z-fs-mono); color: var(--z-text-4); }
.z-modal__actions { margin-left: auto; display: flex; align-items: center; gap: var(--z-space-4); }

.z-btn {
  min-height: 38px; padding: 0 var(--z-space-7);
  border: 1px solid rgba(196,181,253,.28); border-radius: var(--z-radius-ctl);
  background: rgba(124,58,237,.16); color: var(--z-violet-200);
  font-size: 13px; font-weight: 700; white-space: nowrap; cursor: pointer;
}
.z-btn:hover { border-color: rgba(232,215,255,.6); background: rgba(124,58,237,.28); }
.z-btn:active { transform: translateY(1px); }
.z-btn[disabled] { opacity: .45; cursor: default; }
.z-btn--primary {
  padding: 0 18px;
  border-color: var(--z-line-strong);
  background: var(--z-grad-cta); color: var(--z-text); font-weight: 750;
}
.z-btn--primary:hover { border-color: rgba(232,215,255,.7); }

/* ------------------------------------------------------------ app picker */
.z-picker__cat { display: flex; flex-direction: column; gap: var(--z-space-4); }
.z-picker__strip { display: flex; gap: var(--z-space-5); padding: 2px 2px var(--z-space-3); overflow-x: auto; }
.z-picker__tile {
  position: relative; flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  width: 106px; padding: 11px 3px 9px;
  border: 1px solid var(--z-line); border-radius: var(--z-radius-inner);
  background: rgba(22,17,36,.5); cursor: pointer;
}
.z-picker__tile:hover { border-color: rgba(196,181,253,.6); }
.z-picker__tile[data-z-picked="1"] { border-color: var(--z-line-strong); background: rgba(124,58,237,.24); }
.z-picker__label {
  width: 100%; padding: 0 1px;
  font-size: var(--z-fs-mono); font-weight: 650; line-height: 1.22;
  text-align: center; color: var(--z-text-2); white-space: pre-line;
}
.z-picker__tag {
  padding: 2px 7px; border-radius: var(--z-radius-pill);
  background: rgba(168,85,247,.18); box-shadow: inset 0 0 0 1px rgba(196,181,253,.28);
  font-family: var(--z-font-mono); font-size: 8.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: #d8b4fe; white-space: nowrap;
}
.z-picker__keep {
  position: absolute; top: var(--z-space-3); right: var(--z-space-3);
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; padding: 0;
  border: 1px solid rgba(196,181,253,.3); border-radius: 5px;
  background: transparent; color: #0d0617; cursor: pointer;
}
.z-picker__keep[data-z-on="1"] { border-color: var(--z-line-strong); background: var(--z-violet-300); }
.z-picker__keep svg { width: 11px; height: 11px; opacity: 0; }
.z-picker__keep[data-z-on="1"] svg { opacity: 1; }

/* ----------------------------------------------------------- signed out */
.z-signedout {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 100dvh; padding: 56px var(--z-space-7);
  text-align: center;
}
.z-signedout__grid {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(10px, 1.4vw, 22px);
  margin-top: clamp(18px, 3vh, 34px);
  width: min(560px, 78vw);
  opacity: .3; filter: grayscale(.55); pointer-events: none;
}
.z-signedout__grid img { display: block; width: 100%; border-radius: var(--z-radius-inner); }

/* The login affordance occupies the dock's position: right edge, centred. */
.z-login {
  position: absolute; inset: 0 0 0 auto; z-index: var(--z-layer-dock);
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: var(--z-space-8);
  pointer-events: none;
}
.z-login__btn {
  pointer-events: auto;
  position: relative;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--z-space-2);
  width: 76px; height: 76px; padding: 0;
  border: 1px solid var(--z-line); border-radius: var(--z-radius);
  background: var(--z-grad-dock); box-shadow: var(--z-shadow-dock);
  backdrop-filter: blur(20px);
  color: var(--z-violet-200); cursor: pointer;
  transition: transform var(--z-dur) var(--z-ease),
              border-color var(--z-dur) ease,
              box-shadow var(--z-dur) ease;
}
.z-login__btn::after {
  content: ""; position: absolute; inset: -1px;
  border-radius: inherit; pointer-events: none;
  box-shadow: var(--z-glow-halo-lo); opacity: 0;
  transition: opacity var(--z-dur) ease;
}
.z-login__btn:hover { transform: translateX(-4px); border-color: var(--z-line-strong); }
.z-login__btn:hover::after { opacity: 1; }
.z-login__btn:focus-visible { outline: 2px solid var(--z-cyan-400); outline-offset: 3px; }
.z-login__btn:active { transform: translateX(-1px) scale(.96); box-shadow: inset 0 2px 10px rgba(0,0,0,.5); }
.z-login__art {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: var(--z-radius-pill);
  background: radial-gradient(circle at 50% 50%, rgba(58,34,104,.75), rgba(10,6,22,.25) 70%, transparent);
}
.z-login__art svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.z-login__btn:hover .z-login__art svg { stroke: var(--z-cyan-300); }
.z-login__label {
  font-family: var(--z-font-mono); font-size: 9px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: rgba(196,181,253,.8);
}
.z-login__btn:hover .z-login__label { color: var(--z-violet-200); }

/* ========================================================================
   NATIVE STATIC DOCK — Z_DOCK_STATIC_FIRST_PAINT_2026-08-30
   The permanent host/furniture is in the served index.html. These rules are
   loaded from the head with the document and do not wait for JavaScript,
   reparenting, a timer, an observer, or a runtime-created Dock. The server
   fills data-z-signed-in from its trusted access result before the response
   is sent; the signed-out rule keeps the locked Dock from being exposed. */
body > #z-shell[data-z-static-shell="1"] {
  position: fixed;
  inset: 0;
  min-height: 0;
  overflow: visible;
  background: transparent;
  pointer-events: none;
  z-index: 2147481500;
}
body > #z-shell[data-z-static-shell="1"] > [data-z-windows] {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* ==========================================================================
 * Z_A_SIGNED_OUT_PERSON_HAS_NO_APPS_ON_THE_RAIL_2026-08-31 (Assistant C)
 *
 * FOUNDER: "Let's show it even to logged-out users. When logged out:
 *   * No apps should be on the dock"
 *
 * MY OWN MISS, CAUGHT BY LOOKING AT A PICTURE. When I made the rail show to
 * everyone I deleted the rule that used to hide the whole rail and never put
 * back a rule for the APPS. A live picture of the sign-in screen showed Mail,
 * Calendar and Drive sitting on the rail with nobody signed in.
 *
 * The orb, Dashboard, Tools and the plus stay - they are the rail itself, and
 * he asked for all four to open the log-in sheet. Only the apps go.
 *
 * WHY IT KEYS OFF "false" AND NOT "not true": the page the server sends does
 * not say who you are, so the mark is absent until the page works it out. If
 * this hid on "not true" it would blank a signed-in person's apps for the first
 * moment of every load. Keying off a definite "false" means a signed-in person
 * never flickers. A signed-out person sees the three for a moment and then they
 * go - honest once settled, and the moment is only there because the served
 * page cannot yet say who is looking at it.
 * THE REAL FIX, WHEN IT EXISTS: the server stamps who you are AND your own
 * saved apps into the page it sends. That is written up for Assistant A at the
 * top of FILE 2 as part of saving the dock. Then this rule can go.
 *
 * REVERT, THIS PART ALONE: delete this block. A signed-out visitor then sees
 * Mail, Calendar and Drive on the rail again.
 * ======================================================================== */
body > #z-shell[data-z-static-shell="1"][data-z-signed-in="false"] .z-dock__slot[data-z-dock-slot]:not([data-z-dock-slot="dashboard"]):not([data-z-dock-slot="tools"]) {
  display: none;
}

body > #z-shell[data-z-static-shell="1"] .z-dockwrap {
  position: absolute;
  inset: 0 0 0 auto;
  z-index: var(--z-layer-dock);
  margin: 0;
  padding: 72px 0;
  pointer-events: none;
  transform: none;
}
body > #z-shell[data-z-static-shell="1"] .z-dock {
  margin-right: 0;
  padding-right: 11px;
}
body > #z-shell[data-z-static-shell="1"] [data-z-dock-slots] {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--z-dock-gap);
}

/* ==========================================================================
 * Z_THE_RAIL_SCROLLS_WHEN_IT_RUNS_OUT_OF_ROOM_2026-08-31 (Assistant C)
 *
 * FOUNDER, answering his own question "what happens when the rail runs out of
 * room for all your apps": "Check how many can be opened at once per screen
 * (browser and mobile). We can invent a type of scroller so they can tap scroll
 * or scroll with a mouse".
 *
 * THE ARITHMETIC, so the number is not a guess: each app on the rail takes 40
 * plus a 9 gap, so 49. The rail keeps 72 clear top and bottom, and the orb, the
 * two permanent tiles, the plus and the two dividers sit above and below the
 * apps. On a 900-tall screen that leaves room for about eleven apps; on a
 * 1400-tall screen about twenty-one; on a phone at 700 tall about seven. Past
 * that they used to run off the screen with no way to reach them.
 *
 * NOW: the apps take whatever room is left and no more, and scroll inside it -
 * a finger drag on a touch screen and the wheel with a mouse, which is exactly
 * the two he named. Nothing scrolls while everything fits. The scrollbar itself
 * is hidden because the rail is a floating slab, and a scroll never leaks out
 * to the page behind it. The orb, the two permanent tiles and the plus never
 * scroll away - only the apps move.
 *
 * REVERT, THIS PART ALONE: delete this block. The rail then runs off the screen
 * again once there are too many apps.
 * ======================================================================== */
body > #z-shell[data-z-static-shell="1"] .z-dock {
  max-height: 100%;
  min-height: 0;
}
body > #z-shell[data-z-static-shell="1"] [data-z-dock-slots] {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* THE HOVER ZOOM WOULD HAVE BEEN CUT IN HALF. A box that scrolls one way
     clips the other way too - the browser gives you no choice. A tile grows
     34 per cent on hover from its right edge, so it reaches about 14 to the
     LEFT, and that is exactly what would have been sliced off. The room is
     added inside and taken back outside, so nothing moves and the zoom is
     whole. Same trick top and bottom for the first and last tile. */
  /* Z_THE_OPEN_DOT_TOUCHES_THE_WALL_2026-09-01 (Assistant A)
     Founder, 2026-09-01: "the purple open button is supposed to be on the right
     side of the app icon, not underneath. Make that so the purple button for an
     open icon is touching the wall, not in between the apps."
     The dot has to sit past the tile's right edge, and a box that scrolls one
     way clips the other way. So the SAME trick already used on the left is used
     on the right: room added inside, taken back outside. Nothing moves, and the
     dot is no longer sliced off.
     REVERT THIS ALONE: delete the two right-hand values below. */
  padding: 6px 14px 6px 14px;
  margin-left: -14px;
  margin-right: -14px;
  scroll-padding: 6px 0;
}
body > #z-shell[data-z-static-shell="1"] [data-z-dock-slots]::-webkit-scrollbar {
  width: 0;
  height: 0;
}
/* Z_DOCK_SHOWS_SIGNED_OUT_2026-08-30 (Assistant C, founder-ordered).
   FOUNDER: "Let's show it even to logged-out users. When logged out:
     * No apps should be on the dock
     * When dashbaord, tools or the plus sign is clicked, a popup ... with the
       title 'Log In to your Account' ... should appear"
   The whole rail used to be hidden until the server said signed in. Now the rail
   is there for everyone from the first painted frame - it is permanent furniture,
   like the top menu - and only the APPS are absent while nobody is signed in.
   Absent, not hidden-but-present: a signed-out person genuinely has no apps, so
   the truthful rail carries the orb, Dashboard, Tools and the plus, and nothing
   else. All of this is static CSS in the served head; no script reveals anything.
   REVERT: restore the two rules this block replaced -
     :not([data-z-signed-in="true"]) .z-dockwrap { visibility:hidden; pointer-events:none; }
     [data-z-signed-in="true"] .z-dockwrap { visibility:visible; }
*/
body > #z-shell[data-z-static-shell="1"] .z-dockwrap {
  visibility: visible;
}
/* WHY THIS KEYS ON data-z-server-auth AND NOT data-z-signed-in:
   measured live 2026-08-30 in a fresh private window with nobody signed in -
   the server correctly sends data-z-signed-in="false", it still reads false at
   688ms, and then something on the page flips it to "true" at about 26 seconds.
   So a signed-out visitor ends up marked signed in and sees the apps, which is
   exactly what the Founder reported: "IM LOGGED OUT AND I SEE THE APPS".
   data-z-server-auth carries the same server answer and is written by nobody
   else, so the rail's app slots follow the truth instead of a value that gets
   overwritten. The flip itself is a separate fault, recorded in FILE 1.
   REVERT: change these two selectors back to data-z-signed-in. */
body > #z-shell[data-z-static-shell="1"]:not([data-z-server-auth="true"]) [data-z-dock-slots] {
  display: none;
}
body > #z-shell[data-z-static-shell="1"]:not([data-z-server-auth="true"]) [data-z-dock-sep] {
  display: none;
}

/* Existing Claude Design Dock appearance, now available before paint. */
body > #z-shell[data-z-static-shell="1"] .zd-hubs {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 2px 0 0;
}
body > #z-shell[data-z-static-shell="1"] .zd-orb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: radial-gradient(circle at 50% 50%, rgba(58,34,104,.6), rgba(10,6,22,.2) 70%, transparent);
  cursor: pointer;
  overflow: hidden;
  animation: z-halo var(--z-halo-cycle, 3.2s) cubic-bezier(.45,0,.55,1) infinite;
}
body > #z-shell[data-z-static-shell="1"] .zd-orb > z-orb-mark,
body > #z-shell[data-z-static-shell="1"] .zd-orb .zd-orb-clone,
body > #z-shell[data-z-static-shell="1"] .zd-orb .zd-orb-img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 999px;
}
/* ONE ZOOM ON THE WHOLE DOCK. The hubs and the app slots both grow to 1.34 on
   hover; the orb was the only item that did not move at all, so the rail zoomed
   inconsistently. Founder: "MAKE SURE THE ZOOM FACTOR ON THE DOCK IS THE SAME TOO."
   REVERT: delete the transform and transition lines. */
body > #z-shell[data-z-static-shell="1"] .zd-orb {
  transition: filter 140ms ease, transform 140ms ease;
  transform-origin: right center;
}
body > #z-shell[data-z-static-shell="1"] .zd-orb:hover {
  filter: brightness(1.18) drop-shadow(0 0 10px rgba(45,225,255,.4));
  transform: scale(1.34);
}
body > #z-shell[data-z-static-shell="1"] .zd-hub {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--z-app-icon-box);
  height: var(--z-app-icon-box);
  border: 0;
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
  transition: background 140ms ease, box-shadow 140ms ease, transform 140ms ease;
  transform-origin: right center;
}
body > #z-shell[data-z-static-shell="1"] .zd-hub:hover {
  background: linear-gradient(90deg, rgba(45,225,255,.13), rgba(255,65,221,.09));
  box-shadow: 0 0 16px rgba(45,225,255,.18) inset;
  transform: scale(1.34);
}
body > #z-shell[data-z-static-shell="1"] .zd-sep {
  width: 26px;
  height: 1px;
  margin: 7px auto;
  background: rgba(196,181,253,.28);
}
body > #z-shell[data-z-static-shell="1"] .z-dock__slot {
  position: relative;
  transition: transform 140ms ease;
  transform-origin: right center;
}
body > #z-shell[data-z-static-shell="1"] .z-dock__btn {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  padding: 0;
  transition: transform 140ms ease, background 140ms ease, opacity 140ms ease;
}
body > #z-shell[data-z-static-shell="1"] .z-dock__btn:hover {
  transform: scale(1.34);
}
/* Z_DOCK_ICON_SIZE_IS_THE_TOKEN_2026-08-30 (founder: "I dont know at what
   point you reduced my dock orb sizes into tiny smaller icons, REVERT THAT NOW.
   PUT THEM THE SIZES THEY WERE, AND MAKE SURE THE ZOOM FACTOR ON THE DOCK IS THE
   SAME TOO"). This block hard-coded 24px and beat --z-dock-icon (33px), which is
   the design's own number and what .z-appicon--md uses everywhere else. Hard-coding
   a number here means the token stops being the single source of the icon size, so
   it reads the token instead of restating it. REVERT: put 24px back. */
body > #z-shell[data-z-static-shell="1"] .z-dock__btn img.z-appicon {
  width: var(--z-dock-icon);
  height: var(--z-dock-icon);
  object-fit: contain;
  opacity: 1;
}
body > #z-shell[data-z-static-shell="1"] .z-dock__btn .z-appshell,
body > #z-shell[data-z-static-shell="1"] .z-dock__btn .z-appshell img {
  width: var(--z-dock-icon);
  height: var(--z-dock-icon);
}
body > #z-shell[data-z-static-shell="1"] .z-dock__slot:not(:has(.z-dock__run)) .z-dock__btn {
  opacity: .5;
}
body > #z-shell[data-z-static-shell="1"] .z-dock__slot:has(.z-dock__run) .z-dock__btn,
body > #z-shell[data-z-static-shell="1"] .z-dock__slot:hover .z-dock__btn {
  opacity: 1;
}
body > #z-shell[data-z-static-shell="1"] .zd-hub-img {
  width: var(--z-app-icon-art);
  height: var(--z-app-icon-art);
  display: block;
}

/* ==========================================================================
 * Z_LOGIN_POPUP_WHOLE_FLOW_2026-08-30  (Assistant C, founder-ordered)
 *
 * FOUNDER: "i clicked my name and passcode didnt appear in the popup, but
 * behind on the page. make sure it apepars in the popup and the page stays
 * unchanged"
 *
 * The number pad and the code dots are borrowed into the log-in sheet. Outside
 * the sign-in panel, the site's own "hide the pad until somebody is picked"
 * rule can no longer reach them, so the sheet does that job itself - driven by
 * the sign-in's REAL state, mirrored onto the sheet as data-z-login-step.
 *
 * REVERT: delete this block. The sheet then shows the pad at both steps, which
 * is the state it was in before this change.
 * ======================================================================== */
[data-z-login-picker]:not([data-z-login-step="code"]) .access-lock-display,
[data-z-login-picker]:not([data-z-login-step="code"]) .access-lock-keypad,
[data-z-login-picker]:not([data-z-login-step="code"]) .z-home-back {
  display: none !important;
}
/* at the code step the pad is the whole point - give it room and centre it */
[data-z-login-picker][data-z-login-step="code"] .access-lock-display,
[data-z-login-picker][data-z-login-step="code"] .access-lock-keypad {
  margin-inline: auto;
}
[data-z-login-picker][data-z-login-step="code"] .z-home-back {
  display: none !important;
}
/* Z_BUSINESS_FIRST_SCREEN_NO_BACK_2026-09-30 (Codex199): the first Business
   dock screen has no Back; the second-level passcode screen owns it. */
[data-z-login-picker] .z-home-back { display: none !important; }
[data-z-login-picker][data-z-login-step="code"][data-z-business-passcode-step="true"] .z-home-back {
  display: block !important;
  margin: var(--z-space-4) auto 0;
  text-align: center;
}
/* the borrowed pieces stack down the sheet, never side by side */
[data-z-login-picker] .z-modal__body {
  display: flex;
  flex-direction: column;
  gap: var(--z-space-4);
  align-items: stretch;
}

/* ==========================================================================
 * Z_FILL_STOPS_AT_THE_DOCK_2026-08-31 (Assistant C, founder-direct).
 *
 * FOUNDER: "Currently on desktop: fills the screen and goes over the dock. Make
 * it so the right side of the screen STOPs where the dock is, and doeesnt
 * extend past it."
 * AND: "On mobile, never hide the dock. Apps stretch to full width, but dock
 * stays ontop"
 *
 * MEASURED LIVE 2026-08-31 before writing this: a filled window was 1440 wide on
 * a 1440 screen, and the rail sits from 1376 to 1440. So it really did run
 * underneath, by exactly the rail's width.
 *
 * ONE NUMBER, NOT TWO. The rail is given that same width here, so the space a
 * filled window leaves and the space the rail actually takes are the SAME token
 * and can never drift apart. 64px is what the rail already measured, so the rail
 * does not move because of this.
 *
 * MOBILE KEEPS THE FULL WIDTH, exactly as he asked. The reserve is only turned
 * on where there is a real mouse - which is his own test, in his words: "If no
 * mouse is detected, never hide the dock." A tablet without a mouse therefore
 * behaves like a phone here, with no extra guessing.
 *
 * WINDOWS CAN STILL BE DRAGGED OVER THE DOCK. This only changes what FILL does.
 * His words: "ALLOW users to extend it themselves over the dock if they want".
 *
 * REVERT: delete this block. Fill goes back to the whole screen width.
 * ======================================================================== */
/* ==========================================================================
   Z_MOBILE_GETS_THE_PUSH_OVER_TOO_2026-09-03   (Agent E)
   CHECK THE APPMENU, AND DETAILS+OPTIONS 3 DOTS ARE STILL WORKING PERFECTLY

   FOUNDER, 2026-09-03, word for word:
     "earlier i explained how the dock can push chat elements, buttons, etc over
      BUT not background... All that was explained for desktop. Mobile gets it too."

   MEASURED BEFORE THIS WAS WRITTEN, on his own phone size, signed in as him, three
   of his pages, picture opened:
     --z-fill-reserve read 0px while --z-dock-reserve read 64px, so his message bar
     ran from 0 to 390 while the dock sat at 326 to 390. HIS MESSAGE BAR WAS 64px
     UNDER THE DOCK. Gate: agentE-phone-dock-covers-his-stuff-gate.js, 6 of 7, RED.

   WHY IT HAPPENED: the line below only handed the reserve a real value inside
   "(hover: hover) and (pointer: fine)" - a real mouse. A phone has touch and no
   hover, so it stayed 0 and every rule that reads it collapsed: the app-shell
   padding, a filled window's width, and the message bar rule at the foot of this
   file. Nothing was pushed, so the dock drew on top of his content.

   THE CHANGE, and it invents NOTHING: the reserve is now HIS OWN --z-dock-reserve
   everywhere, instead of only where there is a mouse. No new number, no new
   breakpoint, no width chosen by me. The mouse-only line is left in place directly
   below, unchanged, because it now agrees with the base rather than overriding it -
   deleting someone else's line to make mine tidier is not a fix.

   HIS HARD RULE, KEPT AND PROVEN: THE BACKGROUND NEVER MOVES. The background is
   position:fixed with left:0 and right:0, so padding on .app-shell cannot move it -
   and the same gate asserts it, and it PASSED on all three pages before this change
   and must keep passing after.

   REVERT THIS PART ALONE: put --z-fill-reserve back to 0px on the :root line.
   ========================================================================== */
:root { --z-dock-reserve: 64px; --z-fill-reserve: var(--z-dock-reserve); }
@media (hover: hover) and (pointer: fine) {
  :root { --z-fill-reserve: var(--z-dock-reserve); }
}
.z-dockwrap { width: var(--z-dock-reserve); }

/* ===========================================================================
   Z_NOTHING_RUNS_UNDER_THE_DOCK_2026-09-02 (Agent A)
   FOUNDER, 2026-09-02, with a screenshot of his desktop chat where the dock
   icons sat on top of his message text: "No things like that should ever
   overlap, period."
   MEASURED FIRST, live, signed in as Dare at 1440x900, before changing a thing
   (I broke his chat menu once by adding to a layout I had not measured):
     dock            1376 -> 1440
     .app-shell         0 -> 1440   pokes 64px under the dock
     .app-content-shell 320 -> 1440  same
     .main-panel        320 -> 1440  same
     .chat-body-root    320 -> 1440  same
     .conversation-shell 320 -> 1440 same
     .message-scroll    320 -> 1440  same   <- his messages
   Nine things in all. --z-dock-reserve is already 64px and --z-fill-reserve is
   already that same 64px on a desktop and 0px everywhere else, but the ONLY
   place it was ever spent is a window in fill mode (shell.js:1126). The page
   app never spent it, so every app page ran straight under the dock.
   THIS IS ONE LINE AT THE OUTERMOST CONTAINER. Everything inside stops with it,
   so no per-app rule and no new number. z-windows.js already sets
   html[data-z-pagebar-on="1"] .app-shell{box-sizing:border-box}, so padding
   shrinks the content instead of widening the box. On a phone the variable is
   0px, so nothing changes there at all.
   REVERT THIS PART ALONE: delete the one rule below.
   =========================================================================== */
html[data-z-pagebar-on="1"] .app-shell { padding-right: var(--z-fill-reserve, 0px); }

/* ===========================================================================
   Z_THE_DOCK_PUSHES_THE_PAGE_NEVER_THE_TOP_MENU_2026-09-23 (Fable 5.1)
   HIS-WORDS 2026-09-23: "the dock that pushed the page over ALSO pushed the top menu over -
   settings icon starts way off. the top menu is z-index on top of the entire page, it should
   NEVER be affected by the dock pushing it over. the top menu stays the position its been
   forever, settings icon top right, everything else where they were."
   MEASURED before this: the reserve above pads the whole .app-shell, and his top menu (the
   header inside .main-panel) lives inside that shell, so it was pushed with the page - his
   settings icon sat 64px in from the edge. The header is given the padding back, so it spans
   the full width again and nothing else changes.
   =========================================================================== */
/* MEASURED after a first try that only widened the header: the panel around it clips at the
   shell's padded edge, so his settings icon was drawn under the dock and could not be pressed.
   So the push moves off the shell and onto the two boxes that hold the page itself - the app box
   and the chat body - which is the same slide for the page, while the header above them keeps
   the whole width it always had. */
@media (hover: hover) and (pointer: fine) {
  html[data-z-pagebar-on="1"] .app-shell { padding-right: 0; }
  html[data-z-pagebar-on="1"] .app-shell .main-panel > .z-module-surface {
    width: calc(100% - var(--z-fill-reserve, 0px));
    max-width: calc(100% - var(--z-fill-reserve, 0px));
    box-sizing: border-box;
  }
  html[data-z-pagebar-on="1"] .app-shell .main-panel > .chat-body-root {
    padding-right: var(--z-fill-reserve, 0px);
    box-sizing: border-box;
  }
}

/* ===========================================================================
   Z_ON_A_PHONE_THE_PAGE_RUNS_UNDER_THE_DOCK_AND_FADES_THERE_2026-09-23 (Fable 5.1)
   HIS-WORDS 2026-09-23: "the dock pushes the page over from the right side and pushed it way
   too far. on desktop the sales page has a really nice fade - the dashboard goes under the
   dock but you dont see the fade until its fully gone under the desktop. Fable learn how it
   looks on desktop on the sales page then apply to mobile then all apps. on mobile it fades to
   black before it even touches the dock. on other apps it doesnt fade at all, abrupt stop."
   LEARNED OFF HIS DESKTOP SALES PAGE (sales.html, the home panel): the page is not padded away
   from the dock; it runs under it and a mask fades it to nothing over its last 92px, on a dock
   64px wide - so the fade begins 28px before the dock and is gone under it.
   ON A PHONE the same thing, in his phone dock's own size: the dock is drawn at 0.85 (54px) so
   the fade is 54 + 28*0.85 = 78px, the same picture scaled. The 64px push is taken off on a
   phone (it was the "way too far"), the app box gets the fade, and the top menu above the box
   is not in the fade at all. Every app that draws in the app box gets it.
   UNDO THIS PART ALONE: delete this block and the header rule above it.
   =========================================================================== */
/* ===========================================================================
   Z_THE_DOCK_TOP_NEVER_REACHES_THE_APP_MENU_2026-09-23 (Fable 5.1)
   HIS-WORDS 2026-09-23: "the top of the dock is glitching over the app menu at the top ... something
   on the dock at the top of the dock is just making it glitch".
   MEASURED: on a phone the dock is bottom-anchored and lifted above the bottom row (the rules just
   below), so on a shorter screen - a phone showing its browser bars is about 664 tall - the dock's top
   lands at about 91px, right on the app menu (56 to 98). The thing at the top of the dock is his orb,
   whose halo pulses 22 to 44px past its edge every 3.2s. That pulse over the app menu is the glitch.
   TWO THINGS: the lift is capped so the dock's top never rises above 110px (the app menu's bottom plus
   air); and on a phone the orb's halo is kept inside the dock's own edge. The dock's own height is
   written on the page by z-design.js so the cap can read it.
   UNDO THIS PART ALONE: delete this block. */
@media (max-width: 640px) {
  body:has([data-z-bottom-gui="1"]) .z-dockwrap,
  body:has([data-z-bottom-gui="1"]) .z-dockwrap[data-z-align="start"],
  body:has(.mail-message-actions) .z-dockwrap,
  body:has([data-z-mail-floating]) .z-dockwrap,
  body:has([data-z-message-z-bar]) .z-dockwrap,
  .z-dockwrap,
  .z-dockwrap[data-z-align="start"] {
    padding-bottom: min(
      calc(env(safe-area-inset-bottom, 0px) + var(--composer-height, 118px) + 18px + var(--z-kb-tray-space, 0px)),
      calc(100vh - 110px - var(--z-dock-h, 395px))
    );
  }
  .z-dock .zd-orb {
    --z-glow-halo-lo: 0 0 6px rgba(140,100,255,0.42), 0 0 10px rgba(140,100,255,0.22);
    --z-glow-halo-hi: 0 0 9px rgba(140,100,255,0.62), 0 0 12px rgba(140,100,255,0.34);
  }
}

/* Z_PUSHED_OVER_AND_FADING_AT_THE_EDGE_2026-09-23 (Fable 5.1). HIS-WORDS 2026-09-23: "Deep dive what Z Chat
   looks like on desktop - how the start of the page is pushed over on desktop. Then apply that to all the
   mobile pages so they are all pushed over, but they fade off into transparency, just like the sales page does
   on desktop." READ OFF HIS DESKTOP CHAT: the page box is pushed over by the dock's own width (64px) so it ends
   at the dock's edge. READ OFF HIS DESKTOP SALES: the last 28px before the dock fade to nothing. ON A PHONE the
   dock is drawn at 0.85, so the push is 54px and the fade is 24px, the same two pictures scaled. The push sits
   on the page boxes, never on the top menu (his settings icon stays at the edge). The zero push of the first
   try was wrong and is gone. UNDO THIS PART ALONE: put "--z-phone-push: 0px" and the 78px fades back. */
@media (pointer: coarse) {
  :root { --z-phone-push: calc(var(--z-dock-reserve, 64px) * 0.85); --z-phone-fade: 24px; }
  html[data-z-pagebar-on="1"] .app-shell { padding-right: 0; }
  html[data-z-pagebar-on="1"] .app-shell .main-panel > .z-module-surface {
    width: calc(100% - var(--z-phone-push));
    max-width: calc(100% - var(--z-phone-push));
    box-sizing: border-box;
  }
  html[data-z-pagebar-on="1"] .app-shell .main-panel > .chat-body-root {
    padding-right: var(--z-phone-push);
    box-sizing: border-box;
    -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - var(--z-phone-push) - var(--z-phone-fade)), transparent calc(100% - var(--z-phone-push)));
            mask-image: linear-gradient(to right, #000 0, #000 calc(100% - var(--z-phone-push) - var(--z-phone-fade)), transparent calc(100% - var(--z-phone-push)));
  }
  /* the fade covers only the band of the page the dock actually sits across (its top and
     height are written on the app box by z-design.js from the dock's own place on screen);
     everything above and below that band - his own button rows - stays exactly as drawn.
     Until the band is known the whole box fades, which is the plain rule above. */
  html[data-z-pagebar-on="1"] .app-shell .z-module-content {
    -webkit-mask-image:
      linear-gradient(#000, #000),
      linear-gradient(#000, #000),
      linear-gradient(to right, #000 0, #000 calc(100% - var(--z-phone-fade, 24px)), transparent 100%);
            mask-image:
      linear-gradient(#000, #000),
      linear-gradient(#000, #000),
      linear-gradient(to right, #000 0, #000 calc(100% - var(--z-phone-fade, 24px)), transparent 100%);
    -webkit-mask-size: 100% var(--z-dock-band-top, 0px), 100% calc(100% - var(--z-dock-band-top, 0px) - var(--z-dock-band-h, 100%)), 100% var(--z-dock-band-h, 100%);
            mask-size: 100% var(--z-dock-band-top, 0px), 100% calc(100% - var(--z-dock-band-top, 0px) - var(--z-dock-band-h, 100%)), 100% var(--z-dock-band-h, 100%);
    -webkit-mask-position: 0 0, 0 calc(var(--z-dock-band-top, 0px) + var(--z-dock-band-h, 100%)), 0 var(--z-dock-band-top, 0px);
            mask-position: 0 0, 0 calc(var(--z-dock-band-top, 0px) + var(--z-dock-band-h, 100%)), 0 var(--z-dock-band-top, 0px);
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
  }
}

/* ===========================================================================
   Z_NOTHING_GETS_SELECTED_WHILE_YOU_MOVE_A_WINDOW_2026-08-31  (Assistant B)
   ===========================================================================
   FOUNDER, 2026-08-31: "Whenever I resize/move windows around, it always selects
   text in the app or the top appName File .. Help text. Make it not do that.
   Make sure selecting text on menus and stuff actually is disabled. Make it only
   select on the right things".

   MEASURED: not one user-select rule existed anywhere in the window chrome, so
   dragging a title bar dragged a text selection with it.

   TWO PARTS, and only two:
   1. Chrome is never selectable. A title bar, its menu names, the traffic
      lights, the resize edges, the dock, a menu and a menu row are things you
      press, not things you read. Real content - what is inside a window, a
      message, a note - is untouched and still selects normally.
   2. While a window is actually being moved or resized, nothing at all selects,
      anywhere. The moment it stops, everything goes back to normal.
   REVERT THIS PART ALONE: delete this block and the two lines in shell.js that
   set and clear data-z-moving on the root element.
   =========================================================================== */
.z-bar,
.z-bar__menus,
.z-bar__lights,
.z-bar__appname,
.z-grip,
.z-menu__host,
.z-menu,
.z-menu__row,
.z-dock,
.z-dockwrap,
[data-z-dock],
[data-z-dock-slot],
[data-z-titlebar],
.z-picker__tile,
.z-picker__label,
.z-menu-row {
  -webkit-user-select: none;
  user-select: none;
}

/* while a window is being moved or resized, nothing anywhere selects */
[data-z-moving="1"],
[data-z-moving="1"] * {
  -webkit-user-select: none !important;
  user-select: none !important;
  cursor: inherit;
}

/* ===========================================================================
   Z_ZDESIGN_IS_ONE_PRESS_AWAY_ON_EVERY_PAGE_2026-09-01  (Assistant B)
   Founder row: "Right-click anywhere on any Z page and zDesign is one press
   away." Source: A6 .../05_ZDESIGN_COMPLETE/ZDESIGN_COMPLETE_CURRENT_CANON.md
   - "On current authorized Z World aliases ... the context entry can show a
   moving Z mark with: Open zDesign; Open zDesign in New Tab; Edit here with Z."

   THESE RULES MOVED HERE FROM shared/zdesign/zdesign.css ON 2026-09-01, WHOLE,
   NOT COPIED. zdesign.css is linked on the /zdesign route only, so the menus
   would have shown UNSTYLED - meaning fully visible - on every other page the
   moment they shipped in the served bytes. shell.css is already linked on every
   page, so moving them costs the visitor NOTHING: no extra request, no extra
   parse, and the menus are hidden on the very first frame like all other shell
   furniture. Never a second copy of these rules anywhere.
   =========================================================================== */
[data-z-design-menu] {
  position: fixed;
  /* Z_ONE_LAYER_LEDGER_2026-08-31 - its rung, never a raw number.
     The one ledger lives in shared/z-shell/tokens.css. */
  z-index: var(--z-shell-zdesign, 2147482000);
  min-width: 236px;
  padding: 6px;
  border: 1px solid var(--line, rgba(255,255,255,.10));
  border-radius: var(--radius-md, 16px);
  background-color: rgb(17, 10, 28);
  box-shadow: var(--shadow, 0 18px 48px rgba(0,0,0,.55));
  font-family: var(--z-font-temp, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: var(--text, #f8fafc);
}
/* HIDDEN BY A STATIC RULE, not by a script removing it from the page. */
[data-z-design-menu][data-open="0"] { display: none; }
[data-z-design-menu][data-open="1"] { display: block; }

[data-z-design-menu] .zdm-head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 11px 10px;
  border-bottom: 1px solid var(--line, rgba(255,255,255,.10));
  margin-bottom: 5px;
}
/* the moving Z mark the canon asks for. An animation is the one other thing
   script-free CSS is allowed to do, and this one runs in the stylesheet. */
[data-z-design-menu] .zdm-mark {
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: 50%;
  font-weight: 760; font-size: 13px;
  color: var(--accent, #d0c3ad);
  background: var(--accent-soft, rgba(208,195,173,.13));
  animation: zdm-breathe 3.2s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes zdm-breathe {
  0%, 100% { box-shadow: 0 0 10px rgba(208,195,173,.30); }
  50%      { box-shadow: 0 0 20px rgba(208,195,173,.55); }
}
[data-z-design-menu] .zdm-title {
  font-size: 11px; letter-spacing: .4px; text-transform: uppercase;
  color: var(--muted, #9aa7b4);
}
[data-z-design-menu] .zdm-row {
  display: block; width: 100%;
  appearance: none; border: 0; background: transparent;
  color: var(--text, #f8fafc);
  font: inherit; font-size: 13px; text-align: left;
  padding: 9px 11px;
  border-radius: var(--radius-md, 16px);
  cursor: pointer;
}
[data-z-design-menu] .zdm-row:hover { background: var(--surface-soft, rgba(255,255,255,.06)); }
[data-z-design-menu] .zdm-row[aria-disabled="true"] { opacity: .45; cursor: default; }
[data-z-design-menu] .zdm-sep {
  height: 1px; margin: 5px 8px;
  background: var(--line, rgba(255,255,255,.10));
}

/* ===========================================================================
   Z_THE_DOCK_SITS_AT_HIS_THUMB_ON_A_PHONE_2026-09-01   (Assistant A)
   ===========================================================================
   Founder, 2026-09-01, with a picture of his phone home screen:
     "lets make the dock stick out a LITTTLE lessa, and maybe resize dovk to
      like 90% the current size, so its not covering the 'exocortex' text and
      is a lil less intrusive. ALSO , its centered vertically on mobile, make
      it bottom middle default start, so users have it closer to their thumb"

   MEASURED, not guessed: this whole stylesheet had exactly ONE screen-size
   rule in it, and none of it was about a phone. The dock sat in the middle
   of the right edge at full size, which is why it landed straight across his
   "an obsidian mind, fueled by a neuromorphic mesh intelligence" line.

   On a phone the rail now starts at the BOTTOM of the right edge, at 90% of
   its size, sitting closer in. Nothing about how it works changes - it still
   drags, still opens, still hides the same way.

   REVERT THIS ALONE: delete this block. Nothing else refers to it.
   =========================================================================== */
@media (max-width: 640px) {
  /* Z_HIS_MOBILE_DOCK_2026-09-01 (Agent D) — HIS WORDS: "the dock is currently
     90% size on mobile. change it to 85%, and move it upwards more so the
     STARTING position is ABOVE where the messge Z bar is".
     The lift uses the Message Z bar's OWN height (--composer-height, 118px in
     the chat runtime) instead of a guessed number.
     REVERT THIS PART ALONE: scale(0.9) in both rules and drop the composer
     height back out of the padding. */
  .z-dockwrap,
  .z-dockwrap[data-z-align="start"] {
    align-items: flex-end;
    padding: 20px 0 calc(env(safe-area-inset-bottom, 0px) + 18px) 0;
  }

  .z-dock {
    transform: scale(0.85);
    transform-origin: bottom right;
    padding: 9px 8px 11px 9px;
  }

  /* Z_HIS_DOCK_FADE_REACHES_AS_FAR_ON_A_PHONE_2026-09-20 (seat 1/A, Opus 5)
     HIS-WORDS:"on mobile, the dock fades too early. make fade like slightly underneath the
     dock like how it does in desktop"
     The soft panel behind his dock is what reaches slightly past it. The 0.85 above shrinks
     that reach along with everything else, so on a phone it came up SHORT of what he sees on
     a computer. MEASURED live, signed in, 2026-09-20 on his sales page: computer reaches 4.0
     past the dock top and bottom with its soft edge spread 36; phone reached only 3.0 with
     its spread shrunk to 30.6. Tried in the live page first and measured again: 4.0 past, and
     the soft edge lands at exactly 14 across, 14 down, 36 wide on screen - the same numbers
     the computer already draws. Nothing new is chosen: every value here is his own computer
     value divided by his own 0.85, so the shrink above no longer takes the fade with it.
     Nothing else about the dock moves, changes size or changes shape.
     UNDO THIS PART ALONE: delete this block. The soft panel then falls back to its one rule
     higher up the file and the phone goes back to reaching 3.0. */
  .z-dock__slab {
    inset: calc(-4px / 0.85) 0;
    box-shadow:
      rgba(255, 255, 255, 0.05) 0 0 0 calc(1px / 0.85),
      rgba(0, 0, 0, 0.55) calc(-14px / 0.85) calc(14px / 0.85) calc(36px / 0.85) 0;
  }

  /* hiding still slides it out to the right, just from its new size */
  .z-dock[data-z-hidden="1"] {
    transform: scale(0.85) translateX(26px);
  }
}

/* Z_DOCK_LIFTS_ONLY_WHERE_A_MESSAGE_BAR_EXISTS_2026-09-01 (Agent D)
   HIS CORRECTION: "ON MOBILE ACTUALLY, KEEP IT WHERE IT IS. THE UPDATE I TOLD U
   ABOUT THE MESSAGE BAR, OOOONLY DO THAT WHEN THERS A MESSAGE BAR ON A PAGE. AS
   U SHOULD BE AWARE, LOTS OF APPS WILL HAVE MESSAGE BARS. THE DOCK SHOULD
   AUTO-MOVE UPWARDS WHEN ONE EXISTS."
   I had lifted it on every phone page. Wrong: the dock keeps its normal place,
   and only lifts on a page that actually HAS a message bar. This asks the page
   itself, in CSS, so nothing measures anything and nothing moves after load —
   which is his hard rule. It uses the bar's own height, --composer-height.
   Works on any size, not just a phone, because he said lots of apps will have
   message bars.
   REVERT THIS PART ALONE: delete this block. */
/* EVERY APP'S BOTTOM GUI LIFTS THE DOCK, not just a message bar. HIS WORDS:
   "the dck should also be moved upwards in mail app so its above those buttons
   too. bascially, when you build the apps for all apps, make sure the dock
   auto-moves up to center center when there's GUIs on the screen. mark this in
   all the places u need to for every app so u do NOT forget".
   THE CONTRACT FOR EVERY APP, now and future: put data-z-bottom-gui="1" on any
   bar that sits at the bottom of your app, and the dock lifts above it by
   itself. Nothing to wire, nothing to remember beyond that one attribute. The
   two known ones today are listed by name so they work with no change. */
/* ===========================================================================
   Z_THE_LIFT_IS_A_PHONE_RULE_ONLY_2026-09-02 (Agent A) — FOUNDER, 2026-09-02,
   with a screenshot of his desktop chat:
     "the doc. Do you see how somebody... one of the agents I don't know who
      moved the keyboard up on desktop? That's not supposed to be like that. No
      things like that should ever overlap, period. When you look at the MOBILE
      version of the apps, I had the rule where if there's a message bar or
      you're in the mail app and something like a button is at the bottom of the
      page, the sliding out keyboard doc icon and the full doc itself ON MOBILE,
      they get moved up the page."
   The lift below was written to apply at EVERY width. His newest words say it
   is a MOBILE rule, so it is wrapped in the phone query. On a desktop the dock
   goes back to its normal place on the right edge and stops riding up over his
   messages. His older words that read "works on any size" are SUPERSEDED by
   this message; newest wins.
   REVERT THIS PART ALONE: delete the @media line and its closing brace.
   =========================================================================== */
@media (max-width: 640px) {
body:has([data-z-bottom-gui="1"]) .z-dockwrap,
body:has([data-z-bottom-gui="1"]) .z-dockwrap[data-z-align="start"],
body:has(.mail-message-actions) .z-dockwrap,
body:has(.mail-message-actions) .z-dockwrap[data-z-align="start"],
body:has(.composer-shell) .z-dockwrap,
body:has(.composer-shell) .z-dockwrap[data-z-align="start"],
body:has(.composer) .z-dockwrap,
body:has(.composer) .z-dockwrap[data-z-align="start"] {
  /* Z_THE_DOCK_LEAVES_ROOM_FOR_WHAT_HANGS_UNDER_IT_2026-09-02 (Agent D)
     FOUNDER, 2026-09-02: "I TOLD YOU TO MOVE THE FUCKING KEYBOARD SLIDEOUT AAAND
     THE FUCKING DOCK. WHY THE FUCK WOULD I WANT THAT UGLY MASHOP OF THEM
     OVERLAPPING!?"
     The keyboard tray hangs a fixed gap UNDER the dock and always has. Lifting the
     dock by the message bar alone left the tray still sitting on the message bar,
     and forcing the tray up on its own jammed it into the dock. Both were wrong.
     The dock now also leaves room for whatever hangs below it. z-keyboard.js
     measures its own tray and publishes --z-kb-tray-space; it is 0 when there is
     no tray, so nothing changes on pages without one. The two move as one stack
     and the gap between them never changes.
     REVERT THIS PART ALONE: delete "+ var(--z-kb-tray-space, 0px)". */
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--composer-height, 118px) + 18px + var(--z-kb-tray-space, 0px));
}
}


/* Z_THE_LIFT_HAS_TO_BEAT_THE_STATIC_SHELL_RULE_2026-09-02 (Agent D)
   MEASURED, NOT GUESSED, live on a phone: --z-kb-tray-space read back as "76px"
   exactly as intended, and the dock wrapper's padding-bottom was 72px — not the
   sum above. The rule that actually wins is
   `body > #z-shell[data-z-static-shell="1"] .z-dockwrap { padding: 72px 0; }`
   near the top of this file. It carries an id, so it beats the plain
   body:has(...) .z-dockwrap lift, and it is a SHORTHAND, so it resets the bottom
   too. The lift above has therefore never applied on this page at all.
   THIS IS THE SAME LIFT, written so it wins: identical value, same four things
   counted as a bottom bar, just scoped through the same shell the winning rule
   uses. No new number and no second idea.
   REVERT THIS PART ALONE: delete this whole block. */
/* Z_THE_LIFT_IS_A_PHONE_RULE_ONLY_2026-09-02b (Agent A) — this is the copy that
   actually WINS (it carries the #z-shell id). I wrapped the weaker copy above in
   the phone query first and the desktop dock was STILL lifted - measured live at
   178px of padding on a 1440 window. This one was the reason. Same founder words:
   the move-up is a MOBILE rule, so it is now phone-only too. On a desktop the
   dock keeps its normal place on the right edge.
   REVERT THIS PART ALONE: delete the @media line and its closing brace. */
@media (max-width: 640px) {
body:has([data-z-bottom-gui="1"]) > #z-shell[data-z-static-shell="1"] .z-dockwrap,
body:has(.mail-message-actions) > #z-shell[data-z-static-shell="1"] .z-dockwrap,
body:has(.composer-shell) > #z-shell[data-z-static-shell="1"] .z-dockwrap,
body:has(.composer) > #z-shell[data-z-static-shell="1"] .z-dockwrap {
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--composer-height, 118px) + 18px + var(--z-kb-tray-space, 0px));
}
}

/* Z_THE_DOCK_SLIDES_WHEN_IT_MOVES_UP_2026-09-01 (Agent D)
   HIS WORDS: "make sure the dock moving to the upwards position uses a slide
   animation. look at all animations on the website and make sure it fits the
   family speed-wise, etc".
   THE FAMILY, read from tokens.css rather than picked: --z-dur is 180ms, fast is
   120ms, slow is 240ms, and the shared easing is --z-ease. The dock's own buttons
   already use var(--z-dur) var(--z-ease). So the slide uses the SAME pair — it
   belongs to the family instead of being a new speed.
   It is a slide because only the padding changes, which moves the dock up and
   down its own edge. Anyone who has asked for less motion gets none.
   REVERT THIS PART ALONE: delete this block. */
.z-dockwrap,
.z-dockwrap[data-z-align="start"] {
  transition: padding-bottom var(--z-dur, 180ms) var(--z-ease, cubic-bezier(.45,0,.55,1));
}
@media (prefers-reduced-motion: reduce) {
  .z-dockwrap,
  .z-dockwrap[data-z-align="start"] { transition: none; }
}

/* Z_MOBILE_APP_MENU_ALWAYS_FITS_2026-09-01 (Agent D) — HIS WORDS: "THE MOBILE
   APP MENU DOESNT SHOW WHEN THE 3 DOTS ARE CLICKED. MAKE IT SHOW THE MENYU, AND
   MAKE IT FIT IN THAT RED BOX- 90% THE WIDTH OF THE MENU, SO IT ALWAYS FITS".
   It carried min-width:258px and opened from the button's left edge, so on a
   phone it ran off the screen and the rows were unreachable. On a phone it is
   now fixed at 90% of the width, centred, sitting just under the app menu.
   REVERT THIS PART ALONE: delete this block. */
@media (max-width: 640px) {
  .z-pop--menu,
  .z-pop--sub {
    position: fixed;
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    top: calc(56px + 46px);
    min-width: 0;
    width: 90vw;
    max-width: 90vw;
    max-height: 60vh;
    overflow-y: auto;
  }
}

/* ===========================================================================
   Z_MOVING_A_WINDOW_FEELS_RIGHT_UNDER_A_FINGER_2026-09-01   (Assistant A)
   ===========================================================================
   Founder, 2026-09-01: "floating, dragging , resizing on mobile needs to be
   smoother and work better with touch".

   MEASURED, not guessed: the title bar and the eight edge grips had no rule
   telling the browser that a finger on them is a DRAG. So a finger scrolled
   the page instead, the phone took the gesture back mid-drag, and the window
   either did not move or stuck to the finger. That one missing rule is the
   whole "does not work with touch".

   The edges were also 9px wide and the corners 18px - fine for a mouse
   pointer, far too small for a fingertip. On a touch screen they are now
   nearly twice that, without changing how they look.

   REVERT THIS ALONE: delete this block.
   =========================================================================== */
.z-bar,
.z-grip {
  touch-action: none;
}

@media (pointer: coarse) {
  .z-grip--n, .z-grip--s { height: 16px; }
  .z-grip--w, .z-grip--e { width: 16px; }
  .z-grip--nw, .z-grip--ne, .z-grip--sw, .z-grip--se { width: 30px; height: 30px; }
  .z-bar { min-height: 42px; }
}

/* ==========================================================================
   Z_THE_OPTIONS_AND_3_DOTS_ARE_DRESSED_BEFORE_ANY_SCRIPT_RUNS_2026-09-03  (Agent A)
   ==========================================================================
   FOUNDER 2026-09-03: "APPMENU, DETAILS + 3 DOTS OPTIONS ARE NOT THERE ONLOAD...
   CONNECT IT FULLY TO THE DOCK & HOW IT LOADS."
   MEASURED at 250ms on a signed-in cold load: his dock is on screen at ~1.5s
   because its markup is in the SERVED BYTES. These two buttons are at ~2.1s
   because they have ZERO references there and are built by script.
   His law line 194: a control that script CREATES after load is a defect - it
   ships in the page, in place, first frame; script only fills and opens it.
   THE BLOCKER THIS REMOVES: the tray's own dress came from a <style> that
   z-design.js CREATES at runtime, so shipping the markup alone would have shown
   an undressed tray until that script ran. These four rules are copied WORD FOR
   WORD out of z-design.js zChatTabsCss so the look cannot drift, and they live
   here because this stylesheet is already linked on every page - it costs a
   visitor no extra request and it is in force on the very first frame, exactly
   like the dock's own rules above.
   z-design.js still injects its identical copy; identical rules applied twice
   change nothing on screen, and its own id guard means it never stacks up.
   REVERT THIS PART ALONE: delete this block. The script's copy still dresses
   the tray exactly as it does today.
   ========================================================================== */
.z-win .zd-chat-tabs,.z-window .zd-chat-tabs,[data-z-win] .zd-chat-tabs{position:absolute;}
.zd-chat-tabs{position:fixed;right:0;top:69px;z-index:2147482700;display:flex;flex-direction:column;gap:6px;padding:8px 7px;border-radius:14px 0 0 14px;border:0;background:linear-gradient(180deg,rgba(20,14,36,0.96),rgba(10,7,20,0.96));box-shadow:0 12px 34px rgba(0,0,0,0.42);}
.zd-chat-tab{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:0;border-radius:10px;background:transparent;color:#c4b5fd;cursor:pointer;}
.zd-chat-tab:hover,.zd-chat-tab:focus-visible{background:rgba(168,85,247,0.22);box-shadow:inset 3px 0 0 rgba(168,85,247,0.9);color:#fff;}

/* ===========================================================================
   Z_HIS_MESSAGE_BAR_REACHES_THE_END_2026-09-03   (Agent E)   ledger row 2209
   CHECK THE APPMENU, AND DETAILS+OPTIONS 3 DOTS ARE STILL WORKING PERFECTLY

   FOUNDER, 2026-09-03, with two screenshots of his own chat page:
     "SEE HOW THE BAGE CHAT GOT PUSHED OVER FOR THE DOCK AND THE OPTIONS Items?
      ... SO THE MESSAGES BAR, BACGKROUND, AND OPTIONS ON THE PPAGE -- WILL
      ALAWSSSYS EXTEND TO THE END.
      ONLY ITMES LIKE MESSAGES, AN D WHATEEVER ELSE IS ON THE PAGE GETS MOVERD
      1. move the page as it is now on chat for places that itd bloc kstuff
      2. stretch the backgorund AND the z message bar/menu items back so its
         JUST the content thats pusshed over"

   MEASURED FIRST, LIVE, SIGNED IN AS DARE, BEFORE A LINE WAS WRITTEN
   (core/tests/proofs/agentE-REACHEND-*, 2000x1600 and 1440x900, 36 of his real
   message rows on screen):
     .app-shell::before  position:fixed  left:0  right:0  width:2000px
        -> HIS BACKGROUND ALREADY REACHES THE END and never stopped short. A
           fixed pseudo element is positioned against the VIEWPORT, so the
           padding above cannot move it. That half of his order was already true.
     .composer-shell     position:absolute  left:0  right:0  inside .chat-body-root
        -> HIS MESSAGE BAR IS THE ONE THAT STOPS SHORT. chat-body-root sits inside
           .app-shell, the rule directly above pads .app-shell by the dock's width,
           so the bar inherits a box 64px narrower and ends at the padded edge
           instead of the real one. That is exactly what he photographed.
     .message-scroll     computed padding right = 10px, from
           max(10px, env(safe-area-inset-right))

   WHAT THIS RULE DOES, AND ONLY THIS:
     · pulls the message bar back out to the true screen edge, by giving it a
       negative right offset of exactly the dock's own reserve - one token, so
       the space the dock takes and the space the bar reclaims can never drift
     · adds that same reserve to the bar's own right padding, so his plus, his
       microphone and his orb keep the SAME clear space they have today and the
       dock never covers them. That is his "ONLY ITMES LIKE MESSAGES ... GETS
       MOVERD" - the bar reaches the end, the things inside it do not move under
       the dock. The existing max(10px, env(safe-area-inset-right)) is carried
       through, never replaced by a bare number, so his safe-area handling on a
       phone survives.

   WHAT IT DELIBERATELY DOES NOT DO, and why:
     · IT DOES NOT TOUCH THE .app-shell PADDING ABOVE. That padding is what keeps
       EVERY app's content clear of the dock, not just chat's - his clause 1 says
       "move the page as it is now ... for places that itd bloc kstuff", so the
       inset STAYS. I planned to move it onto the content and stopped: only chat
       has a .message-scroll, so removing it would have pushed mail, calendar,
       drive and ten more straight under the dock. That is the neighbour trap and
       it would have been a fix for one app that broke thirteen.
     · IT DOES NOT TOUCH THE BACKGROUND. Measured already full width; changing
       something that is already right is how things get broken.
     · It is scoped to the same html[data-z-pagebar-on="1"] state as the padding
       it corrects, so when there is no inset there is nothing to undo.

   --z-fill-reserve is 64px only where there is a real mouse and 0px everywhere
   else, so on a phone both values collapse to zero and nothing changes at all.

   REVERT: delete this whole block. The bar goes back to stopping short by the
   width of the dock.
   =========================================================================== */
html[data-z-pagebar-on="1"] .composer-shell {
  right: calc(-1 * var(--z-fill-reserve, 0px));
  padding-right: calc(max(10px, env(safe-area-inset-right)) + var(--z-fill-reserve, 0px));
}

/* ---- his settings styles (was /shared/settings/settings.css) ---- */
/* Z_ONE_LAYER_LEDGER_2026-08-31 - every layer in this project is written in ONE
   ledger, in shared/z-shell/tokens.css. Never type a raw z-index. If a part has
   no rung yet, add it to that ledger first, then use the token. */
/* ===========================================================================
   SETTINGS — STATIC STYLESHEET.  Assistant B, 2026-08-31.
   Marker: Z_SETTINGS_ONTOP_OF_DOCK_2026-08-31

   FOUNDER, 2026-08-28, verbatim:
     "when settings is open, its ONTOP of the dock."

   WHY THE OBVIOUS FIX DOES NOT WORK, MEASURED LIVE 2026-08-31 18:40 EST.
   My first attempt raised the settings panel's own z-index. It changed nothing,
   and the measurement said exactly why:
       settings panel   z-index 2147482600   and the DOCK was still in front
       dock             z-index 72
   A bigger number lost to a smaller one, so this was never about the number.
   Reading the ancestors of both settled it:
       settings  aside.settings-panel -> div.app-shell -> div#app      z-index 1
       dock      div.z-dockwrap       -> div#z-shell             z-index 2147481500
   Both #app and #z-shell are children of <body> and both start their own
   stacking world. Everything inside #app is trapped below everything inside
   #z-shell, no matter what number the panel itself carries.

   THE FIX, AND WHY IT IS SHAPED THIS WAY.
   While settings is open, #app is lifted one step above #z-shell. The step is
   DERIVED FROM HIS OWN NUMBER (#z-shell's 2147481500), not a number I chose.
   It is scoped to a state HIS OWN CODE already sets - the runtime writes
   data-z-shell-overlay-layer-owner="chat-ui-entry" onto .app-shell whenever the
   settings panel or the mobile drawer is covering the screen. No new state was
   invented and no marker was added to any file.

   THE MOMENT SETTINGS CLOSES, that attribute clears and #app drops back to its
   own layer, so the dock is in front again everywhere else. The dock is never
   hidden, never removed, and never touched - it is a permanent fixture and it
   stays one. The only window where it sits behind is while settings is open,
   which is precisely what he asked for.

   NOTHING IS MADE TO APPEAR HERE. A real stylesheet, linked in the head, parsed
   with the document. It changes only which of two things already on screen is
   drawn in front.

   UNDO: delete this file and the one line in app.js that links it.
   =========================================================================== */

body:has(> #app .app-shell[data-z-shell-overlay-layer-owner="chat-ui-entry"]) > #app {
  /* one step above #z-shell's own 2147481500 */
  /* Z_ONE_LAYER_LEDGER_2026-08-31 - no raw numbers any more. Founder, same day:
     "make sure the z-index of the settings is above the dock and the
     keyboard/gaming/etc tabs." That rung is --z-shell-settings: above the dock,
     the keyboard and its tray, below the sheets and item menus. The one ledger
     lives in shared/z-shell/tokens.css. */
  z-index: var(--z-shell-settings, 2147482900);
}


/* Z_SETTINGS_IS_A_FULL_WIDTH_APP_2026-08-31 -------------------------------
   Founder: "For the settings app, you just take the settings slideout pane and
   turn it into a full-width app that can be opened."
   So on this one route the slideout stops being a slideout: the same pane fills
   the work surface. Everything here is scoped to that route and cannot reach
   any other page. The frame and heading ship in the served HTML, so the page is
   real the moment it loads. */
[data-z-settings-page="true"] .zs-page {
  position: fixed;
  inset: 48px 64px 0 0;
  overflow: auto;
  background-color: rgb(13, 6, 23);
  z-index: 20;
  padding: 22px 26px 40px;
  box-sizing: border-box;
}
[data-z-settings-page="true"] .zs-page-head { margin: 0 0 14px; }
[data-z-settings-page="true"] .zs-page-title {
  margin: 0; font-size: 26px; font-weight: 700; letter-spacing: .2px;
  color: var(--text, #e8e8ea);
}
[data-z-settings-page="true"] .zs-page-sub {
  margin: 6px 0 0; font-size: 13px; color: var(--muted, #a8a8ad);
}
[data-z-settings-page="true"] .zs-page-host { min-height: 40px; }

/* the same pane, full width, on this route only */
[data-z-settings-page="true"] .settings-panel {
  position: fixed !important;
  inset: 48px 64px 0 0 !important;
  width: auto !important;
  max-width: none !important;
  border-radius: 0 !important;
  z-index: 21 !important;
}


/* Z_HIS_PURPLE_GROUND_GOES_2026-09-18 (root seat, Opus 5)
   HIS-WORDS:"PURPLE B ACKGROUND IS NOT REMOVED" - his message, 2026-09-18 01:54 EST.
   HIS-WORDS:"THERE IS A PIUUUUUURPLE FUCKING BACKGROUDN THAT SOME SHITHEADDED CUNT MADE THAT
   I DID NOT APPROVE / REMOOOOOVE IT!!! THE FUKCING ROWS GO RIGHT AGAINST HTE UFKCNIG
   ZHOME/WORLD BACKGROUND" - his message, 2026-09-17 22:01 EST.
   MEASURED 2026-09-18 02:2x EST, signed in, private window: his sales screen painted a flat
   sheet over his zhome background, so the red glow he asked to see never showed. The rule
   below is HIS OWN, written 2026-09-14 into face/deploy/sales/sales.css - and his page has
   never loaded that file, which is why it never reached his screen. Copied here unchanged.
   UNDO THIS PART ALONE: delete from this comment to the end of the block below. */
/* CODEX12_SALES_NATIVE_SHELL_GROUND_2026-09-14 — Sales owns no page-wide
   purple ground. The shared Z shell paints the purple field behind the app;
   these scoped template rules leave that field visible instead of painting a
   second dark-purple Sales rectangle. */
.z-sales-app,
.z-sales-view,
.z-sales-his-dash,
[data-z-sales-dash],
[data-z-sales-dash] .z-frame,
[data-z-sales-dash] .z-panel {
  background: transparent !important;
  background-color: transparent !important;
}
