/* ============================================================
   public/assets/css/consumer.css — the public site

   Shares the shape of the station portal deliberately: same header
   bar, same rounded container, same card stack. They are one site.

   The difference is that this one carries four sections, so it adds
   a tab row under the header. The legacy site had only a hamburger,
   which meant every section change was a menu hunt.
   ============================================================ */

.Container {
  width: min(100%, 1000px);
  margin-inline: auto;
  min-height: 100dvh;
  background: var(--fms-surface);
  box-shadow: var(--fms-shadow-lg);
}

@media (min-width: 1020px) {
  .Container {
    margin-block: var(--fms-space-6);
    min-height: auto;
    border-radius: var(--fms-radius-lg);
    overflow: hidden;
  }
}

/* ---- Header -------------------------------------------------- */

.SiteHeader {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fms-space-3);
  padding: var(--fms-space-3) var(--fms-space-4);
  background: var(--fms-accent);
  color: var(--fms-on-accent);
}

.SiteTitle {
  display: flex;
  align-items: center;
  gap: var(--fms-space-3);
  color: var(--fms-on-accent);
  text-decoration: none;
  font-size: var(--fms-text-xl);
  font-weight: var(--fms-weight-medium);
  letter-spacing: 0.02em;
  text-shadow: 2px 2px 3px rgb(0 0 0 / 0.25);
}

.MonkeyBadge {
  height: 44px;
  width: auto;
  aspect-ratio: 1;
  transition: transform var(--fms-duration-slow) var(--fms-ease);
}
[data-season="christmas"] .MonkeyBadge { aspect-ratio: 128 / 156; }
.SiteTitle:hover .MonkeyBadge { transform: rotate(360deg); }
.MonkeyBadge.Small { height: 28px; }

.MenuButton {
  display: grid;
  gap: 5px;
  padding: var(--fms-space-2);
  min-width: var(--fms-touch-target);
  background: none;
  border: 0;
  border-radius: var(--fms-radius-sm);
}
.MenuButton span {
  display: block;
  width: 26px; height: 3px;
  border-radius: 2px;
  /* On the accent bar — see --fms-on-accent in tokens.css. As a
     `background` this escaped the first sweep, which only caught
     `color`, and the bars stayed charcoal on teal. */
  background: var(--fms-on-accent);
  transition: transform var(--fms-duration) var(--fms-ease),
              opacity var(--fms-duration) var(--fms-ease);
}
.MenuButton[aria-expanded="true"] span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.MenuButton[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.MenuButton[aria-expanded="true"] span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* ---- Section tabs -------------------------------------------- */

/* The tab row has its OWN colour, no longer derived from the
   header's accent.

   Two reasons. Jake wanted the bars different — navy masthead, sage
   tab row (27 Jul 2026) — and separating them gives the seasonal
   colour a single home: on Halloween or Earth Day the masthead
   changes and this bar stays put, so the site is dressed up rather
   than repainted.

   The old rules tinted with rgb(255 255 255 / …) for hover and
   current-page, which only works on a dark ground. On sage those
   washed out to nothing, so the tints are now black at low alpha —
   they darken a pale bar instead of lightening a dark one. */
.SectionNav {
  display: flex;
  gap: var(--fms-space-1);
  padding: var(--fms-space-2) var(--fms-space-4);
  background: var(--fms-nav-bg, var(--fms-accent-dark));
  overflow-x: auto;
  scrollbar-width: none;
}
.SectionNav::-webkit-scrollbar { display: none; }

.SectionNav a {
  padding: var(--fms-space-2) var(--fms-space-4);
  min-height: var(--fms-touch-target);
  display: flex;
  align-items: center;
  white-space: nowrap;
  border-radius: var(--fms-radius-pill);
  color: var(--fms-nav-ink, var(--fms-on-accent));
  text-decoration: none;
  font-size: var(--fms-text-sm);
}
.SectionNav a:hover { background: rgb(0 0 0 / 0.08); }
.SectionNav a[aria-current="page"] {
  background: rgb(0 0 0 / 0.14);
  font-weight: var(--fms-weight-bold);
}

/* ---- The centre card unfolding in --------------------------- */

/* Transcribed from `OpenBox` in fancymonkey/FMS.css, which the
   legacy site ran on .RoundedBox — the main content box — at
   `0.5s ease-in-out 0.1s backwards`. Jake missed it (27 Jul 2026).

   Note there is no `perspective` here, and there wasn't in the
   original either. Without it, rotateX(-90deg) doesn't swing in
   three dimensions — it flattens to nothing and unfolds vertically,
   like a card standing up. That flattened unfold IS the effect, not
   an approximation of a 3D one.

   `backwards` matters: the 0.1s delay would otherwise show the card
   at full opacity for a frame before it vanished to start.

   Applied via a class the router adds per navigation. The element
   itself persists — only its contents are replaced — so a plain
   animation would run once on first load and never again. */
.MainPanel.Opening {
  transform-origin: top left;
  animation: fms-open-box 0.5s ease-in-out 0.1s backwards;
}

@keyframes fms-open-box {
  0%   { opacity: 0; transform: rotateX(-90deg); }
  70%  { opacity: 1; }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .MainPanel.Opening { animation: none; }
}


/* ---- Gift certificate redemption (gift.html) ------------------ */

.GiftPicker {
  max-height: 24rem;
  overflow-y: auto;
  border: 1px solid var(--fms-rule);
  border-radius: var(--fms-radius-sm);
  padding: var(--fms-space-2);
  margin-bottom: var(--fms-space-4);
  background: var(--fms-white);
}

.GiftItem {
  display: flex;
  align-items: center;
  gap: var(--fms-space-3);
  padding: var(--fms-space-2);
  border-radius: var(--fms-radius-sm);
  cursor: pointer;
}
.GiftItem:hover { background: var(--fms-surface-alt); }

/* Once the allowance is spent the rest go quiet — still visible, so
   the list doesn't appear to shrink, but clearly not available. */
.GiftItem:has(input:disabled) { color: var(--fms-muted); cursor: default; }


/* ---- Order page (order.html) ---------------------------------- */

.DownloadList { list-style: none; padding-left: 0; }

.DownloadItem {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--fms-space-3);
  padding: var(--fms-space-3) 0;
  border-bottom: 1px solid var(--fms-rule);
}

.DownloadName { font-weight: var(--fms-weight-medium); }

/* A gift message is the buyer's words, not ours — set apart so it
   doesn't read as site copy. */
.GiftMessage {
  margin: 0 0 var(--fms-space-4);
  padding: var(--fms-space-3) var(--fms-space-4);
  border-left: 4px solid var(--fms-accent);
  background: var(--fms-surface-alt);
  font-style: italic;
}

.FinePrint { font-size: var(--fms-text-sm); color: var(--fms-muted); }
.FieldError { color: var(--fms-danger); font-size: var(--fms-text-sm); }


/* ---- Product listings (the Products pages) -------------------- */

.ProductList { margin-top: var(--fms-space-5); }

.ProductCard {
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: var(--fms-space-4);
  padding: var(--fms-space-4) 0;
  border-top: 1px solid var(--fms-rule);
  align-items: start;
}

/* One column on a phone — a 200px cover beside a paragraph leaves
   neither enough room. */
@media (max-width: 34rem) {
  .ProductCard { grid-template-columns: 1fr; }
}

/* And one column when there is no cover at all, so the copy uses
   the full width instead of the picture's slot. */
.ProductCard.NoCover { grid-template-columns: 1fr; }

/* Covers are photographs and flat art on white; the card behind
   content images would only add a border here. */
.ProductImage {
  width: 100%;
  height: auto;
  border-radius: var(--fms-radius-sm);
  background: none;
  padding: 0;
}

/* The card's second grid column. `min-width: 0` is the whole point:
   a grid item defaults to min-content width, so one unbreakable
   string in the copy — a long URL, an ISBN, "Three Wise Men and a
   Baby — Performance Split Trax" — pushes the column wider than its
   track and the cover beside it gets squeezed to nothing. Was used
   by features.js and defined by no stylesheet until 27 Jul 2026. */
.ProductBody {
  min-width: 0;
}

.ProductName {
  margin-bottom: var(--fms-space-1);
  color: var(--fms-heading);
}

.ProductPrice {
  font-size: var(--fms-text-lg);
  font-weight: var(--fms-weight-bold);
  color: var(--fms-heading);
  margin-bottom: var(--fms-space-2);
}

/* The books have carried "$5.95, limited time $4.95" for twenty
   years, so the original price is real and worth showing. */
.ProductWas {
  margin-left: var(--fms-space-2);
  font-size: var(--fms-text-sm);
  font-weight: var(--fms-weight-normal);
  color: var(--fms-muted);
  text-decoration: line-through;
}

.ProductMeta {
  font-size: var(--fms-text-sm);
  color: var(--fms-muted);
  margin-bottom: var(--fms-space-1);
}

/* Deliberately not muted. On a page selling the same content as
   both a download and a disc, this is the line that tells the two
   apart — it should read before the specifications, not after. */
.ProductDelivery {
  margin-bottom: var(--fms-space-2);
  font-size: var(--fms-text-sm);
  font-weight: var(--fms-weight-medium);
  color: var(--fms-accent);
}

.ProductSoldOut {
  font-weight: var(--fms-weight-bold);
  color: var(--fms-crimson-deep);
  margin-bottom: var(--fms-space-2);
}

.ProductPreview {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--fms-space-2);
  margin: var(--fms-space-2) 0 var(--fms-space-3);
}

/* Native controls, deliberately. They are familiar, keyboard
   accessible and work on every phone without a line of JavaScript —
   and a custom player here would be decoration standing between
   someone and hearing the show. */
.ProductPreview audio { max-width: 100%; height: 2.2rem; }

.ProductCopy { margin-top: var(--fms-space-3); }
.ProductCopy img { max-width: 100%; height: auto; }

/* Each copy field is its own block.

   `overflow: hidden` makes each one a formatting context, so a
   floated image inside copy_2 is contained by it instead of
   spilling past the end of the card — and starts at the top of its
   own block rather than wherever the previous paragraph ran out. */
.ProductCopyBlock { overflow: hidden; }
.ProductCopyBlock + .ProductCopyBlock { margin-top: var(--fms-space-4); }

/* Images hoisted out of the copy sit at the top and float right, so
   the text wraps around them from the first line.

   Legacy copy uses align='right', which modern layout ignores —
   float is what it meant. Sized down too: these were drawn for a
   full-width page, not a card that already has a cover beside it. */
.ProductCopy > img {
  float: right;
  max-width: 38%;
  margin: 0 0 var(--fms-space-3) var(--fms-space-4);
}


/* ---- Station directory (page 203) ----------------------------- */

.StationList { margin-top: var(--fms-space-5); }

.StationGroup { margin-bottom: var(--fms-space-5); }

.StationPlace {
  margin-bottom: var(--fms-space-2);
  padding-bottom: var(--fms-space-1);
  border-bottom: 1px solid var(--fms-rule);
  font-size: var(--fms-text-sm);
  font-weight: var(--fms-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fms-muted);
}

.StationItems { list-style: none; padding-left: 0; }

.Station {
  padding: var(--fms-space-1) 0;
  line-height: var(--fms-leading-normal);
}

/* The call letters are what someone scans for. */
.Station a, .StationCall { font-weight: var(--fms-weight-medium); }

.StationFreq { color: var(--fms-heading); }
.StationCity, .StationTimes { color: var(--fms-muted); font-size: var(--fms-text-sm); }


/* ---- Full menu ------------------------------------------------ */

.MenuPanel {
  position: absolute;
  top: 100%;
  right: var(--fms-space-4);
  z-index: var(--fms-z-nav);
  display: grid;
  gap: var(--fms-space-4);

  /* `min(160px, 100%)` rather than a bare 160px: when the panel is
     narrower than one column, a fixed track floor can't shrink and
     the content overflows instead of wrapping. */
  grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));

  min-width: min(90vw, 620px);

  /* Without this the panel is free to grow LEFTWARDS off-screen. It
     is absolutely positioned and anchored by its right edge, so
     nothing bounds its left one: four 160px columns plus gaps need
     more than a phone has, and instead of wrapping to fewer columns
     the grid simply overflowed and clipped the first one — taking
     the whole Fancy Monkey Studios group with it (found 27 Jul
     2026 at a narrow desktop width; a phone was worse).

     Percentages resolve against .SiteHeader, the positioned
     ancestor, so the panel now stops at the header's edges with the
     same inset on both sides — and auto-fit does its job. */
  max-width: calc(100% - (2 * var(--fms-space-4)));

  /* Tall menu on a short screen: scroll rather than run off the
     bottom, where the last group would be unreachable. */
  max-height: calc(100vh - 100%);
  overflow-y: auto;
  overscroll-behavior: contain;

  padding: var(--fms-space-4);
  background: var(--fms-accent);
  border-radius: 0 0 var(--fms-radius) var(--fms-radius);
  box-shadow: var(--fms-shadow-lg);
}
.MenuPanel[hidden] { display: none; }

/* The legacy menu floated up into place rather than appearing, and
   Jake missed it (27 Jul 2026). Restored.

   Driven by an animation on :not([hidden]) rather than a transition,
   because the panel toggles `display` — and display is not
   transitionable, so a transition would simply never run. The
   animation replays every time the attribute is removed, which is
   exactly the moment we want it.

   transform-origin sits at the top right so it grows out of the
   hamburger it came from, instead of expanding from its own middle.

   This is the ORIGINAL, not an approximation. Transcribed from
   `MenuSlideUp` in fancymonkey/FMS.css, with the 0.3s ease-in-out
   timing used by every menu animation in that file.

   Three guesses preceded it and all three were wrong in the same
   direction: too little travel, too much time. The original moves
   8rem — around 128px — in 300ms. That reads as one quick decisive
   slide. Making it slower, as I kept doing, only made a short move
   look hesitant. There is no scale in it either; that was mine. */
.MenuPanel:not([hidden]) {
  transform-origin: top left;
  animation: fms-menu-slide-up 0.3s ease-in-out;
}

@keyframes fms-menu-slide-up {
  from { opacity: 0; transform: translateY(8rem); }
  to   { opacity: 1; transform: none; }
}

/* Anyone who has asked the OS for less motion gets none of it. */
@media (prefers-reduced-motion: reduce) {
  .MenuPanel:not([hidden]) { animation: none; }
}

.MenuGroup h2 {
  margin-bottom: var(--fms-space-2);
  font-size: var(--fms-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgb(255 255 255 / 0.65);
}
.MenuGroup a {
  display: flex;
  align-items: center;
  min-height: 38px;
  padding: var(--fms-space-1) var(--fms-space-2);
  color: var(--fms-on-accent);
  text-decoration: none;
  border-radius: var(--fms-radius-sm);
  font-size: var(--fms-text-sm);
}
.MenuGroup a:hover { background: rgb(255 255 255 / 0.16); }

/* ---- Layout --------------------------------------------------- */

.Body {
  display: grid;
  gap: var(--fms-space-6);
  padding: var(--fms-space-5) var(--fms-space-4) var(--fms-space-7);
}

@media (min-width: 900px) {
  .Body {
    grid-template-columns: minmax(0, 1fr) 240px;
    padding-inline: var(--fms-space-6);
  }
}

.Headline {
  font-family: var(--fms-font-display);
  font-size: var(--fms-text-3xl);
  color: var(--fms-heading);
  text-align: center;
  text-shadow: var(--fms-shadow-title);
}

/* ---- Page copy -----------------------------------------------
   .Copy / .CopyCentered / .CopyHeadline / .TinyType are the legacy
   class names. The extracted markup still carries them, so they
   have to keep working. */

.Copy { color: var(--fms-body); line-height: var(--fms-leading-normal); }
.Copy p, p.Copy { max-width: var(--fms-measure); }
.Copy ul, .Copy ol { max-width: var(--fms-measure); padding-left: 1.4em; }
.Copy li { margin-bottom: var(--fms-space-2); }

.CopyCentered, p.CopyCentered { text-align: center; max-width: none; }

.CopyHeadline, .CopyHeadline300, .CopyHeadline900 {
  font-size: var(--fms-text-xl);
  text-align: center;
  color: var(--fms-heading);
  letter-spacing: 0.06em;
}
.CopyHeadline300 { font-weight: var(--fms-weight-light); }
.CopyHeadline900 { font-weight: var(--fms-weight-black); }

.TinyType { font-size: var(--fms-text-xs); }

/* Word-pasted markup sets widths on images inline; those became
   generated classes in content.css. This keeps them from overflowing
   on a phone regardless of what the original declared. */
.Copy img {
  max-width: 100%;
  height: auto;
  border-radius: var(--fms-radius-sm);

  /* Twenty years of art was drawn for a white page, and a lot of it
     is dark linework on a transparent background — the "Little Dogs
     on the Prairie" title, Millard's signature, the hand-lettered
     headers. On the dark theme those very nearly vanish.

     So every content image sits on its own white card. Photographs
     and full-bleed art are opaque and cover the card entirely, so
     they are unaffected; only the transparent pieces use it, and for
     them it restores exactly the background they were drawn against.

     The alternative was re-cutting the artwork light-on-dark, which
     would change what a visitor sees. This doesn't. See DECISIONS #6
     — text and images identical, presentation modernized. */
  background: #fff;
  padding: var(--fms-space-2);
}

/* Two exceptions, both already opaque and framed by their own layout:
   the home page monkey and the review scans. A card behind these just
   adds a stray white border. */
.Copy img.NoCard,
.HomeMonkeyImage,
.ReviewScan img {
  background: none;
  padding: 0;
}

.Copy video, .Copy audio { width: 100%; max-width: 640px; margin-inline: auto; }

.Copy table { max-width: 100%; }

/* ---- Sidebar cards -------------------------------------------- */

.SidePanel { display: grid; gap: var(--fms-space-4); align-content: start; }

.RoundedBox {
  padding: var(--fms-space-4);
  background: var(--fms-surface-alt);
  border: 1px solid var(--fms-rule);
  border-radius: var(--fms-radius);
  box-shadow: var(--fms-shadow-sm);
}

.CardHeading {
  margin-bottom: var(--fms-space-2);
  font-size: var(--fms-text-sm);
  font-weight: var(--fms-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fms-muted);
}

.CardLinks { display: grid; }
.CardLinks a {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding-inline: var(--fms-space-2);
  font-size: var(--fms-text-sm);
  border-radius: var(--fms-radius-sm);
  text-decoration: none;
}
.CardLinks a:hover { background: color-mix(in srgb, var(--fms-accent) 10%, transparent); }
.CardLinks a[aria-current="page"] {
  font-weight: var(--fms-weight-bold);
  color: var(--fms-heading);
  background: color-mix(in srgb, var(--fms-accent) 14%, transparent);
}

/* ---- Footer ---------------------------------------------------- */

.SiteFooter {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--fms-space-2);
  padding: var(--fms-space-5);
  border-top: 1px solid var(--fms-rule);
  font-size: var(--fms-text-xs);
  color: var(--fms-muted);
}
.SiteFooter .MonkeyBadge { transition: transform var(--fms-duration-slow) var(--fms-ease); }
.SiteFooter:hover .MonkeyBadge { transform: rotateY(360deg); }

.SeasonGreeting {
  flex-basis: 100%;
  text-align: center;
  color: var(--fms-accent);
  font-weight: var(--fms-weight-medium);
}
.SeasonGreeting[hidden] { display: none; }

.NoScriptNotice { text-align: center; padding: var(--fms-space-6); }


/* ============================================================
   Quizzes — pages 205 and 304
   ============================================================ */

.QuizName {
  margin-bottom: var(--fms-space-2);
  font-weight: var(--fms-weight-bold);
  color: var(--fms-heading);
}

.QuizCard { margin-block: var(--fms-space-4); }

.QuizProgress {
  margin-bottom: var(--fms-space-3);
  font-weight: var(--fms-weight-bold);
  text-align: center;
}
.QuizProgress .Muted { font-weight: var(--fms-weight-normal); color: var(--fms-muted); }

.QuizQuestion {
  margin-bottom: var(--fms-space-4);
  font-size: var(--fms-text-lg);
  max-width: none;
}

.QuizOptions { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--fms-space-2); }

.QuizOption {
  display: flex;
  align-items: flex-start;
  gap: var(--fms-space-3);
  width: 100%;
  padding: var(--fms-space-3);
  text-align: left;
  background: var(--fms-surface);
  border: 2px solid var(--fms-rule);
  border-radius: var(--fms-radius);
  color: var(--fms-fg);
  font: inherit;
  transition: border-color var(--fms-duration-fast) var(--fms-ease),
              background var(--fms-duration-fast) var(--fms-ease);
}
.QuizOption:hover:not(:disabled) { border-color: var(--fms-accent); }
.QuizOption:disabled { opacity: 1; cursor: default; }

/* After answering: the right one is always marked, whether or not it
   was chosen. Colour is paired with a symbol via ::after so it doesn't
   rely on colour alone. */
.QuizOption[data-correct="true"] {
  border-color: var(--fms-success);
  background: color-mix(in srgb, var(--fms-success) 12%, transparent);
  font-weight: var(--fms-weight-medium);
}
.QuizOption[data-correct="true"]::after { content: '✓'; margin-left: auto; color: var(--fms-success); }

.QuizOption[data-chosen="true"] {
  border-color: var(--fms-danger);
  background: color-mix(in srgb, var(--fms-danger) 10%, transparent);
}
.QuizOption[data-chosen="true"]::after { content: '✕'; margin-left: auto; color: var(--fms-danger); }

.QuizLetter {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.9em;
  height: 1.9em;
  border-radius: 50%;
  background: var(--fms-accent);
  color: var(--fms-on-accent);
  font-weight: var(--fms-weight-bold);
  font-size: 0.85em;
}

.QuizResult {
  margin-top: var(--fms-space-4);
  text-align: center;
  font-weight: var(--fms-weight-bold);
  font-size: var(--fms-text-lg);
  min-height: 1.5em;
}
.QuizResult[data-tone="ok"]  { color: var(--fms-success); }
.QuizResult[data-tone="bad"] { color: var(--fms-danger); }

.QuizExplanation {
  margin-top: var(--fms-space-2);
  text-align: center;
  color: var(--fms-link);
  font-style: italic;
}

.QuizScore {
  text-align: center;
  font-size: var(--fms-text-lg);
  max-width: none;
}

.QuizAgain {
  display: block;
  margin: var(--fms-space-4) auto 0;
  padding: var(--fms-space-3) var(--fms-space-5);
  border: 2px solid var(--fms-accent);
  border-radius: var(--fms-radius);
  background: var(--fms-accent);
  color: var(--fms-on-accent);
  font: inherit;
  font-weight: var(--fms-weight-medium);
}


/* ============================================================
   Press reviews — page 305
   ============================================================ */

.Review { margin-top: var(--fms-space-5); }

.ReviewHead {
  padding-bottom: var(--fms-space-3);
  margin-bottom: var(--fms-space-4);
  border-bottom: 2px solid var(--fms-rule);
}

.ReviewSource {
  margin-bottom: var(--fms-space-1);
  font-size: var(--fms-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fms-muted);
}

.ReviewHeadline {
  font-family: var(--fms-font-slab);
  font-size: var(--fms-text-xl);
  margin-bottom: var(--fms-space-2);
}

.ReviewSubhead { font-style: italic; color: var(--fms-muted); margin-bottom: var(--fms-space-2); }
.ReviewByline { font-size: var(--fms-text-sm); color: var(--fms-muted); margin: 0; }

.ReviewRating { margin: var(--fms-space-2) 0 0; font-size: var(--fms-text-lg); color: var(--fms-warning); }
.ReviewAcceptability { font-size: var(--fms-text-sm); color: var(--fms-muted); }

.ReviewCredits {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--fms-space-1) var(--fms-space-4);
  margin-top: var(--fms-space-5);
  padding-top: var(--fms-space-4);
  border-top: 1px solid var(--fms-rule);
  font-size: var(--fms-text-sm);
}
.ReviewCredits dt { color: var(--fms-muted); }
.ReviewCredits dd { margin: 0; color: var(--fms-fg); }

.ReviewBuy { margin-top: var(--fms-space-4); font-weight: var(--fms-weight-medium); }

.ReviewScan { margin-top: var(--fms-space-5); }
.ReviewScan summary {
  cursor: pointer;
  padding: var(--fms-space-2);
  color: var(--fms-link);
  font-size: var(--fms-text-sm);
}
.ReviewScan img {
  margin-top: var(--fms-space-3);
  max-width: 100%;
  height: auto;
  border: 1px solid var(--fms-rule);
  border-radius: var(--fms-radius-sm);
}


/* ============================================================
   Contact Us / FAQ — page 102

   The legacy page was a list of `· Question` links, each swapping
   itself for a .RoundedBox holding the question and its answer.
   These are <details> elements doing the same job, so the closed
   state has to keep looking like a bulleted list and the open state
   has to become that box.
   ============================================================ */

.FAQ { margin-top: var(--fms-space-4); }

.FAQItem {
  border-radius: var(--fms-radius);
  /* Only the open one draws a box. Closed, the nine of them should
     read as a list of questions, not as nine empty cards. */
  transition: background var(--fms-duration) var(--fms-ease);
}

.FAQItem[open] {
  margin: var(--fms-space-3) 0;
  padding: var(--fms-space-4);
  background: var(--fms-surface-alt);
  border: 1px solid var(--fms-rule);
  box-shadow: var(--fms-shadow-sm);
}

.FAQQuestion {
  cursor: pointer;
  padding: var(--fms-space-2) 0;
  color: var(--fms-link);
  font-weight: var(--fms-weight-medium);
  /* The legacy bullet was a literal &middot; before each question.
     ::marker can't be styled consistently across browsers for an
     open/closed summary, so the disclosure triangle is removed and
     the middot put back as content — which is what the page always
     showed. */
  list-style: none;
}
.FAQQuestion::-webkit-details-marker { display: none; }
.FAQQuestion::before {
  content: '· ';
  color: var(--fms-muted);
}
.FAQQuestion:hover { text-decoration: underline; }

/* Open, the question is the box's heading rather than a link to
   click — it still collapses, but it should not go on shouting in
   link blue underneath its own answer. */
.FAQItem[open] .FAQQuestion {
  margin-bottom: var(--fms-space-3);
  color: var(--fms-fg);
  font-weight: var(--fms-weight-bold);
}

/* Answers are legacy HTML separated by <br><br> rather than by
   paragraphs, so the spacing has to come from line-height. */
.FAQAnswer {
  margin: 0;
  line-height: var(--fms-leading-loose);
}

.FAQContact {
  margin-top: var(--fms-space-5);
  padding-top: var(--fms-space-4);
  border-top: 1px solid var(--fms-rule);
}


/* ============================================================
   Guest book — page 104
   ============================================================ */

.GuestBookDialog {
  width: min(100% - 2rem, 460px);
  padding: var(--fms-space-5);
  border: 0;
  border-radius: var(--fms-radius-lg);
  background: var(--fms-surface);
  color: var(--fms-fg);
  box-shadow: var(--fms-shadow-lg);
}
.GuestBookDialog::backdrop { background: rgb(0 0 0 / 0.5); }

.GuestBookDialog h2 {
  font-family: var(--fms-font-slab);
  font-size: var(--fms-text-xl);
  text-shadow: none;
}

.GuestBookDialog input,
.GuestBookDialog textarea {
  width: 100%;
  margin-bottom: var(--fms-space-3);
  padding: var(--fms-space-3);
  border: 1px solid var(--fms-rule);
  border-radius: var(--fms-radius-sm);
  background: var(--fms-white);
  color: var(--fms-ink);
  font: inherit;
}
.GuestBookDialog input { min-height: var(--fms-touch-target); }
.GuestBookDialog textarea { resize: vertical; min-height: 8rem; }

.DialogNote { font-size: var(--fms-text-sm); color: var(--fms-muted); min-height: 1.4em; margin: 0; }
.DialogError { font-size: var(--fms-text-sm); color: var(--fms-danger); min-height: 1.4em; margin: 0; }

.DialogButtons {
  display: flex;
  justify-content: flex-end;
  gap: var(--fms-space-3);
  margin-top: var(--fms-space-4);
}

.GuestBookThanks { text-align: center; }
.GuestBookThanks h2 { margin-bottom: var(--fms-space-3); }

.ButtonPrimary, .ButtonQuiet {
  padding: var(--fms-space-3) var(--fms-space-5);
  border-radius: var(--fms-radius);
  border: 2px solid var(--fms-accent);
  font: inherit;
  font-weight: var(--fms-weight-medium);
}
.ButtonPrimary { background: var(--fms-accent); color: var(--fms-on-accent); }
.ButtonPrimary:disabled { opacity: 0.5; cursor: not-allowed; }
.ButtonQuiet { background: none; color: var(--fms-accent); }


/* Page 101's home image — the only content that page has ever had. */
.HomeMonkey { margin-inline: auto; width: 90vw; max-width: 650px; }
.HomeMonkeyImage { width: 100%; height: auto; border-radius: var(--fms-radius); }

/* Guest book */
.GuestBook { margin-top: var(--fms-space-6); }
.GuestBookYear { margin-bottom: var(--fms-space-7); }
.GuestBookYearHeading {
  padding-bottom: var(--fms-space-2);
  margin-bottom: var(--fms-space-4);
  border-bottom: 2px solid var(--fms-rule);
  font-family: var(--fms-font-slab);
  font-size: var(--fms-text-xl);
  text-shadow: none;
}
.GuestbookBody { margin: 0; white-space: pre-line; max-width: none; }
.GuestbookByline {
  margin: var(--fms-space-3) 0 0;
  text-align: right;
  font-style: italic;
  font-size: var(--fms-text-sm);
  color: var(--fms-muted);
  max-width: none;
}

/* Guest book entries, as rendered on page 104. */
.GuestbookEntry {
  position: relative;
  margin-bottom: var(--fms-space-5);
  padding: var(--fms-space-4) var(--fms-space-4) var(--fms-space-4) var(--fms-space-7);
  background: var(--fms-surface-alt);
  border-radius: var(--fms-radius);
}
.DropQuote {
  position: absolute;
  left: var(--fms-space-3);
  top: var(--fms-space-2);
  font-family: var(--fms-font-display);
  font-size: 3rem;
  line-height: 1;
  color: var(--fms-accent);
  opacity: 0.4;
}


/* ============================================================
   Legacy markup preserved verbatim in the page copy

   site-content.js is generated from Site.json and the copy is
   VERBATIM (DECISIONS #6), so class names the old site used
   survive into the modern pages. They need rules here, because
   content.css is generated and only carries lifted inline styles.
   ============================================================ */

/* Page 101 kept `<div class='CoversFrame' id='CoversFrame'>` from
   the legacy home page, where a script rotated cover art through
   it (.Covers / .CoversFadeIn in fancymonkey/FMS.css). That
   rotator has not been rebuilt, so the frame is always empty.

   The legacy rule was a 200x200 GRAY square — porting it as-is
   would put a gray block on the home page for a feature that does
   not exist. :empty collapses it instead, and the day the rotator
   returns it fills out to the size it always had, with no CSS
   change. See docs/DECISIONS.md Open. */
.CoversFrame {
  position: relative;
  float: left;
  width: 200px;
  height: 200px;
  margin: 1px 5px 5px 0;
}
.CoversFrame:empty { display: none; }


/* A bundle row: several download buttons under one name.

   .DownloadItem is a wrapping flex row, which is right for a single
   button and a line of fine print. With three buttons the names run
   together, so a bundle stacks instead — the item name, then one
   button per file, then the shared attempt count.

   FMSDL069 "Video Download Special" is the only one today (three
   Little Dogs videos, no combined zip). See functions/api/order.js. */
.DownloadItem.Bundle {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--fms-space-2);
}
.DownloadItem.Bundle .DownloadName {
  font-weight: var(--fms-weight-bold);
}


/* ---- Characters (page 202) ------------------------------------

   Picture beside its description, stacking on a phone. The legacy
   page used a two-column <table> per character; this is the same
   arrangement without the table, so it reflows instead of forcing a
   sideways scroll on a 320px screen.

   The 179px column is the width the legacy images were served at
   (width="179" in Characters.htm), so at full size they render at
   their natural resolution rather than being scaled up. */
.Characters { margin-top: var(--fms-space-5); }

.Character {
  display: grid;
  grid-template-columns: minmax(0, 179px) minmax(0, 1fr);
  gap: var(--fms-space-4);
  padding: var(--fms-space-4) 0;
  border-top: 1px solid var(--fms-rule);
  align-items: start;
}

@media (max-width: 34rem) {
  .Character { grid-template-columns: 1fr; }
}

.CharacterImage {
  width: 100%;
  height: auto;
  border-radius: var(--fms-radius-sm);
}

/* min-width: 0 for the same reason as .ProductBody — a long
   unbroken verse reference would otherwise widen the column past
   its track and squeeze the picture. */
.CharacterBody { min-width: 0; }

.CharacterName {
  margin-bottom: var(--fms-space-2);
  color: var(--fms-heading);
}

.CharacterFact {
  margin-bottom: var(--fms-space-2);
  font-size: var(--fms-text-sm);
}

/* The label carries the weight so the six lines scan as a list of
   facts rather than a paragraph, which is what the legacy <b> did. */
.CharacterLabel { font-weight: var(--fms-weight-bold); }


/* ---- Episode guide (page 204) ---------------------------------

   42 episodes, most with two stories. A long page, so the episode
   title is the anchor a reader scans for and the lesson line is
   the anchor within an episode. Nothing is hidden behind a
   disclosure: the legacy guide was one continuous document and
   people read it looking for a particular story, which
   find-in-page does better than an accordion. */
.EpisodeGuide { margin-top: var(--fms-space-5); }

.GuideEpisode {
  padding: var(--fms-space-4) 0;
  border-top: 1px solid var(--fms-rule);
}

.GuideTitle {
  margin-bottom: var(--fms-space-3);
  color: var(--fms-heading);
}

.GuideStory + .GuideStory { margin-top: var(--fms-space-4); }

/* The scripture reference and the lesson, e.g.
   "Matthew 22:39 - Loving Your Neighbor". The legacy page gave
   this its own paragraph; it keeps that, with weight instead of
   the <b> the Word export used. */
.GuideLesson {
  margin-bottom: var(--fms-space-2);
  font-weight: var(--fms-weight-bold);
  color: var(--fms-accent);
}
