/* The phone layout and touch controls (the mobile wave, docs/plans/mobile.md, lane L).
   Phone-only rules go under html[data-layout="phone"] (set by client/js/mobileLayout.js); rules for
   any touch device go under @media (hover: none) or (pointer: coarse). Loaded after the feature
   stylesheets and before the theme stylesheets (client/index.html).

   Phones show one pane at a time (#app[data-pane="nav|chat|members"]): the server rail and channel
   list (the drawer) on the left and the member list on the right sit under the chat, which slides
   aside to show one and keeps a 56 px edge in view. mobileLayout.js keeps --app-height and
   --app-offset (the visible viewport, so the keyboard never covers the composer) and
   --keyboard-inset (the part of the page the iOS keyboard covers) on <html>. */

/* ---- the page: one screen, the size of what is visible ---- */
/* The body is the visible viewport (iOS slides it up over the keyboard: --app-offset), and #app
   takes what its column leaves: the desktop app's title bar in a narrow window, and a notice bar
   (Enable notifications, Add to Home Screen) while one shows, sit above it. */
html[data-layout="phone"] body {
  position: fixed; left: 0; right: 0; bottom: auto;
  top: var(--app-offset, 0px);
  height: 100vh;
  height: var(--app-height, 100dvh);
  overscroll-behavior: none;
}
/* An iPhone Home Screen app draws the page under a see-through status bar whose clock and battery
   are always white (apple-mobile-web-app-status-bar-style black-translucent, client/index.html;
   theme-color doesn't change them). Over the Light theme's light headers they would vanish, so a
   dark strip goes under them. env(safe-area-inset-top) is 0 wherever the page isn't drawn under a
   status bar (a Safari tab, landscape, Android, desktops): there the strip has no height. Settings
   is a full-screen dialog, above the page, so it gets its own. */
:root[data-theme="light"] body::after,
:root[data-theme="light"] #settings[open]::after {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: env(safe-area-inset-top);
  background: rgba(0, 0, 0, 0.6);
  pointer-events: none;
  z-index: 2147483647;
}

/* The sign-in screen scrolls when its card is taller than what is left of the screen (landscape,
   the keyboard up, the Add to Home Screen hint above it): the body itself never scrolls. The card
   is centred by its margins, which give way to the top when it doesn't fit. */
html[data-layout="phone"] .auth {
  min-height: 0;
  overflow-y: auto;
  place-items: start center;
  padding: 12px max(8px, env(safe-area-inset-right)) max(12px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
}
html[data-layout="phone"] .auth-card { margin: auto 0; }
html[data-layout="phone"] .app {
  --drawer: min(calc(100% - 56px), 420px); /* rail and channel list; % of #app (and of .chat, as wide) */
  --members: min(calc(100% - 56px), 360px);
  position: relative;
  isolation: isolate; /* the panes stack among themselves, under popouts, menus and toasts */
  display: block;
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
}

/* ---- the three panes ---- */
html[data-layout="phone"] .guild-rail {
  position: absolute; top: 0; bottom: 0; left: 0;
  width: calc(72px + env(safe-area-inset-left));
  padding: calc(12px + env(safe-area-inset-top)) 0 calc(12px + env(safe-area-inset-bottom)) env(safe-area-inset-left);
}
html[data-layout="phone"] .sidebar {
  position: absolute; top: 0; bottom: 0;
  left: calc(72px + env(safe-area-inset-left));
  width: calc(var(--drawer) - 72px - env(safe-area-inset-left));
}
html[data-layout="phone"] #app > .member-list {
  display: block; /* the desktop layout hides it below 1000 px, or on request */
  position: absolute; top: 0; bottom: 0; right: 0;
  width: var(--members);
  padding: calc(16px + env(safe-area-inset-top)) calc(8px + env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) 8px;
}
html[data-layout="phone"] .app > .chat {
  position: absolute; inset: 0; z-index: 2;
  transition: transform 200ms ease, box-shadow 200ms ease;
}
html[data-layout="phone"] .app[data-pane="nav"] > .chat { transform: translateX(var(--drawer)); box-shadow: -4px 0 18px rgba(0, 0, 0, 0.45); }
html[data-layout="phone"] .app[data-pane="members"] > .chat { transform: translateX(calc(-1 * var(--members))); box-shadow: 4px 0 18px rgba(0, 0, 0, 0.45); }
/* Panes out of view can't be reached (or focused) behind the chat; they stay drawn while it slides. */
html[data-layout="phone"] .app > :is(.guild-rail, .sidebar, .member-list) { visibility: hidden; transition: visibility 0s linear 200ms; }
html[data-layout="phone"] .app[data-pane="nav"] > :is(.guild-rail, .sidebar),
html[data-layout="phone"] .app[data-pane="members"] > .member-list { visibility: visible; transition-delay: 0s; }
html[data-layout="phone"] .app[data-pane="nav"] .mobile-nav-button,
html[data-layout="phone"] .app[data-pane="members"] .mobile-members-button { color: var(--text-strong); }
@media (prefers-reduced-motion: reduce) {
  html[data-layout="phone"] .app > .chat, html[data-layout="phone"] .app > :is(.guild-rail, .sidebar, .member-list) { transition: none; }
}
/* Search results take the whole screen, over the chat. */
html[data-layout="phone"] #app > .search-panel { position: absolute; inset: 0; z-index: 5; border: 0; padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
html[data-layout="phone"] .search-panel-header { height: 52px; }

/* ---- the drawer ---- */
html[data-layout="phone"] .sidebar-header { height: calc(48px + env(safe-area-inset-top)); padding-top: env(safe-area-inset-top); }
html[data-layout="phone"] .user-panel { height: calc(56px + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom); }
.mobile-find { display: none; }
html[data-layout="phone"] .mobile-find { display: flex; flex: none; align-items: center; gap: 8px; margin: 10px 8px 0; padding: 9px 10px; border: 0; border-radius: 6px; background: var(--bg-rail); color: var(--text-muted); font-size: 14px; text-align: left; }
html[data-layout="phone"] .mobile-find .icon { flex: none; }
/* Home has its own "Find or start a conversation" (the DM finder) at the top of the list. */
html[data-layout="phone"] .sidebar:has(.dm-find) .mobile-find { display: none; }
html[data-layout="phone"] .channel { min-height: 36px; }

/* ---- the chat: header, messages, composer ---- */
html[data-layout="phone"] .chat-header {
  height: calc(48px + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) calc(8px + env(safe-area-inset-right)) 0 calc(4px + env(safe-area-inset-left));
  gap: 4px;
}
html[data-layout="phone"] .chat-header .topic, html[data-layout="phone"] .member-list-toggle { display: none; }
html[data-layout="phone"] .chat-header .channel-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
html[data-layout="phone"] .chat-header > :is(.mobile-nav-button, .mobile-members-button) { flex: none; display: grid; place-items: center; width: 40px; height: 40px; padding: 0; }
html[data-layout="phone"] .chat-header > .mobile-members-button { order: 1; margin-left: auto; }
html[data-layout="phone"] .app:has(> #member-list:empty) .mobile-members-button { display: none; } /* nothing to show */
html[data-layout="phone"] .chat-header:has(> :is(.pins-button, .dm-call-buttons, .voice-chat-toggle)) > .mobile-members-button { margin-left: 0; }
/* The search box is a magnifier at the header's right end that widens over the header while typing. */
html[data-layout="phone"] #app .chat > .channel-search { top: calc(8px + env(safe-area-inset-top)); right: calc(8px + env(safe-area-inset-right)); width: 36px; transition: none; }
html[data-layout="phone"] #app .chat:has(> .inbox-button:not([hidden])) > .channel-search { right: calc(48px + env(safe-area-inset-right)); }
html[data-layout="phone"] #app .chat > .channel-search:not(:focus-within) .search-input { color: transparent; background: none; padding: 0; cursor: pointer; }
html[data-layout="phone"] #app .chat > .channel-search:not(:focus-within) .search-input::placeholder { color: transparent; }
html[data-layout="phone"] #app .chat > .channel-search:not(:focus-within) .search-glass { display: grid; right: 8px; }
html[data-layout="phone"] #app .chat > .channel-search:not(:focus-within) .search-clear { display: none; }
html[data-layout="phone"] #app .chat > .channel-search:focus-within { left: calc(8px + env(safe-area-inset-left)); right: calc(8px + env(safe-area-inset-right)); width: auto; z-index: 7; }
html[data-layout="phone"] .search-suggestions { left: 0; right: 0; width: auto; max-height: calc(var(--app-height, 100dvh) - 64px - env(safe-area-inset-top)); }
html[data-layout="phone"] #app .chat > .inbox-button { top: calc(8px + env(safe-area-inset-top)); right: calc(8px + env(safe-area-inset-right)); }
html[data-layout="phone"] #app .chat:has(> .channel-search:not([hidden])) > .chat-header,
html[data-layout="phone"] #app .chat:has(> .inbox-button:not([hidden])) > .chat-header { padding-right: calc(48px + env(safe-area-inset-right)); }
html[data-layout="phone"] #app .chat:has(> .inbox-button:not([hidden])):has(> .channel-search:not([hidden])) > .chat-header { padding-right: calc(88px + env(safe-area-inset-right)); }

/* Messages: on a touch screen long-press opens a message's actions, so its hover toolbar goes (a
   narrow window with a mouse keeps it). */
html[data-layout="phone"] .messages { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
html[data-layout="phone"] .message { grid-template-columns: 52px minmax(0, 1fr); padding: 2px 12px; }
@media (hover: none) {
  html[data-layout="phone"] .message .actions { display: none !important; }
}
html[data-layout="phone"] .reply-preview { margin-left: 52px; }

html[data-layout="phone"] .composer-wrap { padding: 0 calc(8px + env(safe-area-inset-right)) 4px calc(8px + env(safe-area-inset-left)); }
/* The home indicator's strip, except while the keyboard covers it anyway. */
html[data-layout="phone"]:not([data-keyboard="open"]) .composer-wrap { padding-bottom: calc(4px + env(safe-area-inset-bottom)); }
html[data-layout="phone"] .composer textarea { max-height: 30vh; max-height: 30dvh; }
.composer-send { flex: none; align-self: flex-end; display: grid; place-items: center; width: 36px; height: 36px; margin: 6px 6px 6px 0; padding: 0; border: 0; border-radius: 50%; background: var(--bg-active); color: var(--text-muted); }
.composer-send.ready { background: var(--accent); color: #fff; }
/* The edit box's Cancel and Save on touch screens (app.js attachEditor). */
.message .edit-buttons { display: flex; justify-content: flex-end; gap: 8px; margin: 6px 0 2px; }
.message .edit-buttons button { padding: 8px 16px; }

/* ---- sheets: the shared #popout, at the bottom (mobileLayout.js placeSheet) ---- */
html[data-layout="phone"] .sheet-backdrop { position: fixed; inset: 0; z-index: 29; background: rgba(0, 0, 0, 0.55); }
html[data-layout="phone"] .popout.sheet {
  left: 0; right: 0; top: auto;
  bottom: var(--keyboard-inset, 0px);
  max-height: calc(100vh - 24px);
  max-height: calc(var(--app-height, 100dvh) - 24px - env(safe-area-inset-top));
  display: flex; flex-direction: column;
  overflow: hidden auto;
  filter: none;
  background: var(--bg-rail);
  border-radius: 14px 14px 0 0;
  padding-bottom: env(safe-area-inset-bottom);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.45);
}
html[data-layout="phone"] .popout.sheet > * { width: auto; max-width: none; flex: none; border-radius: 0; border-left: 0; border-right: 0; }
html[data-layout="phone"] .popout.sheet > :is(.status-menu, .attach-menu) { padding: 8px; }
html[data-layout="phone"] .popout.sheet .status-option { min-height: 48px; }
/* Lists and profiles fill the screen, under a Close bar. */
html[data-layout="phone"] .popout.sheet.full {
  top: var(--app-offset, 0px); bottom: auto;
  height: 100vh; height: var(--app-height, 100dvh);
  max-height: none; border-radius: 0;
  padding-top: env(safe-area-inset-top);
}
html[data-layout="phone"] .popout.sheet.full > :not(.sheet-bar) { flex: 1 1 auto; min-height: 0; height: auto; max-height: none; border: 0; }
html[data-layout="phone"] .popout.sheet.full > .profile-card { overflow-y: auto; }
html[data-layout="phone"] .sheet-bar { display: flex; justify-content: flex-end; align-items: center; height: 48px; padding: 0 8px; background: var(--bg-rail); }
html[data-layout="phone"] .sheet-close { display: grid; place-items: center; width: 40px; height: 40px; padding: 0; }
/* The emoji picker: the whole width, 60% of the screen high. */
html[data-layout="phone"] .popout.sheet > .emoji-picker { height: 60vh; height: 60dvh; max-height: none; border-top: 0; }

/* ---- context menus as action sheets (client/js/contextMenu.js sheet mode) ---- */
html[data-layout="phone"] .context-menu-layer.sheet-mode { inset: 0; }
html[data-layout="phone"] .context-sheet-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
html[data-layout="phone"] .context-sheet {
  position: absolute; left: 0; right: 0;
  bottom: var(--keyboard-inset, 0px);
  max-height: calc(100vh - 48px);
  max-height: calc(var(--app-height, 100dvh) - 48px - env(safe-area-inset-top));
  display: flex; flex-direction: column;
  padding: 4px env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background: var(--bg-rail);
  border-radius: 14px 14px 0 0;
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.45);
}
html[data-layout="phone"] .context-sheet-title { flex: none; padding: 12px 20px 4px; font-size: 12px; font-weight: 700; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html[data-layout="phone"] .sheet-mode .context-menu { position: static; flex: 1 1 auto; min-width: 0; max-width: none; max-height: none; overflow-y: auto; padding: 4px 8px 8px; border: 0; border-radius: 0; background: none; box-shadow: none; font-size: 16px; }
html[data-layout="phone"] .sheet-mode .context-menu-item { min-height: 48px; padding: 10px 12px; }
html[data-layout="phone"] .sheet-mode .context-menu-item:focus:not(:focus-visible) { background: none; color: var(--text); }
html[data-layout="phone"] .sheet-mode .context-menu-item.danger:focus:not(:focus-visible) { color: var(--danger); }
html[data-layout="phone"] .sheet-mode .context-menu-item:not(.disabled):active { background: var(--bg-hover); }
html[data-layout="phone"] .sheet-mode .context-sheet-back { color: var(--text-muted); }
html[data-layout="phone"] .sheet-mode .context-menu-custom { padding: 8px 12px; }

/* ---- Settings: the list of sections, then one page (mobileLayout.js settingsOpened) ---- */
html[data-layout="phone"] .settings {
  position: fixed; inset: var(--app-offset, 0px) 0 auto 0;
  width: 100%; max-width: none;
  height: 100vh; height: var(--app-height, 100dvh); max-height: none;
  margin: 0; border-radius: 0;
}
html[data-layout="phone"] .settings .settings-layout { display: block; height: 100%; }
html[data-layout="phone"] .settings[data-settings-view="list"] .settings-content,
html[data-layout="phone"] .settings[data-settings-view="page"] .settings-nav { display: none; }
html[data-layout="phone"] .settings .settings-nav { height: 100%; overflow-y: auto; flex-direction: column; padding: calc(56px + env(safe-area-inset-top)) calc(12px + env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left)); }
html[data-layout="phone"] .settings .settings-nav button { min-height: 48px; padding: 12px; font-size: 16px; }
html[data-layout="phone"] .settings .settings-content { height: 100%; padding: calc(4px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left)); }
html[data-layout="phone"] .settings .settings-close { top: calc(6px + env(safe-area-inset-top)); right: calc(8px + env(safe-area-inset-right)); z-index: 2; }
.settings-back { display: flex; align-items: center; gap: 2px; min-height: 48px; margin: 0 48px 8px -8px; padding: 0 8px 0 0; border: 0; background: none; color: var(--text-strong); font-size: 17px; font-weight: 700; }
html[data-layout="phone"] .settings-split { grid-template-columns: 1fr; }

/* ---- dialogs, toasts and the rest ---- */
html[data-layout="phone"] dialog.modal { width: calc(100% - 24px); max-height: calc(100vh - 24px); max-height: calc(var(--app-height, 100dvh) - 24px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); overflow-y: auto; }
html[data-layout="phone"] .quick-switcher { width: calc(100% - 16px); margin: calc(8px + env(safe-area-inset-top)) auto auto; max-height: calc(var(--app-height, 100dvh) - 16px - env(safe-area-inset-top)); }
html[data-layout="phone"] .toasts { bottom: calc(80px + env(safe-area-inset-bottom) + var(--keyboard-inset, 0px)); width: calc(100% - 32px); align-items: center; }
html[data-layout="phone"] .connection-banner { top: calc(8px + env(safe-area-inset-top)); }

/* ---- touch screens: no hover ---- */
/* Text boxes under 16 px make iOS zoom the page while typing. */
@media (pointer: coarse) {
  input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"]), textarea, select { font-size: 16px !important; }
}
@media (hover: none) {
  /* Long-press opens these rows' menus, not the browser's text selection or image callout. */
  :is(.message, .channel, .channel-item, .category-header, .member, .voice-user, .guild-icon, .dm-row, .friend-row, .pin-item, .search-result, .inbox-item, .tile, .role-row, .reaction),
  .message img, .message video { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }

  /* Controls that only showed on hover. (The message toolbar, member Kick and Ban and Close DM
     are in their rows' long-press menus instead.) */
  .reaction.reaction-add { visibility: visible; }
  .tile .fullscreen-btn { display: block; }
  .pin-item .pin-controls, .inbox-item .inbox-controls { display: flex; }
  .role-row .role-move-buttons { display: inline-flex; }
  .voice-chat-button { opacity: 1; }
  .invite-row .invite-revoke, .search-result .search-jump, .call-pip .call-pip-hide, .strip-toggle { opacity: 1; }
  .friend-row .friend-username { visibility: visible; }
  .lightbox.media-viewer.mv-zoomed .mv-nav { opacity: 1; }
  /* The open channel keeps its gear; the others' invisible gears would catch taps meant for the
     channel (Edit Channel is in the long-press menu). */
  .channel-settings-button { visibility: hidden; }
  :is(.channel-row, .voice-channel-row):has(.channel.active) .channel-settings-button { visibility: visible; opacity: 1; }
}
