/* preview.css -- BL#17186 landing-page rebuild. The page's OWN layout and moment
 * panel. Its companion, preview-wheel.css, is a verbatim port of the app's wheel
 * styles and should not be edited independently -- see that file's own header.
 *
 * WHY A public/ FILE AND NOT AN ASTRO <style> BLOCK IN THE COMPONENT. Scoped
 * component styles are the idiomatic Astro answer and were the first choice here.
 * They are wrong for THIS site: Layout.astro serves every page under
 * `style-src 'self'` with no 'unsafe-inline' (its own header comment calls out
 * style-guide.astro as the single deliberate exception), and Astro's default
 * build.inlineStylesheets:'auto' emits any stylesheet under ~4kB as an inline
 * <style> tag. A component style block small enough to be inlined would be blocked
 * by the page's own CSP -- silently, as an unstyled page rather than an error.
 * Linking from `cssFiles` is also what all eleven existing pages already do, so this
 * is the site's convention, not a workaround.
 *
 * NO-SCROLL IS THE POINT (Jonah, 2026-10-08): "ideally, we should not have any
 * scrolling on the landing page and just a few clickable previews." The page is a
 * fixed-height viewport, not a tall document that happens to fit. .landing-page
 * (set via Layout's bodyClass prop) is what actually enforces it; everything below
 * is sized to live inside that budget rather than to grow.
 */

/* body is flex-column with min-height:100vh (main.css) and main is flex:1, so the
 * page already fills the viewport -- what it does NOT do is refuse to exceed it.
 * dvh, not vh: on mobile Safari/Chrome the collapsing URL bar makes 100vh TALLER
 * than the visible viewport, which would reintroduce exactly the scroll this is
 * removing. overflow:hidden on the body is the hard stop -- any overflow is then
 * the moment panel's own problem to absorb (see .moment-body), never the page's. */
.landing-page {
  height: 100dvh;
  min-height: 100dvh;
  overflow: hidden;
}

/* THE RULE THAT ACTUALLY MAKES THE PAGE FIT. main.css gives <main> `flex: 1` with
   no min-height, and a flex item's default `min-height: auto` means it REFUSES to
   shrink below its content's intrinsic height -- so the fixed-height body above
   simply overflowed and clipped, hiding the CTA off the bottom of a phone screen.
   Measured, not theorised: 237px of overflow at 360x740 before this rule, 0 after.
   Every descendant in the chain needs the same escape hatch, which is why .landing,
   .landing-stage and .moment-body each carry their own min-height:0 -- one missing
   link anywhere re-breaks the whole chain. */
.landing-page main { min-height: 0; }

.landing {
  flex: 1;
  width: 100%;
  max-width: 1120px; /* the homepage rail -- matches .header-inner--wide exactly */
  margin: 0 auto;
  padding: 1.25rem 2rem 1rem;
  display: flex;
  flex-direction: column;
  /* 2026-10-10: space-between, not the plain stacking gap alone --
     .landing has exactly two children (<BrandRevealHero/>, .landing-foot-
     row), and .landing's OWN box height is already fixed by the page
     geometry (.landing-page's 100dvh, header's fixed height), independent
     of either child's content. Needed once BrandRevealHero's caption
     became content-driven (brand-reveal.css's own comment on
     .brand-reveal-caption) instead of a constant fixed height -- with
     plain stacking, .landing-foot-row's Y position would drift every
     time the caption grows or shrinks a bubble, directly violating the
     earlier, explicit "CTA size/position must never change, regardless
     of whatever else is happening on screen" requirement. space-between
     pins the foot row to .landing's bottom edge regardless of how tall
     the hero's content happens to be at any instant -- `gap` becomes a
     MINIMUM distance between them rather than the actual spacing, so the
     visual gap above the chip/CTA row can grow past 20px when the
     caption is short, but the row's own position never does. Confirmed
     live: this is the correct trade-off per Jonah's own stated priority
     (position stability over a perfectly constant gap). */
  justify-content: space-between;
  gap: 1rem;
  /* Without this a flex child refuses to shrink below its content's intrinsic
     height, which is how a "100dvh" page still manages to overflow. */
  min-height: 0;
}

/* ---- The one piece of selling copy on the page ------------------------------
 * Two lines, total. Jonah: "the job of the landing page is to encourage people to
 * create their basalmind account so i don't want to waste too much time trying to
 * convince people... i am very confident in basalmind's ability to sell itself, we
 * just need to help users see it for themselves." Everything that used to argue
 * the case in prose is now something the visitor can click instead. */
.landing-head {
  text-align: center;
  flex: 0 0 auto;
}

.landing-head h1 {
  font-size: clamp(1.4rem, 3.2vw, 2rem);
  line-height: 1.25;
  color: var(--basal-text-bright);
  margin: 0;
}

.landing-head p {
  font-size: clamp(0.85rem, 1.5vw, 0.95rem);
  color: var(--basal-text-muted);
  margin: 0.4rem 0 0;
}

/* ---- Stage: tabs | wheel | moment ------------------------------------------- */
.landing-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  gap: 1.25rem;
  align-items: center;
  /* Mobile-first: one column, tabs as a horizontal row above the wheel. The
     3-column desktop shape is the media query at the bottom of this file. */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}

/* The wheel's own column. .sunburst-wrap (preview-wheel.css) caps itself at
   min(100%,320px) regardless of viewport, so this just centres it. */
.landing-wheel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  max-width: 320px;
}

/* ---- Life tabs --------------------------------------------------------------
 * The same four dimensions the app's own habits tab uses, same round-ball
 * treatment. Horizontal here on mobile (the app stacks them vertically at every
 * width) because this page has no vertical room to spare and does have horizontal
 * room above the wheel. */
.life-tabs {
  display: flex;
  flex-direction: row;
  gap: 0.75rem;
  justify-content: center;
  flex: 0 0 auto;
}

.life-tab {
  all: unset;
  box-sizing: border-box;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0.55;
  background: radial-gradient(circle at 32% 28%, var(--basal-surface-mid), var(--basal-surface-low) 70%);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.07), 0 1px 3px rgba(0, 0, 0, 0.5);
  transition: opacity 120ms ease, box-shadow 120ms ease;
}

.life-tab svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--basal-text-secondary);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.life-tab:hover,
.life-tab:focus-visible { opacity: 0.85; }
.life-tab:focus-visible { box-shadow: 0 0 0 2px var(--basal-accent-light); }

.life-tab.is-active {
  opacity: 1;
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.07), 0 0 0 1px var(--basal-accent-border), 0 1px 3px rgba(0, 0, 0, 0.5);
}

.life-tab.is-active svg { stroke: var(--basal-accent-light); }

/* ---- The moment panel -------------------------------------------------------
 * Deliberately NOT the app's .segment-detail-panel (which preview-wheel.css
 * declines to port): that panel is a data-capture surface for a signed-in
 * person's real habits. This one shows an authored exchange for whichever wedge
 * is focused. Same wheel, different payload. */
.moment-panel {
  width: 100%;
  max-width: 520px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: 0.6rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--basal-border);
  border-radius: 12px;
  background: var(--basal-surface-low);
}

.moment-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex: 0 0 auto;
}

.moment-title {
  font-size: 0.95rem;
  color: var(--basal-text-heading);
  margin: 0;
  font-weight: 600;
}

/* ---- Per-moment honesty badge ----------------------------------------------
 * This replaces the single page-wide "The real BasalBuddy engine -- not a mockup"
 * badge the old hero carried. That claim was true of its one sleep storyline and
 * false of most of what this page now shows: pantry extraction and recipe lookup
 * both route through the person's OWN connected vendor, so they are not the free
 * mechanical tree. Keeping one page-wide badge over BYOK-tier moments would have
 * made the page's most trust-building element its least true one. The badge is
 * per-moment now, and says which tier each one actually needs. */
.moment-tier {
  flex: 0 0 auto;
  font-family: var(--basal-font-sans);
  font-size: 0.65rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid var(--basal-border);
  color: var(--basal-text-dim);
}

.moment-tier[data-tier="free"] {
  color: var(--basal-accent-light);
  border-color: var(--basal-accent-border);
}

/* 'soon' is the one tier that must never read as a feature. Dimmer than the rest,
   no accent, matching the dashed/uncolored treatment its wedges get on the wheel. */
.moment-tier[data-tier="soon"] {
  color: var(--basal-text-ghost);
  border-style: dashed;
}

/* The scrolling member of the panel, and the only scrolling element on the page.
   A long exchange scrolls HERE rather than growing the page past the viewport --
   that is what keeps "no scrolling on the landing page" true without capping how
   much an individual moment is allowed to say. */
.moment-body {
  /* flex-grow deliberately 0, not 1. Growing it to fill the panel is what produced
     a tall, mostly-empty bordered box in the app's own equivalent panel -- Jonah,
     reviewing that one live: "on mobile, we are wasting about 35% of the screen...
     with empty space." Same lesson applied here rather than re-learned: the body
     sizes to its own content, and `flex-shrink:1` plus `min-height:0` is what lets
     a long exchange shrink it and scroll INSIDE it instead of growing the page. */
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.moment-turn {
  font-size: 0.9rem;
  line-height: 1.5;
  margin: 0;
  padding: 0.5rem 0.75rem;
  border-radius: 10px;
  max-width: 92%;
}

.moment-turn--bot {
  align-self: flex-start;
  background: var(--basal-surface-mid);
  color: var(--basal-text-secondary);
  border-bottom-left-radius: 3px;
}

.moment-turn--you {
  align-self: flex-end;
  background: var(--basal-accent-glow);
  border: 1px solid var(--basal-accent-border);
  color: var(--basal-text);
  border-bottom-right-radius: 3px;
}

/* An empty wedge's panel. Status information, not an apology -- the same
   distinction the app's own habits tab draws when it keeps "Coming soon." on
   placeholder tabs but cut "Tap a segment to see that habit." */
.moment-empty {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--basal-text-dim);
  margin: 0;
}

.moment-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  flex: 0 0 auto;
}

.moment-chip {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  font-family: var(--basal-font-sans);
  font-size: 0.8rem;
  line-height: 1.35;
  padding: 0.4rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--basal-accent-border);
  color: var(--basal-text-secondary);
  transition: background-color 120ms ease, color 120ms ease;
}

.moment-chip:hover,
.moment-chip:focus-visible {
  background: var(--basal-accent-glow);
  color: var(--basal-text-bright);
}

.moment-chip:focus-visible { outline: 2px solid var(--basal-accent-light); outline-offset: 2px; }

/* The chip that does the page's actual job. One per moment, always last. */
.moment-chip--cta {
  background: var(--basal-accent);
  border-color: var(--basal-accent);
  color: var(--basal-bg);
  font-weight: 600;
}

.moment-chip--cta:hover,
.moment-chip--cta:focus-visible {
  background: var(--basal-accent-light);
  color: var(--basal-bg);
}

/* ---- Closing row: the reassurance chip + the persistent Create Account --
 * 2026-10-10 (Jonah): this used to be plain text in --basal-text-ghost, the
 * SAME color/size as .footer-nav's links right below it, so the two visually
 * read as one group, and the cosmic/starfield background (ambient-field.js)
 * sitting behind the whole page ate into its already-low contrast. A small
 * pill now gives it its own quiet surface -- holds contrast regardless of
 * what the starfield is doing behind it at any instant -- and separates it
 * from the real footer nav without competing with the hero's CTAs: still
 * small, still muted (one step brighter than ghost, not all the way to an
 * accent color), no fill/border bold enough to read as a third button.
 *
 * 2026-10-10, same-day mobile-optimization follow-up (Jonah): "Create
 * Account" (shortened from "Create free account" -- the chip right next to
 * it already explains no card is required) now sits to the right of this
 * chip, structurally -- see index.astro's own comment on #landing-cta-
 * account for why. .landing-foot-row is the new wrapper making the two
 * elements one fixed row; .landing-foot itself (the chip, still a <p>, not
 * a link -- see test_landing_foot_has_no_link) is unchanged other than
 * losing its own self-centering, which the row now does for both
 * children. */
.landing-foot-row {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

/* 2026-10-10 (Jonah): "let's also wait to paint the no credit card required
   chip until the same moment the CTAs appear." Same keyframe/timing
   brand-reveal.css's own .brand-reveal-cta uses for the hero's CTAs --
   --brand-reveal-peak lives on :root now specifically so this file (the
   chip and #landing-cta-account aren't descendants of .brand-reveal-hero)
   can reference the identical instant. No pulse here -- the chip never
   had one, only the Create Account button does. */
.landing-foot {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0.8rem;
  border-radius: 999px;
  background: var(--basal-surface-low);
  border: 1px solid var(--basal-border-faint);
  font-size: 0.8rem;
  color: var(--basal-text-dim);
  opacity: 0;
  transform: translateY(6px);
  animation: brand-reveal-cta-in 0.18s var(--brand-reveal-peak) both;
}

@media (prefers-reduced-motion: reduce) {
  .landing-foot {
    animation: brand-reveal-cta-in 0.01s var(--brand-reveal-peak) both;
  }
}

.landing-foot svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  stroke: var(--basal-accent);
  opacity: 0.85;
}

/* #landing-cta-account itself is styled by brand-reveal.css's
   .brand-reveal-cta / .brand-reveal-cta--primary (reused, not duplicated --
   see that file's own comment on the #landing-cta-account rule). Sized
   down slightly from the hero's own CTAs here, since this one now has to
   share a row with the chip at every viewport, including the narrowest
   phones -- flex:0 0 auto keeps it from ever stretching or shrinking with
   whatever else is in the row, which is the actual "size... should not
   change" requirement, not just a visual choice. */
#landing-cta-account {
  flex: 0 0 auto;
  font-size: 0.8rem;
  padding: 0.5rem 0.85rem;
  gap: 0.3rem;
  display: inline-flex;
  align-items: center;
}

/* ---- Desktop: tabs | wheel | moment, side by side ---------------------------
 * 900px, not the 768px the app's own legend branch uses: this page needs room for
 * a 320px wheel AND a readable panel beside it, which 768px does not give. The
 * legend deliberately keeps its mobile (edge-radius) placement at every width
 * here -- see the component's own comment on _positionLegend for why the app's
 * desktop branch does not apply to this layout. */
@media (min-width: 900px) {
  /* 2026-10-10 (Jonah): "on a desktop the controls bar is hiding
     underneath the cta button." Root cause: .brand-reveal-hero went
     flex-shrink:0 the same session (brand-reveal.css) to stop its
     children overflowing ITS OWN box -- correct fix for that bug, but it
     exposed a real, separate budget problem underneath: at this
     breakpoint the stage caps at 480px (not the 400px this padding/gap
     was tuned against), and once the caption also went to a genuinely
     fixed 88px (BL#17309), hero's real combined content (480 stage + 2
     gaps + 88 caption + 44 controls = 652px) measurably overflowed
     .landing's available content budget by ~35px at 1280x900 (confirmed
     live via scrollHeight > clientHeight) -- and once a flex container's
     content genuinely overflows, justify-content:space-between stops
     guaranteeing the chip/CTA row stays pinned to the bottom edge; it
     silently degrades to flex-start-like packing instead, which is
     exactly why the row visibly dropped down into/past the controls.
     padding trimmed here, .brand-reveal-hero's own internal gap trimmed
     alongside it (brand-reveal.css) -- together they reclaim ~40px,
     comfortably covering the deficit without shrinking anything visually
     prominent (the stage, the caption's own line count). */
  .landing { padding: 1rem 2rem 0.75rem; gap: 0.75rem; }

  .landing-stage {
    grid-template-columns: auto minmax(0, 320px) minmax(0, 1fr);
    justify-items: stretch;
    gap: 1.5rem;
  }

  .life-tabs { flex-direction: column; align-self: center; }

  /* Sizes to its own content, NOT stretched to the row height. `height: 100%`
     here produced a very tall bordered box with its exchange floating in the
     middle of it -- the same "mostly-empty container reads as wasted space"
     failure the app's own detail panel already learned once. The grid's
     align-items:center is what centres it against the wheel instead. */
  .moment-panel { max-width: none; align-self: center; }
}

/* ---- Phones -----------------------------------------------------------------
 * Everything stacks here, so the viewport budget is genuinely tight: the site
 * header wraps to two rows at this width, and the wheel, the tabs, the panel and
 * the footer all have to fit under it. Measured live at 390x844 rather than
 * estimated -- the first attempt overflowed by ~300px and cut the CTA chip off the
 * bottom of the screen, which is a worse failure than scrolling would have been.
 * The wheel is what gives: it is the biggest single block, and it stays perfectly
 * legible smaller.
 *
 * 2026-10-10 (Jonah, mobile optimization pass): most of this page's own real
 * estate logic changed again, now that the wheel is gone and BrandRevealHero
 * (not .landing-wheel/.life-tab/.moment-panel -- all three dead on this page
 * since BL#17194, kept here per that same orphaned-not-deleted precedent) is
 * what actually fills the viewport. Three separate asks, same breakpoint:
 *
 * 1. "do we even need any side margins at all... or should we go clear to
 *    the edge?" -- .landing's own horizontal padding drops to 0 here, so
 *    .brand-reveal-stage (which has none of its own) renders genuinely
 *    edge-to-edge, true-to-life size rather than letterboxed. Content rows
 *    that still need breathing room (the caption, the CTA rows, the fixed
 *    chip+account row) get their OWN padding-inline below instead -- the
 *    stage is the one thing meant to go all the way to the glass.
 * 2. The site header -- "one single row especially on mobile... move the
 *    login button to the far right, minimal right margin... completely
 *    remove the Resources link... rename Documentation to Docs on
 *    mobile." Resources is gone from the markup entirely (index.astro),
 *    not hidden here. Documentation/Docs is two spans already in the
 *    markup, toggled below -- no JS. flex-wrap:nowrap plus tighter
 *    padding/gaps is what keeps "Logo | Docs Blog | [user icon] Log In"
 *    on one line down to 360px (measured live, not assumed).
 * 3. Forward/restart/mute going icon-only (BrandRevealHero.astro) also
 *    needed the caption's min-height raised here -- at this width the
 *    longest real caption ("Decide. Prepare. Do. -- shown, not just
 *    explained.") wraps to two lines, and an unguarded min-height would
 *    let that reflow push the fixed bottom row down exactly when Jonah
 *    said its position must never change. */
.nav-label-short { display: none; }

@media (max-width: 899px) {
  .site-header { padding: 0.85rem 0.75rem 0.85rem 1rem; }
  .header-inner { flex-wrap: nowrap; }
  /* main.css's own .site-nav carries flex-wrap:wrap as its base rule --
     header-inner's nowrap only keeps the LOGO and the nav from wrapping
     relative to EACH OTHER; without this, the nav's own three children
     (Docs, Blog, the Log In button) still wrapped onto a second line
     inside the nav's own box, which is what was actually causing the
     two-row header at narrow widths, not header-inner. Caught live at
     360px -- 390px alone didn't surface it, the items happened to still
     fit there by coincidence. */
  .site-nav { flex-wrap: nowrap; gap: 0.75rem; }
  .nav-label-full { display: none; }
  .nav-label-short { display: inline; }

  /* 2026-10-10 (Jonah): "make the top of the slideshow start after only a
     small margin below the header, like 20px... move the control bar...
     down to appear only about 20px above the credit card chip and create
     account cta." padding-top and gap both move to 1.25rem (20px) --
     gap is what actually sets the space between BrandRevealHero's own
     last row (the restart/breadcrumbs/forward controls) and
     .landing-foot-row (the chip + CTA) below it, since those are
     .landing's only two children. Horizontal padding stays 0 -- untouched
     by this, see this file's own earlier comment on that. */
  .landing { padding: 1.25rem 0 0.5rem; gap: 1.25rem; }

  .brand-reveal-caption,
  .brand-reveal-ctas,
  .brand-reveal-demo-controls {
    padding-inline: 1rem;
  }

  /* Tighter than the others above -- this is the one row where two
     fixed-content elements (the chip, the account button) have to share a
     line at the narrowest supported width (measured live at 360px, not
     just 390px) without wrapping, which is the actual "position must never
     change" requirement for this specific pair. */
  .landing-foot-row { padding-inline: 0.75rem; gap: 0.5rem; }
}

/* 360px (a real, common phone width -- iPhone SE/mini-class devices, not a
   guess) is narrow enough that the chip+button pair above still wrapped
   even after the 899px breakpoint's own tightening -- measured live, not
   assumed: 191px + 159px + gap + row padding totalled ~384px against a
   360px viewport. This is the one additional cut needed to close that
   last gap, scoped tightly so it never touches the room this pair already
   has at 390px and up. */
@media (max-width: 400px) {
  .landing-foot { font-size: 0.74rem; padding: 0.35rem 0.65rem; gap: 0.3rem; }
  .landing-foot svg { width: 12px; height: 12px; }
  #landing-cta-account { font-size: 0.74rem; padding: 0.45rem 0.7rem; }
  .landing-foot-row { gap: 0.4rem; padding-inline: 0.5rem; }

  /* Overrides preview-wheel.css's ported `min(100%, 320px)` -- the app's own cap,
     set for a viewport that does not also carry a marketing header and footer.
     Overriding here rather than editing the ported file keeps that file a true
     verbatim copy (see its header). */
  .landing-wheel,
  .landing-wheel .sunburst-wrap { width: min(100%, 248px); max-width: 248px; }

  .landing-head h1 { font-size: 1.2rem; }
  /* The sub-line goes on a phone. At this width the site header wraps to two rows
     and the footer nav to two more -- 312px of preserved chrome (Jonah: the header
     and footer "are the way i want them") out of a 740px screen. The h1 still says
     what the page is, and the wedge the visitor taps says the rest. */
  .landing-head p { display: none; }
  .landing-foot { font-size: 0.75rem; }

  .life-tab { width: 34px; height: 34px; }
  .life-tab svg { width: 16px; height: 16px; }

  /* The panel takes whatever is left and scrolls inside itself. Without the
     explicit row sizing the grid gives every row its content height and the
     column overruns the viewport instead. */
  .landing-stage { grid-template-rows: auto auto minmax(0, 1fr); gap: 0.6rem; }
  .moment-panel { min-height: 0; padding: 0.7rem 0.8rem; }
  .moment-turn { font-size: 0.85rem; }
}

/* Short viewports (a laptop at 1280x720, a phone in landscape) have no room for
   both the heading and a full-height panel. The sub-line is the part that can give
   -- the h1 still says what the page is; the panel is what the visitor came to
   click. */
@media (max-height: 700px) {
  .landing-head h1 { font-size: 1.15rem; }
  .landing-head p { display: none; }
  .landing { gap: 0.6rem; padding-top: 0.75rem; }
}

/* ---- Phone, landscape -------------------------------------------------------
 * 2026-10-10 (Jonah): "when i flip the phone sideways, the layout is terrible...
 * the header and side margins are way too tall." A real phone turned sideways is
 * a DIFFERENT shape problem from either "desktop" (900px+ width, generous height)
 * or "phone, portrait" (narrow width, generous height) -- it's narrow-ish width
 * AND short height at once, so neither existing breakpoint fits it: the 900px
 * width query assumes room this doesn't have, and the 899px-max-width query's own
 * numbers (20px top padding, a near-full-height square stage) were tuned for a
 * TALL narrow viewport, not a short wide one.
 *
 * max-height:500px, not a width check -- orientation:landscape alone would also
 * catch a genuine desktop/laptop window, which has an entirely different budget
 * problem (plenty of height to spare). Every common phone's landscape height
 * (iPhone SE 375, iPhone 14 390, 14 Pro Max 430, Pixel-class devices in the same
 * range) sits comfortably under 500px; a desktop window would need to be
 * unusually short to accidentally match this, an acceptable edge case rather
 * than one worth a more complex check (e.g. pointer:coarse, which does not
 * reliably distinguish all real phones either).
 *
 * The actual stage/caption/controls GRID (the "square slideshow and chat
 * bubble scroller side by side" part) lives in brand-reveal.css, right after
 * .brand-reveal-hero's own base rule, NOT here -- cssFiles loads this file
 * BEFORE brand-reveal.css (index.astro), so a same-specificity override
 * written in THIS file for a property brand-reveal.css's own unconditional
 * base rule also sets (display/width/height/max-width) loses the cascade
 * regardless of whether the media query matches: equal specificity falls
 * back to source order, and brand-reveal.css's plain rule simply comes
 * later. Confirmed live, not assumed -- the grid rule was first written
 * here and silently never applied (computed display stayed "flex"). This
 * block only keeps what genuinely belongs to it: .site-header/.landing,
 * whose OWN base rules already live in this same file, so no cross-file
 * ordering conflict exists for them. */
@media (orientation: landscape) and (max-height: 500px) {
  .site-header { padding: 0.35rem 0.75rem; }
  .landing { padding: 0.5rem 0.75rem; gap: 0.5rem; }
  .landing-foot-row { padding-inline: 0; }

  /* 2026-10-10 (Jonah): "should we put the copyright on the same row as
     the other footer links, so we can make the footer smaller, when
     space conservation is the most important... landscape does not have
     much height in it innately." .footer-nav and .footer-copyright are
     plain stacked siblings (Layout.astro) in every other context; here
     their shared parent becomes a single centered flex row instead, and
     both elements' own stacking margins (.footer-nav's margin-bottom,
     .footer-copyright's margin-top -- both from main.css, tuned for the
     stacked case) are zeroed since there's no longer a second line to
     separate from. */
  .site-footer { padding: 0.35rem 0.75rem; }
  .site-footer .container {
    display: flex;
    align-items: baseline;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
  }
  .footer-nav { margin-bottom: 0; }
  .footer-copyright { margin-top: 0; }
}
