/* ============================================================
   MELODIC FOUNDRY — FRONT OFFICE MOTIF PRIMITIVES
   The recurring motifs from the design handoff (board 8b and
   design/HANDOFF.md "Recurring motifs"), built once and reused
   by every screen. Depends on tokens.css being loaded first.
   Page layout lives in site.css — nothing here knows about a
   specific screen.
   ============================================================ */

/* ---------- base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--sem-bg);
  color: var(--sem-text-primary);
  font-family: var(--mf-font-body);
  font-size: var(--mf-text-md);
  line-height: var(--mf-leading-body);
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--sem-link);
  text-decoration: none;
}

/* ---------- theme aliases (8a) ----------
   Dark is native; the day shift ([data-theme="light"] on <html>)
   swaps -500 hues for their ink pairs per the handoff's rule.
   These MUST stay custom properties, not attribute-scoped rules:
   app content renders inside shadow roots, where a
   `[data-theme] .fo-x` selector can't see the html attribute —
   inherited properties are the only thing that crosses over. */
:root {
  --fo-body-bright: var(--mf-lavender-200);
  --fo-stage-plan-text: var(--stage-plan);
  --fo-stage-review-text: var(--stage-review);
  --fo-stage-review-glow: rgba(255, 46, 126, 0.35);
  --fo-stage-dock-text: var(--stage-dock);
  --fo-state-quoted-text: var(--state-quoted);
  --fo-band-bg: var(--mf-plum-1000);
  --fo-panel-shadow: 0 14px 40px rgba(0, 0, 0, 0.45);
}

[data-theme="light"] {
  --fo-body-bright: var(--sem-text-secondary);
  --fo-stage-plan-text: var(--stage-plan-ink);
  --fo-stage-review-text: var(--stage-review-ink);
  --fo-stage-review-glow: rgba(192, 16, 89, 0.18);
  --fo-stage-dock-text: var(--stage-dock-ink);
  --fo-state-quoted-text: var(--mf-blue-700);
  --fo-band-bg: var(--mf-lavender-100);
  --fo-panel-shadow: var(--sem-elev-2);
}

/* ---------- type roles ---------- */
/* Signage only: heroes, stamps, plaques, section titles, big prices. */
.fo-stencil {
  font-family: var(--mf-font-display);
  font-weight: 400;
  letter-spacing: var(--mf-track-sign);
}

/* Labels, data, microcopy — never content a user must read to proceed. */
.fo-mono {
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: var(--mf-track-label);
  text-transform: uppercase;
  color: var(--sem-text-muted);
}

/* ---------- buttons ---------- */
.fo-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: var(--btn-pad);
  border: 1px solid transparent;
  border-radius: var(--btn-radius);
  font: var(--btn-font);
  cursor: pointer;
  transition: all var(--mf-dur-base) var(--mf-ease-out);
}

.fo-btn-primary {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-ink);
}

.fo-btn-primary:hover {
  background: var(--btn-primary-hover);
}

.fo-btn-primary.fo-glow {
  box-shadow: var(--sem-glow-accent);
}

.fo-btn-outline {
  background: transparent;
  color: var(--sem-text-primary);
  border-color: var(--btn-ghost-border);
}

.fo-btn-outline:hover {
  border-color: var(--sem-link);
  color: var(--sem-accent-hover);
}

.fo-btn-lg {
  padding: var(--btn-pad-lg);
  font-size: 15px;
}

/* Mono-labelled button (the header's SIGN IN). */
.fo-btn-mono {
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: var(--mf-track-label);
  text-transform: uppercase;
  padding: 9px 15px;
}

/* Mono label buttons: COPY, EDIT, START OVER … */
.fo-chip {
  display: inline-flex;
  align-items: center;
  padding: var(--btn-mono-chip);
  border: 1px solid var(--sem-border-strong);
  border-radius: var(--mf-radius-full);
  background: transparent;
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 11px;
  /* Explicit, because the element decides otherwise: a <button> takes the
     UA's `normal`, an <a> inherits the page's taller body line-height, and
     the same chip rendered 4px taller as a link than as a button in one row
     (the slip header's BACK TO THE QUEUE beside its button chips,
     2026-09-12). `normal` is what every button chip already had, so this
     moves only the link chips. .fo-btn gets the same from its `font`
     shorthand. */
  line-height: normal;
  letter-spacing: var(--mf-track-label);
  text-transform: uppercase;
  color: var(--sem-text-secondary);
  cursor: pointer;
  transition: border-color var(--mf-dur-base) var(--mf-ease-out);
}

.fo-chip:hover {
  border-color: var(--sem-link);
}

/* ---------- choice chips ---------- */
/* Chips that carry a SETTING rather than an action (delivery, today). Every
   option stays on screen with the current one lit, so changing your mind is
   one click — a chat quick-reply disappears the moment it is answered, and
   then there is nothing left to click. */
.fo-choice-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.fo-choice-chip {
  display: inline-flex;
  align-items: center;
  /* Tighter than .fo-chip on purpose: three of these have to sit on one
     row inside the manifest panel's narrow value column. */
  padding: 6px 11px;
  border: 1px solid var(--sem-border-subtle);
  border-radius: var(--mf-radius-full);
  background: transparent;
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sem-text-faint);
  cursor: pointer;
  transition:
    border-color var(--mf-dur-base) var(--mf-ease-out),
    color var(--mf-dur-base) var(--mf-ease-out);
}

.fo-choice-chip:hover {
  border-color: var(--sem-border-strong);
  color: var(--sem-text-secondary);
}

.fo-choice-chip.is-on {
  border-color: var(--sem-link);
  color: var(--sem-text-primary);
}

.fo-choice-chip:disabled {
  cursor: default;
  opacity: 0.6;
}

/* ---------- disabled + working ---------- */
/* A disabled button used to look EXACTLY like a live one: same fill, same
   hover, same cursor. So a click that had registered and a click that had
   not were indistinguishable, and the honest reaction was to click again
   (reported on the back office's SEND QUOTE, 2026-09-01 — the button was
   already disabled the whole time it was posting). Dimming every disabled
   control is the floor. */
.fo-btn:disabled,
.fo-chip:disabled,
.fo-addon-toggle:disabled {
  opacity: 0.5;
  /* Not `cursor: not-allowed`: pointer-events kills the hover states too,
     and there are a dozen per-variant :hover rules that would otherwise
     each need a :not(:disabled). One rule, no variant left behind. */
  pointer-events: none;
}

/* The button that is actually working keeps its full colour — it is the
   one live thing on a panel of dimmed ones — and grows the house conveyor
   along its bottom edge. The conveyor is this system's loading state
   everywhere else (.fo-conveyor above, the thinking bubble in refine.css);
   a button is no reason to introduce a spinner. */
.fo-btn.is-working:disabled,
.fo-chip.is-working:disabled {
  opacity: 1;
}

.fo-btn.is-working {
  position: relative;
  overflow: hidden;
}

.fo-btn.is-working::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 2px;
  /* currentColor, not --loading-conveyor: the stock conveyor is border-grey
     and vanishes on a filled primary button. The button's own ink contrasts
     with its own fill by construction, on every variant and both themes.
     Longhand background-image — see the .fo-conveyor note above. */
  background-image: repeating-linear-gradient(90deg, currentColor 0 10px, transparent 10px 20px);
  background-size: 20px 2px;
  opacity: 0.75;
  animation: var(--loading-anim);
}

/* A chip is a pill: a bar along the bottom would be clipped to a stub by
   the full radius, so the whole control breathes instead. Same vocabulary
   (mfPulse is the system's other waiting motif), no spinner. */
.fo-chip.is-working {
  animation: mfPulse 1.4s ease-in-out infinite;
}

/* ---------- state badge ---------- */
.fo-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border: 1px solid currentColor;
  border-radius: var(--badge-radius);
  font: var(--badge-font);
  letter-spacing: var(--badge-track);
  text-transform: uppercase;
}

/* ---------- station plaque ---------- */
/* Small radius-2 tile: mono STA·0x over stencil station name. */
.fo-plaque {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 7px 12px;
  background: var(--sem-surface-1);
  border: 1px solid var(--sem-border-subtle);
  border-radius: var(--mf-radius-xs);
}

.fo-plaque-no {
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 9px;
  letter-spacing: var(--mf-track-label);
  color: var(--sem-text-faint);
}

.fo-plaque-name {
  font-family: var(--mf-font-display);
  font-size: 13px;
  letter-spacing: var(--mf-track-sign);
  color: var(--sem-text-primary);
  text-transform: uppercase;
  white-space: nowrap;
}

/* ---------- stamp ---------- */
/* 3px double border in the state colour + stencil face, rotated. */
.fo-stamp {
  display: inline-block;
  padding: 5px 14px;
  border: var(--stamp-border);
  border-radius: var(--mf-radius-xs);
  font-family: var(--stamp-font);
  font-size: 19px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transform: rotate(var(--stamp-rotate));
}

/* ---------- conveyor ---------- */
/* Dashed rule, always moving. The loading state of this whole system —
   never a spinner. */
.fo-conveyor {
  height: 2px;
  /* background-image LONGHAND on purpose: the melodic-styles adoption
     round-trips rules through CSSOM cssText, and Chrome drops a
     `background` shorthand carrying var() when background-size is also
     set — the conveyor rendered blank in every shadow root. */
  background-image: var(--loading-conveyor);
  background-size: 20px 2px;
  animation: var(--loading-anim);
}

/* ---------- rounds / readiness meter ---------- */
.fo-meter {
  display: inline-flex;
  gap: var(--meter-seg-gap);
}

.fo-meter i {
  width: var(--meter-seg-w);
  height: var(--meter-seg-h);
  border-radius: 1px;
  background: var(--meter-seg-off);
}

.fo-meter i.on {
  background: var(--meter-seg-on);
}

.fo-meter i.spent {
  background: var(--meter-seg-spent);
}

/* ---------- manifest card (the work order) ---------- */
.fo-manifest {
  background: var(--manifest-bg);
  border: 1px solid var(--sem-border-strong);
  border-radius: var(--mf-radius-md);
  padding: 20px 22px;
}

.fo-manifest-id {
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: var(--mf-track-label);
  color: var(--sem-link);
}

.fo-manifest-title {
  font-size: 19px;
  font-weight: 600;
  margin: 8px 0 4px;
}

.fo-manifest-line {
  display: flex;
  gap: 14px;
  padding: 11px 0;
  border-top: var(--manifest-rule);
  font-size: var(--mf-text-sm);
  line-height: 1.55;
  color: var(--fo-body-bright);
}

.fo-manifest-line dt {
  flex: 0 0 92px;
  margin: 0;
  font-family: var(--mf-font-mono);
  font-weight: 600;
  font-size: 10px;
  letter-spacing: var(--mf-track-label);
  text-transform: uppercase;
  color: var(--sem-text-faint);
  padding-top: 2px;
}

.fo-manifest-line dd {
  margin: 0;
}

/* ---------- pixel character (seasoning only) ---------- */
/* A rounded square: skin, with a shirt band across the bottom ~45% in the
   relevant stage/job colour (set --fo-shirt). No other illustration. */
.fo-pixel {
  width: var(--avatar-pixel);
  height: var(--avatar-pixel);
  border-radius: 5px;
  background: linear-gradient(
    to bottom,
    var(--avatar-pixel-skin) 0 55%,
    var(--fo-shirt, var(--sem-accent)) 55% 100%
  );
}

/* ---------- crate (delivery) ---------- */
.fo-crate {
  border: var(--crate-stroke);
  border-radius: 2px;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 26%,
    var(--stage-package) 26% calc(26% + 3px),
    transparent calc(26% + 3px) 60%,
    var(--stage-package) 60% calc(60% + 3px),
    transparent calc(60% + 3px) 100%
  );
}

/* ---------- live dot ---------- */
.fo-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--sem-accent);
  animation: mfPulse 1.6s ease-in-out infinite;
}

/* ---------- logo lockup ---------- */
/* Icon + MF + 1px divider + wordmark (design/logo/HANDOFF.md). Set
   font-size on .fo-logo to size the whole lockup; the icon box equals the
   MF font size, which lands the shared cap line within a pixel. */
.fo-logo {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  font-size: 24px;
  line-height: 1;
}

.fo-logo svg {
  width: 1em;
  height: 1em;
  color: var(--sem-link);
}

.fo-logo-mf {
  display: inline-flex;
  font-family: var(--mf-font-display);
  font-size: 1em;
  text-transform: uppercase;
}

.fo-logo-mf .m {
  color: var(--sem-text-primary);
}

/* The face's default M→F pairing is far too loose; this is not optional. */
.fo-logo-mf .f {
  color: var(--sem-link);
  margin-left: -0.085em;
}

.fo-logo-divider {
  width: 1px;
  height: 0.75em;
  background: var(--sem-border-subtle);
  margin: 0 0.25em;
}

.fo-logo-wordmark {
  font-family: var(--mf-font-display);
  font-size: 0.68em;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sem-text-primary);
  white-space: nowrap;
}

/* ---------- toast shelf (front-kit/toast) ---------- */
/* One line, one dot, optional single action (the --toast-* spec). Fixed
   bottom-right so the arrival moves regardless of scroll — action feedback
   that a quiet inline line can't deliver mid-task. */
.fo-toasts {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(380px, calc(100vw - 36px));
  pointer-events: none;
}

.fo-toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: var(--toast-pad);
  background: var(--sem-surface-2);
  border: 1px solid var(--sem-border-strong);
  border-radius: var(--toast-radius);
  box-shadow: var(--fo-panel-shadow);
  font-family: var(--mf-font-body);
  font-size: var(--mf-text-sm);
  line-height: var(--mf-leading-snug);
  color: var(--fo-body-bright);
  pointer-events: auto;
  animation: mfToastIn var(--mf-dur-slow) var(--mf-ease-out);
}

.fo-toast-dot {
  flex: none;
  width: var(--toast-dot);
  height: var(--toast-dot);
  margin-top: 5px;
  border-radius: 50%;
  background: var(--sem-info);
}

.fo-toast.is-success .fo-toast-dot {
  background: var(--sem-success);
}

.fo-toast.is-error .fo-toast-dot {
  background: var(--sem-danger);
}

.fo-toast.is-error {
  border-color: var(--sem-danger);
}

.fo-toast-text {
  flex: 1;
  overflow-wrap: anywhere;
}

.fo-toast-close {
  flex: none;
  margin: 0;
  padding: 2px;
  border: 0;
  background: none;
  font-family: var(--mf-font-mono);
  font-size: 11px;
  color: var(--sem-text-muted);
  cursor: pointer;
}

.fo-toast-close:hover {
  color: var(--sem-text-primary);
}

/* ---------- popover (front-kit/popover) ---------- */
/* Hover/focus tip pinned to an inline anchor — the "why is this button
   dead" answer where the pointer already is. Works over a disabled
   button (the wrapper still hover-hits), and the tip itself accepts the
   pointer so links inside are clickable. */
.fo-popover {
  position: relative;
  display: inline-flex;
}

.fo-popover-tip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  z-index: 70;
  width: max-content;
  max-width: 260px;
  padding: 10px 12px;
  background: var(--sem-surface-2);
  border: 1px solid var(--sem-border-strong);
  border-radius: var(--mf-radius-sm);
  box-shadow: var(--fo-panel-shadow);
  font-family: var(--mf-font-body);
  font-size: var(--mf-text-xs);
  font-weight: 400;
  line-height: var(--mf-leading-snug);
  letter-spacing: normal;
  text-transform: none;
  color: var(--fo-body-bright);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 4px);
  transition:
    opacity var(--mf-dur-base) var(--mf-ease-out),
    transform var(--mf-dur-base) var(--mf-ease-out),
    visibility var(--mf-dur-base);
  pointer-events: none;
}

.fo-popover-tip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border: 5px solid transparent;
  border-top-color: var(--sem-border-strong);
}

.fo-popover:hover .fo-popover-tip,
.fo-popover:focus-within .fo-popover-tip {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  pointer-events: auto;
}

.fo-popover.is-below .fo-popover-tip {
  bottom: auto;
  top: calc(100% + 10px);
  transform: translate(-50%, -4px);
}

.fo-popover.is-below .fo-popover-tip::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: var(--sem-border-strong);
}

.fo-popover.is-below:hover .fo-popover-tip,
.fo-popover.is-below:focus-within .fo-popover-tip {
  transform: translate(-50%, 0);
}

/* ---------- motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .fo-conveyor,
  .fo-dot {
    animation: none;
  }

  .fo-toast {
    animation: none;
  }

  .fo-popover-tip {
    transition: none;
  }
}

/* The hidden attribute must always win — .fo-btn's display otherwise beats
   it (the M21 lesson, institutionalized: header auth chrome toggles rely
   on it). */
[hidden] {
  display: none !important;
}
