/*
 * chrome.css — the layout that makes a generated app feel like an app.
 *
 * Injected by the builder. Do not edit inside a generated app.
 *
 * WHY THIS IS NOT LEFT TO THE MODEL
 * A model asked to design an app produces a web page: chrome that scrolls away
 * with the content, destinations as a row of text links across the top, and a
 * document that scrolls as one long column. That is a website. An app has
 * persistent chrome, one scrolling region, and its destinations along the
 * bottom where a thumb reaches.
 *
 * None of that is app-specific, so none of it should cost tokens or vary per
 * build. The model keeps what genuinely is its job -- the art direction and
 * what each screen says -- and this takes the furniture.
 *
 * WHAT IT DELIBERATELY DOES NOT TOUCH
 * Colour, typography and spacing inside a screen. Everything here uses the
 * app's own custom properties where it needs a colour, so an earthy field
 * guide stays earthy and a stark monochrome app stays stark. It changes where
 * things sit and how they scroll, not how they look.
 *
 * THE CONTRACT IT RELIES ON
 * Two things the build prompt guarantees: a <nav data-app-nav> container, and
 * a <main id="view"> the router renders into. Everything else is best-effort
 * and degrades to the page simply looking as it did before.
 */

/* --- the frame ------------------------------------------------------------
   The document itself must not scroll. One region does, which is what makes
   headers stay put and what stops iOS rubber-banding the whole app. */
html.app-chrome,
html.app-chrome body {
  /* 100% resolves against the LARGE viewport -- the page as it would be if the
     browser's address bar were retracted. On a phone it is not retracted, so
     the body ends up taller than what anybody can see, and because the body
     does not scroll (below), the bottom nav sits under the browser chrome with
     no way to reach it. It looked perfect on a desktop, where there is no
     retractable browser UI and 100% is the visible height.
     dvh tracks the viewport that is actually visible right now. The 100% above
     it stays as the fallback for anything too old to know the unit. */
  height: 100%;
  height: 100dvh;
  margin: 0;
}

html.app-chrome body {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  overscroll-behavior: none;
  /* Chrome is fixed, so a long page cannot be reached by scrolling the body. */
  padding: 0;
}

/* The only scroller. Momentum on iOS, and a scroll that stops at its own edges
   rather than dragging the page behind it. */
html.app-chrome #view {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding-bottom: 1.5rem;
}

/* --- a floor under anything you have to hit ------------------------------
   The model writes the app's own controls, and it does not always size them:
   a published app shipped its three main buttons at 288x25, which is Chrome's
   DEFAULT button padding showing through a rule that set typography and never
   set height. Twenty-five pixels is a miss, not a tap.

   Only on coarse pointers, so nothing a model deliberately designed for a
   mouse is disturbed. Only a floor -- anything already larger keeps its size.

   min-width is deliberately NOT set. A row of small chips would each grow and
   could push the row wider than the screen, and horizontal overflow on a phone
   is a worse bug than a narrow button. align-items is inert on anything that
   is not a flex or grid container, and centres the label on anything that is. */
@media (pointer: coarse) {
  html.app-chrome button,
  html.app-chrome [role="button"],
  html.app-chrome select,
  html.app-chrome summary,
  html.app-chrome input:not([type="hidden"]):not([type="range"]):not([type="checkbox"]):not([type="radio"]) {
    min-height: 44px;
    align-items: center;
  }
}

/* --- the top bar ----------------------------------------------------------
   Whatever the model called it, the first header in the body is the app bar.
   It keeps its own styling; it just stops scrolling away. */
html.app-chrome > body > header {
  flex: 0 0 auto;
  padding-top: max(env(safe-area-inset-top), 0px);
  z-index: 20;
}

/* --- destinations ---------------------------------------------------------
   A row of text links across the top is how a website presents sections. An
   app puts them at the bottom, with an icon, sized for a thumb. */
html.app-chrome [data-app-nav] {
  flex: 0 0 auto;
  display: flex;
  align-items: stretch;
  justify-content: space-around;
  gap: 0;
  margin: 0;
  padding: 0 max(env(safe-area-inset-left), .25rem) max(env(safe-area-inset-bottom), .25rem) max(env(safe-area-inset-right), .25rem);
  background: var(--surface, var(--bg, #fff));
  border-top: 1px solid var(--border, var(--line, rgba(127, 127, 127, .22)));
  z-index: 20;
  /* Six is already too many for a phone; let them scroll rather than crush. */
  overflow-x: auto;
  scrollbar-width: none;
}
html.app-chrome [data-app-nav]::-webkit-scrollbar { display: none; }

html.app-chrome [data-app-nav] a {
  flex: 1 0 auto;
  min-width: 4.5rem;
  min-height: 3.25rem;          /* comfortably past the 44px floor */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .15rem;
  padding: .4rem .3rem;
  text-decoration: none;
  text-transform: none;
  letter-spacing: 0;
  font-size: .68rem;
  line-height: 1.15;
  text-align: center;
  color: var(--muted, var(--text-muted, #6b7280));
  transition: color .12s ease-out;
}

html.app-chrome [data-app-nav] a .tab-icon {
  width: 1.45rem;
  height: 1.45rem;
  display: block;
  flex: none;
}

html.app-chrome [data-app-nav] a[aria-current] {
  color: var(--accent, var(--primary, #4f46e5));
  font-weight: 600;
}

/* --- touch ----------------------------------------------------------------
   Small things that are absent from a page and present in every app. */
html.app-chrome * {
  -webkit-tap-highlight-color: transparent;
}
html.app-chrome a,
html.app-chrome button,
html.app-chrome [role="button"] {
  touch-action: manipulation;
}
/* Chrome is furniture, not text: selecting it on a long-press feels broken.
   Content is left alone, because copying out of an app is normal. */
html.app-chrome > body > header,
html.app-chrome [data-app-nav] {
  -webkit-user-select: none;
  user-select: none;
}

/* --- wider screens --------------------------------------------------------
   A bottom bar on a desktop monitor is a phone app in a window. Past tablet
   width the destinations go back to the top, where a pointer expects them. */
@media (min-width: 48rem) {
  html.app-chrome [data-app-nav] {
    order: -1;
    justify-content: flex-start;
    gap: .25rem;
    padding: .35rem max(env(safe-area-inset-left), 1rem);
    border-top: 0;
    border-bottom: 1px solid var(--border, var(--line, rgba(127, 127, 127, .22)));
  }
  html.app-chrome [data-app-nav] a {
    flex: 0 0 auto;
    min-width: 0;
    min-height: 2.5rem;
    flex-direction: row;
    gap: .45rem;
    padding: .4rem .8rem;
    font-size: .82rem;
    border-radius: .5rem;
  }
  html.app-chrome [data-app-nav] a .tab-icon { width: 1.1rem; height: 1.1rem; }
  html.app-chrome #view { padding-bottom: 2.5rem; }
}

/* Somebody who asked for less motion gets less of it. */
@media (prefers-reduced-motion: reduce) {
  html.app-chrome [data-app-nav] a { transition: none; }
}

/* A tab label is a name, not a sentence. "Regions in the Cellar" rendered 60%
   wider than its neighbours and broke the even rhythm a tab bar depends on, so
   long ones are clipped rather than allowed to push the row around. */
html.app-chrome [data-app-nav] a .tab-label {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
html.app-chrome [data-app-nav] a {
  max-width: 7rem;
}
@media (min-width: 48rem) {
  html.app-chrome [data-app-nav] a { max-width: none; }
}

/* WHY THE WHOLE SELECTOR IS INSIDE :where(), NOT JUST ITS TAIL
   Because these three rules promise, in their own comments, that a rule the
   app sets deliberately still wins -- and until this was fixed they did the
   opposite. `html.app-chrome #view :where(*)` is one id, one class and one
   element: :where() zeroes only what is inside it, and the prefix was outside.
   At (1,1,1) it outranked every class an app could write.

   It was doing real damage rather than theoretical. A published app set
   `.preset-button { min-height: 46px }` and got 25px controls, because this
   reset won. The grid rule below is worse: it would replace the columns of any
   grid an app declared by class, collapsing a row of three into a stack.

   Wrapped whole, the specificity is (0,0,0) and the promise is true. */

/* --- making content fit a phone -------------------------------------------
   A model lays a screen out at desktop width and it does not survive 375px. The
   usual mechanism is not a fixed width anywhere -- it is that flex and grid
   items default to `min-width: auto`, so they refuse to shrink below their
   content, and a grid track sizes itself to whatever that turns out to be. A
   real app produced a 560px row inside a 343px card this way.

   `:where()` carries no specificity, so any rule the app sets deliberately
   still wins. This only supplies the default the box model should have had. */
:where(html.app-chrome #view *) {
  min-width: 0;
  min-height: 0;
}

/* Long unbroken strings -- a URL, a producer name with no spaces -- would still
   push a row wider than the screen. */
:where(html.app-chrome #view p, html.app-chrome #view li, html.app-chrome #view td, html.app-chrome #view h1, html.app-chrome #view h2, html.app-chrome #view h3, html.app-chrome #view h4, html.app-chrome #view span, html.app-chrome #view a, html.app-chrome #view div) {
  overflow-wrap: break-word;
}

/* --- the grid blowout ------------------------------------------------------
   A grid with no declared columns gets one implicit `auto` track, and an auto
   track's automatic minimum is min-content -- so a single wide child drags the
   whole track past its container and the rest of the screen with it. A real
   app put a 560px row inside a 343px card exactly this way, and nothing on the
   ITEM fixes it: min-width:0 on the row changed nothing, while minmax(0,1fr)
   on the container collapsed it to fit.

   Supplying it through :where() means any grid whose columns the app DID
   declare keeps them -- a class selector outranks zero specificity -- and only
   the ones that declared none get a floor. On anything that is not a grid the
   property does nothing at all. */
:where(html.app-chrome #view *) {
  grid-template-columns: minmax(0, 1fr);
}

/* --- the way out ----------------------------------------------------------
   A back control on a detail screen, a skip on onboarding. Both sit at the
   start of the app bar, where a thumb reaches and where every phone app has
   put them for fifteen years.

   Generated apps mostly had neither: two of six screens offered a way back in
   one app and none at all in another, which is why detail screens ended up in
   the tab bar -- being a tab was the only way to reach them. */
html.app-chrome .screen-affordance {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  margin-right: .25rem;
  padding: 0 .6rem;
  border: 0;
  border-radius: .6rem;
  background: none;
  color: inherit;
  font: inherit;
  font-size: .88rem;
  cursor: pointer;
}
html.app-chrome .screen-affordance svg {
  width: 1.35rem;
  height: 1.35rem;
}
html.app-chrome .screen-affordance:hover,
html.app-chrome .screen-affordance:focus-visible {
  background: var(--surface-2, rgba(127, 127, 127, .12));
}
/* Skip is a way out, not the point of the screen: quieter than the CTA it
   sits opposite. */
html.app-chrome .screen-affordance.is-skip {
  color: var(--muted, var(--text-muted, #6b7280));
}
