/* Kronenfall – phones.
 *
 * Phones used to be locked to landscape by a "rotate your device" gate. The gate is
 * gone (WCAG 1.3.4), so this sheet gives the game a phone layout in both
 * orientations. js/ui/mobile-layout.js sets `html.is-mobile-client` plus
 * `body.is-mobile-portrait` or `body.is-mobile-landscape`. Section 1 applies to
 * every phone; the castle HUD (3) is one compact layout for both orientations;
 * the rest is portrait. styles/mobile-landscape.css keeps the older
 * landscape-only rules (profile stage, event screens) and loads before this.
 *
 * Castle HUD budget on a 390x844 phone: a slim top row (crest, name, three
 * resource chips), a 44px icon rail down each side, and at the bottom a
 * swipeable nav, the event-poster strip above it and the chat bar above that.
 * The map gets the rest. 44px (2.75rem) is the tap-target floor for everything
 * a thumb aims at.
 */

/* ---------------------------------------------------------------------------
 * 1. Every phone, both orientations
 * ------------------------------------------------------------------------- */

html.is-mobile-client {
  --kf-safe-t: env(safe-area-inset-top, 0px);
  --kf-safe-r: env(safe-area-inset-right, 0px);
  --kf-safe-b: env(safe-area-inset-bottom, 0px);
  --kf-safe-l: env(safe-area-inset-left, 0px);
  --kf-tap: 2.75rem;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* A drag across the map must never become the browser's pull-to-refresh or
   back-swipe; the map views scroll nothing at page level anyway. */
html.is-mobile-client,
html.is-mobile-client body {
  overscroll-behavior: none;
}

/* No 300ms double-tap-zoom wait on anything tappable, and no grey flash. */
html.is-mobile-client :is(button, a[href], [role="button"], label, summary, select, input) {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* iOS Safari zooms the whole page when a field under 16px takes focus. */
html.is-mobile-client
  :is(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]), select, textarea) {
  font-size: max(1rem, 16px);
}

/* A long press on the map or a launcher selected text and opened the callout. */
html.is-mobile-client :is(.castle-overlay-hud, .castle-map-shell, .world-map, .map-hud, .castle-bottom-nav) {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

html.is-mobile-client :is(.castle-overlay-hud, .world-map) :is(input, textarea) {
  -webkit-user-select: text;
  user-select: text;
}

/* A touch screen keeps :hover stuck where the finger last lifted. A tooltip that
   rendered under that point opened by itself — and, as a sheet over the map,
   swallowed the next tap. On touch they open by tap only (js/ui/ui-hud.js). */
@media (hover: none) {
  .resource-with-tooltip:hover:not(.is-tooltip-open):not(:focus-within) .resource-tooltip {
    opacity: 0;
    pointer-events: none;
  }

  .resource-with-tooltip:hover:not(.is-tooltip-open):not(:focus-within)::after {
    display: none;
  }
}

/* Fullscreen: an icon on phones, the word only where there is room for it. */
.mobile-fullscreen-toggle {
  align-items: center;
  gap: 0.35rem;
  justify-content: center;
}

.mobile-fullscreen-icon {
  display: inline-flex;
  line-height: 0;
}

.mobile-fullscreen-icon svg {
  display: block;
  height: 1.15rem;
  width: 1.15rem;
}

html.is-mobile-client .mobile-fullscreen-toggle {
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
  padding: 0 0.6rem;
}

html.is-mobile-client .mobile-fullscreen-label {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

/* Chat on phones: 16px field (no iOS zoom), 44px buttons, and the enlarged chat
   above every piece of HUD chrome — it sat under the top-right column, so its
   shrink button used to open the Season Hub. */
html.is-mobile-client .castle-chat-toggle,
html.is-mobile-client .castle-chat-send {
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
}

html.is-mobile-client .castle-chat-input {
  min-height: var(--kf-tap);
}

html.is-mobile-client .castle-chat-tab {
  min-height: 2.5rem;
}

html.is-mobile-client .castle-log-alert .text-button {
  min-height: 2.25rem;
  padding-block: 0.4rem;
}

/* Above the fixed Social button (z 120) on the world map; still under modals (200). */
html.is-mobile-client .castle-chat-expanded-overlay {
  padding: 0;
  z-index: 130;
}

html.is-mobile-client .castle-chat-expanded-panel {
  border-radius: 0;
  height: 100dvh;
  max-height: none;
  max-width: none;
  padding: var(--kf-safe-t) var(--kf-safe-r) var(--kf-safe-b) var(--kf-safe-l);
  width: 100vw;
}

/* Phones know two chat sizes (js/systems/chat-admin.js): collapsed is one "Chat"
   button, open is the sheet above. The in-between panel used to open on every
   load and cover the castle. */
html.is-mobile-client .castle-chat-panel.is-collapsed {
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
}

html.is-mobile-client .castle-chat-panel.is-collapsed :is(.castle-chat-head-title, .castle-chat-world-badge, .castle-chat-admin-badge) {
  display: none;
}

html.is-mobile-client .castle-chat-panel.is-collapsed .castle-chat-toggle {
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-card);
  font-size: var(--text-small);
  letter-spacing: 0.04em;
  padding: 0 0.9rem;
  text-transform: uppercase;
}

/* ⤢ / ⤡ pick the size in between; there is none on phones. */
html.is-mobile-client .castle-chat-toggle[aria-pressed] {
  display: none;
}

/* ---------------------------------------------------------------------------
 * 2. Phone layout tokens and page frame
 * ------------------------------------------------------------------------- */

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) {
  --kf-gutter: 0.5rem;
  --kf-nav-h: calc(4.6rem + var(--kf-safe-b));
  --kf-ads-h: 3.4rem;
  --kf-top-h: 4.75rem;
  --kf-hud-icon: 2.4rem;
}

/* Landscape has height to spare nowhere: a lower nav, and the posters move to a
   column beside the right rail instead of a strip above the nav. */
html.is-mobile-client body.is-mobile-landscape {
  --kf-gutter: 0.4rem;
  --kf-nav-h: calc(4.1rem + var(--kf-safe-b));
  --kf-ads-h: 0rem;
  --kf-top-h: 4.5rem;
  --kf-hud-icon: 2.2rem;
}

html.is-mobile-client body.is-mobile-portrait .app:is(.is-castle-view, .is-capital-view, .is-demon-view, .is-island-view, .is-world-view) {
  min-height: 100vh;
  min-height: 100dvh;
}

html.is-mobile-client body.is-mobile-portrait .app.is-castle-view #castlePanel.panel,
html.is-mobile-client body.is-mobile-portrait .app.is-castle-view .castle-map-shell {
  max-height: 100vh;
  max-height: 100dvh;
  min-height: 100vh;
  min-height: 100dvh;
}

/* ---------------------------------------------------------------------------
 * 3. Castle HUD on phones, both orientations (also drawn over the capital city).
 *    Only the poster strip (3c) and the tray sheet (3g) differ by orientation.
 * ------------------------------------------------------------------------- */

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud {
  --castle-nav-icon: var(--kf-hud-icon);
  --castle-nav-pad: 0.15rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud :is(
    .castle-quest-toggle-icon,
    .castle-minigame-toggle-icon,
    .castle-queue-toggle-icon,
    .season-launcher-icon,
    .castle-world-map-button-icon
  ) {
  height: var(--kf-hud-icon);
  width: var(--kf-hud-icon);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud :is(
    .castle-quest-toggle--icon,
    .castle-minigame-toggle--icon,
    .castle-queue-toggle--icon,
    .season-launcher--icon
  ) {
  padding: var(--castle-nav-pad);
}

/* 3a. Left side: the account row on top, then a rail of Map / Quests / Resources,
   and the chat + log pair at the bottom of the band. The wrappers are full-width
   boxes, so they let taps through; only their controls take them. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-column {
  bottom: calc(var(--kf-nav-h) + var(--kf-ads-h) + 1.1rem);
  gap: var(--kf-gutter);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + var(--kf-gutter));
  width: calc(100vw - var(--kf-safe-l) - var(--kf-safe-r) - 4.25rem);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-column :is(
    .castle-left-top,
    .castle-left-bottom,
    [data-castle-hud-section],
    .castle-quest-launcher,
    .castle-resource-launcher,
    .castle-log-launcher
  ) {
  pointer-events: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-column :is(
    button,
    input,
    form,
    .castle-account-panel,
    .castle-chat-panel,
    .castle-hud-dropdown,
    .castle-menu-dropdown,
    .castle-upkeep-warnings,
    .resource-with-tooltip:is(.is-tooltip-open, :focus-within) .resource-tooltip
  ) {
  pointer-events: auto;
}

/* Only an OPEN tooltip takes hits. A closed one is opacity 0 but still laid out
   as a fixed 374x416 sheet over the map's centre (3h below); with pointer-events
   on it swallowed every one-finger pan and building tap that started there. On a
   mouse the hover-opened sheet must stay hittable so it can be scrolled. */
@media (hover: hover) {
  html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-column .resource-with-tooltip:hover .resource-tooltip {
    pointer-events: auto;
  }
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-top {
  gap: var(--kf-gutter);
  justify-items: start;
}

/* The Map launcher is drawn by another section (top-center); it takes the first
   slot of the rail, so the rail starts one launcher lower. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-top > [data-castle-hud-section="quest-launcher"] {
  margin-top: calc(var(--kf-hud-icon) + 0.3rem + 1.05rem);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-quest-launcher,
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-resource-launcher,
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-column .castle-log-launcher {
  width: max-content;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-column .castle-log-toggle {
  width: auto;
}

/* Account row: crest, then name + house thumb over the three resource chips. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-account-panel--crest {
  align-items: center;
  display: flex;
  flex-direction: row;
  gap: var(--kf-gutter);
  max-width: 100%;
  min-height: var(--kf-top-h);
  padding: 0.25rem 0.45rem 0.25rem 0.25rem;
  width: max-content;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-account-crest-hero {
  flex: 0 0 3.75rem;
  margin: 0;
  max-width: 3.75rem;
  width: 3.75rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-account-crest-hero:has(.crest-signature-composed--supporters) {
  flex-basis: 6rem;
  max-width: 6rem;
  width: 6rem;
}

/* The whole badge opens the roadmap, not a 42%-wide sliver of it. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-level-overlay,
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-level-overlay:is(:hover, :focus-visible) {
  height: 100%;
  inset: 0;
  justify-content: center;
  padding-bottom: 22%;
  transform: none;
  width: 100%;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-level-num {
  font-size: var(--text-subhead);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-level-xp {
  height: 0.2rem;
  margin-top: 0.12rem;
  width: 46%;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-prestige-overlay {
  bottom: -0.15rem;
  gap: 0;
  min-width: 0;
  padding: 0.05rem 0.3rem;
  top: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-prestige-label {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-prestige-crown {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-prestige-value {
  font-size: var(--text-micro);
}

/* Visually a small chip; the hit area is the lower half of the crest. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-prestige-overlay::after {
  content: "";
  inset: -0.6rem -0.9rem -0.4rem;
  position: absolute;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-account-panel--crest .castle-account-panel-body {
  align-items: center;
  display: grid;
  flex: 1 1 auto;
  gap: 0.3rem 0.4rem;
  grid-template-columns: minmax(0, max-content) auto;
  justify-content: start;
  min-width: 0;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-profile-banner {
  background: none;
  border: 0;
  flex-wrap: nowrap;
  justify-content: flex-start;
  min-width: 0;
  padding: 0;
  text-align: left;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-profile-banner .castle-player-name {
  font-size: var(--text-body);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-profile-banner :is(
    .castle-crest-profile-divider,
    .castle-name-label,
    .castle-prestige-title,
    .castle-game-date
  ) {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-account-panel-body .house-identity-crest-line {
  flex-wrap: nowrap;
  height: 2.25rem;
  justify-content: center;
  justify-self: start;
  margin: 0;
  padding: 0;
  width: 2.25rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-account-panel-body .house-identity-motto {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-resource-strip {
  display: flex;
  gap: 0.3rem;
  grid-column: 1 / -1;
  width: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-resource-chip {
  align-items: center;
  display: flex;
  flex: 0 1 auto;
  gap: 0.25rem;
  min-height: 2.25rem;
  padding: 0.1rem 0.45rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-resource-icon {
  font-size: var(--text-body);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-crest-resource-value {
  font-size: var(--text-small);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) :is(.castle-crest-resource-label, .castle-crest-resource-rate) {
  display: none;
}

/* Map launcher: top of the left rail, under the account row. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-center {
  --castle-nav-icon: var(--kf-hud-icon);
  --castle-nav-pad: 0.15rem;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + var(--kf-gutter) * 2 + var(--kf-top-h));
  transform: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud .castle-hud-icon-caption {
  font-size: var(--text-micro);
}

/* 3b. Right rail: ☰ first, then season / minigame / queue, fullscreen last. The
   panel spans the width so the "next up" chip can sit centred between the rails;
   the panel box itself takes no taps (it used to swallow a 179x366 block). */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-panel {
  gap: 0.4rem;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-width: none;
  pointer-events: none;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + var(--kf-gutter));
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-panel > *,
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-icons > * {
  pointer-events: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-icons {
  gap: 0.4rem;
  pointer-events: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-panel .castle-menu-launcher {
  order: -1;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-panel .castle-fullscreen-toggle {
  order: 5;
  padding: 0;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-menu-toggle {
  height: var(--kf-tap);
  min-width: var(--kf-tap);
  width: var(--kf-tap);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-panel .castle-menu-dropdown,
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-top-right-panel .castle-hud-dropdown {
  max-height: calc(100dvh - var(--kf-nav-h) - var(--kf-safe-t) - 4.5rem);
  overflow: auto;
  overscroll-behavior: contain;
  width: min(18rem, calc(100vw - 1rem));
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-next-up-launcher {
  display: flex;
  justify-content: center;
  left: 3.5rem;
  max-width: none;
  position: absolute;
  right: 3.5rem;
  top: calc(var(--kf-top-h) + var(--kf-gutter));
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-next-up-chip {
  max-width: 100%;
  min-height: 2.5rem;
  overflow: hidden;
  text-align: center;
  text-overflow: ellipsis;
}

/* 3c. Event posters: one swipeable strip just above the nav. */
html.is-mobile-client body.is-mobile-portrait .castle-event-ad-rail {
  bottom: calc(var(--kf-nav-h) + 0.35rem);
  flex-direction: row;
  gap: 0.4rem;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  padding-top: 0.4rem;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  scrollbar-width: none;
  top: auto;
  transform: none;
  width: auto;
}

html.is-mobile-client body.is-mobile-portrait .castle-event-ad-rail::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client body.is-mobile-portrait .castle-event-ad-rail:empty {
  display: none;
}

html.is-mobile-client body.is-mobile-portrait .castle-event-ad {
  flex: 0 0 8.75rem;
  gap: 0.1rem;
  min-height: var(--kf-ads-h);
  padding: 0.2rem 0.3rem 0.25rem 0.4rem;
  width: 8.75rem;
}

html.is-mobile-client body.is-mobile-portrait .castle-event-ad-copy {
  max-width: 72%;
}

html.is-mobile-client body.is-mobile-portrait .castle-event-ad-title {
  font-size: var(--text-small);
}

html.is-mobile-client body.is-mobile-portrait .castle-event-ad-tag {
  display: none;
}

/* Landscape: a column of compact posters beside the right rail. */
html.is-mobile-client body.is-mobile-landscape .castle-event-ad-rail {
  bottom: calc(var(--kf-nav-h) + 0.35rem);
  gap: 0.35rem;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-top: 0.4rem;
  right: calc(var(--kf-safe-r) + var(--kf-gutter) * 2 + var(--kf-tap));
  scrollbar-width: none;
  top: calc(var(--kf-safe-t) + var(--kf-gutter) - 0.4rem);
  transform: none;
  width: min(9rem, 24vw);
}

html.is-mobile-client body.is-mobile-landscape .castle-event-ad-rail::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client body.is-mobile-landscape .castle-event-ad {
  flex: 0 0 auto;
  gap: 0.1rem;
  min-height: 3rem;
  padding: 0.2rem 0.3rem 0.25rem 0.4rem;
}

html.is-mobile-client body.is-mobile-landscape .castle-event-ad-title {
  font-size: var(--text-small);
}

html.is-mobile-client body.is-mobile-landscape .castle-event-ad-tag {
  display: none;
}

/* 3d. Chat + log: side by side at the bottom of the left band. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-bottom {
  align-items: flex-end;
  display: flex;
  gap: 0.4rem;
  width: 100%;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-bottom > [data-castle-hud-section="chat"] {
  flex: 0 1 auto;
  min-width: 0;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-bottom .castle-chat-panel {
  max-width: min(16.5rem, calc(100vw - 8.5rem));
  padding: 0.3rem 0.4rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-bottom .castle-chat-panel:not(.is-collapsed) {
  width: min(16.5rem, calc(100vw - 8.5rem));
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-bottom .castle-chat-list {
  max-height: 2.6rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-left-bottom .castle-chat-panel.is-collapsed .castle-chat-head {
  min-height: var(--kf-tap);
}

/* 3e. Bottom nav: one full-width, swipeable row. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-bottom-nav {
  --castle-nav-gap: 0.3rem;
  --castle-nav-icon: var(--kf-hud-icon);
  --castle-nav-pad: 0.15rem;
  align-items: flex-start;
  background: color-mix(in srgb, var(--bg-panel) 94%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--accent-gold) 26%, transparent);
  bottom: 0;
  box-shadow: 0 -6px 18px rgba(0, 0, 0, 0.35);
  justify-content: flex-start;
  left: 0;
  max-width: none;
  min-height: var(--kf-nav-h);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  padding: 0.5rem calc(var(--kf-safe-r) + var(--kf-gutter)) calc(var(--kf-safe-b) + 0.3rem)
    calc(var(--kf-safe-l) + var(--kf-gutter));
  right: 0;
  scrollbar-width: none;
  transform: none;
  width: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-bottom-nav::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-bottom-nav :is(.castle-bottom-nav-side, .castle-commerce-launchers) {
  display: contents;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-bottom-nav .castle-hud-icon-stack {
  max-width: 3.5rem;
  width: 3.5rem;
}

/* 3f. Map controls above the poster strip, bottom right. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-rotate-view-button {
  bottom: calc(var(--kf-nav-h) + var(--kf-ads-h) + 1.1rem);
  height: var(--kf-tap);
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  width: var(--kf-tap);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-build-view-toggle {
  right: calc(var(--kf-safe-r) + var(--kf-gutter) + var(--kf-tap) + 0.4rem);
}

/* + / − stacked above the rotate button (js: renderCastleMapZoomButtons). */
.castle-map-zoom-buttons {
  bottom: calc(var(--kf-nav-h) + var(--kf-ads-h) + 1.1rem + var(--kf-tap) + 0.4rem);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  pointer-events: none;
  position: absolute;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  z-index: 15;
}

.castle-map-zoom-buttons > .castle-map-zoom-button {
  font-size: var(--text-title);
  font-weight: 700;
  height: var(--kf-tap);
  line-height: 1;
  pointer-events: auto;
  position: static;
  width: var(--kf-tap);
}

html.is-mobile-client body.is-mobile-landscape .castle-map-zoom-buttons {
  flex-direction: row-reverse;
  bottom: calc(var(--kf-nav-h) + 1.1rem);
  right: calc(var(--kf-safe-r) + var(--kf-gutter) + var(--kf-tap) + 0.4rem);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud:has(.castle-docked-tray) .castle-map-zoom-buttons {
  visibility: hidden;
}

/* 3g. Construct tray: a bottom sheet above the nav; the rest of the HUD steps
   aside while it is open, it used to cover the tray's own controls. */
html.is-mobile-client body.is-mobile-portrait .castle-docked-tray {
  border-radius: var(--radius-xl);
  bottom: calc(var(--kf-nav-h) + 0.35rem);
  height: min(64dvh, 36rem);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-height: calc(100dvh - var(--kf-nav-h) - var(--kf-safe-t) - 1rem);
  padding: 0.6rem 0.6rem 0.7rem;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: auto;
}

html.is-mobile-client body.is-mobile-portrait .castle-docked-tray-bar {
  flex-wrap: wrap;
  row-gap: 0.45rem;
}

html.is-mobile-client body.is-mobile-portrait .castle-docked-tray-tools {
  flex: 1 0 100%;
  order: 3;
  overflow-x: auto;
  scrollbar-width: none;
}

html.is-mobile-client body.is-mobile-portrait :is(.castle-docked-tray-tab, .castle-docked-tray-tool, .castle-docked-tray-close) {
  min-height: var(--kf-tap);
}

html.is-mobile-client .castle-docked-tray .leaderboard-tab {
  min-height: 2.5rem;
}

html.is-mobile-client body.is-mobile-portrait .castle-docked-tray-close {
  min-width: var(--kf-tap);
}

html.is-mobile-client body.is-mobile-portrait .castle-docked-tray .shop-showroom-scroll,
html.is-mobile-client body.is-mobile-portrait .castle-docked-tray .shop-showroom-canvas {
  min-height: 12rem;
}

html.is-mobile-client body.is-mobile-portrait .castle-overlay-hud:has(.castle-docked-tray) :is(
    .castle-left-column,
    [data-castle-hud-section="top-center"],
    [data-castle-hud-section="top-right"],
    .castle-event-ad-rail,
    .castle-rotate-view-button
  ) {
  visibility: hidden;
}

/* Landscape: the tray takes the whole height above the nav. At 32rem it left
   the building cards no room at all on a 390px-tall screen. */
html.is-mobile-client body.is-mobile-landscape .castle-docked-tray {
  bottom: calc(var(--kf-nav-h) + 0.3rem);
  gap: 0.35rem;
  height: auto;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-height: none;
  padding: 0.45rem 0.6rem 0.5rem;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + 0.3rem);
}

html.is-mobile-client body.is-mobile-landscape :is(.castle-docked-tray-tab, .castle-docked-tray-tool, .castle-docked-tray-close) {
  min-height: 2.5rem;
}

html.is-mobile-client body.is-mobile-landscape .castle-docked-tray .shop-showroom-scroll,
html.is-mobile-client body.is-mobile-landscape .castle-docked-tray .shop-showroom-canvas {
  min-height: 0;
}

html.is-mobile-client body.is-mobile-landscape .castle-docked-tray .shop-showroom-pan-hint {
  display: none;
}

html.is-mobile-client body.is-mobile-landscape .castle-overlay-hud:has(.castle-docked-tray) :is(
    .castle-left-column,
    [data-castle-hud-section="top-center"],
    [data-castle-hud-section="top-right"],
    .castle-event-ad-rail,
    .castle-rotate-view-button
  ) {
  visibility: hidden;
}

/* 3h. Resource tooltips and the resources dropdown open as sheets. As anchored
   popovers they ran off the right edge and sat under the nav and posters (the
   left column is its own stacking context below both). */
html.is-mobile-client .castle-left-column:has(
    .resource-with-tooltip:is(:hover, .is-tooltip-open, :focus-within),
    .castle-resource-dropdown
  ) {
  z-index: 25;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud .resource-with-tooltip .resource-tooltip {
  bottom: calc(var(--kf-nav-h) + 0.5rem);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-height: min(55dvh, 26rem);
  max-width: none;
  min-width: 0;
  position: fixed;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: auto;
  transform: none;
  width: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud .castle-resource-dropdown.castle-hud-dropdown {
  bottom: auto;
  max-height: calc(100dvh - var(--kf-safe-t) - var(--kf-top-h) - var(--kf-nav-h) - 1.5rem);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  overflow: auto;
  overscroll-behavior: contain;
  position: fixed;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + var(--kf-top-h) + 1rem);
  width: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud .castle-resource-dropdown {
  align-content: start;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-resource-dropdown .castle-resource-list--grid {
  align-content: start;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

html.is-mobile-client .castle-left-column:has(.castle-resource-dropdown) .castle-left-bottom {
  visibility: hidden;
}

/* ---------------------------------------------------------------------------
 * 4. World map on phones, both orientations
 *
 *    Top: one scrollable row of compact HUD chips, the zoom controls as a rail
 *    down the right edge. Bottom: chat on the left, the Castle button, the Social
 *    button on the right. The map owns every touch (pinch zooms it, not the page;
 *    js/ui/world-map-zoom.js).
 * ------------------------------------------------------------------------- */

html.is-mobile-client .app.is-world-view .world-map {
  touch-action: none;
}

html.is-mobile-client .app.is-world-view #worldPanel.panel {
  margin: 0;
  min-height: 100dvh;
  padding: 0;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .app.is-world-view .world-map {
  height: 100dvh;
  min-height: 100dvh;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud {
  align-items: stretch;
  display: flex;
  flex-wrap: nowrap;
  gap: 0.4rem;
  grid-template-columns: none;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  padding-top: 0.35rem;
  pointer-events: none;
  right: calc(var(--kf-safe-r) + var(--kf-gutter) * 2 + var(--kf-tap));
  scrollbar-width: none;
  top: calc(var(--kf-safe-t) + var(--kf-gutter) - 0.35rem);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud > * {
  flex: 0 0 auto;
  pointer-events: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud :is(.map-date, .map-army, .map-capital-hud, .map-world-boss-timer) {
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: var(--kf-tap);
  min-width: 0;
  padding: 0.2rem 0.6rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud :is(.map-date, .map-army, .map-capital-hud, .map-world-boss-timer) span {
  font-size: var(--text-micro);
  letter-spacing: 0.04em;
  white-space: nowrap;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud :is(.map-date, .map-army, .map-capital-hud, .map-world-boss-timer) strong {
  font-size: var(--text-small);
  line-height: 1.2;
  margin-top: 0;
  white-space: nowrap;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud .season-launcher--icon {
  align-self: stretch;
  padding: 0.15rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud .season-launcher-icon {
  height: 2.3rem;
  width: 2.3rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .map-hud > .map-menu-launcher {
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  width: auto;
}

/* Zoom: a rail down the right edge; the % reads as a label between − and +. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-zoom-controls {
  align-items: center;
  flex-direction: column;
  gap: 0.35rem;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + var(--kf-gutter));
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-zoom-button {
  font-size: var(--text-body-lg);
  height: var(--kf-tap);
  min-width: 0;
  padding: 0;
  width: var(--kf-tap);
}

.world-map-zoom-controls .pill {
  align-items: center;
  align-self: center;
  display: inline-flex;
  font-variant-numeric: tabular-nums;
  justify-content: center;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-zoom-controls .pill {
  font-size: var(--text-micro);
  min-width: var(--kf-tap);
  padding: 0.15rem 0.25rem;
}

/* Bottom row: chat left, Castle, then the Social button in the corner. */
html.is-mobile-client .social-root {
  bottom: calc(var(--kf-safe-b) + 0.6rem);
  right: calc(var(--kf-safe-r) + 0.5rem);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-bottom-nav {
  bottom: calc(var(--kf-safe-b) + 0.6rem);
  left: auto;
  right: calc(var(--kf-safe-r) + 6.5rem);
  transform: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-castle-button {
  min-height: var(--kf-tap);
  min-width: 6.5rem;
  padding: 0.5rem 1rem;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-chat-overlay {
  bottom: calc(var(--kf-safe-b) + 0.6rem);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-width: min(22rem, calc(100vw - 15rem));
}

/* An open chat rises above the bottom row and takes the width it needs. */
html.is-mobile-client body.is-mobile-portrait .world-map-chat-overlay:has(.castle-chat-panel:not(.is-collapsed)) {
  bottom: calc(var(--kf-safe-b) + var(--kf-tap) + 1.1rem);
  max-width: none;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  width: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .world-map-chat-overlay .castle-chat-list {
  max-height: 4.5rem;
}

/* The open chat sheet mounts inside .world-map, whose touch-action: none would
   otherwise stop the message list from scrolling under a finger. */
html.is-mobile-client .world-map .castle-chat-expanded-overlay {
  touch-action: auto;
}

/* Labels only from 4× on phones (balance.js labelZoomThresholdMobile); the ones
   that do show keep to a width a 390px screen can hold several of. */
html.is-mobile-client .world-map .map-label {
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* March detail: a sheet above the bottom row (portrait), a card left of the zoom
   rail (landscape). */
html.is-mobile-client body.is-mobile-portrait .map-troop-detail-panel {
  bottom: calc(var(--kf-safe-b) + var(--kf-tap) + 1.1rem);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-height: 45dvh;
  max-width: none;
  overflow: auto;
  overscroll-behavior: contain;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  z-index: 13;
}

html.is-mobile-client body.is-mobile-landscape .map-troop-detail-panel {
  bottom: calc(var(--kf-safe-b) + var(--kf-tap) + 1.1rem);
  max-height: calc(100dvh - var(--kf-tap) * 2 - 2rem);
  max-width: none;
  overflow: auto;
  overscroll-behavior: contain;
  right: calc(var(--kf-safe-r) + var(--kf-gutter) * 2 + var(--kf-tap));
  top: calc(var(--kf-safe-t) + var(--kf-tap) + 1rem);
  width: min(22rem, 48vw);
  z-index: 13;
}

html.is-mobile-client .map-troop-detail-close {
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .demon-march-planning-banner {
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-width: none;
  right: calc(var(--kf-safe-r) + var(--kf-gutter) * 2 + var(--kf-tap));
  top: calc(var(--kf-safe-t) + var(--kf-gutter) + var(--kf-tap) + 0.5rem);
  transform: none;
}

/* ---------------------------------------------------------------------------
 * 5. Other map views on phones: island, capital city, demon castle
 *
 *    They reuse the castle HUD (section 3) with their own bottom nav, and the
 *    global Social button floats bottom-right in all of them — the nav leaves
 *    it room instead of running underneath it.
 * ------------------------------------------------------------------------- */

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .app:is(.is-island-view, .is-capital-view, .is-demon-view) .castle-bottom-nav {
  padding-right: calc(var(--kf-safe-r) + 6.5rem);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .island-bottom-nav :is(button, .secondary-button) {
  flex: 0 0 auto;
  min-height: var(--kf-tap);
  white-space: nowrap;
}

/* Island: stock strip above the nav, the chat above the strip (portrait) or
   out of the way (landscape, where there is no height for both). */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .island-stock-bar {
  bottom: calc(var(--kf-nav-h) + 0.4rem);
  justify-content: flex-start;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-width: min(22rem, calc(100vw - 1rem));
  padding: 0.4rem 0.55rem;
  /* Desktop centres the strip under the map button (styles.css); phones have no
     height for that and keep it bottom-left. */
  top: auto;
  transform: none;
  width: auto;
}

html.is-mobile-client body.is-mobile-portrait .island-overlay-hud .castle-left-column {
  bottom: calc(var(--kf-nav-h) + 10.5rem);
}

html.is-mobile-client body.is-mobile-landscape .island-overlay-hud .castle-left-bottom {
  display: none;
}

html.is-mobile-client body.is-mobile-landscape .island-stock-bar {
  left: calc(var(--kf-safe-l) + var(--kf-gutter) * 2 + var(--kf-tap));
  max-width: min(20rem, 45vw);
}

/* Island palettes: full width above the nav; the stock strip steps aside. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .island-dock {
  bottom: calc(var(--kf-nav-h) + 0.4rem);
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-height: calc(100dvh - var(--kf-nav-h) - var(--kf-safe-t) - 5.5rem);
  max-width: none;
  overflow: auto;
  overscroll-behavior: contain;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  width: auto;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .island-dock .meadow-editor-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

html.is-mobile-client .island-overlay-hud:has(.island-dock) :is(.island-stock-bar, .castle-left-bottom) {
  display: none;
}

/* Capital city and demon castle: the plate scrolls under a fixed HUD instead of
   being cropped to the middle (the capital showed 1 of its 11 buildings). */
html.is-mobile-client .map-plate-scroller {
  display: flex;
  inset: 0;
  overflow: auto;
  overscroll-behavior: contain;
  position: absolute;
  scrollbar-width: none;
  touch-action: pan-x pan-y;
  z-index: 1;
}

html.is-mobile-client .map-plate-scroller::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client .map-plate-scroller > :is(.capital-plate, .demon-plate) {
  flex-shrink: 0;
  margin: auto;
}

html.is-mobile-client .app.is-demon-view .demon-plate {
  max-height: none;
  max-width: none;
  width: auto;
}

html.is-mobile-client .demon-building-name {
  font-size: var(--text-micro);
}

/* Demon castle: the plate lives between the resource pills and the nav. */
html.is-mobile-client .app.is-demon-view .map-plate-scroller {
  padding: calc(var(--kf-safe-t) + 3rem) 0 calc(var(--kf-nav-h) + 0.25rem);
}

html.is-mobile-client body.is-mobile-portrait .app.is-demon-view .demon-plate {
  height: calc(100dvh - var(--kf-safe-t) - 3rem - var(--kf-nav-h) - 1rem);
}

html.is-mobile-client body.is-mobile-landscape .app.is-demon-view .demon-plate {
  height: calc(100dvh - var(--kf-safe-t) - 3rem - var(--kf-nav-h) - 0.75rem);
}

/* ---------------------------------------------------------------------------
 * 6. Menus and dialogs on phones
 * ------------------------------------------------------------------------- */

/* Portrait: every dialog is a full-width sheet anchored to the bottom edge — a
   short one sits where the thumb is, a long one grows to the top of the screen.
   Full-screen stages (weekly event, sprint, palace …) stay full-screen. */
html.is-mobile-client body.is-mobile-portrait .modal-backdrop {
  align-items: flex-end;
  padding: var(--kf-safe-t) 0 0;
}

html.is-mobile-client body.is-mobile-portrait .modal-panel {
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  max-height: calc(100dvh - var(--kf-safe-t));
  max-width: 100vw;
  overscroll-behavior: contain;
  padding-bottom: var(--kf-safe-b);
  width: 100vw;
}

/* Close buttons are the one control every dialog shares. */
html.is-mobile-client :is(.close-button, .weekly-event-close, .modal-close) {
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
}

/* Event stages (weekly event, sprint rankings, hallowtide) share one frame: a
   top bar, a three-column hub and a tab dock. Portrait stacks the hub into one
   scrolling column, puts the currencies on a second top-bar line, and lets the
   dock scroll sideways instead of wrapping every label onto two lines. */
html.is-mobile-client body.is-mobile-portrait .modal-panel:has(.weekly-event-stage) {
  border-radius: 0;
  height: calc(100dvh - var(--kf-safe-t));
  padding-bottom: 0;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-topbar {
  flex-wrap: wrap;
  gap: 0.35rem 0.4rem;
  padding: 0.45rem 0.5rem;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-topbar > .weekly-event-close:first-child {
  order: 0;
}

html.is-mobile-client body.is-mobile-portrait :is(.weekly-event-top-title, .sprint-rankings-title) {
  flex: 1 1 60%;
  flex-wrap: wrap;
  font-size: var(--text-body);
  letter-spacing: 0.02em;
  line-height: 1.2;
  margin-right: 0;
  min-width: 0;
  order: 1;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-topbar > .weekly-event-close:not(:first-child) {
  order: 2;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-topbar > :not(.weekly-event-close, .weekly-event-top-title, .sprint-rankings-title) {
  order: 3;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-top-title .hallowtide-sub {
  flex-basis: 100%;
}

/* The pet's wings rise above its plate; leave them room under the banner. */
html.is-mobile-client body.is-mobile-portrait .weekly-event-iso {
  padding-top: 2.5rem;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-body--hub {
  overflow: auto;
  overscroll-behavior: contain;
  padding: 0 0.6rem;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-hub {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: none;
  height: auto;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-hub > * {
  grid-column: 1;
  grid-row: auto;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-title {
  font-size: var(--text-headline);
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-iso {
  order: 2;
  width: 100%;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-iso-stage {
  height: min(15rem, 32dvh);
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-roster {
  flex-direction: row;
  order: 3;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  padding-bottom: 0.2rem;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-roster-card {
  flex: 0 0 auto;
  min-height: var(--kf-tap);
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-roster-card.is-selected::before {
  display: none;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-stats {
  order: 4;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-footer {
  grid-template-columns: minmax(0, 1fr);
  padding: 0.4rem 0.5rem calc(var(--kf-safe-b) + 0.5rem);
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-footer > * {
  grid-column: 1;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-footer .weekly-event-cta {
  justify-self: stretch;
  min-height: var(--kf-tap);
  min-width: 0;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-quote {
  display: none;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-dock {
  justify-self: stretch;
  overflow-x: auto;
  scrollbar-width: none;
}

html.is-mobile-client body.is-mobile-portrait .weekly-event-dock::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client .weekly-event-dock button {
  flex: 1 0 auto;
  min-height: var(--kf-tap);
  white-space: nowrap;
}

/* Emerald well: the card is one fixed-proportion painting; portrait gives it
   the whole width instead of 78% of it. */
html.is-mobile-client body.is-mobile-portrait .emerald-well-card {
  --u: min(1.4px, calc((100vw - 1rem) / 1300), calc((100dvh - 16px) / 744));
}

html.is-mobile-client body.is-mobile-portrait .modal-backdrop:has(.emerald-well-card) {
  align-items: center;
}

html.is-mobile-client body.is-mobile-portrait .modal-panel:has(.emerald-well-card) {
  border-radius: 0;
  padding-bottom: 0;
  width: auto;
}

/* Research tree and Pantheon: their branch / goddess lists become one swipeable
   row. As a column they took half a portrait screen away from the tree itself. */
html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) :is(.research-tree-tabs, .god-tree-god-picker) {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.4rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) :is(.research-tree-tabs, .god-tree-god-picker)::-webkit-scrollbar {
  display: none;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) :is(.research-tree-tab, .god-tree-god-chip) {
  flex: 0 0 auto;
  min-height: var(--kf-tap);
}

/* Its close is sized in card units, which made it a 15px glyph on a phone. */
html.is-mobile-client .emerald-well-close,
html.is-mobile-client .emerald-well-info-close {
  align-items: center;
  display: inline-flex;
  font-size: var(--text-title);
  height: var(--kf-tap);
  justify-content: center;
  width: var(--kf-tap);
}

html.is-mobile-client .emerald-well-close {
  right: calc(var(--kf-safe-r) + 0.25rem);
  top: calc(var(--kf-safe-t) + 0.25rem);
}

/* ---------------------------------------------------------------------------
 * 7. Castle edit modes on phones (place, move, roads, landscape tools)
 *
 *    The banner spans the width at the top and the rest of the HUD steps aside:
 *    its Done / Cancel sat under the right rail, whose box took the tap.
 * ------------------------------------------------------------------------- */

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-move-mode-banner {
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  left: calc(var(--kf-safe-l) + var(--kf-gutter));
  max-width: none;
  padding: 0.45rem 0.6rem;
  right: calc(var(--kf-safe-r) + var(--kf-gutter));
  top: calc(var(--kf-safe-t) + var(--kf-gutter));
  transform: none;
  width: auto;
  z-index: 22;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-move-mode-copy {
  flex: 1 1 12rem;
  font-size: var(--text-small);
  min-width: 0;
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-move-mode-actions {
  display: flex;
  gap: 0.4rem;
  margin-left: auto;
}

html.is-mobile-client .castle-move-mode-actions :is(button, .secondary-button, .primary-button) {
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
}

html.is-mobile-client body:is(.is-mobile-portrait, .is-mobile-landscape) .castle-overlay-hud:has(.castle-move-mode-banner) :is(
    .castle-left-column,
    [data-castle-hud-section="top-center"],
    [data-castle-hud-section="top-right"],
    .castle-event-ad-rail
  ) {
  visibility: hidden;
}

/* ---------------------------------------------------------------------------
 * 8. Object panels on phones (lands, fortresses, camps, server capital)
 * ------------------------------------------------------------------------- */

/* The sticky header faded to transparent over its lower quarter, so the list
   scrolled visibly through the title and the Close row. */
html.is-mobile-client .building-work-scroll-chrome {
  background: rgba(12, 10, 8, 0.97);
  box-shadow: 0 8px 12px -10px rgba(0, 0, 0, 0.7);
}

/* Landscape has ~390px of height: the flavour line goes, so the header keeps
   title, tags and Close and the panel keeps room for its list. */
html.is-mobile-client body.is-mobile-landscape .building-work-scroll-header p:not(.eyebrow) {
  display: none;
}

html.is-mobile-client .building-work-scroll-header :is(.close-button, .land-chrome-btn) {
  flex-shrink: 0;
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
}

/* Unit rows: the stepper wraps under the name instead of widening the row. */
html.is-mobile-client .attack-unit-row {
  flex-wrap: wrap;
}

html.is-mobile-client .attack-unit-row .attack-unit-info {
  flex: 1 1 9rem;
  min-width: 0;
}

html.is-mobile-client .attack-unit-row .amount-stepper {
  margin-left: auto;
}

html.is-mobile-client .amount-stepper :is(button, .secondary-button) {
  min-height: 2.5rem;
  min-width: 2.5rem;
}

/* ---------------------------------------------------------------------------
 * 9. Before the game: realm picker, create wizard, legal footer
 * ------------------------------------------------------------------------- */

html.is-mobile-client .profile-create-wizard-close {
  align-items: center;
  display: inline-flex;
  justify-content: center;
  min-height: var(--kf-tap);
  min-width: var(--kf-tap);
}

html.is-mobile-client .site-legal-footer a {
  display: inline-block;
  padding-block: 0.6rem;
}

/* Portrait profile stage: the three columns (realm, hero, roster) ran off the
   right edge of a 375px screen; stacked, the page scrolls instead. */
html.is-mobile-client body.is-mobile-portrait .profile-stage,
html.is-mobile-client body.is-mobile-portrait .profile-stage--realms {
  grid-template-areas:
    "top"
    "realm"
    "roster"
    "hero"
    "foot";
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto;
  height: auto;
  min-height: 100dvh;
  overflow: visible;
  padding: calc(var(--kf-safe-t) + 0.75rem) 0.75rem 0;
}

/* ---------------------------------------------------------------------------
 * 10. Raster budget on phones
 *
 *    A phone draws the castle at 2-3x the pixels of a desktop with a fraction
 *    of the GPU, and every filter and blur below re-rasterises whenever
 *    something moves under it. The backdrops are 88-94% opaque already, so
 *    nothing readable is lost.
 * ------------------------------------------------------------------------- */

/* Buildings keep the sunlight lift, lose the two chained contour drop-shadows. */
html.is-mobile-client .castle-iso-stage .placed-building.is-iso-placed .building-texture-layer,
html.is-mobile-client .castle-iso-stage .placement-preview.is-iso-placed .building-texture-layer {
  filter: var(--iso-sprite-lift);
}

html.is-mobile-client .castle-iso-stage .castle-road-layer {
  filter: none;
}

/* One animated layer per producing building. */
html.is-mobile-client .castle-iso-stage .placed-building .building-smoke {
  display: none;
}

html.is-mobile-client :is(.castle-docked-tray, .season-hud, .world-map-chat-overlay .castle-chat-panel) {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

html.is-mobile-client .building-interface.iap-hub-stage {
  --iap-glass-blur: none;
}

/* The tooltip's progress pulse ran in every hidden tooltip, keeping the
   compositor busy for nothing. */
html.is-mobile-client .resource-tooltip .resource-progress span {
  animation: none;
}

/* ---------------------------------------------------------------------------
 * 11. Minigame hub on phones, both orientations
 *
 * Measured at 932x430 before this section: header, tabs and the admin banner took
 * 227 px, the poster stacked a 10.5 rem art tile over its copy and put Start at
 * y = 550, and every running board ran past the fold (styles.css has no phone
 * rule for any .minigame-* class). Budget here: one 44 px header row, no tabs
 * while a round runs, and in landscape the boards laid out side by side so the
 * butt, the D-pad and the memory grid each get the full height.
 * ------------------------------------------------------------------------- */

html.is-mobile-client .modal-panel:has(.minigame-hub) {
  border-radius: 0;
  height: 100dvh;
  max-height: 100dvh;
  max-width: 100vw;
  width: 100vw;
}

html.is-mobile-client .modal-panel .building-interface.minigame-hub {
  gap: 0.35rem;
  padding: 0.4rem 0.6rem calc(0.4rem + var(--kf-safe-b));
}

/* One header row: name, badges, Close. The eyebrow only said "Minigame" above the name. */
html.is-mobile-client .minigame-hub .building-interface-header {
  align-items: center;
  gap: 0.4rem;
}

html.is-mobile-client .minigame-hub .building-interface-header .eyebrow {
  display: none;
}

html.is-mobile-client .minigame-hub .building-interface-header h3 {
  font-size: var(--text-body);
}

/* Badges and Close in one row; stacked they made the header 109 px tall in landscape. */
html.is-mobile-client .minigame-hub .building-interface-header .castle-actions {
  align-items: center;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 0.3rem;
  justify-content: flex-end;
}

/* Portrait has no room for two badges beside the name; the record card repeats them. */
html.is-mobile-client body.is-mobile-portrait .minigame-hub .castle-actions .badge {
  display: none;
}

html.is-mobile-client .minigame-hub .memory-game-tabs {
  margin-bottom: 0.25rem;
}

html.is-mobile-client .minigame-hub .leaderboard-tab {
  font-size: var(--text-small);
  padding: 0.3rem 0.55rem;
}

html.is-mobile-client .minigame-test-banner {
  font-size: var(--text-caption);
  margin-bottom: 0.35rem;
  padding: 0.3rem 0.5rem;
}

/* While a round runs, the tabs and the banner are only a way to lose it. */
html.is-mobile-client .minigame-hub:has(.minigame-stage.is-running) :is(.memory-game-tabs, .minigame-test-banner) {
  display: none;
}

/* One column on every phone: the 17 rem side column left the poster 70 px in portrait. */
html.is-mobile-client .minigame-hub .minigame-stage {
  gap: 0.5rem;
  grid-template-columns: minmax(0, 1fr);
}

/* Poster: thumbnail beside the title instead of a tile above it. The long memory rule
   goes; the facts and Start say what matters. */
html.is-mobile-client .minigame-hub .minigame-poster {
  gap: 0.6rem;
  grid-template-columns: auto minmax(0, 1fr);
  padding: 0.6rem;
}

html.is-mobile-client .minigame-poster-art {
  height: 4.4rem;
  width: 4.4rem;
}

html.is-mobile-client .minigame-poster-title {
  font-size: var(--text-subhead);
}

html.is-mobile-client .minigame-poster-howto {
  display: none;
}

html.is-mobile-client .minigame-poster-copy > p {
  font-size: var(--text-small);
}

html.is-mobile-client .minigame-hub .minigame-board {
  gap: 0.4rem;
  padding: 0.5rem;
}

html.is-mobile-client .minigame-hub :is(.fechtschule-board, .schuetzenfest-range, .kornboerse-floor, .tierrennen-track) {
  min-height: 0;
}

/* -- Fencing: wave left, D-pad right, 44 px icons --------------------------- */

html.is-mobile-client .fechtschule-icon {
  font-size: var(--text-subhead);
  height: 2.75rem;
  width: 2.75rem;
}

html.is-mobile-client body.is-mobile-landscape .fechtschule-board {
  column-gap: 0.75rem;
  grid-template-areas:
    "head head"
    "track track"
    "wave pad"
    "hint pad";
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto auto 1fr auto;
}

html.is-mobile-client body.is-mobile-landscape .fechtschule-board .memory-game-timer-row {
  grid-area: head;
}

html.is-mobile-client body.is-mobile-landscape .fechtschule-board .memory-game-timer-track {
  grid-area: track;
}

html.is-mobile-client body.is-mobile-landscape .fechtschule-wave {
  align-self: center;
  grid-area: wave;
}

html.is-mobile-client body.is-mobile-landscape .fechtschule-pad {
  align-self: center;
  grid-area: pad;
}

html.is-mobile-client body.is-mobile-landscape .fechtschule-hint {
  grid-area: hint;
}

/* -- Archery: butt left, meter / shots / hint right --------------------------- */

html.is-mobile-client body.is-mobile-landscape .schuetzenfest-range {
  column-gap: 0.75rem;
  grid-template-areas:
    "head head"
    "track track"
    "butt meter"
    "butt log"
    "butt hint";
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto auto auto 1fr;
}

html.is-mobile-client body.is-mobile-landscape .schuetzenfest-range .memory-game-timer-row {
  grid-area: head;
}

html.is-mobile-client body.is-mobile-landscape .schuetzenfest-range .memory-game-timer-track {
  grid-area: track;
}

/* Sized by height, not width: the square takes what the row leaves (56vh = 241 px on a
   430 px phone), the right column gets the rest. */
html.is-mobile-client body.is-mobile-landscape .schuetzenfest-butt {
  grid-area: butt;
  height: auto;
  max-height: none;
  max-width: none;
  width: min(56vh, 16rem);
}

html.is-mobile-client body.is-mobile-landscape .schuetzenfest-meter {
  grid-area: meter;
  margin-top: 0.5rem;
}

html.is-mobile-client body.is-mobile-landscape .schuetzenfest-log {
  grid-area: log;
}

html.is-mobile-client body.is-mobile-landscape .schuetzenfest-hint {
  grid-area: hint;
}

/* -- Grain: a shorter slate, the buttons stay 44 px --------------------------- */

html.is-mobile-client body.is-mobile-landscape .kornboerse-chart {
  height: 6.5rem;
}

/* -- Memory: grid left, status / result / Submit right ------------------------ */

html.is-mobile-client body.is-mobile-landscape .minigame-stage-main:has(.memory-game-grid) {
  align-items: start;
  column-gap: 0.75rem;
  grid-template-areas:
    "grid phase"
    "grid actions"
    "grid legend";
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto 1fr;
}

html.is-mobile-client body.is-mobile-landscape .minigame-stage-main:has(.memory-game-grid) .memory-game-phase {
  grid-area: phase;
  margin: 0;
}

html.is-mobile-client body.is-mobile-landscape .memory-game-interface .memory-game-grid {
  grid-area: grid;
  margin: 0;
  width: min(62vh, 22.5rem);
}

html.is-mobile-client body.is-mobile-landscape .memory-game-interface .memory-game-actions {
  grid-area: actions;
  margin: 0;
  max-width: none;
}

html.is-mobile-client body.is-mobile-landscape .memory-game-interface .memory-game-legend {
  grid-area: legend;
  margin: 0;
  max-width: none;
}

html.is-mobile-client body.is-mobile-portrait .memory-game-interface .memory-game-grid {
  max-width: 100%;
}

/* -- Race: the lane takes the height it has; the stable scrolls sideways ------ */

html.is-mobile-client body.is-mobile-landscape .tierrennen-lane {
  aspect-ratio: auto;
  height: min(58vh, 22rem);
}

html.is-mobile-client .tierrennen-lineup {
  display: flex;
  gap: 0.4rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding-bottom: 0.2rem;
  scroll-snap-type: x proximity;
}

html.is-mobile-client .tierrennen-entrant {
  flex: 0 0 7.5rem;
  padding: 0.35rem;
  scroll-snap-align: start;
}

html.is-mobile-client .tierrennen-entrant-art {
  height: 2.5rem;
  width: 2.5rem;
}

/* One line per card: a wrapped "Kerberos of the Threshold" made the row 153 px tall and
   pushed Start under the fold in landscape. Stars and level are on the result poster. */
html.is-mobile-client .tierrennen-entrant-name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

html.is-mobile-client .tierrennen-entrant .muted {
  display: none;
}
