/* AudioPress platform shared layer. Builds on base.css (design tokens,
   reset, base type, dark-mode palette). Classes/ids only — no bare element
   selectors (those would leak between marketing and dashboard surfaces).
   All motion is gated behind `prefers-reduced-motion: no-preference`. */

.platform-page {
  /* Wider than a reading column — this is a marketing surface that should make
     use of large screens. */
  --page-max: 72rem;
}

/* The platform's light "daytime studio" runs a touch dimmer + warmer than
   base.css's default light page: the near-white default reads glary on this
   large marketing surface and over-sharpens the contrast with the dark studio
   hardware. Light only — base.css's dark palette wins on specificity
   (`:root:not([data-theme="light"])` / `[data-theme="dark"]` both beat a bare
   `:root`), and this stylesheet is platform-only, so tenant sites are
   untouched. */
:root {
  --bg: hsl(40 32% 93.5%);
  --surface: hsl(42 42% 98%);
  /* The brand row of the header, stated rather than left to its content.

     Almost nothing needs this any more. A bar that docks under the header is
     rendered *inside* it, and the DOM stacks the two — that is the fix for a
     problem no arithmetic here could solve, because the header is content-sized
     and a sum of "row plus padding" double-counts under `box-sizing:
     border-box` the moment the content wins. The error grew with zoom, since
     only one side of the comparison tracked the text size: bars sat up to 19px
     behind the header, and 69px once it wrapped.

     What is left reading these are the few places that cannot nest — a jump
     target's `scroll-margin`, and the one bar on the show board that lives in
     the region datastar patches. Where the header is only this row, the stated
     value is exact; where the page puts more rows inside it, `dash-dock.js`
     publishes the real box instead. */
  --platform-header-block: 3.5rem;
  /* The section-jump row under the brand on the shows index. Stated for the
     same reason: `scroll-margin` on the headings it jumps to reads this number
     rather than re-deriving the row from its own padding. */
  --dash-section-nav-block: 2.75rem;
  --platform-sticky-header-block: calc(
    var(--min-tap) +
    (2 * var(--space-2xs)) +
    var(--space-3xs) +
    env(safe-area-inset-top, 0px)
  );
}

/* ---- Shared bits -------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-block-size: var(--min-tap);
  padding-block: var(--space-2xs);
  padding-inline: clamp(var(--space-s), 4vw, var(--space-l));
  font: inherit;
  font-weight: 600;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  max-inline-size: 100%;
  line-height: 1.12;
  text-align: center;
  white-space: normal;
  overflow-wrap: anywhere;
}
.btn:focus-visible {
  text-decoration: none;
}

/* A button-styled link (`a.btn`) must not pick up the global `a:hover`
   underline (`base.css`) — its specificity would otherwise win on hover. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover {
    text-decoration: none;
  }
}

.btn:disabled,
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.55;
  transform: none;
  box-shadow: none;
}
/* A Save that is mid-save (`dashboard.js` `holdSave`). It is held with
   `aria-disabled` so it keeps focus, but it must not read as "nothing to save":
   full strength, a progress cursor, and a sheen sweeping across it while the
   request is out. The sweep is motion, so reduced-motion users keep the rest. */
.btn[data-state="saving"] {
  cursor: progress;
  opacity: 1;
}
@media (prefers-reduced-motion: no-preference) {
  .btn[data-state="saving"] {
    background-image: linear-gradient(
      100deg,
      transparent 30%,
      color-mix(in oklab, var(--on-accent) 22%, transparent) 50%,
      transparent 70%
    );
    background-size: 250% 100%;
    background-repeat: no-repeat;
    animation: btn-saving-sweep 1.2s linear infinite;
  }
  @keyframes btn-saving-sweep {
    from {
      background-position: 100% 0;
    }
    to {
      background-position: -150% 0;
    }
  }
}
.btn-small {
  min-block-size: auto;
  padding-block: var(--space-3xs);
  padding-inline: var(--space-s);
}
.btn-primary {
  color: var(--on-accent);
  background: var(--accent);
}
.btn-ghost {
  color: var(--text);
  background: transparent;
  border-color: var(--border);
}
@media (prefers-reduced-motion: no-preference) {
  .btn {
    transition:
      transform var(--dur-quick) var(--ease-out),
      box-shadow var(--dur-default) var(--ease-out),
      filter var(--dur-quick) var(--ease-out);
  }
  @media (hover: hover) and (pointer: fine) {
    .btn-primary:hover {
      transform: translateY(-2px);
      box-shadow: 0 8px 24px -8px var(--accent);
    }
    .btn-ghost:hover {
      border-color: var(--muted);
    }
  }
  .btn:active {
    transform: translateY(0) scale(0.98);
  }
}

/* ---- Shared page containers -------------------------------------------- */

/* Public platform panels and signed-in dashboard mains both use `.panel` as
   their centred, padded page container. Keep the foundation in the shared
   layer; surface bundles may specialize it without owning its geometry. */
.panel {
  inline-size: 100%;
  min-inline-size: 0;
  max-inline-size: var(--page-max);
  margin-inline: auto;
  padding-block: clamp(var(--space-xl), 6vw, var(--space-2xl));
  padding-inline: clamp(var(--space-s), 4vw, var(--space-xl));
}
.panel > h2 {
  font-size: var(--step-2);
  letter-spacing: 0;
  text-align: center;
  text-wrap: balance;
}
.panel-lead {
  max-inline-size: 52ch;
  margin-inline: auto;
  color: var(--muted);
  font-size: var(--step-0);
  text-align: center;
}

/* ---- Chrome ------------------------------------------------------------- */

.platform-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  /* Keep chrome contrast independent of the content scrolling underneath. */
  background: var(--bg);
  border-block-end: 1px solid var(--border);
}
.platform-header-inner,
.hero-inner,
.features-inner,
.platform-footer {
  inline-size: 100%;
  max-inline-size: var(--page-max);
  margin-inline: auto;
  padding-inline: clamp(var(--space-s), 4vw, var(--space-xl));
}
.platform-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Wrap at ANY width: when the nav can't sit beside the brand it drops to its
     own full row (rather than squishing + wrapping internally with the toggle
     orphaned). `row-gap` separates the two rows when that happens. Above the
     breakpoint this is overridden — see the stated-height block below. */
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-s);
  padding-block: var(--space-2xs);
  min-block-size: var(--min-tap);
}

/* The header used to be pinned to one row of a stated height above this
   breakpoint, and the nav was told to scroll within itself rather than wrap, so
   that the height stayed true. Both are gone.

   `overflow-x: auto` makes an element a scroll container, and a scroll
   container clips its absolutely-positioned descendants — so the account menu,
   which hangs off the nav, was cut off at the nav's own 32px row. The menu is
   the taller thing by far; there was nothing to see.

   Nothing needs the height stated any more: a bar that docks is a row *of* the
   header, and the DOM stacks it. What is left below is the fallback value for
   the few places that cannot nest — a first paint before `dash-dock.js`
   measures the real box, and a jump target's `scroll-margin`. */
@media (min-width: 34.001rem) {
  :root {
    --platform-sticky-header-block: calc(
      var(--platform-header-block) +
      1px +
      env(safe-area-inset-top, 0px)
    );
  }
}
.brand-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  /* Let a long show-context name ellipsis instead of shoving the nav. */
  min-inline-size: 0;
}
.platform-brand {
  flex: none;
  font-size: var(--step-1);
  font-weight: 800;
  letter-spacing: 0;
  color: var(--text);
  text-decoration: none;
}
.platform-brand .brand-press {
  color: var(--accent);
}
/* "You are in this show" context beside the wordmark (show-detail page): a quiet
   separator + the show name linking back to the show, truncated when cramped so
   the nav keeps its row. The sticky header keeps it in view while scrolling. */
.brand-sep {
  flex: none;
  color: var(--border);
  font-size: var(--step-1);
  user-select: none;
}
.platform-brand-show {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: var(--step-0);
  font-weight: 600;
  text-decoration: none;
}
.platform-brand-show:focus-visible {
  color: var(--accent);
}
@media (hover: hover) and (pointer: fine) {
  .platform-brand-show:hover {
    color: var(--accent);
  }
}

/* The relocated "beta" mark — a quiet pill beside the wordmark, not a banner.
   A leading "live" dot ties it to the studio theme. */
.beta-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.2rem 0.6rem;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  background: color-mix(in oklab, var(--accent) 13%, transparent);
  border: 1px solid color-mix(in oklab, var(--accent) 34%, transparent);
  border-radius: var(--radius-pill);
}
.beta-tag::before {
  content: "";
  inline-size: 0.4em;
  block-size: 0.4em;
  border-radius: var(--radius-pill);
  background: var(--accent);
}
@media (prefers-reduced-motion: no-preference) {
  .beta-tag::before {
    animation: beta-pulse 2.4s ease-in-out infinite;
  }
}
@keyframes beta-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.3;
  }
}
.platform-nav {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  /* Grow to fill the space right of the brand (items right-aligned). When the
     header stacks the nav onto its own row below the breakpoint, this makes it
     span the full width and lay out on one tidy line — never squished beside
     the brand. */
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.platform-nav a:not(.btn) {
  color: var(--muted);
  text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .platform-nav a:not(.btn):hover {
    color: var(--text);
  }
}

@media (max-width: 34rem) {
  /* On phones the header already stacks (brand row, nav row — see the general
     `flex-wrap` above). Drop the decorative beta tag to reclaim width and keep
     the nav to one internal row; if it needs more width, that row scrolls
     within itself instead of changing the sticky offset. */
  :root {
    --platform-sticky-header-block: calc(
      (2 * var(--min-tap)) +
      (3 * var(--space-2xs)) +
      var(--space-3xs) +
      env(safe-area-inset-top, 0px)
    );
  }

  .beta-tag {
    display: none;
  }
  .platform-nav {
    flex-wrap: nowrap;
    gap: var(--space-s);
    justify-content: flex-start;
    overflow: visible;
    font-size: var(--step--1);
  }
  .platform-nav > * {
    flex: none;
  }
  .platform-nav > .user-menu {
    flex: 1 1 auto;
    min-inline-size: 0;
  }
  .user-menu-trigger {
    max-inline-size: 100%;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* Dark/light theme toggle — same markup + classes as the tenant banner, so the
   shared base.css palette flips and this just styles the button + swaps the
   sun/moon glyph for the effective scheme. The button (unlike the text links)
   stays visible at every width. */
.theme-toggle {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--min-tap);
  block-size: var(--min-tap);
  padding: 0;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover {
    background: color-mix(in oklab, var(--text) 9%, transparent);
  }
}

.theme-glyph {
  inline-size: 1.25rem;
  block-size: 1.25rem;
}
/* Show the glyph for the *current* effective scheme: default follows the OS
   (prefers-color-scheme); an explicit override (`:root[data-theme]`) wins. */
.theme-icon {
  display: none;
  line-height: 0;
}
.theme-icon-sun {
  display: inline-flex;
}
@media (prefers-color-scheme: dark) {
  .theme-icon-sun {
    display: none;
  }
  .theme-icon-moon {
    display: inline-flex;
  }
}
:root[data-theme="light"] .theme-icon-sun {
  display: inline-flex;
}
:root[data-theme="light"] .theme-icon-moon {
  display: none;
}
:root[data-theme="dark"] .theme-icon-sun {
  display: none;
}
:root[data-theme="dark"] .theme-icon-moon {
  display: inline-flex;
}

.platform-footer {
  padding-block: var(--space-l);
  color: var(--muted);
  text-align: center;
}
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  justify-content: center;
  margin-block-end: var(--space-2xs);
}
.footer-links a {
  color: var(--muted);
  text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .footer-links a:hover {
    color: var(--text);
  }
}

/* Keep anchor jumps clear of the sticky header. */
#subscribe,
#features,
#demo {
  scroll-margin-block-start: 5rem;
}
/* Authentication/status success state shared by public and dashboard pages. */

/* ---- Auth-flow motion: success check + card entrances -------------------- */

/* A self-drawing success check — shown on the email-confirm page
   (`.panel-status.is-success`) and the first post-sign-in dashboard view
   (`.dashboard-welcome`). Decorative + `aria-hidden` (the heading carries the
   message). Default — and the reduced-motion state — is a static, fully-drawn
   check; the keyframes below only add the spring-in + draw. */
.success-check {
  display: block;
  inline-size: clamp(3rem, 9vw, 3.75rem);
  block-size: clamp(3rem, 9vw, 3.75rem);
  margin: 0 auto var(--space-m);
  color: hsl(151 55% 45%);
  filter: drop-shadow(0 0 12px hsl(151 55% 45% / 0.4));
}
.success-check-ring,
.success-check-tick {
  transform-box: fill-box;
  transform-origin: center;
}
/* `stroke-dashoffset: 0` = drawn by default, so no-JS / reduced-motion shows the
   whole tick; the keyframe draws it in from fully retracted. */
.success-check-tick {
  stroke-dasharray: 32;
  stroke-dashoffset: 0;
}
/* The dashboard's welcome check sits a touch smaller, above the heading. */
.dashboard-welcome .success-check {
  inline-size: clamp(2.5rem, 7vw, 3rem);
  block-size: clamp(2.5rem, 7vw, 3rem);
  margin-block-end: var(--space-s);
}

@media (prefers-reduced-motion: no-preference) {
  /* Each step of the flow rises + fades as it loads.

     `backwards`, not `both`. `both` keeps applying the animated properties
     after the animation ends, and an animated `transform` that has settled
     back to no movement still computes to the identity matrix rather than to
     `none` -- which makes the element a containing block for every
     `position: fixed` descendant, permanently. That is invisible until
     something inside wants to be fixed to the viewport: the people board's
     floating link was pinned to the foot of `.dashboard-main` instead, four
     thousand pixels down the page, and only for readers who had *not* asked
     for reduced motion. `backwards` fills before the animation starts, which
     is all an entrance needs, and releases the element afterwards. */
  .login-card,
  .panel-status {
    animation: card-rise 420ms var(--ease-out) backwards;
  }
  /* The dashboard is somewhere people move around in, many times a session:
     a 420ms rise on every page is a first-visit flourish that turns into a
     wait by the tenth. A short settle keeps the page from snapping in without
     ever holding up the reader who already knows where they are going. */
  .dashboard-main {
    animation: dashboard-settle 180ms var(--ease-out) backwards;
  }
  /* Success beat: the ring springs in, then the tick draws across it. */
  .panel-status.is-success .success-check-ring,
  .dashboard-welcome .success-check-ring,
  .account-celebration .success-check-ring {
    animation: check-ring 480ms var(--ease-out) both;
  }
  .panel-status.is-success .success-check-tick,
  .dashboard-welcome .success-check-tick,
  .account-celebration .success-check-tick {
    animation: check-tick 360ms var(--ease-out) 300ms both;
  }
}
@keyframes card-rise {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}
@keyframes dashboard-settle {
  from {
    opacity: 0.4;
    translate: 0 3px;
  }
}
@keyframes check-ring {
  from {
    opacity: 0;
    transform: scale(0.4);
  }
  60% {
    transform: scale(1.06);
  }
}
@keyframes check-tick {
  from {
    stroke-dashoffset: 32;
  }
}
