/* ============================================================================
   DIALR — APP SHELL & LAYOUT
   ----------------------------------------------------------------------------
   The shell is a fixed stack of layers. Nothing in the app creates a new
   full-screen layer on its own — it mounts into one of these roots.

     wallpaper  →  screens  →  scrim  →  search  →  dock
                   →  sheets  →  modals  →  call  →  toasts  →  dev
   ========================================================================== */

#dialr-root { height: 100%; }

.app {
  position: relative;
  height: 100%;
  width: 100%;
  overflow: hidden;
  background: var(--bg);
  isolation: isolate;
  contain: strict;
}

/* ---- wallpaper layer ------------------------------------------------------
   Holds the app-wide theme wallpaper. Deliberately dimmed and desaturated so
   that content contrast never depends on the image.
   ------------------------------------------------------------------------ */
.app__wallpaper {
  position: absolute; inset: 0;
  z-index: var(--z-wallpaper);
  background: var(--bg);
  pointer-events: none;
}
.app__wallpaper-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: var(--wallpaper-opacity, 0);
  filter: saturate(var(--wallpaper-sat, 0.85)) brightness(var(--wallpaper-bright, 0.55));
  transform: scale(1.06);
  transition: opacity var(--d-xslow) var(--e-standard);
}
/* Legibility veil: a vertical gradient that guarantees text contrast at the
   top (titles) and bottom (dock zone) regardless of the image behind it. */
.app__wallpaper::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom,
      rgba(var(--scrim), var(--wall-veil-top, .55)) 0%,
      rgba(var(--scrim), var(--wall-veil-mid, .20)) 38%,
      rgba(var(--scrim), var(--wall-veil-bot, .78)) 100%);
  opacity: var(--wallpaper-active, 0);
  transition: opacity var(--d-xslow) var(--e-standard);
}

/* ---- screen layer -------------------------------------------------------- */
.app__screens {
  position: absolute; inset: 0;
  z-index: var(--z-screen);
}

.screen {
  position: absolute; inset: 0;
  display: flex;
  flex-direction: column;
  padding-top: calc(var(--safe-t) + var(--sp-4));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--d-base) var(--e-standard),
              transform var(--d-base) var(--e-standard),
              visibility 0s linear var(--d-base);
  transform: translate3d(0, 6px, 0);
}
.screen.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition: opacity var(--d-base) var(--e-enter),
              transform var(--d-slow) var(--e-spring),
              visibility 0s;
}
/* Lateral tab movement: screens to the left/right of the active tab slide. */
.screen.is-left  { transform: translate3d(-14px, 0, 0); }
.screen.is-right { transform: translate3d( 14px, 0, 0); }

.screen__header {
  flex: 0 0 auto;
  padding: var(--sp-6) var(--screen-pad-x) var(--sp-5);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
  z-index: var(--z-screen-head);
}
.screen__header--center { justify-content: center; }

.screen__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding: 0 var(--screen-pad-x);
  /* Content always clears the one-handed zone. --bottom-actual is measured at
     runtime (src/app/main.js) because that zone changes height: keypad on the
     dialer, search bar elsewhere, nothing at all if search is switched off. */
  padding-bottom: calc(var(--bottom-actual, var(--bottom-zone)) + var(--sp-8));
  scroll-padding-bottom: var(--bottom-actual, var(--bottom-zone));
  /* Content dissolves into the bottom zone instead of being sliced by it. */
  -webkit-mask-image: linear-gradient(to bottom,
      #000 0,
      #000 calc(100% - var(--bottom-actual, var(--bottom-zone)) - 34px),
      transparent calc(100% - var(--bottom-actual, var(--bottom-zone)) + 6px));
  mask-image: linear-gradient(to bottom,
      #000 0,
      #000 calc(100% - var(--bottom-actual, var(--bottom-zone)) - 34px),
      transparent calc(100% - var(--bottom-actual, var(--bottom-zone)) + 6px));
}
.screen__body::-webkit-scrollbar { width: 0; }
.screen__body--nosearch { padding-bottom: calc(var(--bottom-actual, var(--bottom-zone-nosearch)) + var(--sp-8)); }
.screen__body--flush { padding-left: 0; padding-right: 0; }

/* Constrain to a readable measure on wide viewports without becoming a website */
.screen__inner {
  width: 100%;
  max-width: var(--screen-max-w);
  margin: 0 auto;
}

/* ---- bottom interaction zone (search + dock) ----------------------------- */
.app__bottom {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-dock);
  display: flex;
  flex-direction: column;
  gap: var(--search-gap);
  padding: 0 var(--dock-inset-x) calc(var(--dock-inset-b) + var(--safe-b));
  pointer-events: none;
}
.app__bottom > * { pointer-events: auto; }
.app__bottom-inner {
  width: 100%;
  max-width: var(--screen-max-w);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--search-gap);
}

/* ---- global scrim -------------------------------------------------------- */
.app__scrim {
  position: absolute; inset: 0;
  z-index: var(--z-scrim);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-base) var(--e-standard);
  /* Not a flat modal wash: a bottom-weighted gradient that lifts the dock and
     search off the content without hiding it. */
  background: linear-gradient(
      to top,
      rgba(var(--scrim), var(--scrim-strong)) 0%,
      rgba(var(--scrim), var(--scrim-medium)) 26%,
      rgba(var(--scrim), 0) 62%);
}
.app__scrim.is-on { opacity: 1; pointer-events: auto; }
.app__scrim.is-full {
  background: rgba(var(--scrim), var(--scrim-strong));
  backdrop-filter: blur(var(--blur-sm));
  -webkit-backdrop-filter: blur(var(--blur-sm));
}

/* ---- overlay roots ------------------------------------------------------- */
.app__sheets { position: absolute; inset: 0; z-index: var(--z-sheet); pointer-events: none; }
.app__sheets > * { pointer-events: auto; }
.app__modals { position: absolute; inset: 0; z-index: var(--z-modal); pointer-events: none; }
.app__modals > * { pointer-events: auto; }
.app__call   { position: absolute; inset: 0; z-index: var(--z-call);  pointer-events: none; }
.app__call > * { pointer-events: auto; }
.app__toasts {
  position: absolute; left: 0; right: 0;
  bottom: calc(var(--bottom-actual, var(--bottom-zone)) + var(--sp-4));
  z-index: var(--z-toast);
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  pointer-events: none;
  padding: 0 var(--sp-6);
}
.app__toasts > * { pointer-events: auto; }

/* ---- flex/grid utilities ------------------------------------------------- */
.row  { display: flex; align-items: center; }
.row-b{ display: flex; align-items: baseline; }
.row-t{ display: flex; align-items: flex-start; }
.col  { display: flex; flex-direction: column; }
.grow { flex: 1 1 auto; min-width: 0; }
.center { display: flex; align-items: center; justify-content: center; }
.between { justify-content: space-between; }
.wrap { flex-wrap: wrap; }

.g-1 { gap: var(--sp-1); } .g-2 { gap: var(--sp-2); } .g-3 { gap: var(--sp-3); }
.g-4 { gap: var(--sp-4); } .g-5 { gap: var(--sp-5); } .g-6 { gap: var(--sp-6); }
.g-7 { gap: var(--sp-7); } .g-8 { gap: var(--sp-8); } .g-9 { gap: var(--sp-9); }

.mt-2{margin-top:var(--sp-2)} .mt-4{margin-top:var(--sp-4)} .mt-5{margin-top:var(--sp-5)}
.mt-6{margin-top:var(--sp-6)} .mt-7{margin-top:var(--sp-7)} .mt-8{margin-top:var(--sp-8)}
.mt-9{margin-top:var(--sp-9)} .mt-10{margin-top:var(--sp-10)}
.mb-4{margin-bottom:var(--sp-4)} .mb-6{margin-bottom:var(--sp-6)} .mb-8{margin-bottom:var(--sp-8)}

/* ---- hairline rule — the short white line seen across the references ----- */
.rule {
  height: 2px;
  width: 116px;
  max-width: 60%;
  background: var(--fg);
  border-radius: 2px;
  opacity: .92;
}
.rule--full { width: 100%; max-width: none; height: 1px; background: var(--line); opacity: 1; }
.rule--soft { background: var(--line-strong); height: 1px; }

/* ---- device frame for desktop development viewport ----------------------- */
@media (min-width: 760px) and (min-height: 640px) {
  body.is-framed {
    display: grid;
    place-items: center;
    background:
      radial-gradient(120% 90% at 50% 0%, #1b1b1e 0%, #0a0a0b 60%, #050506 100%);
  }
  body.is-framed #dialr-root {
    width: min(430px, 34vw + 200px);
    height: min(932px, 92vh);
    border-radius: 46px;
    overflow: hidden;
    box-shadow: 0 40px 120px rgba(0,0,0,.7), 0 0 0 10px #131316, 0 0 0 11px #2a2a2e;
  }
  body.is-framed .app { border-radius: 36px; }
}
