:root {
  color-scheme: light;
  --bg: #fdf6f0;
  --surface: #ffffff;
  --text: #2b2118;
  --muted: #8a7b6c;
  --accent: #d9612b;
  --accent-hover: #c1521f;
  --border: #eee0d4;
}
* { box-sizing: border-box; }
/* Author rules like `.banner { display: flex }` normally beat the
   UA's `[hidden] { display: none }` regardless of specificity, since
   author-origin styles always outrank user-agent-origin ones in the
   cascade - so anything toggled via the `hidden` property needs this
   to actually disappear instead of just losing its own display rule. */
[hidden] { display: none !important; }
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  margin: 0;
  padding: 2.5rem 1rem;
}
.container {
  max-width: 640px;
  margin: 0 auto;
}
h1 {
  font-family: 'Fredoka', sans-serif;
  font-weight: 400;
  font-size: 1.85rem;
  margin: 0 0 0.25rem;
}
.subtitle {
  color: var(--muted);
  margin: 0 0 1.5rem;
}
/* grocery-list.ftl - jump link to the #recipes-used section at the bottom,
   only rendered when the list has at least one recipe behind it. */
.recipes-used-shortcut {
  display: inline-block;
  color: var(--accent);
  font-size: 0.9rem;
  text-decoration: none;
  margin: 0 0 1.5rem;
}
.recipes-used-shortcut:hover {
  text-decoration: underline;
}
a.button, button, label.button {
  display: inline-block;
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 0.75rem 1.5rem;
  border-radius: 8px;
  font-size: 1rem;
  font-family: inherit;
  text-decoration: none;
  cursor: pointer;
  text-align: center;
}
a.button:hover, button:hover, label.button:hover {
  background: var(--accent-hover);
}
button:disabled, label.button[aria-disabled="true"] {
  background: var(--muted);
  cursor: default;
  pointer-events: none;
}
button.danger {
  background: var(--surface);
  color: #b3261e;
  border: 1px solid #b3261e;
}
button.danger:hover {
  background: #b3261e;
  color: #fff;
}
/* Secondary action alongside a solid .button primary (e.g. "Accept" next to
   "Accept & make active") - same outline treatment as button.danger, in the
   accent color instead of red since this isn't a destructive action. */
a.button-secondary, button.button-secondary {
  display: inline-block;
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent);
  padding: 0.75rem 1.5rem;
  border-radius: 8px;
  font-size: 1rem;
  font-family: inherit;
  text-decoration: none;
  cursor: pointer;
  text-align: center;
}
a.button-secondary:hover, button.button-secondary:hover {
  background: var(--accent);
  color: #fff;
}
.nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-bottom: 1.5rem;
  font-size: 0.9rem;
}
.nav-right {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-left: auto;
}
/* Hamburger menu (_nav.ftl) - collapses secondary nav links (Shared Lists,
   Sign out) that don't fit as top-level nav items. */
.nav-menu {
  position: relative;
}
.nav-menu-panel {
  display: none;
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(43, 33, 24, 0.15);
  padding: 0.4rem;
  min-width: 160px;
  z-index: 20;
}
.nav-menu.open .nav-menu-panel {
  display: flex;
  flex-direction: column;
}
.nav-menu-panel a,
.nav-menu-panel .nav-logout {
  margin: 0;
}
.nav-menu-panel a,
.nav-menu-panel .nav-logout button {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 0.9rem;
  text-align: left;
  background: none;
  border: none;
  font-family: inherit;
  cursor: pointer;
}
.nav-menu-panel a:hover,
.nav-menu-panel .nav-logout button:hover {
  background: var(--bg);
  color: var(--text);
}
.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
}
.icon-button:hover {
  background: var(--accent-hover);
}
.icon-button:disabled,
.fab-actions.fab-disabled .icon-button {
  background: #9a9a9a;
  cursor: not-allowed;
  pointer-events: none;
}
.icon-button svg {
  width: 1.15rem;
  height: 1.15rem;
  fill: currentColor;
}
.fab-actions {
  position: fixed;
  right: calc(1.25rem + env(safe-area-inset-right));
  bottom: calc(1.25rem + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  z-index: 10;
}
.fab-actions .icon-button {
  width: 3.25rem;
  height: 3.25rem;
  box-shadow: 0 4px 12px rgba(43, 33, 24, 0.3);
}
.fab-actions .icon-button svg {
  width: 1.5rem;
  height: 1.5rem;
}
.icon-button.icon-button-danger {
  background: var(--surface);
  color: #b3261e;
  border: 1px solid #b3261e;
}
.icon-button.icon-button-danger:hover {
  background: #b3261e;
  color: #fff;
}
/* grocery-list.ftl's #groceryFab is just the add-item toggle - Start New
   List/Share live in .list-actions under the subtitle instead (see
   below). align-items: flex-end keeps the toggle flush against the right
   edge even once the form panel (wider than the round button) becomes
   the stack's widest child when open. Collapsed by default; only .open
   (toggled in app.js, same open/close-on-outside-click shape as
   .speed-dial below) reveals the form, which grows the stack upward -
   the container is anchored by `bottom`, not `top`. No close-on-submit
   though - typing and submitting stay inside the box, so it's still
   possible to add a whole batch of items in a row without it closing
   between each one. */
#groceryFab {
  align-items: flex-end;
}
/* Previously only `right` was set here, leaving `width` to shrink-to-fit the
   form's content. That content (input + submit button) settles around
   ~270-290px regardless of screen size, comfortably under the old
   `max-width: 300px` ceiling on any normal phone width - so on a
   genuinely narrow available width (a resized Chromebook browser window, an
   installed PWA/WebView running in a split-screen or otherwise narrower-
   than-usual window - the two platforms this bug kept reproducing on) the
   panel doesn't shrink at all, it just slides its whole shrink-to-fit box
   left of the true left edge, since nothing was anchoring that side. The
   JS clamp in app.js (clampGroceryFabIntoView) was meant to catch exactly
   this after the fact, but that still depends on the browser's own
   viewport-measurement APIs (getBoundingClientRect/visualViewport) agreeing
   with where things are actually rendered on the affected platform - which
   is precisely where two prior fixes (100vw math, then innerWidth, then
   visualViewport) kept coming up "no observable difference." Setting `left`
   once open removes that dependency: with both `left` and `right` non-auto
   and `width: auto`, the browser solves for width directly from the real
   containing-block edges (the same scrollbar-excluded box `clientWidth`
   reports) - not the shrink-to-fit content size - so the panel's width is
   now bounded by construction, at layout time, on every resize, without
   relying on any JS measurement being correct. */
#groceryFab.open {
  left: 1rem;
}
#groceryFab .add-item-form {
  display: none;
  margin-bottom: 0;
  flex-wrap: nowrap;
  /* min(300px, 100%): the 100% now resolves against #groceryFab's own
     width, which is real/determinate once #groceryFab.open sets `left`
     (see above) - so this caps the panel at 300px on a normal-width
     screen, or shrinks it further only on a genuinely narrow one, using
     the browser's own box-model math rather than a vw-based guess (100vw
     is well-known to include a classic, non-overlay scrollbar's width in
     many browsers, which this panel's `right`-anchor does not - the
     mismatch was the very first thing found bugging this panel). box-sizing:
     border-box makes that 100% (and the 300px) apply to the border box, so
     the panel's own padding/border can't push it past the cap the way they
     would under the default content-box (where padding/border are added on
     top of a content-box width, not counted against it). */
  box-sizing: border-box;
  max-width: min(300px, 100%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.6rem;
  box-shadow: 0 4px 12px rgba(43, 33, 24, 0.3);
}
#groceryFab.open .add-item-form {
  display: flex;
}
.add-item-fab-toggle svg {
  transition: transform 0.15s ease;
}
#groceryFab.open .add-item-fab-toggle svg {
  transform: rotate(45deg);
}
/* grocery-list.ftl's per-list actions (Start New List/Share), sitting
   under the subtitle rather than in the FAB or the hamburger menu - see
   the comment on .list-actions in grocery-list.ftl. Sized to match
   .icon-button's 2.25rem height rather than the 2.75rem (44px) a brand
   new control would otherwise get, since these read as secondary next to
   the page's main actions (checking off items, the add-item FAB). */
.list-actions {
  display: flex;
  gap: 0.625rem;
  margin: 0 0 1.5rem;
}
.pill-button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  width: auto;
  flex-shrink: 0;
  height: 2.25rem;
  box-sizing: border-box;
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 0 0.875rem 0 0.75rem;
  font-size: 0.8rem;
  font-weight: 500;
  font-family: inherit;
  white-space: nowrap;
  cursor: pointer;
}
.pill-button:hover {
  background: var(--accent);
  color: #fff;
}
.pill-button svg {
  width: 0.9rem;
  height: 0.9rem;
  fill: currentColor;
  flex-shrink: 0;
}
.speed-dial .fab-mini {
  display: none;
}
.speed-dial.open .fab-mini {
  display: block;
}
.fab-toggle svg {
  transition: transform 0.15s ease;
}
.speed-dial.open .fab-toggle svg {
  transform: rotate(45deg);
}
/* recipe.ftl's speed-dial (#listFab) is position: fixed, sized to whatever
   fab-minis the page renders - it has no idea where the document's own
   content actually ends, so on a recipe short enough that its content
   doesn't fill the viewport, the dial can cover the last thing on the page.
   Sized to clear only the COLLAPSED dial (one 3.25rem toggle + its 1.25rem
   offset from the viewport bottom = 4.5rem, rounded up with a buffer) - not
   the fully-expanded stack. The collapsed state is what sits over content
   at rest, essentially permanently, which is the actual reported problem;
   the expanded state only briefly overlaps the last row while someone is
   already mid-tap on the dial itself, and collapses again the moment they
   pick an action or tap away - reserving ~20rem of permanently empty page
   just to avoid that transient, self-resolving overlap was worse than the
   overlap itself. */
.recipe-body .container {
  padding-bottom: 5.5rem;
}
/* recipe.ftl's "Link a recipe" modal (#linkRecipeDialog), opened via
   showModal() from the speed-dial's fab-mini (app.js) - see the dialog's
   own doc comment in recipe.ftl for why this is a modal instead of living
   inline on the page. */
#linkRecipeDialog {
  border: none;
  border-radius: 10px;
  padding: 1.25rem;
  width: calc(100% - 2.5rem);
  max-width: 400px;
  background: var(--surface);
  color: var(--text);
}
#linkRecipeDialog::backdrop {
  background: rgba(43, 33, 24, 0.45);
}
#linkRecipeDialog h3 {
  margin-top: 0;
}
#linkRecipeDialog form + form {
  margin-top: 0.75rem;
}
.wordmark {
  font-family: 'Fredoka', sans-serif;
  font-weight: 400;
  color: var(--text);
  text-transform: lowercase;
  letter-spacing: -0.01em;
  text-decoration: none;
  line-height: 1;
}
.wordmark .flame-i {
  position: relative;
  display: inline-block;
}
.wordmark .flame-i::after {
  content: "\1F525";
  position: absolute;
  top: -0.32em;
  left: -0.01em;
  font-size: 0.4em;
  filter: brightness(0);
}
.nav .wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.5rem;
  color: var(--text);
  margin-right: auto;
}
.nav-logo {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 6px;
  flex-shrink: 0;
}
h1.wordmark {
  font-size: 2.5rem;
  margin: 0 0 0.25rem;
}
.auth-card h1.wordmark {
  font-size: 2.5rem;
}
.nav-logout {
  margin: 0;
}
.nav-logout button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--muted);
  cursor: pointer;
}
.nav-logout button:hover {
  color: var(--text);
}
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.25rem;
  margin-bottom: 0.75rem;
}
/* share-list.ftl's Accept / Accept & make active choice. */
.share-actions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 1rem;
}
.share-actions button {
  width: 100%;
}
/* shared-lists.ftl picker rows - a whole clickable card, same pattern as
   home.ftl's a.recipe-link, rather than separate View/Make active buttons. */
a.list-entry {
  display: block;
  color: var(--text);
  text-decoration: none;
  transition: border-color 0.15s ease;
}
a.list-entry:hover {
  border-color: var(--accent);
}
.list-entry-meta {
  color: var(--muted);
  font-size: 0.85rem;
  margin-top: 0.15rem;
}
.list-entry-preview {
  color: var(--text);
  font-size: 0.85rem;
  margin-top: 0.25rem;
}
/* archived-lists.ftl - the card wraps a list-entry link plus a delete
   button, unlike shared-lists.ftl's plain whole-card link (a.list-entry
   above) - an <a> can't contain another interactive form/button, so the
   link and the delete form sit side by side instead, same .recipe-header
   flex-row pattern recipe.ftl uses for its own title+delete layout. */
.list-entry-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  transition: border-color 0.15s ease;
}
.list-entry-row:hover {
  border-color: var(--accent);
}
.list-entry-row .list-entry {
  flex: 1;
  min-width: 0;
}
.list-entry-row form {
  flex-shrink: 0;
}
/* Read-only grocery-list.ftl (interactive=false) - a plain checkmark in
   place of the interactive checkbox, since there's nothing to toggle. */
.item-check-static {
  width: 1.15rem;
  flex-shrink: 0;
  text-align: center;
  color: var(--accent);
}
a.recipe-link {
  display: block;
  font-family: 'Fredoka', sans-serif;
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
  transition: border-color 0.15s ease;
}
a.recipe-link:hover {
  border-color: var(--accent);
}
.tag {
  display: inline-block;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.75rem;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  margin-left: 0.5rem;
  text-transform: capitalize;
}
.filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.25rem;
}
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  text-decoration: none;
  font-size: 0.85rem;
  padding: 0.4rem 0.8rem;
  border-radius: 999px;
  text-transform: capitalize;
}
.filter-chip:hover {
  border-color: var(--accent);
}
.filter-chip-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.filter-chip-active .filter-count {
  color: rgba(255, 255, 255, 0.8);
}
.filter-count {
  color: var(--muted);
  font-size: 0.8rem;
}
.banner {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.25rem;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  font-size: 0.9rem;
}
.banner-processing {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}
.banner-error {
  background: #fbe9e7;
  border: 1px solid #f0b8ae;
  color: #8a3a2b;
  justify-content: space-between;
}
.banner-success {
  background: #e8f5e9;
  border: 1px solid #a5d6a7;
  color: #2e7d32;
}
.banner-dismiss {
  background: transparent;
  border: 1px solid currentColor;
  color: inherit;
  padding: 0.25rem 0.65rem;
  border-radius: 6px;
  font-size: 0.8rem;
}
.banner-dismiss:hover {
  background: rgba(0, 0, 0, 0.05);
}
.staging-area {
  margin-top: 1.25rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}
.staged-photos {
  /* Not a flex container itself - its children (.staged-photo) become
     direct items of .staging-area's flex row, so thumbnails and the
     action buttons share one wrapping row instead of stacking as two. */
  display: contents;
}
.staged-photo {
  position: relative;
  width: 2.25rem;
  height: 2.25rem;
}
.staged-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
}
.recipe-url-input {
  flex: 1 1 200px;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem 0.75rem;
  font-size: 1rem;
  font-family: inherit;
  background: var(--surface);
  color: var(--text);
}
.staged-photo-remove {
  position: absolute;
  top: -0.3rem;
  right: -0.3rem;
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 50%;
  border: none;
  background: #b3261e;
  color: #fff;
  font-size: 0.6rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.staging-actions {
  display: flex;
  gap: 0.5rem;
  margin-left: auto;
}
.spinner {
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  flex-shrink: 0;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
.empty-state {
  color: var(--muted);
  text-align: center;
  padding: 2.5rem 1rem;
  border: 1px dashed var(--border);
  border-radius: 10px;
  margin-top: 1.5rem;
}
@media (max-width: 480px) {
  body { padding: 1.5rem 1rem; }
  h1 { font-size: 1.5rem; }
  a.button, button, label.button, a.button-secondary, button.button-secondary {
    display: block;
    width: 100%;
  }
  .nav {
    gap: 0.85rem;
  }
  .nav .wordmark {
    gap: 0.35rem;
    font-size: 1.3rem;
  }
  .nav-logo {
    width: 1.4rem;
    height: 1.4rem;
  }
}
.recipe-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}
.recipe-header form { flex-shrink: 0; }
#recipe h1 { margin-top: 0; }
#recipe h3 { font-family: 'Fredoka', sans-serif; font-weight: 400; }
#recipe ul, #recipe ol { padding-left: 1.25rem; margin: 0.5rem 0; }
#status { margin: 1rem 0; color: var(--muted); }
#cameraInput, #galleryInput { display: none; }
.section-heading {
  color: var(--muted);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 1.5rem 0 0.5rem;
}
.section-heading:first-of-type { margin-top: 0; }
.grocery-item { padding: 0; position: relative; overflow: hidden; }
.grocery-item.removing { display: none; }
.grocery-item-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  background: var(--surface);
  position: relative;
  z-index: 1;
  touch-action: pan-y;
}
.item-check { display: flex; align-items: center; padding: 0.35rem; margin: -0.35rem; cursor: pointer; }
.grocery-item input[type=checkbox] { width: 1.15rem; height: 1.15rem; flex-shrink: 0; }
.item-text { cursor: pointer; }
.checked-text { text-decoration: line-through; color: var(--muted); }
.item-delete-btn {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 84px;
  background: #b3261e;
  color: #fff;
  border: none;
  font-size: 0.9rem;
  cursor: pointer;
}
.item-edit-row { display: flex; flex: 1; min-width: 0; }
.item-edit-row input {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.4rem 0.5rem;
  font-size: 0.95rem;
  font-family: inherit;
  background: var(--surface);
  color: var(--text);
  min-width: 0;
  width: 100%;
}
.undo-toast {
  position: fixed;
  left: 50%;
  bottom: calc(1.5rem + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  background: #323232;
  color: #fff;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 1rem;
  font-size: 0.9rem;
  z-index: 100;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.undo-toast button {
  background: transparent;
  border: none;
  color: #8ab4f8;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}
.add-item-form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}
/* select added alongside input for recipe.ftl's "link a recipe" picker
   (add-item-form is otherwise text-input-only elsewhere it's used) - same
   look as the input rather than each browser's unstyled default. */
.add-item-form input,
.add-item-form select {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.75rem;
  font-size: 1rem;
  font-family: inherit;
  background: var(--surface);
  color: var(--text);
}
/* min-width: 0 overrides the flex item default of min-width: auto (which
   resolves to the input's own content-based intrinsic width) - without it,
   once the panel above is genuinely bounded to less than ~270px on a
   narrow screen, the input would refuse to shrink below that intrinsic
   width and poke out past the panel's own right edge instead. */
.add-item-form .name-input { flex: 1 1 200px; min-width: 0; }
body.auth-body {
  padding: 0;
}
.auth-page {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  position: relative;
  overflow: hidden;
}
.auth-card {
  position: relative;
  z-index: 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 8px 30px rgba(43, 33, 24, 0.08);
  padding: 2.5rem;
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.auth-icon {
  width: 72px;
  height: 72px;
  margin-bottom: 1rem;
  border-radius: 16px;
}
.auth-card h1 { margin: 0 0 0.25rem; }
.auth-card .subtitle { margin: 0 0 2rem; }
.auth-session {
  margin: 0 0 2rem;
  color: var(--muted);
  font-size: 0.9rem;
}
.google-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  width: 100%;
  background: #fff;
  color: #3c4043;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.75rem 1.5rem;
  font-size: 1rem;
  font-family: inherit;
  text-decoration: none;
  cursor: pointer;
}
.google-button:hover {
  background: #f7f7f7;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.auth-card .button { width: 100%; }
.auth-signout {
  margin-top: 0.5rem;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--muted);
  text-decoration: underline;
  cursor: pointer;
}
.auth-signout:hover { color: var(--text); }

/* welcome.ftl - shown instead of the auth-icon/wordmark when the visitor
   arrived via a shared recipe link (see SHARE_RECIPE_PATH_REGEX in Auth.kt) -
   the recipe itself is the hero here, not the app's own branding. */
.by-line {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.9rem;
}
.recipe-chip {
  width: 100%;
  display: flex;
  gap: 0.75rem;
  align-items: center;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.6rem;
  margin: 0 0 1.5rem;
  text-align: left;
}
.recipe-chip .thumb {
  width: 46px;
  height: 46px;
  flex-shrink: 0;
}
.recipe-chip .thumb svg { width: 100%; height: 100%; display: block; }
.recipe-chip .meta { min-width: 0; }
.recipe-chip .meta .name {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.recipe-chip .meta .sub {
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 0.15rem;
}
.fine-link {
  margin-top: 0.9rem;
  font-size: 0.8rem;
  color: var(--muted);
  text-decoration: underline;
}
.fine-link:hover { color: var(--text); }

/* welcome.ftl - separates the Google button from the email-magic-link form
   beneath it (a second, independent sign-in method - see CLAUDE.md's Auth
   section). ::before/::after rules, not a background image, so it adapts to
   .auth-card's width without a separate asset. */
.auth-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  margin: 1.1rem 0;
  color: var(--muted);
  font-size: 0.8rem;
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}
.email-signin-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  width: 100%;
}
.email-signin-form input {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.75rem;
  font-size: 1rem;
  font-family: inherit;
  background: var(--surface);
  color: var(--text);
  width: 100%;
  box-sizing: border-box;
}
/* .banner is normally only used inline on home/recipe/list pages with more
   surrounding context (a dismiss button, etc.) - reused as-is here rather
   than a new welcome-page-specific style, just centered to match the rest
   of .auth-card's text-align: center. */
.auth-card .banner {
  width: 100%;
  box-sizing: border-box;
  text-align: center;
  justify-content: center;
}

@media (max-width: 480px) {
  .auth-card { padding: 2rem 1.5rem; }
}
/* admin.ftl - a wider container than the default .container (640px), since
   the users table has enough columns to feel cramped at that width. */
.container-wide {
  max-width: 900px;
}
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}
.stat-card {
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
}
.stat-value {
  font-family: 'Fredoka', sans-serif;
  font-size: 1.75rem;
  line-height: 1.2;
}
.stat-label {
  color: var(--muted);
  font-size: 0.85rem;
}
.stat-sublabel {
  color: var(--muted);
  font-size: 0.75rem;
  margin-top: 0.15rem;
}
/* Wide content (the users table) must scroll inside its own container
   rather than the page itself going horizontally scrollable. */
.admin-table-wrap {
  overflow-x: auto;
}
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.admin-table th,
.admin-table td {
  text-align: left;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.admin-table th {
  color: var(--muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
}

/* splash.ftl - the public marketing page at "/". Scoped under .splash-body
   throughout since it uses its own wider layout (main, not .container) and
   doesn't want the page-wide 2.5rem/1rem body padding every other page gets. */
.splash-body {
  padding: 0;
}
.splash-topbar {
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.splash-topbar-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.5rem;
}
.splash-topbar-inner .wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.4rem;
}
.splash-topbar-cta {
  padding: 0.5rem 1.1rem;
  font-size: 0.9rem;
}
.splash-body main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.5rem;
}
.splash-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 3rem;
  padding: 4rem 0 3rem;
}
.splash-hero-copy {
  flex: 1 1 380px;
}
.splash-hero h1 {
  font-family: 'Fredoka', sans-serif;
  font-weight: 400;
  font-size: 2.75rem;
  line-height: 1.15;
  margin: 0 0 1rem;
}
.splash-hero-subtitle {
  color: var(--muted);
  font-size: 1.1rem;
  line-height: 1.6;
  margin: 0 0 1.75rem;
  max-width: 32rem;
}
.splash-cta-row {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}
.splash-hero-visual {
  flex: 1 1 380px;
  display: flex;
  align-items: center;
  gap: 1rem;
}
.splash-recipe-stack {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.splash-mini-card {
  padding: 0.75rem 1rem;
  font-size: 0.9rem;
  pointer-events: none;
  margin-bottom: 0;
}
.splash-hero-arrow {
  font-size: 1.75rem;
  color: var(--accent);
  flex-shrink: 0;
}
.splash-grocery-mockup {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  flex: 1;
  min-width: 220px;
}
.splash-grocery-mockup .card.grocery-item {
  margin-bottom: 0.5rem;
  pointer-events: none;
}
.splash-grocery-mockup .grocery-item-row {
  padding: 0.5rem 0.85rem;
}
.splash-section {
  padding: 3rem 0;
  border-top: 1px solid var(--border);
}
.splash-section h2 {
  font-family: 'Fredoka', sans-serif;
  font-weight: 400;
  font-size: 1.9rem;
  margin: 0 0 1rem;
}
.splash-section p {
  color: var(--muted);
  font-size: 1.05rem;
  line-height: 1.6;
  max-width: 42rem;
  margin: 0 0 0.75rem;
}
.splash-emphasis {
  color: var(--text) !important;
  font-weight: 500;
}
.splash-feature-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 2.5rem;
  align-items: flex-start;
  margin-top: 1.5rem;
}
.splash-feature-points {
  flex: 1 1 320px;
  margin: 0;
  padding-left: 1.25rem;
  color: var(--text);
  line-height: 2;
}
.splash-grocery-mockup-large {
  flex: 1 1 320px;
  position: relative;
  padding-bottom: 3.5rem;
}
/* Mimics grocery-list.ftl's real #groceryFab: a floating round "+" toggle
   anchored to the list's bottom-right corner, not an inline input row -
   the real add-item field only appears once that FAB is tapped. */
.splash-add-item-btn {
  position: absolute;
  bottom: 0.85rem;
  right: 0.85rem;
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  box-shadow: 0 2px 6px rgba(43, 33, 24, 0.2);
}
.splash-trip-card {
  max-width: 26rem;
  margin-top: 1.5rem;
}
.splash-trip-label {
  font-family: 'Fredoka', sans-serif;
  margin-bottom: 0.75rem;
}
.splash-trip-stats {
  display: flex;
  gap: 2rem;
}
.splash-trip-stats div {
  display: flex;
  flex-direction: column;
}
.splash-trip-stats strong {
  font-family: 'Fredoka', sans-serif;
  font-size: 1.5rem;
  color: var(--accent);
}
.splash-trip-stats span {
  color: var(--muted);
  font-size: 0.85rem;
}
.splash-steps-heading {
  text-align: center;
}
.splash-steps-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  justify-content: center;
  margin-top: 1.5rem;
}
.splash-step-card {
  flex: 1 1 220px;
  max-width: 300px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1.5rem;
  text-align: center;
}
.splash-step-number {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 0.75rem;
  font-family: 'Fredoka', sans-serif;
}
.splash-step-card h3 {
  font-family: 'Fredoka', sans-serif;
  font-weight: 400;
  margin: 0 0 0.4rem;
}
.splash-step-card p {
  margin: 0;
  font-size: 0.95rem;
}
.splash-pricing-grid {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-top: 1.5rem;
}
.splash-pricing-card {
  flex: 1 1 260px;
  max-width: 320px;
}
.splash-pricing-card h3 {
  font-family: 'Fredoka', sans-serif;
  font-weight: 400;
  margin: 0 0 1rem;
}
.splash-pricing-list {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
  color: var(--text);
  line-height: 2;
}
.splash-pricing-list li::before {
  content: "\2713\0020";
  color: var(--accent);
}
.splash-pricing-cta {
  width: 100%;
}
.splash-closing {
  text-align: center;
  padding: 4rem 0;
}
.splash-closing h2 {
  max-width: 36rem;
  margin: 0 auto 1.5rem;
}
.splash-footer {
  text-align: center;
  color: var(--muted);
  padding: 2rem 1rem 3rem;
  font-family: 'Fredoka', sans-serif;
}
@media (max-width: 640px) {
  .splash-hero {
    padding: 2.5rem 0 2rem;
  }
  .splash-hero h1 {
    font-size: 2.1rem;
  }
  .splash-hero-visual {
    flex-direction: column;
  }
  .splash-hero-arrow {
    transform: rotate(90deg);
  }
}
