/* =====================================================================
   Asset photo crop editor (Asset Settings modal).
   Presentation only. No accounting, no data, no layout outside the modal.

   Rendering model (matches window.balenAssetHero.heroCssVars):
     .ahe-frame   overflow:hidden aspect-ratio box (padding-top trick, so
                  no aspect-ratio support is required)
     .ahe-media   inner layer, background-size:cover +
                  background-position:<focal>, then transform:scale(zoom)
                  with transform-origin:<focal>. Because the layer already
                  COVERS at scale 1, scaling up from the focal origin still
                  covers at every aspect ratio -- blank areas are
                  impossible without per-viewport arithmetic.
     .ahe-scrim   the two localized overlay bands (heroCssVars.scrimLayers)
     .ahe-chrome  representative hero content so the user judges the real
                  composition, not a bare image.
   ===================================================================== */

.ahe { margin-top: 12px; }

.ahe-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; flex-wrap: wrap; margin-bottom: 8px;
}
.ahe-title { font-size: 12px; font-weight: 700; color: var(--ink2); }

/* viewport toggle ---------------------------------------------------- */
.ahe-vp { display: inline-flex; border: 1.5px solid var(--border); border-radius: 999px; overflow: hidden; }
.ahe-vpbtn {
  appearance: none; -webkit-appearance: none;
  background: var(--bg); color: var(--ink2);
  border: 0; padding: 6px 12px; font: inherit; font-size: 12px; line-height: 1.2;
  cursor: pointer; min-height: 44px;   /* touch target floor */
}
.ahe-vpbtn + .ahe-vpbtn { border-left: 1.5px solid var(--border); }
.ahe-vpbtn[aria-pressed="true"] { background: var(--ink); color: var(--card, #fff); font-weight: 700; }

/* stage / frame ------------------------------------------------------ */
.ahe-stage { width: 100%; }
.ahe-stage.ahe-vp-mobile { max-width: 300px; margin: 0 auto; }

.ahe-frame {
  position: relative;
  width: 100%;
  /* Desktop hero geometry, derived from the REAL breakpoints rather than
     guessed: at >=1200 .bh-stage is max-width 1440 with 48px side padding
     (css/billy.home.css:460), so the hero is 1344 wide, and .bh-hero is
     520 tall (:465) => 520/1344 = 38.7%. The previous 47% made the preview
     TALLER than the shipped hero, so a subject framed just inside the
     preview's bottom edge was cropped off on Home. */
  padding-top: 38.7%;
  border-radius: 14px;
  overflow: hidden;
  border: 1.5px solid var(--border);
  background: var(--bg);
  touch-action: none;             /* drag inside the frame, never scroll */
  cursor: grab;
  outline-offset: 3px;
}
/* Mobile hero geometry: below 768px .bh-stage has NO horizontal padding, so
   the hero is full-bleed viewport width at height 320px (css/billy.home.css:98).
   On a 390px phone that is 320/390 = 82%. The previous 93% assumed a 343px
   inset hero that does not exist. Narrower phones are taller (320px wide =>
   100%), so 82% is the representative mid-case, not an exact match at every
   width - the toggle is labelled as approximate for that reason. */
.ahe-stage.ahe-vp-mobile .ahe-frame { padding-top: 82%; }
.ahe-frame.is-dragging { cursor: grabbing; }
.ahe-frame:focus-visible { outline: 3px solid var(--blue, #2563eb); }
.ahe-frame:focus { outline: 3px solid var(--blue, #2563eb); }
.ahe-frame.is-static { cursor: default; touch-action: auto; }
/* No photo loaded => nothing to drag. touch-action:none on an empty box
   in the middle of a long modal is a scroll trap on iOS: a swipe that
   starts here moves nothing AND scrolls nothing. JS adds/removes
   .is-empty (and the tabindex) in _asHeroPaintNow. */
.ahe-frame.is-empty { cursor: default; touch-action: auto; }
.ahe-frame.is-empty:focus, .ahe-frame.is-empty:focus-visible { outline: none; }

.ahe-media {
  position: absolute; inset: 0;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  transform-origin: 50% 50%;
  will-change: transform;
}
.ahe-scrim { position: absolute; inset: 0; pointer-events: none; }

/* the hidden loader <img>: keeps the existing data-asset staleness guard
   and its onerror fallback without occupying the frame. */
.ahe-loader {
  position: absolute; left: 0; top: 0;
  width: 1px; height: 1px; opacity: 0; pointer-events: none;
}

.ahe-empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: var(--ink3); text-align: center; padding: 0 12px;
}

/* representative hero content --------------------------------------- */
.ahe-chrome { position: absolute; inset: 0; pointer-events: none; color: #fff; }
/* Offsets are PROPORTIONAL, not the literal hero pixels: the frame is a
   scaled-down hero, so copying left:32px onto a ~440px-wide preview would
   put the name 2.5x too far in. .bh-hero-id is left:32px/top:30px on the
   1100x520 desktop hero (2.9% / 5.8%) and left:20px/top:18px on the
   343x320 mobile hero (5.8% / 5.6%). The old flat 14px/12px sat the name
   noticeably higher and further left than it really lands, which is
   exactly where the top-left identity band is densest -- so the preview
   flattered readability twice over. */
.ahe-id { position: absolute; left: 2.9%; top: 5.8%; right: 2.9%; }
.ahe-stage.ahe-vp-mobile .ahe-id { left: 5.8%; top: 5.6%; right: 5.8%; }
/* Text-shadow mirrors css/billy.home.css .bh-has-photo hero type: the
   shadow is what carries a long name's tail past the 44% end of the
   localized top-left band, so the preview must judge WITH it. */
.ahe-name {
  margin: 0; font-size: 18px; line-height: 22px; font-weight: 600;
  letter-spacing: -0.2px; color: #fff;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0,0,0,0.45), 0 2px 14px rgba(0,0,0,0.35);
}
.ahe-model { margin: 2px 0 0; font-size: 11px; color: rgba(255,255,255,0.78); text-shadow: 0 1px 2px rgba(0,0,0,0.45), 0 2px 14px rgba(0,0,0,0.35); }
.ahe-state { display: flex; align-items: center; gap: 6px; margin-top: 6px; font-size: 11px; font-weight: 600; text-shadow: 0 1px 2px rgba(0,0,0,0.45), 0 2px 14px rgba(0,0,0,0.35); }
.ahe-dot { width: 7px; height: 7px; border-radius: 50%; background: #4ade80; display: inline-block; }

/* The real metric row (.bh-instruments) is a full-bleed band flush at
   bottom:0 carrying its OWN rgba(8,9,10,0.62) fill on top of the scrim
   (kept byte-consistent with css/billy.home.css). Floating bare tiles
   10px off the bottom showed the owner a LIGHTER backdrop than ships, so
   they raised the overlay to compensate for darkness the band was
   already providing. Padding is the hero's (12px 20px mobile / 18px 32px
   desktop) scaled by the preview ratio. */
.ahe-tiles {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: rgba(8,9,10,0.62);
  padding: 7px 13px;
  display: flex; gap: 6px; flex-wrap: wrap;
}
.ahe-tile { min-width: 0; }
.ahe-tile-l { margin: 0; font-size: 9px; letter-spacing: 0.6px; text-transform: uppercase; color: rgba(255,255,255,0.7); }
.ahe-tile-v { margin: 1px 0 0; font-size: 14px; font-weight: 600; color: #fff; }

.ahe-stage.ahe-vp-mobile .ahe-name { font-size: 16px; line-height: 20px; }
.ahe-stage.ahe-vp-mobile .ahe-tiles { gap: 14px; padding: 10px 17px; }

/* controls ----------------------------------------------------------- */
.ahe-hint { margin: 8px 0 0; font-size: 11px; line-height: 1.5; color: var(--ink3); }

.ahe-row { margin-top: 10px; }
.ahe-lab {
  display: block; font-size: 11px; font-weight: 700; color: var(--ink2);
  margin-bottom: 4px;
}
/* ---------------------------------------------------------------------
   Range inputs. These are the FIRST input[type=range] in the app, and
   app.html has a global `input, select, textarea { -webkit-appearance:
   none; appearance: none; height: 44px; padding: 0 14px; border: 1.5px
   solid ...; background: var(--card) }`. appearance:none on a range strips
   the native widget WITHOUT substituting anything, so both sliders painted
   as empty rounded boxes on Chrome and iOS Safari: no track, no thumb, no
   position indicator. The two primary controls of the editor were
   literally invisible.

   So: undo every part of that global rule here, then draw the track and
   the thumb from pseudo-elements. The INPUT keeps the 44px touch target;
   the visible track is 6px inside it (the thumb's negative margin-top
   re-centres it on WebKit, which positions the thumb against the track
   box rather than the input box).
   --------------------------------------------------------------------- */
.ahe-slide { display: flex; align-items: center; gap: 8px; }
.ahe-slide input[type="range"] {
  -webkit-appearance: none; appearance: none;
  flex: 1 1 auto; min-width: 0;
  height: 44px;                 /* touch target, not the visible track */
  margin: 0; padding: 0;
  border: 0; border-radius: 0;
  background: transparent;      /* kills the var(--card) box */
  color: var(--ink);
  cursor: pointer;
  touch-action: pan-y;          /* vertical page scroll still works */
}
.ahe-slide input[type="range"]:focus { outline: none; }
.ahe-slide input[type="range"]:focus-visible { outline: 3px solid var(--blue, #2563eb); outline-offset: 2px; border-radius: 999px; }

/* WebKit / Blink (Chrome, Edge, iOS Safari) */
.ahe-slide input[type="range"]::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px;
  background: var(--border); border: 0;
}
.ahe-slide input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--ink);
  border: 2px solid var(--card, #fff);
  box-shadow: 0 1px 3px rgba(0,0,0,0.35);
  margin-top: -8px;             /* (6 - 22) / 2 */
}
.ahe-slide input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.08); }

/* Gecko (Firefox) */
.ahe-slide input[type="range"]::-moz-range-track {
  height: 6px; border-radius: 999px;
  background: var(--border); border: 0;
}
.ahe-slide input[type="range"]::-moz-range-progress {
  height: 6px; border-radius: 999px;
  background: var(--ink3, #8a8a85);
}
.ahe-slide input[type="range"]::-moz-range-thumb {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--ink);
  border: 2px solid var(--card, #fff);
  box-shadow: 0 1px 3px rgba(0,0,0,0.35);
}
.ahe-slide input[type="range"]::-moz-focus-outer { border: 0; }

.ahe-val { font-size: 11px; color: var(--ink3); min-width: 42px; text-align: right; }

.ahe-btns { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.ahe-btn {
  appearance: none; -webkit-appearance: none;
  background: var(--bg); color: var(--ink);
  border: 1.5px solid var(--border); border-radius: 9px;
  padding: 7px 12px; font: inherit; font-size: 12px; line-height: 1.2;
  cursor: pointer; min-height: 44px;   /* touch target floor */
}
.ahe-btn:hover { border-color: var(--ink3); }
/* Reset crop is the one DESTRUCTIVE control in the strip and it has no
   undo, so it does not sit a thumb-width from Recenter. */
.ahe-btn-sep { margin-left: auto; }
.ahe-sel { width: 100%; }

@media (max-width: 360px) {
  .ahe-btn { flex: 1 1 46%; text-align: center; }
  /* margin-left:auto has nothing to push against once the row wraps, so
     give Reset crop its own row instead. */
  .ahe-btn-sep { flex: 1 1 100%; margin-left: 0; margin-top: 6px; }
  .ahe-vpbtn { padding: 6px 9px; }
}

@media (prefers-reduced-motion: reduce) {
  .ahe-media { will-change: auto; }
}
