/* ==========================================================================
   AI Gradient Mapper — light UI
   Bright white stage, a large centered oval ("pill") photo preview, with
   two compact floating white cards (upload/export, render controls)
   sitting beside it.
   ========================================================================== */

@font-face {
  font-family: "Pretendard";
  src: url("fonts/Pretendard-Medium.woff") format("woff");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg-app: #fcfcfc;
  --panel-bg: rgba(245, 245, 245, 0.7);
  --panel-blur: blur(20px);
  --panel-border: rgba(0, 0, 0, 0.07);
  --text-primary: #111111;
  --text-secondary: #6b6b70;
  --text-tertiary: #a3a3a8;
  --radius-lg: 26px;
  --radius-pill: 999px;
  --header-h: 72px;
  --footer-h: 52px;
  --left-w: 206px;
  --right-w: 210px;
  --page-margin: 24px;
  font-size: 14px;
}

* { box-sizing: border-box; }

html, body {
  /* 100dvh tracks the *actual* visible viewport as mobile browser chrome
     (address bar / bottom nav) shows or hides, unlike 100vh which locks to
     the largest possible viewport and leaves dead space (or clips content)
     once the chrome collapses. The 100% line is a fallback for browsers
     without dvh support — declared first so dvh overrides it where available. */
  height: 100%;
  height: 100dvh;
  margin: 0;
  padding: 0;
}

body {
  background-color: var(--bg-app);
  background-image: url("images/backgorund.png");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: var(--text-primary);
  font-family: "Pretendard", -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-weight: 500;
  letter-spacing: -0.02em;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

button, input {
  font-family: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
}

/* ---------------------------------- Header / Footer ---------------------------------- */

.app-header {
  height: var(--header-h);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 var(--page-margin);
}

.app-header__logo {
  height: 20px;
  width: auto;
}

.app-footer {
  height: var(--footer-h);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 var(--page-margin);
}

.app-footer__mark {
  height: 9px;
  width: auto;
  opacity: 0.55;
}

/* ---------------------------------- Shell ---------------------------------- */

.app-shell {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 0 var(--page-margin) 32px;
}

.glass-panel {
  background: var(--panel-bg);
  backdrop-filter: var(--panel-blur);
  -webkit-backdrop-filter: var(--panel-blur);
  border-radius: var(--radius-lg);
  flex: none;
  align-self: center;
  max-height: 90%;
  overflow-y: auto;
}

.glass-panel--left {
  width: var(--left-w);
  padding: 32px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Y=524 in the 1440x810 reference frame, converted into the app-shell's
     own coordinate space (which starts below the 72px header). */
  align-self: flex-start;
  margin-top: 452px;
}

.glass-panel--right {
  width: var(--right-w);
  padding: 20px 18px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.panel-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.panel-title {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text-tertiary);
  margin: 0;
}

.field-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.field-label {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
}

/* ---------------------------------- Buttons ---------------------------------- */

.btn {
  appearance: none;
  border: 1px solid #0e030c;
  background: transparent;
  color: var(--text-primary);
  border-radius: var(--radius-pill);
  padding: 4.5px 12px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.05s ease;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-align: center;
}

.btn:hover { background: rgba(14, 3, 12, 0.05); }

.btn__icon {
  width: 17px;
  height: 17px;
  flex: none;
}
.btn:active { transform: scale(0.98); }

.btn--primary {
  background: #0e030c;
  border-color: #0e030c;
  color: #ffffff;
}
.btn--primary:hover { background: #262626; }

.btn--dark {
  background: #111111;
  border-color: #111111;
  color: #ffffff;
}
.btn--dark:hover { background: #262626; }

.btn--reset {
  width: auto;
  align-self: flex-end;
  padding: 4.5px 12px;
  font-size: 14px;
  margin-top: 4px;
}

.btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.file-meta {
  font-size: 11.5px;
  color: var(--text-tertiary);
  padding: 2px 2px 0;
  word-break: break-all;
}

/* ---------------------------------- Pill preview ---------------------------------- */

.pill-stage-wrapper {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
}

.canvas-wrapper {
  flex: 0 1 90%;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* No-op everywhere except the mobile media query, which turns this into a
   real box: a fixed-size circular "window" that flex-centers #canvasWrapper
   inside it. display:contents removes it from the box tree entirely here,
   so desktop/tablet layout is untouched (#canvasWrapper behaves as if it
   were still a direct child of .pill-stage-wrapper). */
.canvas-frame {
  display: contents;
}

.canvas-stage {
  position: relative;
  flex: none;
}

#artCanvas {
  /* The canvas bitmap itself is already clipped to a true ellipse (see
     canvasView.js's compositeLayers) with fully transparent corners, so no
     CSS border-radius is applied here — that would clip to a "stadium"
     shape instead of a true oval and fight the canvas's own alpha shape.
     drop-shadow (not box-shadow) is used so the shadow hugs the actual
     oval silhouette instead of the rectangular DOM box. */
  display: block;
  touch-action: none;
  cursor: none;
  filter: drop-shadow(0 24px 50px rgba(0, 0, 0, 0.14));
}

/* ---------------------------------- Render controls ---------------------------------- */

.controls-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.control {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.control__label-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 12px;
}

.control__label {
  color: var(--text-primary);
  font-weight: 500;
}

.control__value {
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

.control input[type="range"] {
  -webkit-appearance: none;
  width: 100%;
  height: 4px;
  border-radius: 999px;
  background: transparent;
  border: 2px solid var(--panel-border);
  outline: none;
}

.control input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #111111;
  border: none;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  margin-top: -5.5px;
}

.control input[type="range"]::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #111111;
  border: none;
  cursor: pointer;
}

.control input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: transparent;
  border: 2px solid var(--panel-border);
}

/* ---------------------------------- Custom cursor ---------------------------------- */

.custom-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 187px;
  height: 60px;
  object-fit: contain;
  pointer-events: none;
  opacity: 0;
  z-index: 999999;
  will-change: transform;
  transition: opacity 0.15s ease;
}

/* ---------------------------------- Mobile-only elements ---------------------------------- */
/* Hidden by default; shown only inside the mobile media query below. New
   selectors only — nothing existing touched. */
.mobile-header { display: none; }
.mobile-controls-card { display: none; }
.mobile-onboarding { display: none; }
.mobile-export-backdrop { display: none; }
.mobile-export-footer { display: none; }

/* ---------------------------------- Scrollbars ---------------------------------- */

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.14); border-radius: 999px; }
::-webkit-scrollbar-track { background: transparent; }

/* ---------------------------------- Responsive fallback ---------------------------------- */

@media (max-width: 1080px) {
  :root {
    --left-w: 200px;
    --right-w: 250px;
    --page-margin: 20px;
  }
  .app-shell { gap: 18px; }
}

/* ---------------------------------- Short-viewport fix (tablet/landscape) ---------------------------------- */
/* .glass-panel--left's margin-top:452px above assumes a >=900px-tall
   viewport (the desktop design reference). On shorter, wider viewports —
   e.g. a tablet or phone held in landscape — that fixed offset pushes the
   card past the bottom edge, where body's overflow:hidden silently clips
   it. Anchor it to the bottom instead (matching the reference composition,
   where the card sits low, near the pill's lower edge) only when the
   viewport is too short for the fixed offset to fit safely; true desktop
   (>=900px tall) and the <=768px mobile layout (handled separately below)
   are unaffected. */
@media (min-width: 769px) and (max-height: 899px) {
  .glass-panel--left {
    margin-top: 0;
    align-self: flex-end;
  }
}

/* ---------------------------------- Mobile (<=768px, or a phone rotated to landscape) ---------------------------------- */
/* Best-effort layout from two reference screenshots — real Figma Dev Mode
   spacing/padding values weren't accessible (auth-gated link), so these are
   approximations, not exact pixel parity. Everything above 768px in portrait
   (including the 1080px tablet tweak above) is completely untouched — this
   block only repositions the existing desktop DOM via CSS; no HTML/JS
   layout logic changed.
   The second condition (max-height:500px + landscape) catches phones
   rotated sideways, whose width commonly exceeds 768px (e.g. 844px) but
   whose height stays well under a tablet's — tablets in landscape (e.g.
   1024x768 iPad) keep the tablet/desktop layout since their height exceeds
   500px. */
@media (max-width: 768px), (max-height: 500px) and (orientation: landscape) {
  :root {
    --page-margin: 14px;
    --radius-lg: 20px;
    /* Tool screen photo card diameter — see .pill-stage-wrapper's longer
       comment for why this is viewport-proportional instead of a flat
       307px. */
    --circle-d: clamp(260px, 78.7vw, 340px);
  }

  body {
    background-image: url("images/mobile_bag.jpg");
    /* Longhand override only — overflow-x stays hidden from the base
       shorthand. Short/landscape viewports (e.g. a phone rotated sideways)
       aren't tall enough to fit header+card+controls, so this lets the
       page scroll to reach the bottom controls card instead of clipping
       it, unlike the base desktop layout which never needs to scroll. */
    overflow-y: auto;
  }

  .app-header { display: none; }

  .mobile-header {
    display: block;
    width: 100%;
    padding-top: env(safe-area-inset-top, 0px);
  }
  .mobile-header img {
    display: block;
    width: 100%;
    height: auto;
  }

  /* Reference design has no footer/copyright on this screen. */
  .app-footer { display: none; }

  /* The circle<->Reset (34px) and circle<->controls-card (20px) gaps are
     exact Figma Dev Mode measurements and stay fixed — both now expressed
     as real flex `gap`s (see .pill-stage-wrapper and .app-shell below)
     instead of position:absolute + a magic top offset, so they hold
     regardless of device/browser. The *overall* group's distance from the
     header is NOT a fixed Figma pixel value: a fixed offset assumed one
     specific reference frame height and looked "pushed down" on real
     devices with a shorter viewport (e.g. Galaxy phones vs. whatever the
     Figma frame's own height was). Centering the group vertically in the
     remaining space via justify-content instead adapts to whatever height
     is actually available. env(safe-area-inset-*) padding keeps that
     available space from running under the iPhone home indicator or an
     Android gesture/notch inset. */
  .app-shell {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    padding:
      0
      calc(var(--page-margin) + env(safe-area-inset-right, 0px))
      calc(24px + env(safe-area-inset-bottom, 0px))
      calc(var(--page-margin) + env(safe-area-inset-left, 0px));
  }

  .glass-panel--left,
  .glass-panel--right {
    display: none;
  }

  /* Outer flex column for the mobile "stage": the Reset button followed by
     the circular canvas frame, spaced by a 21px gap. Pure document flow —
     no position:absolute, no manual offsets — so DOM order (Reset first,
     see js/mobileLayout.js's prepend) is what puts Reset on top.

     --circle-d (defined on :root above, shared with .mobile-onboarding__gif)
     drives the circle's diameter as a fraction of viewport width instead of
     a hard 307px: a fixed px value looks visibly smaller on a wide iPhone
     than on a narrower Galaxy, even though both render the literal same
     307px, because it's a different proportion of each screen. 78.7vw
     reproduces exactly 307px at the 390px width this was originally
     measured against, and scales proportionally above/below that so the
     circle occupies the same relative amount of screen on any device;
     clamp()'s min/max keep it sane on very narrow or wide phones. */
  .pill-stage-wrapper {
    flex: none;
    width: auto;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 21px;
  }

  /* Responsive circular "window" (see --circle-d above): flex-centers the
     scaled #canvasWrapper inside it and clips its overflow. Only a box in
     the mobile media query — display:contents everywhere else (see base
     rule near .canvas-wrapper), so desktop/tablet are untouched. */
  .canvas-frame {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: var(--circle-d);
    height: var(--circle-d);
    overflow: hidden;
  }

  /* True circle per the Figma spec, without touching pillPath()/circleEngine
     (still an unmodified stadium internally). At the reference --circle-d
     of 307px, #canvasWrapper is a 472x472 square — applyFitScale()
     (unmodified) reads its clientWidth/Height and, since 1200:780 is wider
     than tall, naturally comes out width-bound: scale = 472/1200 ≈ 0.393 ->
     canvas renders at ~472x307. A 153.5px-radius clip-path centered in that
     472x472 box exactly matches the canvas's own 307px rendered height
     (472/2 - 153.5 = 82.5 = (472-307)/2, the canvas's vertical centering
     gap), so the circle has zero empty margin top/bottom and the canvas's
     full 472px width comfortably covers it side to side. Both figures now
     scale off --circle-d (472/307 and 1/2 are exact ratios) so that math
     holds at every size, and .canvas-frame (overflow:hidden) clips nothing
     further — it only exists to give the visible circle a real,
     flex-participating layout box. */
  #canvasWrapper {
    flex: none;
    width: calc(var(--circle-d) * 472 / 307);
    height: calc(var(--circle-d) * 472 / 307);
    clip-path: circle(calc(var(--circle-d) / 2) at center);
  }

  /* Relocated (see js/mobileLayout.js) reset button — now a normal flex
     item in .pill-stage-wrapper's column, centered by align-items:center
     and spaced from the circle by that column's 21px gap. No absolute
     positioning needed. align-self:center overrides the desktop rule's
     align-self:flex-end (meant for the right panel), which otherwise leaks
     through here and pushes the button to the right instead of centering it.
     Figma has this frame set to Hug x Hug — width/height are left unset
     here so the button sizes itself from its padding + text, same as
     Figma. Padding loosened from the strict 3px/15px Figma reading (felt
     cramped in practice) to a more comfortable 8px/20px. */
  .btn--reset {
    flex: none;
    align-self: center;
    position: relative;
    top: 1px;
    width: auto;
    height: auto;
    margin-top: 0;
    padding: 7px 18px;
    font-size: 16px;
    line-height: normal;
    letter-spacing: -0.046em;
  }

  .custom-cursor {
    width: 58px;
    height: 33.31px;
  }

  .mobile-controls-card {
    display: flex;
    flex-direction: column;
    gap: 18px;
    width: 100%;
    max-width: 360px;
    padding: 20px 18px;
  }

  /* DOM order (circleSize, density, overlap, random) alone produces the
     row1/row2 layout the reference shows via normal grid auto-placement. */
  .mobile-controls-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 16px;
    row-gap: 16px;
  }

  .mobile-controls-grid .control__label-row {
    font-size: 13px;
  }

  .mobile-next-btn {
    width: 100%;
    height: 45px;
    border-width: 1.74px;
    font-size: 18px;
    letter-spacing: -0.046em;
  }

  /* ---------------------------------- Mobile export view ---------------------------------- */
  /* Entered by tapping Next (js/mobileExport.js adds .mobile-export-active
     to <body>) — keeps the header, hides Reset/controls-card, and drops a
     blurred backdrop behind the still-sharp circle, with a caption plus
     Download/Share actions below it. Nothing is removed from the DOM, so
     leaving this view would just be removing the class (no re-entry flow
     exists yet — out of scope per spec, matches the reference screens
     having no back button).

     visibility:hidden (not display:none) on Reset/controls-card: display:
     none would've pulled them out of .app-shell's flex flow, and since the
     circle centers *together* with them via justify-content:center, that
     shifted the circle down the moment this view was entered (a taller
     flex group centers higher than a short one). visibility:hidden keeps
     their layout space reserved, so the circle's own position is pixel-
     identical between the editing screen and this one. */
  body.mobile-export-active .btn--reset,
  body.mobile-export-active .mobile-controls-card {
    visibility: hidden;
  }

  /* display:block unconditionally (not gated by .mobile-export-active) so
     the opacity transition below has something to animate — display can't
     be transitioned, only actually-rendered properties like opacity can.
     pointer-events:none keeps it from intercepting taps while invisible.
     Fill #FFFFFF at 10%, blur 10px. */
  .mobile-export-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 5;
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
  }
  body.mobile-export-active .mobile-export-backdrop {
    opacity: 1;
    pointer-events: auto;
  }

  /* Stacked above the backdrop so the header and circle (both otherwise
     unpositioned, which paints them *below* any positioned sibling
     regardless of z-index) read sharp against the blurred confetti body
     background instead of getting blurred out along with it. */
  body.mobile-export-active .mobile-header,
  body.mobile-export-active .pill-stage-wrapper {
    position: relative;
    z-index: 10;
  }

  /* Wraps the caption + actions row as one fixed-position group so the
     caption sits a fixed distance above the buttons regardless of viewport
     height. Same display-unconditional + opacity-transition treatment as
     the backdrop above, so both fade in together with it. */
  .mobile-export-footer {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(90px + env(safe-area-inset-bottom, 0px));
    z-index: 10;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
  }
  body.mobile-export-active .mobile-export-footer {
    opacity: 1;
    pointer-events: auto;
  }

  .mobile-export-caption {
    margin: 0;
    color: #0e030c;
    text-align: center;
    font-family: "Pretendard", sans-serif;
    font-size: 14.216px;
    font-style: normal;
    font-weight: 500;
    line-height: 150%;
    letter-spacing: -0.569px;
  }

  .mobile-export-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 15px;
  }

  /* Both are pre-built button graphics (bg + icon/text baked into the SVG,
     same pattern as onboarding_upload button.svg) rather than CSS-drawn —
     these elements just size and click-handle them. 45.69px matches
     Figma's own Hug height for this button group. */
  .mobile-export-icon-btn {
    flex: none;
    width: 45.69px;
    height: 45.69px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
  }
  .mobile-export-icon-btn img {
    display: block;
    width: 100%;
    height: 100%;
  }
  .mobile-export-icon-btn:disabled {
    opacity: 0.5;
  }

  .mobile-share-btn {
    flex: none;
    height: 45.69px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
  }
  .mobile-share-btn img {
    display: block;
    height: 100%;
    width: auto;
  }
  .mobile-share-btn:disabled {
    opacity: 0.5;
  }

  .control input[type="range"]::-webkit-slider-thumb {
    width: 12px;
    height: 12px;
    margin-top: -4px;
  }
  .control input[type="range"]::-moz-range-thumb {
    width: 12px;
    height: 12px;
  }

  /* ---------------------------------- Onboarding overlay ---------------------------------- */
  /* Fixed full-screen layer, shown until the user picks their first photo
     (js/mobileLayout.js adds .is-hidden on the shared "agm:imageReady"
     event) — sits above the tool UI underneath it rather than replacing it
     in the DOM, so nothing has to wait for onboarding to unmount. Its own
     .mobile-header reuses the same class (and mo_header sizing/position)
     as the tool screen's header, just with mo_header.jpg instead of
     mo_header.png per spec.

     .is-hidden fades this out via opacity instead of an instant
     display:none, so the tool screen underneath (already rendered — see
     above) reveals itself smoothly rather than snapping into view.
     pointer-events:none stops it from intercepting taps once invisible;
     no explicit display:none afterward needed since position:fixed
     already keeps it out of every other element's layout regardless of
     display. */
  .mobile-onboarding {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: #0ed7ff;
    overflow: hidden;
    opacity: 1;
    transition: opacity 0.9s ease;
  }

  .mobile-onboarding.is-hidden {
    opacity: 0;
    pointer-events: none;
  }

  /* Circular crop of the (16:9) source gif — object-fit:cover crops it the
     same way the main tool's photo card cover-crops an upload, just without
     needing a canvas since there's no mask/circle-gradient step here.
     min() of three terms, each a safety cap on the diameter:
       - calc(100dvh - 14.87vw - 166px): this screen's other vertical
         content, subtracted from the available height, so a short
         real-device viewport (address bar/nav chrome eating into 100dvh)
         shrinks the circle instead of forcing a scroll. The 14.87vw term
         tracks mo_header.jpg's own aspect ratio (its rendered height
         scales with viewport width); 166px covers margin-top (32) + no
         more gap to the footer (0px, see .mobile-onboarding__footer) +
         the caption/gap/button/footer-padding block (134px) — measured
         directly against the DOM rather than guessed.
       - calc(100vw + 60px): a small bleed past both edges (full
         off-screen bleed and any scrolling were both tried and rejected
         earlier) — the actual binding constraint at ordinary phone
         widths, since the 198.14vw term below is always bigger and never
         wins on its own.
       - 198.14vw: aspirational size if neither safety cap applied; kept
         for headroom on unusually tall/narrow viewports.
     No floor value here on purpose — an earlier max(412px, min(...)) let
     that floor override the height safety cap on very short viewports,
     overflowing past the fold again. Letting it shrink freely on those is
     better than forcing an overflow. */
  .mobile-onboarding__gif {
    flex: none;
    margin-top: 32px;
    width: min(198.14vw, calc(100vw + 60px), calc(100dvh - 14.87vw - 166px));
    height: min(198.14vw, calc(100vw + 60px), calc(100dvh - 14.87vw - 166px));
    border-radius: 50%;
    object-fit: cover;
  }

  /* No gap from the gif circle above (was margin-top:auto, which pushed
     this group all the way to the bottom of the column regardless of
     viewport height — now the gif's own position stays put and this
     group sits directly below it instead, per spec). Shrunk to 0
     (30px -> 5px -> 0) to raise the group as far as it goes without
     overlapping the circle. */
  .mobile-onboarding__footer {
    margin-top: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-bottom: calc(35px + env(safe-area-inset-bottom, 0px));
  }

  .mobile-onboarding__caption {
    margin: 0;
    font-size: 14px;
    color: var(--text-primary);
  }

  .mobile-onboarding__upload-btn {
    appearance: none;
    border: none;
    background: none;
    padding: 0;
    margin-top: 19px;
    width: 355px;
    max-width: 90vw;
    cursor: pointer;
  }

  .mobile-onboarding__upload-btn img {
    display: block;
    width: 100%;
    height: 63px;
  }
}
