/* Mobile product overrides. Every rule in this file stays behind the runtime
   mode class so a narrow desktop window continues to use desktop behavior. */
body.is-mobile {
  --editor-rail-width: 136px;
  --editor-resume-rail-width: 124px;
  --editor-toolbar-width: 64px;
  --editor-tools-card-width: 64px;
  --editor-expanded-tools-card-width: 104px;
  --editor-tool-group-width: 56px;
  --editor-slider-length: 88px;
  --editor-progression-button-width: 128px;
  --editor-history-button-size: 36px;
  --editor-tool-button-size: 44px;
  --workspace-zoom-button-size: 36px;
  --workspace-help-button-size: 36px;
}

/* The native shell spends its header on one global menu control. The logo and
   workflow strip remain in the DOM for the desktop product, which keeps its
   existing header unchanged. */
.mobile-menu-button {
  display: none;
}

body.is-mobile .app-header {
  position: sticky;
  top: 0;
  z-index: 80;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  min-width: 0;
  min-height: 56px;
  padding: calc(8px + var(--safe-area-inset-top)) 14px 8px;
  overflow: visible;
}

body.is-mobile .app-brand-navigation,
body.is-mobile .workflow-steps {
  display: none;
}

body.is-mobile .mobile-menu-button {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  min-height: 44px;
  border: 0;
  border-radius: 50%;
  padding: 10px;
  background: transparent;
  color: #fff;
}

body.is-mobile .mobile-menu-button:hover,
body.is-mobile .mobile-menu-button[aria-expanded="true"] {
  background: rgb(255 255 255 / 0.12);
}

body.is-mobile .mobile-menu-button span {
  display: block;
  width: 23px;
  height: 2px;
  border-radius: 999px;
  background: currentColor;
}

body.is-mobile .header-account-actions {
  position: absolute;
  top: calc(100% + 8px);
  right: max(14px, var(--safe-area-inset-right));
  z-index: 90;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  max-width: calc(100vw - 28px);
  margin: 0;
  border: 1px solid #424242;
  border-radius: 14px;
  padding: 8px;
  background: #1f1f1f;
  box-shadow: 0 12px 30px rgb(0 0 0 / 0.36);
}

body.is-mobile .header-account-actions:not(.is-mobile-menu-open) {
  display: none;
}

body.is-mobile .header-account-actions .user-button-slot {
  margin-left: 4px;
}

/* Phase 5: canvas screens use the remaining native viewport rather than the
   document scroll. Non-canvas screens keep the Phase 3 responsive document
   flow, including their ordinary vertical scrolling. */
body.is-mobile:has(#imageWorkspace:not([hidden])) {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

body.is-mobile:has(#imageWorkspace:not([hidden])) .app-header {
  flex: 0 0 auto;
}

body.is-mobile .app-shell:has(#imageWorkspace:not([hidden])) {
  flex: 1 1 0;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  gap: 6px;
  width: 100%;
  height: auto;
  min-height: 0;
  max-height: none;
  overflow: hidden;
  padding: 6px max(6px, var(--safe-area-inset-right))
    max(6px, var(--safe-area-inset-bottom)) max(6px, var(--safe-area-inset-left));
}

body.is-mobile .app-shell:has(#imageWorkspace:not([hidden])) > #setupPanel,
body.is-mobile .app-shell:has(#imageWorkspace:not([hidden])) > #editorToolbar,
body.is-mobile .app-shell:has(#imageWorkspace:not([hidden])) > #layoutToolbar {
  grid-column: 1;
  grid-row: 1;
}

body.is-mobile .app-shell:has(#imageWorkspace:not([hidden])) > #imageWorkspace {
  grid-column: 1;
  grid-row: 2;
}

/* A landscape source spends the short edge on a side header. This class is
   set from the loaded image/canvas dimensions, never from the viewport. */
body.is-mobile .app-shell.mobile-image-landscape:has(#imageWorkspace:not([hidden])) {
  grid-template-columns: 92px minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
}

body.is-mobile .app-shell.mobile-image-landscape:has(#imageWorkspace:not([hidden])) > #setupPanel,
body.is-mobile .app-shell.mobile-image-landscape:has(#imageWorkspace:not([hidden])) > #editorToolbar,
body.is-mobile .app-shell.mobile-image-landscape:has(#imageWorkspace:not([hidden])) > #layoutToolbar {
  grid-column: 1;
  grid-row: 1;
}

body.is-mobile .app-shell.mobile-image-landscape:has(#imageWorkspace:not([hidden])) > #imageWorkspace {
  grid-column: 2;
  grid-row: 1;
}

body.is-mobile .app-shell.is-perspective-processing-mode > #imageWorkspace,
body.is-mobile .app-shell.is-resume-loading-mode > #imageWorkspace {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}

body.is-mobile .image-workspace,
body.is-mobile .image-stage {
  min-width: 0;
  min-height: 0;
}

body.is-mobile .image-stage {
  border-radius: 6px;
}

/* Compact object/layout headers. The portrait form is one horizontally
   scrollable row; the same controls rotate into a vertically scrollable side
   header for a landscape source. No tool is removed. */
body.is-mobile .app-shell.is-editor-mode .editor-toolbar,
body.is-mobile .app-shell.is-layout-mode .editor-toolbar {
  align-self: stretch;
  justify-self: stretch;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  width: 100%;
  min-width: 0;
  max-height: 72px;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0 0 2px;
  scrollbar-width: thin;
}

body.is-mobile .editor-toolbar .editor-tools-card {
  flex: 0 0 auto;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 6px;
  width: max-content;
  max-width: none;
  min-height: 64px;
  border-radius: 7px;
  padding: 5px;
  box-shadow: 0 3px 10px rgb(25 31 28 / 0.1);
}

body.is-mobile .object-editor-tools-card .history-button-row,
body.is-mobile .layout-editor-tools-card .history-button-row {
  flex: 0 0 auto;
  width: auto;
}

body.is-mobile .layout-editor-tools-card .history-button-row {
  margin: 0 2px 0 0;
  border-right: 1px solid #e1e6e2;
  border-bottom: 0;
  padding: 0 8px 0 0;
}

body.is-mobile .editor-tools-card .object-editor-toolbar-divider {
  align-self: stretch;
  width: 1px;
  height: auto;
}

body.is-mobile .editor-toolbar .brush-erase-tool-group {
  flex: 0 0 auto;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 6px;
  width: auto;
  min-height: 52px;
  padding: 4px 5px;
}

body.is-mobile .editor-toolbar .finger-notch-tool-group,
body.is-mobile .editor-toolbar .text-tool-group {
  flex: 0 0 auto;
  grid-template-columns: auto 132px;
  align-items: center;
  justify-items: stretch;
  gap: 6px;
  width: 190px;
  min-height: 52px;
  padding: 4px 5px;
}

body.is-mobile .editor-toolbar .brush-erase-shared-controls {
  grid-template-columns: auto auto 112px;
  align-items: center;
  justify-items: stretch;
  gap: 6px;
  width: 205px;
  min-height: 44px;
  padding: 0;
}

body.is-mobile .editor-toolbar .finger-notch-tool-group .notch-size-control,
body.is-mobile .editor-toolbar .text-tool-group .text-size-control {
  grid-template-columns: auto minmax(82px, 1fr);
  align-items: center;
  justify-items: stretch;
  gap: 5px;
  width: 100%;
  min-height: 44px;
}

body.is-mobile .editor-toolbar .brush-size-label,
body.is-mobile .editor-toolbar .notch-size-label,
body.is-mobile .editor-toolbar .text-size-label {
  grid-auto-flow: column;
  align-items: center;
  justify-content: start;
}

body.is-mobile .editor-toolbar .brush-erase-shared-controls input[type="range"],
body.is-mobile .editor-toolbar .notch-size-control input[type="range"],
body.is-mobile .editor-toolbar .text-size-control input[type="range"] {
  width: 100%;
  height: var(--range-hit-size);
  direction: ltr;
  writing-mode: horizontal-tb;
}

body.is-mobile .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-runnable-track,
body.is-mobile .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-runnable-track,
body.is-mobile .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-runnable-track {
  width: auto;
  height: var(--range-track-thickness);
  background: linear-gradient(to right,
      var(--range-accent) var(--range-fill-pos),
      var(--range-groove) var(--range-fill-pos));
}

body.is-mobile .editor-toolbar .brush-erase-shared-controls input[type="range"]::-moz-range-track,
body.is-mobile .editor-toolbar .notch-size-control input[type="range"]::-moz-range-track,
body.is-mobile .editor-toolbar .text-size-control input[type="range"]::-moz-range-track {
  width: auto;
  height: var(--range-track-thickness);
  background: linear-gradient(to right,
      var(--range-accent) var(--range-fill-pos),
      var(--range-groove) var(--range-fill-pos));
}

body.is-mobile .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-thumb,
body.is-mobile .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-thumb,
body.is-mobile .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-thumb {
  margin-top: calc((var(--range-track-thickness) - var(--range-thumb-size)) / 2);
  margin-left: 0;
}

body.is-mobile .editor-toolbar > .toolbar-primary-action,
body.is-mobile .editor-toolbar > .toolbar-secondary-action,
body.is-mobile .editor-toolbar > .toolbar-preview-actions {
  flex: 0 0 auto;
  width: auto;
  min-width: 112px;
  min-height: 44px;
  margin: 0;
}

body.is-mobile .editor-toolbar > .toolbar-preview-actions .toolbar-primary-action {
  width: 100%;
  min-height: 44px;
}

body.is-mobile .editor-toolbar > .dxf-preview-boundary-warning {
  flex: 0 0 180px;
  width: 180px;
  margin: 0;
  font-size: 11px;
  text-align: left;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  width: 92px;
  max-height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 0 2px 0 0;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .editor-tools-card {
  flex-direction: column;
  align-items: center;
  width: 100%;
  min-height: 0;
  padding: 6px;
}

body.is-mobile .app-shell.mobile-image-landscape .layout-editor-tools-card .history-button-row {
  margin: 0 0 2px;
  border-right: 0;
  border-bottom: 1px solid #e1e6e2;
  padding: 0 0 8px;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-tools-card .object-editor-toolbar-divider {
  align-self: stretch;
  width: 100%;
  height: 1px;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-erase-tool-group {
  flex-direction: column;
  width: 100%;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .finger-notch-tool-group,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-tool-group {
  grid-template-columns: 1fr;
  justify-items: center;
  width: 100%;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-erase-shared-controls,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .finger-notch-tool-group .notch-size-control,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-tool-group .text-size-control {
  grid-template-columns: 1fr;
  justify-items: center;
  width: 100%;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-size-label,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .notch-size-label,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-size-label {
  grid-auto-flow: row;
  justify-content: center;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-erase-shared-controls input[type="range"],
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .notch-size-control input[type="range"],
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-size-control input[type="range"] {
  width: var(--range-hit-size);
  height: 64px;
  direction: rtl;
  writing-mode: vertical-lr;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-runnable-track,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-runnable-track,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-runnable-track {
  width: var(--range-track-thickness);
  height: auto;
  background: linear-gradient(to top,
      var(--range-accent) var(--range-fill-pos),
      var(--range-groove) var(--range-fill-pos));
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-erase-shared-controls input[type="range"]::-moz-range-track,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .notch-size-control input[type="range"]::-moz-range-track,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-size-control input[type="range"]::-moz-range-track {
  width: var(--range-track-thickness);
  height: auto;
  background: linear-gradient(to top,
      var(--range-accent) var(--range-fill-pos),
      var(--range-groove) var(--range-fill-pos));
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-thumb,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-thumb,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-thumb {
  margin-top: 0;
  margin-left: calc((var(--range-track-thickness) - var(--range-thumb-size)) / 2);
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar > .toolbar-primary-action,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar > .toolbar-secondary-action,
body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar > .toolbar-preview-actions {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  padding-inline: 5px;
  font-size: 12px;
  white-space: normal;
}

body.is-mobile .app-shell.mobile-image-landscape .editor-toolbar > .dxf-preview-boundary-warning {
  flex: 0 0 auto;
  width: 100%;
  padding: 2px;
  font-size: 10px;
  text-align: center;
}

/* Define Corners puts every immediate action in the orientation-aware header:
   Photo, Rotate, and Detect act at once, and Dimensions collapses a two-field
   panel out of the header. Nothing about the drawer photo is named here — the
   phone that took it is the phone showing it. */
body.is-mobile #setupPanel {
  position: relative;
  align-self: stretch;
  display: block;
  width: 100%;
  height: 60px;
  min-width: 0;
  max-height: none;
  overflow: visible;
}

body.is-mobile .mobile-define-corners-header {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  height: 60px;
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 6px;
  background: var(--panel);
  box-shadow: 0 3px 10px rgb(25 31 28 / 0.1);
}

body.is-mobile .mobile-editor-header-button,
body.is-mobile .mobile-editor-header-action {
  min-height: 44px;
}

body.is-mobile .mobile-editor-header-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 6px 10px;
}

body.is-mobile .mobile-editor-header-button svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

body.is-mobile .mobile-editor-header-action {
  margin-left: auto;
  white-space: nowrap;
}

/* Same red as `.setup-validation-field.has-error`, on the one control that is
   still on screen when the photo is the missing item. */
body.is-mobile .mobile-editor-header-button.is-invalid {
  border-color: #b7131a;
  box-shadow: 0 0 0 1px rgb(183 19 26 / 0.18);
  color: #b7131a;
}

body.is-mobile .app-shell.mobile-image-landscape #setupPanel {
  width: 92px;
  height: 100%;
}

body.is-mobile .app-shell.mobile-image-landscape .mobile-define-corners-header {
  flex-direction: column;
  height: 100%;
  padding: 6px;
  overflow-y: auto;
}

body.is-mobile .app-shell.mobile-image-landscape .mobile-editor-header-button,
body.is-mobile .app-shell.mobile-image-landscape .mobile-editor-header-action {
  flex: 0 0 auto;
  width: 100%;
  min-width: 0;
  margin: 0;
  padding-inline: 5px;
  font-size: 12px;
  white-space: normal;
}

/* Dimensions collapses out of the header rather than sliding up from the
   bottom, so `top`/`left` are written inline by mobile_runtime.js from the
   button's own box — the button sits in a row in portrait and a column in
   landscape, and in the app it lives in the global header, so no static
   anchor is right for all three. */
body.is-mobile #setupPanel > .control-panel {
  position: fixed;
  top: 0;
  left: 0;
  right: auto;
  bottom: auto;
  z-index: 112;
  width: min(260px, calc(100vw - 16px));
  max-height: min(60dvh, 420px);
  margin: 0;
  overflow-y: auto;
  border-radius: 12px;
  padding: 14px;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px);
  transition: opacity 140ms ease, transform 140ms ease,
    visibility 0s linear 140ms;
}

body.is-mobile #setupPanel.is-mobile-dimensions-open > .control-panel {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transform: none;
  transition: opacity 140ms ease, transform 140ms ease;
}

/* Transparent, not dimmed: this is a disclosure hanging off a header button,
   not a modal. It exists only so the first tap outside collapses the panel
   instead of landing on a corner handle. */
body.is-mobile .mobile-dimensions-popover-backdrop {
  position: fixed;
  inset: 0;
  z-index: 111;
  background: transparent;
}

/* The photo picker moved to the header, and the panel is dimensions only. */
body.is-mobile #defineCornersSetupControls .photo-picker-field,
body.is-mobile #setupPanel .define-corners-proceed-area {
  display: none !important;
}

/* The wrapper is layout-neutral in browsers, so desktop and the temporary
   mobile-web bypass keep the authored inline warning cards. */
.quadrilateral-warning-dialog {
  display: contents;
}

.mobile-quadrilateral-warning-close {
  display: none;
}

/* Detection failures stay visible on every mobile surface. Mobile web also
   keeps the pre-existing quadrilateral canvas overlays; the installed app
   replaces only those cautions with the compact warning control below. */
body.is-mobile #detectionFailureNotice,
body.is-mobile:not(.is-capacitor) #quadrilateralWarningDialog > .setup-warning {
  position: relative;
  z-index: 8;
  width: min(520px, calc(100vw - 16px));
  max-height: 36dvh;
  margin: 6px auto 0;
  overflow-y: auto;
  box-shadow: 0 10px 28px rgb(25 31 28 / 0.2);
}

body.is-mobile .app-shell.mobile-image-landscape #detectionFailureNotice,
body.is-mobile:not(.is-capacitor) .app-shell.mobile-image-landscape #quadrilateralWarningDialog > .setup-warning {
  position: fixed;
  right: max(8px, var(--safe-area-inset-right));
  bottom: max(8px, var(--safe-area-inset-bottom));
  left: auto;
  z-index: 108;
  width: min(420px, calc(100vw - 116px));
}

/* Amber lifted for the dark header: with the plate gone the glyph itself is
   the whole warning, so it has to carry the colour the box used to. */
body.is-capacitor .mobile-quadrilateral-warning-button {
  position: fixed;
  z-index: 110;
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
  color: #fbbf24;
}

body.is-capacitor .mobile-quadrilateral-warning-button:hover,
body.is-capacitor .mobile-quadrilateral-warning-button:focus-visible,
body.is-capacitor .mobile-quadrilateral-warning-button[aria-expanded="true"] {
  background: rgb(251 191 36 / 0.18);
  color: #fcd34d;
}

body.is-capacitor .mobile-quadrilateral-warning-button svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

body.is-capacitor .mobile-quadrilateral-warning-button circle {
  fill: currentColor;
  stroke: none;
}

body.is-capacitor .mobile-quadrilateral-warning-backdrop {
  position: fixed;
  inset: 0;
  z-index: 116;
  background: rgb(18 22 20 / 0.52);
}

body.is-capacitor .quadrilateral-warning-dialog {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 117;
  display: none;
  gap: 12px;
  width: min(520px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  border: 1px solid var(--warning-border);
  border-radius: 12px;
  padding: 16px 52px 16px 16px;
  background: var(--warning-bg);
  color: var(--warning-text);
  box-shadow: 0 22px 60px rgb(31 37 35 / 0.32);
  transform: translate(-50%, -50%);
}

body.is-capacitor .quadrilateral-warning-dialog.is-open {
  display: grid;
}

body.is-capacitor .mobile-quadrilateral-warning-close {
  position: absolute;
  top: 8px;
  right: 8px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  min-height: 36px;
  border: 0;
  border-radius: 50%;
  padding: 0;
  background: transparent;
  color: var(--warning-text);
}

body.is-capacitor .mobile-quadrilateral-warning-close:hover {
  background: rgb(217 119 6 / 0.14);
}

body.is-capacitor .mobile-quadrilateral-warning-close svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

body.is-capacitor .quadrilateral-warning-dialog > .setup-warning {
  width: 100%;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  color: inherit;
  box-shadow: none;
}

body.is-capacitor .quadrilateral-warning-dialog > .setup-warning:not([hidden]) ~ .setup-warning:not([hidden]) {
  border-top: 1px solid var(--warning-border);
  padding-top: 12px;
}

body.is-mobile #warningConfirmationBackdrop {
  z-index: 121;
}

body.is-mobile #warningConfirmation {
  z-index: 122;
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
}

/* Mobile keeps the canvas and contextual shape dimensions, but removes the
   desktop-only instructional and zoom surfaces. Event bindings stay intact. */
body.is-mobile #workspaceZoomControl,
body.is-mobile .workspace-help-button,
body.is-mobile #objectEditorHelpModal,
body.is-mobile #defineCornersHelpModal,
body.is-mobile #layoutEditorHelpModal,
body.is-mobile .image-stage .workspace-hint {
  display: none !important;
}

body.is-mobile .image-stage.is-calibration,
body.is-mobile .image-stage.is-result {
  grid-template-rows: minmax(0, 1fr);
  gap: 0;
}

body.is-mobile #instructionBar:not(.is-shape-selected) {
  display: none;
}

body.is-mobile .image-stage.is-result.is-layout:has(#instructionBar.is-shape-selected) {
  grid-template-rows: auto minmax(0, 1fr);
  gap: 4px;
}

body.is-mobile #instructionBar.is-shape-selected {
  display: flex;
  width: calc(100% - 12px);
  margin-top: 6px;
}

/* A real editable control is required for Android to offer its IME. It stays
   mounted and focusable while text is being edited, but contributes no visible
   pixels or pointer target; the canvas remains the visual editor. */
body.is-mobile .mobile-layout-text-input {
  position: fixed;
  top: 50%;
  left: 0;
  z-index: 0;
  width: 1px;
  height: 1px;
  min-width: 1px;
  min-height: 1px;
  margin: 0;
  border: 0;
  padding: 0;
  overflow: hidden;
  opacity: 0.01;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  font-size: 16px;
  line-height: 1;
  pointer-events: none;
  resize: none;
}

/* -------------------------------------------------------------------------
   Capacitor editor command bar

   The installed app reuses the global header for progression and secondary
   actions. The real buttons are moved here by mobile_runtime.js, so their
   existing disabled/busy/save state remains authoritative. Mobile web keeps
   the Phase 5 chrome above unchanged. */

.mobile-editor-command-bar,
.mobile-editor-action-label,
.mobile-editor-action-icon,
.mobile-cart-action-icon {
  display: none;
}

body.is-capacitor {
  --editor-history-button-size: 48px;
  --editor-tool-button-size: 48px;
  /* One length for every size slider in the app -- brush, eraser, notch, and
     text -- so the card is the same object whichever tool is armed. Retune the
     slider here rather than per control. */
  --capacitor-slider-length: 150px;
  /* The size card's outside height, and the height of the band undo and redo
     centre themselves in, so the three read as one row. Both rules take it from
     here rather than from their own content, so neither can drift off the line
     the other is on. 44px is the slider's 36px hit height plus the card's 3px
     of padding and 1px of border on each side -- `--range-hit-size` itself is
     scoped to the range inputs and cannot be read from up here. */
  --capacitor-size-card-height: 44px;
  /* How far in from the screen edge anything stacked outside the tool pill has
     to start: the pill's own 12px inset, its height, and the gap above it.
     `--capacitor-editor-pill-height` is declared with the header pill below. */
  --capacitor-tool-pill-inset: 12px;
  --capacitor-pill-clearance: calc(
    var(--capacitor-tool-pill-inset) + var(--capacitor-editor-pill-height) + 8px
  );
}

/* -------------------------------------------------------------------------
   Direct-download update policy

   Both surfaces are native-only. The minimum-version modal outranks every
   other gate because the bundled frontend is no longer allowed to run at all;
   the latest-version banner is a light, dismissible prompt and floats above
   the current screen without changing either product's layout. */
body.is-capacitor .android-update-banner {
  position: fixed;
  right: max(12px, var(--safe-area-inset-right));
  bottom: calc(12px + var(--safe-area-inset-bottom));
  left: max(12px, var(--safe-area-inset-left));
  z-index: 190;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: min(560px, calc(100vw - 24px));
  margin: 0 auto;
  border: 1px solid #424242;
  border-radius: 12px;
  padding: 12px 14px;
  background: #1f2523;
  box-shadow: 0 14px 34px rgb(0 0 0 / 0.32);
  color: #fff;
}

body.is-capacitor .android-update-banner p {
  margin: 0;
  line-height: 1.35;
}

body.is-capacitor .android-update-banner-actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 8px;
}

body.is-capacitor .android-update-banner a,
body.is-capacitor .android-update-banner button {
  min-height: 40px;
  border-radius: 6px;
  padding: 9px 11px;
  font-size: 0.875rem;
  font-weight: 700;
}

body.is-capacitor .android-update-banner a {
  display: inline-flex;
  align-items: center;
  border: 1px solid #f0474f;
  background: var(--red);
  color: #fff;
  text-decoration: none;
}

body.is-capacitor .android-update-banner button {
  border-color: #69736f;
  background: transparent;
  color: #fff;
}

body.is-capacitor .android-update-required-backdrop {
  z-index: 400;
  padding: 20px;
}

body.is-capacitor .android-update-required-panel {
  width: min(420px, 100%);
  height: auto;
  padding: 26px;
  overflow: auto;
  text-align: center;
}

body.is-capacitor .android-update-required-panel h2 {
  margin: 0 0 12px;
  font-size: 1.45rem;
}

body.is-capacitor .android-update-required-panel p {
  margin: 0 0 22px;
  color: var(--muted);
  line-height: 1.5;
}

body.is-capacitor .android-update-required-panel .primary-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border: 1px solid #b7131a;
  border-radius: var(--button-radius);
  padding: 12px 18px;
  text-decoration: none;
}

@media (max-width: 520px) {
  body.is-capacitor .android-update-banner {
    align-items: stretch;
    flex-direction: column;
  }

  body.is-capacitor .android-update-banner-actions {
    justify-content: flex-end;
  }
}

/* Tool targets on the narrowest phones the app supports.

   The object editor's pill carries seven controls -- edit areas, brush,
   eraser, freehand, straight line, hide visuals, rotate view -- and at 360dp,
   the most common Android width and the narrowest in real use, seven 48px
   targets no longer clear the screen. The last one lands half off the edge,
   which makes it not smaller but unreachable.

   So the targets step down to the 44px mobile web already uses, rather than
   the pill scrolling or wrapping to a second row: a pill that scrolls hides a
   control behind a gesture nothing advertises, and a taller one runs into the
   undo/redo row standing above it. 44px is still a full touch target on a
   surface that is also drag-painted.

   Landscape stands the pill on its side against `100dvh`, so the same
   question is asked there of the height. */
@media (max-width: 400px), (orientation: landscape) and (max-height: 400px) {
  body.is-capacitor {
    --editor-tool-button-size: 44px;
  }
}

/* -------------------------------------------------------------------------
   Non-canvas screens keep a bar, and it is the SaaS header

   The hamburger exists because the three canvas screens have no room for a
   navigation strip beside their own actions. Your Inserts, the cart, and the
   account screens do: they are ordinary scrolling pages with an empty header.
   So the installed app reads the same as the desktop product there -- the
   Cribbit logo on the left, the same navigation icons inline on the right,
   and nothing collapsed one press deep.

   Mobile web is untouched and keeps the hamburger on every screen; it is
   gated behind `mobile_gate.js` and is not a product surface. */
body.is-capacitor:not(:has(#imageWorkspace:not([hidden]))) .app-header {
  justify-content: flex-start;
  gap: 8px;
  padding: calc(8px + var(--safe-area-inset-top))
    max(12px, var(--safe-area-inset-right)) 8px
    max(12px, var(--safe-area-inset-left));
}

body.is-capacitor:not(:has(#imageWorkspace:not([hidden])))
  .app-brand-navigation {
  display: flex;
  min-width: 0;
}

body.is-capacitor:not(:has(#imageWorkspace:not([hidden])))
  .mobile-menu-button {
  display: none;
}

/* Back out of the dropdown the mobile-web rules make of this: it is an inline
   row on the header again, pushed to the right edge by its own auto margin
   exactly as it is on the desktop SaaS. The `.is-mobile-menu-open` class the
   hamburger toggles is irrelevant here -- there is no hamburger to toggle
   it -- so both states resolve to the same row. */
body.is-capacitor:not(:has(#imageWorkspace:not([hidden])))
  .header-account-actions,
body.is-capacitor:not(:has(#imageWorkspace:not([hidden])))
  .header-account-actions:not(.is-mobile-menu-open) {
  position: static;
  display: flex;
  flex: 0 0 auto;
  gap: 2px;
  max-width: none;
  margin-left: auto;
  border: 0;
  border-radius: 0;
  padding: 0;
  background: transparent;
  box-shadow: none;
}

/* Five controls and a wordmark have to fit a 360px phone. The icons keep the
   desktop's 40px target and lose the space between them; the logo comes down
   from 40px to 28px. Measured on a 360px viewport with New, Inserts, Orders,
   Cart and the account button all showing: 328px of 360px. */
body.is-capacitor .app-logo {
  height: 28px;
}

body.is-capacitor .header-account-actions .user-button-slot {
  margin-left: 2px;
}

/* Full-bleed canvas. Three surfaces carry the light product theme into the
   editors -- the page background, the tools card, and each tool button -- so
   all three are repainted rather than just the outermost one. The canvas is
   allowed to run under the gesture bar; the header keeps its safe-area
   padding because its controls must stay tappable.

   mobile_runtime.js withholds the image-orientation class from the app, so
   the mobile-web side rail never reaches in here and one column is enough. */
body.is-capacitor:has(#imageWorkspace:not([hidden])),
body.is-capacitor .app-shell:has(#imageWorkspace:not([hidden])) {
  background: var(--workspace-bg);
}

body.is-capacitor .app-shell:has(#imageWorkspace:not([hidden])) {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  gap: 0;
  padding: 0;
}

body.is-capacitor .app-shell:has(#imageWorkspace:not([hidden]))
  > #imageWorkspace {
  grid-column: 1;
  grid-row: 1;
}

body.is-capacitor .image-stage {
  border: 0;
  border-radius: 0;
}

/* No shape properties bar in the app.

   Width and height are set by dragging the shape's own resize handles, which
   is the gesture a finger already has. A pair of numeric fields costs a strip
   across the top of the canvas plus a soft keyboard over the rest of it, to
   reach a size the handles reach directly. Desktop keeps the bar. */
body.is-capacitor #instructionBar,
body.is-capacitor #instructionBar.is-shape-selected {
  display: none;
}

body.is-capacitor .image-stage.is-result.is-layout:has(#instructionBar.is-shape-selected) {
  grid-template-rows: minmax(0, 1fr);
  gap: 0;
}

/* -------------------------------------------------------------------------
   The editor header is a pill, not a bar

   The three canvas screens now carry the same shape twice: a floating pill of
   tools at the bottom, and a floating pill of screen actions at the top left.
   The header leaves layout flow to do it, so the canvas keeps the whole
   viewport in both orientations rather than paying a bar for the header.

   Slightly transparent, so the drawer underneath is never completely covered
   by chrome. A little more see-through than the tool pill (0.88 against its
   0.95): the tools are dragged on and have to stay legible mid-gesture, while
   these five controls are read once and pressed.

   `--capacitor-editor-pill-height` is the one number the pill and everything
   that hangs below it agree on. Every control inside is 48px, so this is
   48 + 4px padding + 1px border, twice. */
body.is-capacitor {
  --capacitor-editor-pill-inset: 8px;
  --capacitor-editor-pill-height: 58px;
}

body.is-capacitor:has(#imageWorkspace:not([hidden])) .app-header {
  position: fixed;
  top: calc(var(--capacitor-editor-pill-inset) + var(--safe-area-inset-top));
  right: auto;
  bottom: auto;
  left: calc(var(--capacitor-editor-pill-inset) + var(--safe-area-inset-left));
  z-index: 100;
  box-sizing: border-box;
  justify-content: flex-start;
  gap: 2px;
  width: max-content;
  max-width: calc(
    100vw - var(--capacitor-editor-pill-inset) * 2 -
      var(--safe-area-inset-left) - var(--safe-area-inset-right)
  );
  height: var(--capacitor-editor-pill-height);
  min-height: var(--capacitor-editor-pill-height);
  border: 1px solid rgb(255 255 255 / 0.16);
  border-radius: 999px;
  padding: 4px;
  background: rgb(28 31 34 / 0.88);
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.46);
}

/* Nothing grows inside a pill that is only as wide as its contents. Both of
   these were `flex: 1 1 0` to fill a full-width bar; left that way their
   max-content contribution is the flex algorithm's rather than their own. */
body.is-capacitor:has(#imageWorkspace:not([hidden]))
  .mobile-editor-command-bar,
body.is-capacitor:has(#imageWorkspace:not([hidden]))
  > .app-header
  > .mobile-define-corners-header {
  flex: 0 1 auto;
}

/* The menu hangs off the pill's left edge, which is the edge the pill itself
   is anchored to. */
body.is-capacitor:has(#imageWorkspace:not([hidden])) .header-account-actions {
  top: calc(100% + 8px);
  right: auto;
  left: 0;
}

body.is-capacitor:has(#imageWorkspace:not([hidden])) .mobile-menu-button {
  flex: 0 0 48px;
  order: 0;
  width: 48px;
  height: 48px;
  min-height: 48px;
}

body.is-capacitor .mobile-editor-command-bar {
  position: relative;
  order: 2;
  display: flex;
  flex: 1 1 0;
  align-items: center;
  gap: 4px;
  min-width: 0;
  min-height: 48px;
}

/* Secondary actions, in header order: Save, Download DXF, Edit. None of them
   is a box: a rectangle drawn around a 44px touch target on a dark bar is all
   edge and no information. The screen-changing pair, "← Edit" and the forward
   action, are separated from Save and Download DXF by colour instead -- see
   the trial block below. */
body.is-capacitor .mobile-editor-secondary-action-slot {
  display: flex;
  flex: 0 1 auto;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

body.is-capacitor .mobile-editor-secondary-action-slot > button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  height: 44px;
  min-height: 44px;
  margin: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
  color: #fff;
}

body.is-capacitor .mobile-editor-secondary-action-slot > .save-button,
body.is-capacitor .mobile-editor-secondary-action-slot > #downloadDxfButton {
  width: 44px;
  min-width: 44px;
  padding: 0;
}

body.is-capacitor .mobile-editor-secondary-action-slot > .save-button svg,
body.is-capacitor .mobile-editor-secondary-action-slot
  > #downloadDxfButton svg {
  display: block;
  width: 24px;
  height: 24px;
  fill: currentColor;
  stroke: none;
}

body.is-capacitor .mobile-editor-secondary-action-slot > #editObjectsButton {
  flex: 0 1 auto;
  /* The desktop toolbar sizes every progression button to one width. With no
     rectangle left to keep even, the label hugs its own text instead. */
  width: auto;
  min-width: 0;
  padding: 0 10px;
  white-space: nowrap;
}

body.is-capacitor .mobile-editor-secondary-action-slot > button:hover,
body.is-capacitor .mobile-editor-secondary-action-slot > button:focus-visible,
body.is-capacitor .mobile-editor-secondary-action-slot > button:active {
  background: rgb(255 255 255 / 0.12);
  color: #fff;
}

/* The save animation is authored for a light button. On the dark bar the
   glyph, the spinner, and the tick are all white, and only the wash behind
   them changes. */
body.is-capacitor .mobile-editor-secondary-action-slot > .save-button.is-saving,
body.is-capacitor .mobile-editor-secondary-action-slot > .save-button.is-saved,
body.is-capacitor .mobile-editor-secondary-action-slot
  > .save-button.is-save-error {
  border: 0;
  box-shadow: none;
  color: #fff;
}

body.is-capacitor .mobile-editor-secondary-action-slot > .save-button.is-saving,
body.is-capacitor .mobile-editor-secondary-action-slot > .save-button.is-saved {
  background: rgb(47 122 96 / 0.42);
}

body.is-capacitor .mobile-editor-secondary-action-slot
  > .save-button.is-save-error {
  background: rgb(183 19 26 / 0.42);
}

body.is-capacitor .mobile-editor-primary-action-slot {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  min-width: 0;
  /* Nothing grows on this row any more, so the forward action is pushed to
     the right edge rather than left where the screen name used to end. */
  margin-left: auto;
}

body.is-capacitor .mobile-editor-primary-action-slot > .toolbar-primary-action,
body.is-capacitor .mobile-editor-primary-action-slot
  > .toolbar-preview-actions,
body.is-capacitor .mobile-editor-primary-action-slot
  > .toolbar-preview-actions .toolbar-primary-action {
  width: auto;
  min-width: 0;
  min-height: 44px;
  margin: 0;
}

body.is-capacitor .mobile-editor-primary-action-slot
  > .toolbar-preview-actions {
  display: flex;
  flex-direction: row;
}

body.is-capacitor:has(#appShell.is-editor-mode)
  .mobile-editor-primary-action-slot > #cartPreviewActions {
  display: none !important;
}

body.is-capacitor .mobile-editor-primary-action-slot .primary-forward-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 8px 10px;
  white-space: nowrap;
}

body.is-capacitor .desktop-editor-action-label {
  display: none;
}

body.is-capacitor .mobile-editor-action-label {
  display: inline;
}

body.is-capacitor .mobile-editor-action-icon {
  display: block;
}

body.is-capacitor .mobile-cart-action-icon {
  display: inline-block;
}

body.is-capacitor #generateFinalLayoutButton::before,
body.is-capacitor #cartAddPrimaryButton::after {
  content: attr(data-mobile-label);
}

body.is-capacitor .mobile-cart-action-icon {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

/* -------------------------------------------------------------------------
   TRIAL -- the screen-changing actions as bare red words (2026-08-23)

   Every other control on these three headers is already a word or a glyph
   with nothing drawn around it. This takes the last plates off the actions
   that leave the screen -- "Detect Objects →" on Define Corners, "Next →" in
   the object editor, and "← Edit" plus the cart in the layout editor -- and
   gives them colour to carry instead. Installed app only, and only on the three canvas screens:
   the desktop SaaS and the mobile web header keep their filled buttons.

   The red is lifted off the brand fill the same way the corner warning's
   amber was, and for the same reason: #e4232d on the #1f1f1f bar measures
   3.6:1, which does not carry as 15px text, while #ff5a63 measures 5.4:1 at
   the same hue.

   To revert: delete this block and restore the border/font-size pair on
   `> #editObjectsButton` above. (The landscape rail this note used to also
   name was retired in Phase 5V; there is nothing left to undo there.)
   ------------------------------------------------------------------------- */
body.is-capacitor {
  --capacitor-nav-red: #ff5a63;
  --capacitor-nav-red-press: rgb(255 90 99 / 0.16);
}

/* One font-size and weight across all four so every navigation arrow is the
   same glyph at the same size, and their words set the same. */
body.is-capacitor #mobileDetectObjectsButton,
body.is-capacitor #generateFinalLayoutButton,
body.is-capacitor #editObjectsButton,
body.is-capacitor #cartAddPrimaryButton {
  border: 0;
  border-radius: 8px;
  background: transparent;
  background-image: none;
  color: var(--capacitor-nav-red);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  --elevation: 0 0 #0000;
  box-shadow: none;
}

/* A touch leaves a lingering hover in the WebView, so press and hover are the
   same wash rather than two states that can disagree. */
body.is-capacitor #mobileDetectObjectsButton:hover,
body.is-capacitor #mobileDetectObjectsButton:focus-visible,
body.is-capacitor #mobileDetectObjectsButton:active,
body.is-capacitor #generateFinalLayoutButton:hover,
body.is-capacitor #generateFinalLayoutButton:focus-visible,
body.is-capacitor #generateFinalLayoutButton:active,
body.is-capacitor #editObjectsButton:hover,
body.is-capacitor #editObjectsButton:focus-visible,
body.is-capacitor #editObjectsButton:active,
body.is-capacitor #cartAddPrimaryButton:hover,
body.is-capacitor #cartAddPrimaryButton:focus-visible,
body.is-capacitor #cartAddPrimaryButton:active {
  border: 0;
  background: var(--capacitor-nav-red-press);
  background-image: none;
  color: var(--capacitor-nav-red);
  box-shadow: none;
  filter: none;
  transform: none;
}

/* With no plate left to dim, the word is what dims. */
body.is-capacitor #mobileDetectObjectsButton:disabled,
body.is-capacitor #mobileDetectObjectsButton[aria-disabled="true"],
body.is-capacitor #generateFinalLayoutButton:disabled,
body.is-capacitor #generateFinalLayoutButton[aria-disabled="true"],
body.is-capacitor #editObjectsButton:disabled,
body.is-capacitor #editObjectsButton[aria-disabled="true"],
body.is-capacitor #cartAddPrimaryButton:disabled,
body.is-capacitor #cartAddPrimaryButton[aria-disabled="true"] {
  border: 0;
  background: transparent;
  background-image: none;
  color: var(--capacitor-nav-red);
  box-shadow: none;
  opacity: 0.42;
  filter: none;
  transform: none;
}

/* The toast is anchored to the viewport rather than to the header. The header
   is a pill now: hung off `top: 100%` it would be a third of the screen wide
   and sitting in the left corner, which is not where a message about the
   press the user just made belongs. It clears the pill by the one height
   both of them read. */
body.is-capacitor .mobile-editor-notice-slot {
  position: fixed;
  top: calc(
    var(--capacitor-editor-pill-inset) + var(--safe-area-inset-top) +
      var(--capacitor-editor-pill-height)
  );
  right: max(8px, var(--safe-area-inset-right));
  left: max(8px, var(--safe-area-inset-left));
  z-index: 108;
  pointer-events: none;
}

/* The Define Corners hint is moved into the native notice layer but positioned
   independently at the bottom of the screen. The toast keeps the slot's top
   anchor, so a blocked press and this persistent instruction cannot collide.
   The SaaS and mobile web keep the node above the canvas in layout flow, where
   the `.image-stage` rules in styles.css still own it.

   A dark pill rather than bare text: the canvas underneath is the user's
   photo, and 13px of light grey over an arbitrary drawer is not readable.
   Same fill as the tool pill it shares the screen with. It inherits the
   slot's `pointer-events: none`, so it never takes a touch meant for a corner
   handle sitting under it.

   Shown only while Define Corners is actually the open screen -- the node
   lives outside `#imageStage` now, so it cannot inherit that from the stage
   the way the desktop rule does. */
body.is-capacitor #mobileEditorNoticeSlot > .calibration-hint {
  display: none;
}

body.is-capacitor:has(#imageWorkspace:not([hidden]) .image-stage.is-calibration)
  #mobileEditorNoticeSlot
  > .calibration-hint {
  position: fixed;
  right: auto;
  bottom: max(8px, var(--safe-area-inset-bottom));
  left: 50%;
  z-index: 108;
  display: block;
  /* `fit-content` shrink-wraps against the space to the right of `left: 50%`
     before the transform centres the pill, which limits this to roughly half
     the screen. Start from the text's intrinsic width instead; max-width still
     wraps it safely on genuinely narrow viewports. */
  width: max-content;
  max-width: min(440px, calc(100vw - 16px));
  margin: 0;
  border: 1px solid rgb(255 255 255 / 0.14);
  border-radius: 8px;
  padding: 7px 13px;
  background: rgb(28 31 34 / 0.9);
  box-shadow: 0 8px 22px rgb(0 0 0 / 0.38);
  color: #eef2f6;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
  transform: translateX(-50%);
}

/* The blocked-press toast. Red rather than the shared snackbar's dark pill:
   the desktop app already states both of these sentences in red beside the
   button they blocked, and this has three seconds to be read against a dark
   editor canvas that a dark pill sinks into. Solid fill in the same pair as
   .danger-button, because a red *word* at this size does not carry.
   It only sits at the top, because the bottom of both editors is toolbar.
   Never interactive: it says nothing the user can act on here. */
.mobile-validation-toast[hidden] {
  display: none;
}

body.is-capacitor .mobile-editor-notice-slot > .mobile-validation-toast {
  width: fit-content;
  max-width: min(440px, 100%);
  margin: 6px auto 0;
  border: 1px solid #b7131a;
  border-radius: 8px;
  padding: 9px 14px;
  background: var(--red);
  box-shadow: 0 10px 26px rgb(120 10 14 / 0.45);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.35;
  text-align: center;
  pointer-events: none;
}

/* Define Corners fits into the same paid-for global header. Its dimensions
   panel is positioned against the viewport, so the zero-height shell node
   still owns all of its state and event wiring. */
body.is-capacitor .app-header > .mobile-define-corners-header {
  order: 1;
  flex: 1 1 0;
  gap: 2px;
  min-width: 0;
  height: 48px;
  border: 0;
  padding: 0;
  background: transparent;
  box-shadow: none;
}

body.is-capacitor .app-header > .mobile-define-corners-header
  .mobile-editor-header-button,
body.is-capacitor .app-header > .mobile-define-corners-header
  .mobile-editor-header-action {
  min-width: 48px;
  height: 48px;
  min-height: 48px;
  margin: 0;
  padding: 6px 4px;
}

body.is-capacitor .app-header > .mobile-define-corners-header
  > #mobileDetectObjectsButton {
  padding-inline: 2px;
}

/* Capacitor moves the existing Rotate Photo control out of the hidden setup
   field and into the header. The glyph is enough in the tight pill; its full
   accessible name and clockwise title stay on the real button. */
body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton {
  flex: 0 0 44px;
  width: 44px;
  min-width: 44px;
  border: 0;
  border-radius: 8px;
  padding: 0;
  background: transparent;
  box-shadow: none;
  color: #fff;
}

body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton span {
  display: none;
}

body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton .rotate-image-icon {
  width: 24px;
  height: 24px;
}

body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton:hover:not(:disabled),
body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton:focus-visible,
body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton:active:not(:disabled) {
  border: 0;
  background: rgb(255 255 255 / 0.12);
  color: #fff;
  box-shadow: none;
}

body.is-capacitor .app-header > .mobile-define-corners-header
  > #rotateImageButton:disabled {
  background: transparent;
  color: #fff;
  opacity: 0.42;
}

/* Photo and Dims are one word each on a dark bar. A box around each of them
   is two more rectangles competing with the one button the screen is asking
   the user to press, so they are the word alone with a tap target around it.
   Next keeps its fill and is the only filled thing here. */
body.is-capacitor #mobileDefineCornersPhotoButton,
body.is-capacitor #mobileDefineCornersDimensionsButton {
  border: 0;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
  color: #fff;
  font-size: 14px;
  font-weight: 650;
}

body.is-capacitor #mobileDefineCornersPhotoButton:hover,
body.is-capacitor #mobileDefineCornersPhotoButton:focus-visible,
body.is-capacitor #mobileDefineCornersPhotoButton:active,
body.is-capacitor #mobileDefineCornersDimensionsButton:hover,
body.is-capacitor #mobileDefineCornersDimensionsButton:focus-visible,
body.is-capacitor #mobileDefineCornersDimensionsButton[aria-expanded="true"] {
  background: rgb(255 255 255 / 0.12);
  color: #fff;
}

/* The desktop error red does not survive a dark bar, and there is no border
   left to carry it, so the word itself turns. */
body.is-capacitor #mobileDefineCornersPhotoButton.is-invalid {
  border: 0;
  box-shadow: none;
  color: #ff8d92;
}

body.is-capacitor #setupPanel {
  position: absolute;
  width: 1px;
  height: 1px;
}

/* -------------------------------------------------------------------------
   Floating tool pill

   The toolbar leaves layout flow entirely. Nothing shares the shell with the
   canvas any more, so the tools ride over the letterbox band beside the
   drawer photo instead of taking a slice out of the screen.

   Placement follows the viewport, not the loaded image. The image-aspect
   placement this replaces existed because an in-flow tier had to spend the
   short edge of the picture; a pill that costs the canvas nothing only has to
   land near the thumb. */
body.is-capacitor .app-shell.is-editor-mode .editor-toolbar,
body.is-capacitor .app-shell.is-layout-mode .editor-toolbar {
  position: fixed;
  right: 0;
  bottom: calc(
    var(--capacitor-tool-pill-inset) + var(--safe-area-inset-bottom)
  );
  left: 0;
  z-index: 100;
  align-self: auto;
  justify-self: auto;
  flex-direction: row;
  gap: 0;
  width: max-content;
  max-width: calc(100vw - 16px);
  max-height: none;
  /* Auto margins rather than a translate: a transform on this element would
     make the size chip's `position: fixed` resolve against the pill instead of
     the viewport, and drag the chip into the tools. */
  margin: 0 auto;
  overflow: visible;
  padding: 0;
  scrollbar-width: none;
}

/* Text entry takes the tool pill off the screen: it stands exactly where the
   soft keyboard opens, and no tool on it can be reached without leaving the
   box being typed into first. The header pill keeps its actions.
   See setLayoutTextEntry in mobile_runtime.js. */
body.is-capacitor .app-shell.is-layout-mode.is-layout-text-entry
  .layout-toolbar {
  display: none;
}

body.is-capacitor .editor-toolbar .editor-tools-card {
  justify-content: center;
  gap: 2px;
  width: auto;
  min-height: 0;
  border: 1px solid rgb(255 255 255 / 0.16);
  border-radius: 999px;
  padding: 4px;
  background: rgb(28 31 34 / 0.95);
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.46);
}

/* Undo and redo leave the pill.

   They are the two controls a hand reaches for without looking, and inside the
   pill they competed for width with the tools and landed wherever the tool
   count happened to put them. Held out on the edges of the screen they are
   always in the same place, and each one falls under the thumb of the hand
   already holding that side of the phone.

   The row spans the screen, so it must not eat canvas touches: only the two
   buttons take input. */
body.is-capacitor .object-editor-tools-card .history-button-row,
body.is-capacitor .layout-editor-tools-card .history-button-row {
  position: fixed;
  /* Down at the bottom of the screen with the size slider, not up at the
     middle of it. Everything the hand reaches for without looking now sits in
     one band above the tool pill -- undo on the left, redo on the right, and
     the armed tool's size between them -- so the whole reach is one short
     stretch of the thumb and the drawer being edited is left clear above it.

     The row is given the size card's own height and centres its buttons in it,
     so the three line up on one centreline even though the buttons are taller
     than the card. */
  top: auto;
  right: 0;
  bottom: calc(var(--capacitor-pill-clearance) + var(--safe-area-inset-bottom));
  left: 0;
  z-index: 95;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 0;
  width: auto;
  height: var(--capacitor-size-card-height);
  margin: 0;
  border: 0;
  padding-right: max(12px, var(--safe-area-inset-right));
  padding-left: max(12px, var(--safe-area-inset-left));
  pointer-events: none;
}

/* Each button carries the pill's own surface, because out here there is no
   pill behind it -- only the drawer photo. The hover repeat is here for the
   same reason the pill has one: a touch leaves a lingering hover in the
   WebView, and the reset below would otherwise strip the plate off. */
body.is-capacitor .editor-toolbar .history-button-row .history-button,
body.is-capacitor .editor-toolbar .history-button-row .history-button:hover {
  border: 1px solid rgb(255 255 255 / 0.16);
  background: rgb(28 31 34 / 0.95);
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.46);
  pointer-events: auto;
}

body.is-capacitor .editor-toolbar .history-button-row .history-button:disabled {
  background: rgb(28 31 34 / 0.55);
}

body.is-capacitor .editor-tools-card .object-editor-toolbar-divider {
  display: none;
}

/* Icon-only and chrome-free. The glyph shrinks to 22px; the 48px target does
   not, because this is a surface the user also drag-paints on. Undo and redo
   are sized with everything else rather than kept as a lesser pair. */
body.is-capacitor .editor-toolbar .tool-button,
body.is-capacitor .editor-toolbar .history-button {
  width: var(--editor-tool-button-size);
  height: var(--editor-tool-button-size);
  min-height: var(--editor-tool-button-size);
  border: 0;
  border-radius: 50%;
  padding: 0;
  background: transparent;
  color: #e6ebe8;
  --elevation: 0 0 #0000;
  box-shadow: none;
}

body.is-capacitor .editor-toolbar .tool-button svg,
body.is-capacitor .editor-toolbar .history-button svg {
  width: 22px;
  height: 22px;
}

body.is-capacitor .editor-toolbar .finger-notch-tool-icon {
  width: 24px;
  height: 24px;
}

body.is-capacitor .editor-toolbar .history-button:disabled {
  color: rgb(230 235 232 / 0.3);
}

/* A touch leaves a lingering hover in the WebView, and the desktop rules paint
   that white -- one of them through an id selector that outranks everything
   above. The pill has no hover state at all: a button shows whether it is on,
   and nothing else. */
body.is-capacitor .editor-toolbar .tool-button:hover,
body.is-capacitor .editor-toolbar .history-button:hover,
body.is-capacitor .shape-tool-group:hover #shapeTool {
  border: 0;
  background: transparent;
  box-shadow: none;
}

body.is-capacitor .editor-toolbar #shapeTool.is-flyout-open {
  background: rgb(255 255 255 / 0.12);
}

/* One highlight covers both states the pill has to show: which tool is armed
   (.is-selected, from syncEditorToolControl) and whether Hide Visuals is on
   (.is-toggled, from syncHideVisualsButton). Both were already written by
   main.js for the desktop chrome, so neither needs new script here. The
   id-level repeat keeps the shape button lit through the hover reset above. */
body.is-capacitor .editor-toolbar .tool-button.is-selected,
body.is-capacitor .editor-toolbar .tool-button.is-toggled,
body.is-capacitor .editor-toolbar #shapeTool.is-selected {
  border: 0;
  background: rgb(255 255 255 / 0.2);
  color: #fff;
  --elevation: 0 0 #0000;
  box-shadow: none;
}

body.is-capacitor .editor-toolbar .brush-erase-tool-group {
  gap: 2px;
  min-height: var(--editor-tool-button-size);
  border: 0;
  padding: 0;
  background: transparent;
}

body.is-capacitor .editor-toolbar .finger-notch-tool-group,
body.is-capacitor .editor-toolbar .text-tool-group,
body.is-capacitor .editor-toolbar .shape-tool-group {
  display: grid;
  grid-template-columns: var(--editor-tool-button-size);
  width: var(--editor-tool-button-size);
  min-height: var(--editor-tool-button-size);
  border: 0;
  padding: 0;
  background: transparent;
}

/* Shapes: the button shows the shape it will draw -- the same rectangle and
   ellipse glyphs the desktop toolbar uses, swapped by the
   `is-shape-type-*` class `setShapeType` already writes. No caret and no
   corner triangle: pressing the button both arms that shape and opens the
   chooser. */
body.is-capacitor .shape-tool-caret-button,
body.is-capacitor #shapeTool::after {
  display: none;
}

/* The chooser is the same pill turned ninety degrees, and it opens *on* the
   shape button rather than beside it: the armed option lands exactly on the
   button's slot and the pill grows away from the toolbar with the other shape.
   So the press that opens it never moves the thing under the finger, and the
   shape now under the finger is the one already armed.

   Anchored to `.shape-tool-group` rather than the viewport, which is why
   positionShapeTypeMenu returns early in the app. It is free to cover the
   canvas and the pill behind it. */
body.is-capacitor .shape-type-menu {
  position: absolute;
  top: auto;
  right: auto;
  /* The chooser's own 4px padding and 1px border, backed out, so the last
     option's box lands exactly on the shape button's box. */
  bottom: -5px;
  left: -5px;
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: max-content;
  border: 1px solid rgb(255 255 255 / 0.16);
  border-radius: 999px;
  padding: 4px;
  background: rgb(28 31 34 / 0.98);
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.46);
  transform: none;
}

/* The armed shape is the one the toolbar slot is under, so it sits at the end
   the pill is anchored by. `order` puts it there whichever shape it is,
   without the chooser having to care what order the markup lists. */
body.is-capacitor .shape-type-option.is-selected {
  order: 1;
}

body.is-capacitor .shape-type-option {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  gap: 0;
  width: var(--editor-tool-button-size);
  height: var(--editor-tool-button-size);
  min-height: var(--editor-tool-button-size);
  border: 0;
  border-radius: 50%;
  padding: 0;
  background: transparent;
  color: #e6ebe8;
}

body.is-capacitor .shape-type-option:hover {
  border: 0;
  background: transparent;
}

body.is-capacitor .shape-type-option.is-selected,
body.is-capacitor .shape-type-option.is-selected:hover {
  border: 0;
  background: rgb(255 255 255 / 0.2);
  color: #fff;
}

/* Outlines, not solids -- the same drawing of a rectangle and an ellipse the
   desktop toolbar uses. Only the size is the app's. */
body.is-capacitor .shape-type-option svg {
  width: 22px;
  height: 22px;
}

body.is-capacitor .shape-type-option span {
  display: none;
}

/* Tool sizes: one card, always open.

   There is only ever one size to set -- the armed tool's -- so a chip that had
   to be opened first put a press in front of every adjustment. The card is now
   the slider and nothing else: no name, no number, no disclosure. The reading
   is on the canvas, where the brush ring, the notch, and the text are all
   drawn at the size being chosen.

   It is deliberately faint, because it stands over the drawer photo and the
   thing the user is watching while they drag it is behind it. The slider
   itself keeps full strength: it is a few pixels of line and hides nothing. */
body.is-capacitor #fingerNotchSizeControl,
body.is-capacitor #textSizeControl {
  display: none;
}

body.is-capacitor #fingerNotchToolGroup:has(#fingerNotchTool[aria-pressed="true"])
  #fingerNotchSizeControl,
body.is-capacitor #textToolGroup:has(#textTool[aria-pressed="true"])
  #textSizeControl,
body.is-capacitor #brushSizeControl:not([hidden]) {
  position: fixed;
  bottom: calc(var(--capacitor-pill-clearance) + var(--safe-area-inset-bottom));
  left: 50%;
  z-index: 90;
  display: grid;
  /* One column, because one thing is left in the card. The mobile-web rules
     still lay out a label and a value beside the slider. */
  grid-template-columns: auto;
  place-items: center;
  gap: 0;
  width: auto;
  /* Its own height, and the line undo and redo centre on. */
  height: var(--capacitor-size-card-height);
  min-height: 0;
  border: 1px solid rgb(255 255 255 / 0.1);
  border-radius: 12px;
  padding: 3px 10px;
  background: rgb(28 31 34 / 0.34);
  box-shadow: none;
  transform: translateX(-50%);
}

/* The size in words and numbers belongs to the desktop rail. main.js still
   writes it -- these are the nodes it writes into -- but the app does not show
   it. */
body.is-capacitor .editor-toolbar .brush-size-label,
body.is-capacitor .editor-toolbar .notch-size-label,
body.is-capacitor .editor-toolbar .text-size-label {
  display: none;
}

/* Every tool's slider is the same slider: one length for brush, eraser, notch,
   and text, and colours that read on a dark photo rather than on the light
   desktop card. */
body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"],
body.is-capacitor .editor-toolbar .notch-size-control input[type="range"],
body.is-capacitor .editor-toolbar .text-size-control input[type="range"] {
  --range-accent: #eef2f0;
  --range-groove: rgb(255 255 255 / 0.34);
  width: var(--capacitor-slider-length);
  height: var(--range-hit-size);
  direction: ltr;
  writing-mode: horizontal-tb;
}

/* The thumb's ring is the card's own dark, not the desktop card's near-white,
   so the thumb still reads as a disc against the track. */
body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-thumb,
body.is-capacitor .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-thumb,
body.is-capacitor .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-thumb {
  border-color: #1c1f22;
}

body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"]::-moz-range-thumb,
body.is-capacitor .editor-toolbar .notch-size-control input[type="range"]::-moz-range-thumb,
body.is-capacitor .editor-toolbar .text-size-control input[type="range"]::-moz-range-thumb {
  border-color: #1c1f22;
}

/* Freehand and straight line are tools, so they stand in the pill with the
   brush and the eraser instead of riding along with the size card.
   mobile_runtime.js moves them; `inherit` is what keeps them reading in the
   same direction as the group they joined when the phone turns. */
body.is-capacitor .editor-toolbar .brush-mode-control {
  flex: 0 0 auto;
  flex-direction: inherit;
  gap: 2px;
  width: auto;
}

body.is-capacitor .editor-toolbar .brush-mode-button,
body.is-capacitor .editor-toolbar .brush-mode-button:hover {
  width: var(--editor-tool-button-size);
  height: var(--editor-tool-button-size);
  min-height: var(--editor-tool-button-size);
  border: 0;
  border-radius: 50%;
  padding: 0;
  background: transparent;
  color: #e6ebe8;
  --elevation: 0 0 #0000;
  box-shadow: none;
}

body.is-capacitor .editor-toolbar .brush-mode-button.is-selected,
body.is-capacitor .editor-toolbar .brush-mode-button.is-selected:hover {
  background: rgb(255 255 255 / 0.2);
  color: #fff;
}

body.is-capacitor .editor-toolbar .brush-mode-button svg {
  width: 22px;
  height: 22px;
}

/* -------------------------------------------------------------------------
   Confirmations and notices centre on the screen

   `viewport-fit=cover` puts the WebView behind the status and gesture bars,
   so `100vh` here is the whole panel of glass rather than the part the user
   can see. A popup tall enough to hit its cap would run under both bars. The
   backdrop spends the insets as padding and the panel is capped to what is
   left, which also means "centred in the backdrop" is centred in the usable
   screen rather than centred behind the chrome.
   ------------------------------------------------------------------------- */
body.is-capacitor .object-recovery-backdrop {
  padding:
    max(16px, var(--safe-area-inset-top))
    max(16px, var(--safe-area-inset-right))
    max(16px, var(--safe-area-inset-bottom))
    max(16px, var(--safe-area-inset-left));
}

body.is-capacitor .object-recovery-panel {
  max-height: calc(
    100dvh - max(16px, var(--safe-area-inset-top)) -
      max(16px, var(--safe-area-inset-bottom))
  );
}

/* Landscape turns the two chrome edges ninety degrees: the tool pill moves to
   the right edge, which is the one the thumb can still reach when the phone is
   held wide, and the header becomes a rail down the left. Both are the same
   controls in the same order, read top to bottom rather than left to right. */
@media (orientation: landscape) {
  body.is-capacitor .app-shell.is-editor-mode .editor-toolbar,
  body.is-capacitor .app-shell.is-layout-mode .editor-toolbar {
    top: 0;
    right: calc(
      var(--capacitor-tool-pill-inset) + var(--safe-area-inset-right)
    );
    bottom: 0;
    left: auto;
    width: auto;
    height: max-content;
    max-width: none;
    max-height: calc(100dvh - 24px);
    margin: auto 0;
  }

  body.is-capacitor .editor-toolbar .editor-tools-card {
    flex-direction: column;
  }

  /* Undo and redo cross the bottom of the screen instead of its sides. Held
     wide, the sides are where the hands are, not where the thumbs land -- and
     the right edge is the tool pill's. Both are pulled well in from the edges
     so neither ends up under a palm or behind the pill. */
  body.is-capacitor .object-editor-tools-card .history-button-row,
  body.is-capacitor .layout-editor-tools-card .history-button-row {
    top: auto;
    right: 22%;
    bottom: calc(
      var(--capacitor-tool-pill-inset) + var(--safe-area-inset-bottom)
    );
    left: 22%;
    flex-direction: row;
    /* Not the portrait band: held wide, the row is on the floor of the screen
       and the size card is beside the pill, so there is no shared line to sit
       on and the buttons stand at their own height. */
    height: auto;
    padding-right: 0;
    padding-left: 0;
  }

  body.is-capacitor .editor-toolbar .brush-erase-tool-group {
    flex-direction: column;
  }

  /* The chooser turns with the toolbar and stays ninety degrees to it: a row
     now, anchored by its right end on the shape button's slot and growing left
     across the canvas. */
  body.is-capacitor .shape-type-menu {
    top: -5px;
    right: -5px;
    bottom: auto;
    left: auto;
    flex-direction: row;
    transform: none;
  }

  /* The size card turns too: beside the pill, centred on it, with the slider
     running down the screen the way the tools do. */
  body.is-capacitor #fingerNotchToolGroup:has(#fingerNotchTool[aria-pressed="true"])
    #fingerNotchSizeControl,
  body.is-capacitor #textToolGroup:has(#textTool[aria-pressed="true"])
    #textSizeControl,
  body.is-capacitor #brushSizeControl:not([hidden]) {
    top: 50%;
    right: calc(
      var(--capacitor-pill-clearance) + var(--safe-area-inset-right)
    );
    bottom: auto;
    left: auto;
    /* Turned on its side, the card's height is the slider's length, and there
       is no shared line with undo and redo to hold it to a fixed one. */
    height: auto;
    padding: 10px 3px;
    transform: translateY(-50%);
  }

  body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"],
  body.is-capacitor .editor-toolbar .notch-size-control input[type="range"],
  body.is-capacitor .editor-toolbar .text-size-control input[type="range"] {
    width: var(--range-hit-size);
    height: var(--capacitor-slider-length);
    direction: rtl;
    writing-mode: vertical-lr;
  }

  /* A vertical groove, and a thumb centred across it rather than above it.
     This is the geometry styles.css already draws for the desktop rail; it is
     restated because the mobile-web rules turned all three sliders horizontal
     before the app ever got to them. */
  body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-runnable-track,
  body.is-capacitor .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-runnable-track,
  body.is-capacitor .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-runnable-track {
    width: var(--range-track-thickness);
    height: auto;
    background: linear-gradient(to top,
        var(--range-accent) var(--range-fill-pos),
        var(--range-groove) var(--range-fill-pos));
  }

  body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"]::-moz-range-track,
  body.is-capacitor .editor-toolbar .notch-size-control input[type="range"]::-moz-range-track,
  body.is-capacitor .editor-toolbar .text-size-control input[type="range"]::-moz-range-track {
    width: var(--range-track-thickness);
    height: auto;
    background: linear-gradient(to top,
        var(--range-accent) var(--range-fill-pos),
        var(--range-groove) var(--range-fill-pos));
  }

  body.is-capacitor .editor-toolbar .brush-erase-shared-controls input[type="range"]::-webkit-slider-thumb,
  body.is-capacitor .editor-toolbar .notch-size-control input[type="range"]::-webkit-slider-thumb,
  body.is-capacitor .editor-toolbar .text-size-control input[type="range"]::-webkit-slider-thumb {
    margin-top: 0;
    margin-left: calc(
      (var(--range-track-thickness) - var(--range-thumb-size)) / 2
    );
  }

  /* The header does not turn. It is a pill in the top-left corner in both
     orientations -- the corner is the same corner however the phone is held,
     and a pill that costs the canvas nothing has no reason to move. This
     replaces the left rail the header became here until 2026-08-23; the rail
     existed because the header was still a full-width bar that had to spend
     one edge of the screen, and it no longer is. */
}

/* -------------------------------------------------------------------------
   The desktop-editing hint

   Installed app only, once per account, on the first entry to the object
   editor. It never renders anywhere else, so all of its styling lives here:
   the desktop SaaS ships the markup and no rules for it.

   Shaped like the corner-warning dialog above -- a centred card over a dim
   backdrop, sized off the viewport rather than the 760px `.modal-panel`
   default, and scrolled internally if a small phone in landscape cannot fit
   it. */
body.is-capacitor .desktop-editing-hint-backdrop {
  z-index: 130;
  padding: 16px;
  background: rgb(15 20 18 / 0.62);
}

body.is-capacitor .modal-panel.desktop-editing-hint-panel {
  width: min(420px, 100%);
  height: auto;
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  border: 1px solid rgb(91 104 98 / 0.34);
  border-radius: 12px;
  padding: 20px;
  box-shadow:
    0 28px 70px rgb(15 20 18 / 0.34),
    0 3px 12px rgb(15 20 18 / 0.18);
}

body.is-capacitor .desktop-editing-hint-title {
  margin: 0 0 10px;
  font-size: 1.14rem;
  line-height: 1.3;
}

body.is-capacitor .desktop-editing-hint-copy {
  margin: 0 0 18px;
  font-size: 0.94rem;
  line-height: 1.5;
}

/* One action, and it is the only way out other than Escape or the backdrop,
   so it gets the full width of the card rather than a 104px button floating
   at one end of it. */
body.is-capacitor .desktop-editing-hint-actions {
  display: flex;
}

body.is-capacitor .desktop-editing-hint-actions > .primary-button {
  flex: 1 1 auto;
  min-height: 48px;
}
