/* app.css - entry stylesheet (linked from index.html) + app shell layout.
 * tokens -> base -> components are imported in that order; view CSS (css/views/<name>.css) is lazy-loaded by each view. */
@import url("tokens.css");
@import url("base.css");
@import url("components.css");

/* ------------------------------------------------------------------ shell */
#app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: calc(var(--vh, 1vh) * 100);
}

/* The header is a full-width bar; its inner row is centred at the same max width as <main>. */
.app-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--paper);
  padding-top: var(--safe-top);
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
  border-bottom: 1px solid transparent;
}
.app-header.is-stuck { border-bottom-color: var(--line); box-shadow: 0 1px 0 var(--line), 0 6px 14px -10px rgba(27, 36, 32, .25); }
.app-header-inner {
  display: flex;
  flex-wrap: wrap;     /* large text: when [heading + tail] no longer fit, the tail drops to a second row (see .app-heading) */
  align-items: center;
  gap: 2px;
  width: 100%;
  max-width: var(--content-w);
  min-height: 56px;
  margin: 0 auto;
  padding: 0 6px 0 var(--gutter);
}
.app-header.has-back .app-header-inner { padding-left: 6px; }
.app-back { flex: none; }
/* The wordmark/title is the heading's flex-basis (5.6rem = glyph + "Grockall" with a little ellipsis slack). rem, so it grows with the
 * text size: with large text (OS font scale, browser zoom of text only) the toggle + menu used to keep their size and squeeze the
 * title to 0-40 px ("G..."), the subtitle wrapped word by word. Now, once the heading cannot keep that basis, the whole .app-tail wraps
 * to its own row (right-aligned) and the heading takes the full width. At normal text sizes nothing wraps (the basis always fits). */
.app-heading { flex: 1 1 5.6rem; min-width: 0; padding: 4px 0; }
/* The view's actions (list: By area / Added toggle) and the menu button travel together. */
.app-tail { flex: none; display: flex; align-items: center; gap: 2px; margin-left: auto; }
.app-header.has-back .app-heading { padding-left: 4px; }
.app-title {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -.015em;
  line-height: 1.15;
}
/* A long title (large text: "Add from a recipe" at 200 %) wraps onto a second line instead of ending in an ellipsis; only a title that still
 * does not fit in TWO lines is clipped (-webkit-line-clamp supplies the ellipsis). overflow-wrap:anywhere lets one long word break rather than
 * widen the page. At normal sizes every title fits on one line, so nothing changes. */
.app-title-text {
  min-width: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
  /* overflow:hidden clips at the line box (1.15 x font size), which cut the tail of a "g" or "y" by 1-2 px; the padding gives the glyphs
   * room inside the clip and the negative margin gives the layout the same height back */
  padding: 3px 0;
  margin: -3px 0;
}
.app-wordmark-glyph { width: 1.6rem; height: 1.6rem; flex: none; color: var(--accent); }
.app-subtitle { margin-top: 1px; font-size: .82rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.app-actions { flex: none; display: flex; align-items: center; gap: 2px; }
.app-menu-btn { flex: none; }

#banner-root:empty { display: none; }

/* Main column: flex so a view can pin its last block to the bottom of the viewport with `margin-top: auto`. */
#view {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--content-w);
  min-height: calc(100vh - var(--header-h));
  min-height: calc(var(--vh, 1vh) * 100 - var(--header-h));
  margin: 0 auto;
  padding: 0 var(--gutter) calc(var(--space-5) + var(--safe-bottom));
  padding-left: max(var(--gutter), var(--safe-left));
  padding-right: max(var(--gutter), var(--safe-right));
  outline: none;
}

/* Views that want a full-bleed, edge-to-edge region can put this class on a child. */
.bleed { margin-left: calc(var(--gutter) * -1); margin-right: calc(var(--gutter) * -1); }

/* Boot skeleton + load error shown before the first view mounts. */
.boot { display: flex; flex-direction: column; gap: var(--space-3); padding-top: var(--space-4); }
.view-note { margin: auto; text-align: center; }

/* Wide screens: breathing room around the centred column. */
@media (min-width: 900px) {
  #view { padding-top: var(--space-2); }
}

/* The access gate (components/access-gate.js, css/views/gate.css) REPLACES the app: while html.is-gated nothing of the shell, a sheet or a
 * toast is visible, focusable or read out. visibility (not display) keeps the layout, so the scroll position and the open screen are exactly
 * as they were when the gate goes away again. Lives here, not in gate.css, so it holds even if the lazy file fails to load. */
html.is-gated #app,
html.is-gated #sheet-root,
html.is-gated #toast-root { visibility: hidden; }

/* Print: just the list. */
@media print {
  .app-header, #toast-root, #sheet-root { display: none !important; }
}
