/* ============================================================
   PocketHouse — Shared Components
   Loaded once from index.html <head>, before any module CSS.

   WHY THIS FILE EXISTS
   Rules live here for one of two reasons:

   (1) MULTIPLE APPS RENDER THE SAME THING. Every module renders the same
   header cluster (icon tile + wordmark + tagline) and previously each one
   carried its own byte-identical copy of those rules — six module
   stylesheets plus five more copies baked into index.html for the
   flash-free loading headers. Eleven places to keep in sync by hand.

   (2) THE SHELL AND A MODULE BOTH RENDER THE SAME MARKUP. The flash-free
   loading placeholder in index.html renders a module's header before that
   module's stylesheet has loaded, so those rules must resolve from a
   stylesheet that is already present. Previously they were duplicated into
   shell.css under a "keep in sync with <module>.css" comment — and they
   did drift: MealPlan's nav sat a full restructure behind (one-row
   .mp-tabs vs. two-column .mp-nav-col, no .mp-tab.sm, .mp-header padding
   off by 4px), so the placeholder rendered a different layout at a
   different size and the page visibly re-laid-out on handover.

   Case (2) rules stay app-prefixed (.mp-*, .hr-*, …) because only one app
   renders them today. That is fine — the point is single-sourcing, not
   genericity. If a second app ever adopts the same nav shape, add its
   selector to the grouped rules the way the icon tiles below do.

   Defining these once means the loading-state header and the real header
   resolve to literally the same rule, so drift is impossible by
   construction rather than by discipline.

   CASCADE NOTE
   Load order is shell.css → shared-components.css → module CSS (injected
   into <head> at module init). Module CSS therefore wins ties against
   anything here. Keep module stylesheets free of duplicate copies of these
   rules, or the duplicate silently wins and this file stops being the
   source of truth. Watch selectors like `.mp-module button` (0-1-1) too:
   they outrank single-class rules here (0-1-0), so keep such resets to the
   narrowest property set possible.

   HOW THE PER-APP ACCENT WORKS
   Each module keeps its existing class name (.mp-icon-tile, .ll-icon-tile,
   …) and only declares its accent via --ph-tile-accent. The shared rule
   below consumes that. This deliberately avoids renaming classes to a
   single generic .ph-icon-tile, which would mean editing markup in six
   module JS files — a much larger blast radius for zero visual gain.
   Migrating to one class is a reasonable future cleanup, not required now.

   ADDING A NEW MODULE
   Add its selector to the three grouped selectors below and give it a
   --ph-tile-accent line. Nothing else.
   ============================================================ */

/* ── Per-app accent assignment ── */
.mp-icon-tile  { --ph-tile-accent: var(--mealplan); }
.ll-icon-tile  { --ph-tile-accent: var(--livelist); }
.cd-icon-tile  { --ph-tile-accent: var(--countdown); }
.cs-icon-tile  { --ph-tile-accent: var(--coldstore); }
.hpt-icon-tile { --ph-tile-accent: var(--homepulse); }
.hr-icon-tile  { --ph-tile-accent: var(--headroom); }

/* ── Icon tile ── */
.mp-icon-tile,
.ll-icon-tile,
.cd-icon-tile,
.cs-icon-tile,
.hpt-icon-tile,
.hr-icon-tile {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--ph-tile-accent, var(--muted));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
}

/* The diagonal highlight. Previously ColdStore and HeadRoom also carried
   opacity:.9 here while the other four did not — a real (if barely visible)
   inconsistency. Standardised on no extra opacity, since the .35 alpha in
   the gradient already controls the tint strength. */
.mp-icon-tile::after,
.ll-icon-tile::after,
.cd-icon-tile::after,
.cs-icon-tile::after,
.hpt-icon-tile::after,
.hr-icon-tile::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 50%, rgba(255, 255, 255, .35) 50%);
}

.mp-icon-tile span,
.ll-icon-tile span,
.cd-icon-tile span,
.cs-icon-tile span,
.hpt-icon-tile span,
.hr-icon-tile span {
  position: relative;
  z-index: 1;
}

/* ── Wordmark ──
   .hr-app-title is HeadRoom's real wordmark class; .hr-wordmark is what the
   loading placeholder renders. Both are listed so the two spellings can't
   drift apart typographically. (They are still two class names for one
   concept — see the HEADROOM WORDMARK note at the foot of this file.) */
.mp-wordmark,
.ll-wordmark,
.cd-wordmark,
.cs-wordmark,
.hpt-wordmark,
.hr-wordmark,
.hr-app-title {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

/* ── Tagline ── */
.mp-tagline,
.ll-tagline,
.cd-tagline,
.cs-tagline,
.hpt-tagline,
.hr-tagline {
  font-size: 12px;
  color: var(--muted);
  font-style: italic;
  margin-top: 2px;
}

/* ── Pill (toggle/tag chips: filter chips, list-selector tabs, seed tags,
   recurrence options) ──
   Consolidated from five near-duplicates (.cs-chip, .ll-list-tab,
   .ll-seed-pill, .hr-recur-pill, .mp-filter-pill) that had each drifted
   slightly: different font-sizes (12/13px), different padding, and — worst
   offender — .ll-list-tab.active used transform:scale(1.1) to show
   selection, which meant the resting and selected states were physically
   different box sizes (needing z-index to avoid clipping neighbours) and
   scaled the border/text into fractional, slightly-soft pixel values.
   This version fixes the box at 30px tall in both states — only
   background/border/text color change on selection, nothing scales or
   reflows. Line-height is pinned to 1 rather than left at `normal` so the
   height is deterministic instead of drifting with font metrics.
   NOT used for dropdown-trigger buttons (.cd-filter-dropdown-btn,
   .hpt-filter-pill) — those open a menu rather than toggle a selection
   within a row, and their content model (label + chevron, flex:1) doesn't
   fit a fixed-width chip. Kept as their own classes; only their height was
   aligned to match. */
.mp-filter-pill,
.ll-list-tab,
.ll-seed-pill,
.hr-recur-pill,
.cs-chip {
  --ph-pill-accent: var(--muted);
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  padding: 7px 14px;
  border-radius: 20px;
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  transition: background .15s, color .15s, border-color .15s;
}
.mp-filter-pill.active,
.ll-list-tab.active,
.ll-seed-pill.active,
.hr-recur-pill.active,
.cs-chip.active {
  background: var(--ph-pill-accent);
  border-color: var(--ph-pill-accent);
  color: #fff;
}
.mp-filter-pill  { --ph-pill-accent: var(--mealplan); }
.ll-list-tab     { --ph-pill-accent: var(--livelist); }
.ll-seed-pill    { --ph-pill-accent: var(--livelist); }
.hr-recur-pill   { --ph-pill-accent: var(--headroom); }
.cs-chip         { --ph-pill-accent: var(--coldstore); }

/* ── MealPlan header + nav (case 2: shell placeholder + module both render it)
   Single source of truth for .mp-topbar's contents. index.html's
   CUSTOM_MODULE_HEADERS.mealplan() and mealplan.js's mpRender() emit
   identical markup; both resolve against the rules below, so the loading
   state and the loaded module are the same size and shape by construction.
   Neither shell.css nor mealplan.css may redefine these. ── */
.mp-header {
  background: var(--surface);
  /* 18px/16px matches .hr-topbar, .ll-header-row, .hpt-header, .cd-header and
     .cs-header. MealPlan was the lone holdout at 16px/14px, which made its
     title bar 4px shorter than every other app's. */
  padding: 18px 16px 16px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 12px;
  position: sticky;
  top: 0;
  z-index: 10;
}

/* Two columns: each main tab (Calendar / Meals) sits directly above its own
   pair of subtabs, so the subtabs are always visibly owned by their section
   rather than swapping out as you switch tabs. */
.mp-navrow {
  background: var(--bg);
  padding: 12px 16px 0;
  display: flex;
  gap: 12px;
}
.mp-nav-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.mp-tab {
  padding: 10px;
  border-radius: var(--r-md);
  border: 1.5px solid var(--border);
  background: var(--surface2);
  color: var(--muted);
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all .15s;
  margin-bottom: 8px;
}
/* .sm is the variant the markup actually uses — the plain .mp-tab size is
   kept only so the class is usable standalone. Sizes here must stay clearly
   larger than .mp-subtab below or the hierarchy inverts. */
.mp-tab.sm {
  padding: 8px;
  font-size: 13px;
}
.mp-tab.active {
  background: var(--mealplan);
  border-color: var(--mealplan);
  color: #fff;
}
.mp-subtabs {
  display: flex;
  justify-content: center;
  gap: 2px;
  margin-bottom: 0;
}
.mp-subtab {
  /* Sized to content, not flex:1 — stretching each to half its column made
     all four read as one evenly-spread row of four rather than two pairs,
     each belonging to the tab above it. Content-width + centering groups
     them under their own tab, and the active underline hugs the label
     instead of spanning half the column. */
  flex: 0 1 auto;
  min-width: 0;
  padding: 6px 7px;
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--muted);
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .03em;
  cursor: pointer;
  transition: all .15s;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  white-space: nowrap;
}
.mp-subtab.active {
  color: var(--mealplan);
  border-bottom-color: var(--mealplan);
}

/* ════════════════════════════════════════════════════════════
   MODULE HEADER BARS (case 2: shell placeholder + module both render them)

   These are the canonical definitions, copied verbatim from each module's
   own stylesheet — negative bleed margins and sticky positioning included.
   shell.css previously held a second, hand-adapted copy of every one of
   these under a "keep in sync" comment.

   ONE THING DOES LEGITIMATELY DIFFER BY CONTEXT. In the real render the bar
   sits inside a padded app container (.hr-app/.ll-app/.cd-app/.cs-app,
   padding:16px) and uses a negative margin to cancel that padding and bleed
   edge-to-edge. The loading placeholder is NOT nested in that container, so
   the same negative margin would over-shoot the viewport. shell.css handles
   that with a small `.app-screen > …` override that zeroes only the top/left/
   right margin and drops sticky — deliberately NOT margin-bottom, so the
   spacing value below stays single-sourced and can't drift.
   ════════════════════════════════════════════════════════════ */

/* ── HeadRoom ── */
.hr-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 -16px 16px -16px;
  padding: 18px 16px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 10;
}
.hr-topbar-id { display: flex; align-items: center; gap: 12px; }
/* The right-hand action group (search / reconcile / budget). This rule went
   missing when HeadRoom's topbar rules moved out of headroom.css — the class
   stayed in the markup but landed in no stylesheet, so the wrapper fell back
   to display:block and the three buttons stacked vertically at the right
   edge. flex-shrink:0 so a long wordmark can never squeeze the group. */
.hr-topbar-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
  flex-shrink: 0;
}
.hr-search-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--muted);
  padding: 6px;
  border-radius: 8px;
  /* inline-flex, NOT flex. `display:flex` is block-level, so if the wrapper
     holding these buttons is ever a plain block rather than a flex row, each
     button becomes its own block and they stack vertically. Inside a real
     flex container a flex item's display is blockified anyway — inline-flex
     computes to flex — so this is identical when the wrapper is correct and
     degrades gracefully when it isn't. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  transition: background .15s, color .15s;
}
.hr-search-btn:hover { background: var(--surface2); color: var(--text); }

/* ── LiveList ── */
.ll-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  margin: -16px -16px 14px -16px;
  padding: 18px 16px 16px;
  position: sticky;
  top: 0;
  z-index: 10;
}
.ll-header-id { display: flex; align-items: center; gap: 12px; }
.ll-manage-btn {
  font-size: 13px;
  font-weight: 600;
  padding: 7px 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text2);
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
}

/* ── CountDown ── */
.cd-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  margin: -16px -16px 16px -16px;
  padding: 18px 16px 16px;
  position: sticky;
  top: 0;
  z-index: 10;
}
.cd-header-id { display: flex; align-items: center; gap: 12px; }
.cd-header-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  margin-top: 2px;
}
.cd-filter-dropdown-wrap { position: relative; }
.cd-filter-dropdown-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: var(--r-sm);
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  font-family: 'Plus Jakarta Sans', sans-serif;
}
.cd-filter-chevron {
  font-size: 10px;
  transition: transform .15s;
  display: inline-block;
}

/* ── ColdStore ── */
.cs-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  margin: -16px -16px 14px -16px;
  padding: 18px 16px 16px;
  position: sticky;
  top: 0;
  z-index: 10;
}
.cs-header-id { display: flex; align-items: center; gap: 12px; }
.cs-add-btn {
  width: 38px; height: 38px; border-radius: 50%; border: none;
  background: var(--coldstore); color: #fff; font-size: 22px; font-weight: 400;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 3px 10px rgba(58,122,140,.35); line-height: 1; flex-shrink: 0;
}

/* ── HomePulse ── (no padded app container, so no bleed margin to cancel) */
.hpt-header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface); border-bottom: 1px solid var(--border);
  padding: 18px 16px 16px;
  position: sticky; top: 0; z-index: 10;
}
.hpt-header-id { display: flex; align-items: center; gap: 12px; }
.hpt-settings-btn { background:var(--surface2); border:1.5px solid var(--border); border-radius:20px; padding:6px 14px; font-family:'Plus Jakarta Sans',sans-serif; font-size:12px; font-weight:600; color:var(--text2); cursor:pointer; }

/* ── HEADROOM WORDMARK — known inconsistency, left as-is deliberately ──
   The loading placeholder renders <div class="hr-wordmark"> with the accent
   word coloured var(--headroom) (#2A654B, sage). HeadRoom's real header
   renders <div class="hr-app-title"> whose accent span is coloured
   var(--pop) (#C0472E, rust) — see .hr-app-title .hr-wm-accent in
   headroom.css. So the second word visibly changes colour, green → rust,
   when the module finishes loading.

   Typography is now single-sourced above, so the two can't drift in SIZE.
   The colour is not resolved here because either fix is a judgement call,
   not a mechanical one:
     • Change the placeholder to var(--pop) → kills the flash, changes
       nothing about how the app actually looks.
     • Change .hr-wm-accent to var(--headroom) → kills the flash and brings
       HeadRoom in line with the design system, which says the second word
       takes the app accent (every other module does exactly that, which
       makes HeadRoom the outlier). But it changes HeadRoom's real
       appearance, which nobody asked for.
   Also unverified: whether HeadRoom's real header renders a tagline at all.
   The placeholder does; if the real one doesn't, the placeholder is taller
   and the layout will still shift. Confirming needs headroom.js. ── */
/* ============================================================
   PocketHouse — Shared Emoji Picker styles
   Appended to shared-components.css (or loaded alongside it).

   Follows the same bottom-sheet convention as .hpt-sheet / .cs-sheet:
   fixed to the bottom, max-width 480 centred, translateY(100%) when
   closed, same .3s cubic-bezier(.32,.72,0,1) easing. Kept visually
   identical on purpose — a picker that slides differently from every
   other sheet in the suite reads as a different app.

   z-index 10600 sits above ColdStore's lightbox (10500), the current
   ceiling. The picker is always opened from inside something already
   open — a settings sheet, an edit modal — so it must outrank all of
   them rather than negotiate per caller.

   Per-app accent arrives as --phep-accent, set inline by open({accent}),
   the same pattern as --ph-tile-accent in the icon-tile rules above.
   ============================================================ */

.phep-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .45);
  z-index: 10600;
  opacity: 0;
  transition: opacity .22s ease;
}
.phep-overlay.open { display: block; }
.phep-overlay.shown { opacity: 1; }

.phep-sheet {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  max-width: 480px;
  margin: 0 auto;
  background: var(--surface);
  border-radius: 20px 20px 0 0;
  z-index: 10601;
  display: flex;
  flex-direction: column;
  /* Tall enough to show several rows without covering the whole screen —
     the caller's own sheet stays partly visible behind, so the picker
     reads as a layer on top rather than a navigation away from it. */
  height: min(62vh, 520px);
  transform: translateY(100%);
  transition: transform .3s cubic-bezier(.32, .72, 0, 1);
  padding-bottom: env(safe-area-inset-bottom);
}
.phep-overlay.shown .phep-sheet { transform: translateY(0); }

.phep-handle {
  width: 36px;
  height: 4px;
  background: var(--border);
  border-radius: 2px;
  margin: 10px auto 0;
  flex-shrink: 0;
}

.phep-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 18px 10px;
  flex-shrink: 0;
}
.phep-title {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 16px;
  font-weight: 800;
  color: var(--text);
}
.phep-close {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 24px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  font-family: inherit;
}

.phep-searchrow { padding: 0 18px 10px; flex-shrink: 0; }
.phep-search {
  width: 100%;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 15px;   /* not below 16px on iOS would avoid zoom-on-focus, but
                        15px matches the suite's other inputs; the field is
                        not autofocused so the tradeoff is minor */
  padding: 10px 13px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface2);
  color: var(--text);
  outline: none;
}
.phep-search:focus { border-color: var(--phep-accent, var(--text)); }

/* Scope chips. .ph-hscroll on the element opts this strip out of the
   shell's swipe-between-apps recogniser — without it, dragging sideways
   across the chips could change apps mid-pick. */
.phep-scopes {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0 18px 10px;
  flex-shrink: 0;
}
.phep-scopes::-webkit-scrollbar { display: none; }
.phep-scope {
  flex-shrink: 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 7px 12px;
  border-radius: 20px;
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s, color .15s, border-color .15s;
}
.phep-scope.active {
  background: var(--phep-accent, var(--text));
  border-color: var(--phep-accent, var(--text));
  color: #fff;
}

.phep-results {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 2px 18px 18px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.phep-results::-webkit-scrollbar { display: none; }

.phep-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 4px;
}
.phep-item {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  line-height: 1;
  border: 1.5px solid transparent;
  border-radius: var(--r-sm);
  background: none;
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
  transition: background .12s, border-color .12s;
}
.phep-item:hover { background: var(--surface2); }
.phep-item:active { transform: scale(.92); }
.phep-item.selected {
  border-color: var(--phep-accent, var(--text));
  background: var(--surface2);
}

.phep-empty {
  text-align: center;
  padding: 40px 20px;
  color: var(--subtle);
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 14px;
}

@media (min-width: 900px) {
  .phep-sheet { max-width: 640px; }
}

/* Loading note shown while the extended emoji set downloads on first picker
   open. Deliberately a quiet inline strip rather than a spinner over the grid:
   the core emoji are already usable underneath, so this explains why more are
   about to appear rather than blocking what is already there. */
.phep-loading {
  padding: 8px 18px 10px;
  font-family: 'DM Mono', monospace;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--subtle);
  flex-shrink: 0;
}
