/* Shell — the chrome shared by every WordPress surface. HAND-WRITTEN.
 *
 * Not generated: tokens.css, community.css and store.css are. This file is
 * layout, and layout is not derivable from tokens.
 *
 * IT MUST LOAD ON BOTH RENDER PATHS. The portal never calls wp_head(), so
 * anything enqueued normally is invisible there — that is exactly how the
 * first version of the tab bar shipped: styled in the store, raw SVGs and
 * blue underlined links in the community (observed 2026-08-01). functions.php
 * therefore enqueues this for ordinary pages AND injects it, with tokens.css
 * ahead of it, through `fluent_community/portal_data_vars`.
 *
 * Because tokens.css rides along, `var(--color-*)` resolves on both paths.
 * community.css cannot do that — it is written with literal values for the
 * reason recorded in build.mjs — but this file can.
 */

/* ---------------------------------------------------------------
   Mobile tab bar — ADR 0020
   ---------------------------------------------------------------
   One bar across every WordPress surface, replacing FluentCommunity's
   own (emptied via its `mobile_menu` filter in functions.php). Theirs is
   drawn by the portal's Vue app and so exists only inside the portal; a
   tab bar that appears in the community and vanishes in the store is
   worse than no tab bar.

   Phone-only, matching the bar it replaces: above 1024px the header
   carries the navigation and a fixed bottom bar is just lost height.
   --------------------------------------------------------------- */
.tv-tabbar {
  position: fixed;
  inset: auto 0 0 0;
  /* Above the portal's own layered chrome, which climbs into the 20s. */
  z-index: 100;
  background: var(--color-surface, #f7f5f1);
  border-top: 1px solid var(--color-line-subtle, rgb(214 211 209 / 0.7));
  /* Home-indicator and gesture-bar clearance on iOS. */
  padding-bottom: env(safe-area-inset-bottom, 0);
}

.tv-tabbar__list {
  display: flex;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tv-tabbar__item {
  flex: 1 1 0;
  /* The portal's stylesheet gives list items markers and spacing. */
  margin: 0;
}

.tv-tabbar__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  /* 44px minimum touch target, before the label is counted. */
  min-height: 44px;
  padding: 0.5rem 0.25rem;
  color: var(--color-ink-secondary, #44403c);
  font-size: 0.6875rem;
  line-height: 1.2;
  text-decoration: none;
}

.tv-tabbar__link:hover,
.tv-tabbar__link:focus-visible {
  color: var(--color-ink, #1c1917);
  text-decoration: none;
}

/* The icons come from FluentCommunity's menu data, and its own SVGs carry a
   viewBox with no width or height — unconstrained, one filled the screen.
   Size them here rather than trusting the source. */
.tv-tabbar__icon {
  display: block;
  width: 20px;
  height: 20px;
}

.tv-tabbar__icon svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: none;
}

/* Their `spaces` icon paints with fill rather than stroke. */
.tv-tabbar__icon svg [fill]:not([fill="none"]) {
  fill: currentColor;
}

/* Keep the end of the page clear of the bar.
 *
 * Two rules, because the two render paths scroll differently. On ordinary
 * WordPress pages the document scrolls, so padding the body is enough. The
 * portal is an SPA that scrolls an inner container, so body padding does
 * nothing there and its last rows sit under the bar — seen on the community
 * leaderboard, 2026-08-01, where the bottom entries were unreachable.
 *
 * The portal selectors are deliberately several and deliberately defensive:
 * they are its layout containers as of 2.7.5, and padding one that no longer
 * exists costs nothing, while missing one costs unreachable content.
 */
body:has(.tv-tabbar) {
  padding-bottom: 4.5rem;
}

@media (max-width: 1023px) {
  .fhr_wrap .fhr_content,
  .fhr_wrap #fluent_comminity_body,
  .fhr_wrap .feed_layout,
  .fhr_wrap .fcom_main_content {
    padding-bottom: 4.5rem;
  }
}

/* FluentCart's floating cart button is fixed to the bottom-right and lands
   on top of the last tab — the Account tab, observed on staging. Lift it
   above the bar rather than moving the bar, which would leave it floating
   over content instead. */
body:has(.tv-tabbar) .fct-cart-drawer-open-btn {
  bottom: 5.5rem;
}

@media (min-width: 1024px) {
  .tv-tabbar {
    display: none;
  }

  body:has(.tv-tabbar) {
    padding-bottom: 0;
  }

  body:has(.tv-tabbar) .fct-cart-drawer-open-btn {
    bottom: auto;
  }
}

/* ---------------------------------------------------------------
   The platform shell — ADR 0021
   ---------------------------------------------------------------
   Ours, not borrowed. One top bar listing the same five destinations
   everywhere, a left sidebar belonging to the section, and action
   slots whose contents change with context.

   The community keeps its own chrome and is not styled here — it is a
   different room on purpose, and that is the decision, not a gap.
   --------------------------------------------------------------- */
.tv-appbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--color-bg, #fffdfa);
  border-bottom: 1px solid var(--color-line-subtle, rgb(214 211 209 / 0.7));
}

.tv-appbar__bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.625rem var(--spacing-gutter, 1.25rem);
}

.tv-appbar__brand {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  text-decoration: none;
  color: var(--color-ink, #1c1917);
  font-weight: 700;
}

.tv-appbar__logo {
  display: block;
  width: auto;
  height: 34px;
}

/* The destination list scrolls rather than wraps on narrow screens: a top bar
   that becomes two rows moves the content down and reads as a broken page. */
.tv-appbar__nav {
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.tv-appbar__nav::-webkit-scrollbar {
  display: none;
}

.tv-appbar__list {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tv-appbar__link {
  display: inline-block;
  padding: 0.4rem 0.7rem;
  border-radius: 0.5rem;
  color: var(--color-ink-secondary, #44403c);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.tv-appbar__link:hover,
.tv-appbar__link:focus-visible {
  background: var(--color-surface, #f7f5f1);
  color: var(--color-ink, #1c1917);
}

.tv-appbar__link.is-current {
  background: var(--color-surface-alt, #ebe7e0);
  color: var(--color-ink, #1c1917);
}

/* Not yet built. Shown so the shape of the platform is legible, muted and
   unclickable so it never promises a page that would 404. */
.tv-appbar__link.is-soon {
  color: var(--color-ink-muted, #78716c);
  cursor: default;
}

.tv-appbar__soon {
  margin-left: 0.375rem;
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--color-line-subtle, rgb(214 211 209 / 0.7));
  border-radius: 999px;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tv-appbar__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
}

/* --- Action slots: the shell owns the furniture, sections fill it --- */
.tv-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  min-width: 38px;
  height: 38px;
  border-radius: 0.5rem;
  color: var(--color-ink-secondary, #44403c);
  text-decoration: none;
}

.tv-action:hover,
.tv-action:focus-visible {
  background: var(--color-surface, #f7f5f1);
  color: var(--color-ink, #1c1917);
}

.tv-action svg {
  display: block;
  width: 20px;
  height: 20px;
}

.tv-action__count {
  position: absolute;
  top: -2px;
  right: -4px;
  min-width: 1.05rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: var(--color-accent, #fbbf24);
  color: var(--color-on-accent, #09090b);
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1.05rem;
  text-align: center;
}

/* FluentCart empties this element at zero — the same mechanism that keeps the
   count live — so an empty badge means an empty cart and shows nothing. */
.tv-action__count:empty {
  display: none;
}

.tv-action--search {
  min-width: 0;
  height: auto;
}

.tv-action__input {
  width: 12rem;
  max-width: 34vw;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--color-line-subtle, rgb(214 211 209 / 0.7));
  border-radius: 0.5rem;
  background: var(--color-bg, #fffdfa);
  color: var(--color-ink, #1c1917);
  font: inherit;
  font-size: 0.875rem;
}

/* The search field is the first thing to go when space is tight — the cart
   has to survive, a search box can move into the page. */
@media (max-width: 767px) {
  .tv-action--search {
    display: none;
  }
}

.tv-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- The body: contextual sidebar beside the content --- */
.tv-shell {
  display: flex;
  align-items: flex-start;
  gap: 0;
}

.tv-sidebar {
  flex: 0 0 15rem;
  align-self: stretch;
  min-height: calc(100vh - 4rem);
  padding: 1.25rem 0.75rem;
  border-right: 1px solid var(--color-line-subtle, rgb(214 211 209 / 0.7));
}

/* Phones get the tab bar instead — a 15rem rail on a 375px screen is most of
   the screen. */
@media (max-width: 1023px) {
  .tv-sidebar {
    display: none;
  }
}

.tv-sidebar__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.tv-sidebar__heading {
  margin: 1.25rem 0 0.375rem;
  padding: 0 0.6rem;
  color: var(--color-ink-muted, #78716c);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.tv-sidebar__link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.6rem;
  border-radius: 0.5rem;
  color: var(--color-ink-secondary, #44403c);
  font-size: 0.9375rem;
  text-decoration: none;
}

.tv-sidebar__link:hover,
.tv-sidebar__link:focus-visible {
  background: var(--color-surface, #f7f5f1);
  color: var(--color-ink, #1c1917);
}

.tv-sidebar__link.is-current {
  background: var(--color-surface-alt, #ebe7e0);
  color: var(--color-ink, #1c1917);
  font-weight: 600;
}

.tv-sidebar__icon svg {
  display: block;
  width: 20px;
  height: 20px;
}

.tv-shell__content {
  flex: 1 1 auto;
  min-width: 0;
  /* No padding here: the title strip spans the column edge to edge, exactly
     as the community's does, and .tv-page supplies the content inset. */
  padding: 0;
}

/* --- Title strip, then content: the community's two-part page shape --- */
.tv-pagehead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.875rem var(--spacing-gutter, 1.25rem);
  border-bottom: 1px solid var(--color-line-subtle, rgb(214 211 209 / 0.7));
}

.tv-pagehead__title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.tv-page {
  padding: 1.25rem var(--spacing-gutter, 1.25rem);
}

@media (min-width: 1024px) {
  .tv-pagehead {
    padding: 1rem 2rem;
  }

  .tv-page {
    padding: 1.5rem 2rem;
  }
}

/* FluentCart's floating cart button is redundant now that the cart lives in
   the action slots, and it covered the last tab on phones. */
.tv-shell-page .fct-cart-drawer-open-btn {
  display: none;
}

.tv-tabbar__link.is-current {
  color: var(--color-ink, #1c1917);
  font-weight: 600;
}

/* ---------------------------------------------------------------
   Softening the page load between sections
   ---------------------------------------------------------------
   The community is a single-page app; everything else is
   server-rendered, so crossing between them is a real navigation and
   will stay one while they are two applications (ADR 0021).

   Cross-document view transitions close the part of that gap which
   does not need a rebuild: the browser fades between documents
   instead of flashing white. Progressive — unsupported browsers
   navigate exactly as before.
   --------------------------------------------------------------- */
@view-transition {
  navigation: auto;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* FluentCart's literal colours — the `.bg-white` catch and the Element
   Plus variable remap that used to live here — moved to store-skin.css
   when two catches grew into a full skin. One home for all of them. */

/* `.tv-prose` caps text at a readable measure, which is right for an article
   and wrong for a store dashboard — the customer profile is a two-column
   layout, not prose. Inside the shell the section decides its own width. */
.tv-shell-page .tv-prose {
  max-width: none;
}

/* The checkout rendered inside the portal's own modal — ADR 0024.
 *
 * It keeps `.tv-shell-page` so store-skin.css still applies (all 455 of its
 * rules are scoped to that class, and without it the frame falls back to
 * FluentCart's compiled-in light palette while our tokens follow the system
 * into dark — light panels, light text, nothing readable).
 *
 * What it must not keep is chrome. The portal is already supplying the
 * navigation around the frame, and a floating cart button inside a checkout
 * is a second way to start what the member is already finishing. */
.tv-framed-checkout .tv-tabbar,
.tv-framed-checkout .fct-cart-drawer-open-btn {
  display: none;
}

/* A page rendered inside the portal's modal — ADR 0024.
 *
 * No chrome, so no space reserved for chrome either. The frame is the
 * viewport here: the modal supplies the padding around it, and a second
 * gutter inside would waste the width a checkout form needs most on a phone. */
.tv-framed__content {
  display: block;
  width: 100%;
  min-height: 100vh;
  margin: 0;
  padding: 0;
}

/* Inside a frame, whatever the URL said -----------------------------------
 *
 * `.tv-framed` is set in the head from `window.self !== window.top`, which no
 * redirect can strip. The query parameter cannot promise the same: a stalled
 * order's payment link redirects to the checkout page and drops it, and the
 * document that finally rendered drew the full header and tab bar inside the
 * modal.
 *
 * One rule for every framed document. Nothing here is per-modal, and a modal
 * nobody has built yet is already covered. */
.tv-framed .tv-appbar,
.tv-framed .tv-header,
.tv-framed .tv-tabbar,
.tv-framed .tv-sidebar,
.tv-framed .fct-cart-drawer-open-btn {
  display: none !important;
}

/* The shell reserves space for chrome that is no longer there. */
.tv-framed .tv-shell,
.tv-framed .tv-shell__content {
  display: block;
  grid-template-columns: none;
  max-width: none;
  margin: 0;
  padding: 0;
}
