/* ==========================================================================
   La Flora Garden — Custom Ghost Theme
   Colors: #f8f5f0 bg, #0707b7 primary, #0b02f7 hover, #b08f3d gold, #5e5e50 disabled
   Fonts: Elstob (display), Inter (body)
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Elstob';
  src: url('../fonts/Elstob/Elstob.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Elstob';
  src: url('../fonts/Elstob/Elstob-Italic.woff2') format('woff2');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter/InterVariable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter/InterVariable-Italic.woff2') format('woff2');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   Custom Properties
   -------------------------------------------------------------------------- */

:root {
  /* Colors */
  --color-bg: #f8f5f0;
  --color-primary: #0707b7;
  --color-hover: #b08f3d;
  --color-visited: #05058a;
  --color-disabled: #5e5e50;
  --color-bg-alt: #f0ebe3;

  /* Typography. Defers to Ghost admin's font picker (Settings → Design →
     Branding → Typography) via --gh-font-heading / --gh-font-body; falls
     back to Elstob/Inter when the admin hasn't picked anything. */
  --font-serif: var(--gh-font-heading, 'Elstob', Charter, Georgia, 'Times New Roman', Times, serif);
  --font-sans: var(--gh-font-body, 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);

  /* Scale — dramatic jumps for editorial feel */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.375rem;
  --text-2xl: 1.75rem;
  --text-3xl: 2.25rem;
  --text-4xl: 3rem;
  --text-5xl: 4rem;
  --text-hero: 5.5rem;

  /* Spacing */
  --space-xs: 0.25rem;
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2.5rem;
  --space-2xl: 4rem;
  --space-3xl: 6rem;
  --space-4xl: 10rem;

  /* Layout */
  --container-max: 1200px;
  --reading-max: 680px;
  --header-height: 72px;

  /* Text-role defaults. Each named role drives a class of elements site-wide
     (block titles, body prose, list-item titles, list-item descriptions, meta
     captions). Iara overrides any of these via Ghost admin → Customize, which
     emits matching :root rules in default.hbs. Defaults below match the
     "(default)" option in each select. */
  --title-font: var(--font-serif);
  --title-style: normal;
  --title-weight: 400;
  --title-color: var(--color-primary);

  --body-font: var(--font-sans);
  --body-style: normal;
  --body-weight: 400;
  --body-color: var(--color-primary);

  --list-title-font: var(--font-serif);
  --list-title-style: normal;
  --list-title-weight: 400;
  --list-title-color: var(--color-primary);

  --list-description-font: var(--font-sans);
  --list-description-style: normal;
  --list-description-weight: 400;
  --list-description-color: var(--color-disabled);

  --meta-font: var(--font-sans);
  --meta-style: normal;
  --meta-weight: 400;
  --meta-color: var(--color-disabled);
}

/* --------------------------------------------------------------------------
   Reset & Base
   -------------------------------------------------------------------------- */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--color-primary);
  background-color: var(--color-bg);
  min-height: 100vh;
}

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-serif);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

h1 { font-size: var(--text-hero); }
h2 { font-size: var(--text-4xl); }
h3 { font-size: var(--text-3xl); }
h4 { font-size: var(--text-2xl); }
h5 { font-size: var(--text-xl); }
h6 { font-size: var(--text-lg); }

@media (max-width: 768px) {
  h1 { font-size: var(--text-4xl); }
  h2 { font-size: var(--text-3xl); }
  h3 { font-size: var(--text-2xl); }
}

@media (max-width: 375px) {
  h1 { font-size: var(--text-3xl); }
  h2 { font-size: var(--text-2xl); }
}

p {
  margin-bottom: var(--space-md);
}

/* --------------------------------------------------------------------------
   Links
   -------------------------------------------------------------------------- */

a {
  color: var(--color-primary);
  text-decoration: none;
  transition: color 0.2s ease;
}

a:hover,
a:visited:hover {
  color: var(--color-hover);
}

a:visited {
  color: var(--color-primary);
}

a.lf-link--disabled,
a[aria-disabled="true"] {
  color: var(--color-disabled);
  pointer-events: none;
  cursor: default;
}

/* Navigation links should not show visited state */
.lf-header__action,
.lf-header__action:visited,
.lf-footer__link,
.lf-footer__link:visited {
  color: var(--color-primary);
}

.lf-header__action:hover,
.lf-footer__link:hover {
  color: var(--color-hover);
}

/* --------------------------------------------------------------------------
   Content Typography — for post/page body
   -------------------------------------------------------------------------- */

.lf-post__content,
.lf-page__content {
  font-size: var(--text-base);
  line-height: 1.75;
}

.lf-post__content p,
.lf-page__content p {
  margin-bottom: var(--space-lg);
}

.lf-post__content a,
.lf-page__content a {
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

.lf-post__content blockquote,
.lf-page__content blockquote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-lg);
  border-left: 2px solid var(--color-primary);
  padding-left: var(--space-lg);
  margin: var(--space-xl) 0;
}

.lf-post__content ul,
.lf-post__content ol,
.lf-page__content ul,
.lf-page__content ol {
  padding-left: var(--space-lg);
  margin-bottom: var(--space-lg);
}

.lf-post__content li,
.lf-page__content li {
  margin-bottom: var(--space-xs);
}

.lf-post__content img,
.lf-page__content img {
  max-width: 100%;
  height: auto;
  display: block;
  margin: var(--space-xl) 0;
}

.lf-post__content figure,
.lf-page__content figure {
  margin: var(--space-xl) 0;
}

.lf-post__content figcaption,
.lf-page__content figcaption {
  font-size: var(--text-sm);
  color: var(--color-disabled);
  margin-top: var(--space-sm);
  text-align: center;
}

.lf-post__content hr,
.lf-page__content hr {
  border: none;
  border-top: 1px solid var(--color-primary);
  opacity: 0.2;
  margin: var(--space-2xl) 0;
}

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

.lf-container {
  max-width: var(--container-max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-lg);
  padding-right: var(--space-lg);
}

.lf-reading {
  max-width: var(--reading-max);
  margin-left: auto;
  margin-right: auto;
}

/* Album L2 pages (`/<album-slug>/`): widen the reading column. The
   `.lf-reading` 680px max was forcing the album description (a short
   tagline) to wrap with awkward orphans and large negative space on
   wide screens. Body content on these pages is typically just the
   intro audio card — no prose that needs the narrow column. Mirrors
   the no-max-width fix already applied to `.lf-album__description`
   on the L1 page. */
body.tag-hash-album .lf-reading {
  max-width: 56rem;
}

/* L2 album page — inline album player + click-to-play track list.
   Layout: player at top, track list below. Reuses the `.lf-album__list`
   CSS counter for "01 / 02 / 03+" track numbering. */
.lf-album-l2 {
  margin: var(--space-xl) 0 var(--space-lg);
}
.lf-album-l2__list { margin-top: var(--space-lg); }

/* Active row — highlighted; numbering + title shift to the hover/active
   color so the user always knows what's playing. */
.lf-album__item--current {
  background: rgba(7, 7, 183, 0.06);
}
.lf-album__item--current .lf-album__item-title {
  color: var(--color-hover);
  font-weight: 500;
}

/* Row-button variant — rows are <button>s on L2 (click-to-play) instead
   of <a>s. Reset native button look and inherit the row layout. */
.lf-album__item-link--row {
  appearance: none;
  background: transparent;
  border: none;
  padding: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
  /* Match `.lf-album__item-link`'s flex layout + counter prefix. The
     `.lf-album__item-link::before` pseudo applies because we keep the
     base class on the button. */
}
.lf-album__item-link--row:hover .lf-album__item-title {
  color: var(--color-hover);
}

/* "Now playing" strip above the controls — small caps label + serif title. */
.lf-player__now-playing {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  padding: var(--space-xs) 0 var(--space-sm);
  border-bottom: 1px solid rgba(7, 7, 183, 0.08);
  margin-bottom: var(--space-sm);
}
.lf-player__now-label {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-disabled);
}
.lf-player__track-title {
  font-size: var(--text-lg);
  color: var(--color-primary);
}

/* Ambience disabled state — visually mute the controls so it's clear they
   don't apply when Intro or Letter is the active track. Matches the
   pattern letters.js uses for the homepage Meditation Player block. */
.lf-player__ambient--disabled {
  opacity: 0.35;
  pointer-events: none;
  filter: grayscale(0.6);
}

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

/* Padlock icon for paid-only items. Inherits text color so it follows the
   role color rule on the locked title. Sized in em so it scales with the
   surrounding text. */
.lf-lock-icon {
  display: inline-block;
  width: 0.75em;
  height: 0.75em;
  margin-left: 0.4em;
  vertical-align: -0.05em;
  flex-shrink: 0;
}

/* Generic font-family utilities. Wrapped in :where() so they have zero
   specificity — any role-driven rule wins automatically. */
:where(.lf-serif) {
  font-family: var(--font-serif);
}

:where(.lf-sans) {
  font-family: var(--font-sans);
}

/* ============================================================
   Text Roles — drive font / style / weight / color from
   custom theme settings. See :root above for defaults; Iara
   overrides any of these in Ghost admin → Customize.
   ============================================================ */

/* Role: title — block headings, post/page H1, album titles, Sessions page
   title and "Your sessions" section header. */
.lf-block__title,
.lf-album__title,
.lf-post__title,
.lf-page__title,
.lf-sessions-play__title,
.lf-sessions-saved__title {
  font-family: var(--title-font);
  font-style: var(--title-style);
  font-weight: var(--title-weight);
  color: var(--title-color);
}

/* Role: body — block descriptions, album descriptions, post/page reading body,
   Sessions now-playing title and description, empty/complete states. The
   now-title gets an italic override below. */
.lf-block__body,
.lf-album__description,
.lf-post__content,
.lf-page__content,
.lf-sessions-play__now-title,
.lf-sessions-play__now-description,
.lf-sessions-play__empty,
.lf-sessions-play__complete,
.lf-sessions-saved__empty {
  font-family: var(--body-font);
  font-style: var(--body-style);
  font-weight: var(--body-weight);
  color: var(--body-color);
}

/* Role: list_title — items in preview lists, album track lists, Sessions
   queue items, saved session names, Continue Listening track title. */
.lf-block__item-title,
.lf-album__item-title,
.lf-item__title,
.lf-sessions-queue__title,
.lf-sessions-saved__name,
.lf-continue__title {
  font-family: var(--list-title-font);
  font-style: var(--list-title-style);
  font-weight: var(--list-title-weight);
  color: var(--list-title-color);
}

/* Role: list_description — short descriptions next to list items. */
.lf-block__item-excerpt,
.lf-item__excerpt {
  font-family: var(--list-description-font);
  font-style: var(--list-description-style);
  font-weight: var(--list-description-weight);
  color: var(--list-description-color);
}

/* Role: meta — dates, tags, small captions, toggle labels, Sessions hints
   and counts and form labels and status text and Continue banner meta. */
.lf-post__date,
.lf-item__date,
.lf-album__item-date,
.lf-post__tag,
.lf-album__tracks-toggle-label,
.lf-sessions-play__hint,
.lf-sessions-queue__num,
.lf-sessions-saved__count,
.lf-sessions-save__label,
.lf-sessions-save__status,
.lf-continue__label,
.lf-continue__pos {
  font-family: var(--meta-font);
  font-style: var(--meta-style);
  font-weight: var(--meta-weight);
  color: var(--meta-color);
}

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

.lf-header {
  padding: var(--space-md) 0;
}

.lf-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.lf-header__left,
.lf-header__right {
  display: flex;
  gap: var(--space-md);
  min-width: 120px;
}

.lf-header__right {
  justify-content: flex-end;
}

.lf-header__action {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.lf-header__center {
  flex: 1;
  display: flex;
  justify-content: center;
}

.lf-header__logo-img {
  max-width: 420px;
  width: 100%;
  height: auto;
  display: block;
}

/* On tablet/phone: stack header vertically so the logo keeps its presence and
   the account/subscribe/sign-in actions wrap onto a row below it. */
@media (max-width: 768px) {
  .lf-header__inner {
    flex-direction: column;
    gap: var(--space-md);
  }

  .lf-header__left,
  .lf-header__right,
  .lf-header__center {
    min-width: 0;
    width: 100%;
    justify-content: center;
  }

  .lf-header__logo-img {
    max-width: 420px;
  }
}

@media (max-width: 375px) {
  .lf-header__action {
    font-size: var(--text-xs);
  }
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.lf-hero__tagline {
  font-size: var(--text-xl);
  font-weight: 400;
  text-align: center;
  padding: var(--space-sm) 0;
}

@media (max-width: 768px) {
  .lf-hero__tagline {
    font-size: var(--text-lg);
  }
}

/* --------------------------------------------------------------------------
   Ripple panels — text that visitors play with via mouse. The .lf-ripple-panel
   element is the source-of-truth for fonts/colors/emphasis; the JS module
   reads its computed style and replaces its content with a canvas overlay
   while preserving the original text off-screen for accessibility.
   -------------------------------------------------------------------------- */

.lf-ripple-panel {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 220px;
  font-size: var(--text-md);
  line-height: 1.45;
  color: var(--color-primary);
  /* JS module replaces this content with a canvas; cursor hints interactivity. */
  cursor: crosshair;
  overflow: hidden;
  /* Capture touch gestures for the ripple effect; otherwise the browser
     interprets touchmove as a scroll and our pointermove handler stops firing. */
  touch-action: none;
}
.lf-ripple-panel em { font-style: italic; }
.lf-ripple-panel strong { font-weight: 600; }
/* Heading sizes inside the ripple panel must match the multipliers used by
   the canvas layout in text-ripple.mjs (HEADING_FACTORS). Otherwise the
   pre-JS HTML render shows headings at full global size, then "snaps" to the
   smaller canvas size when JS kicks in. Matching them eliminates the flash.
   Margins are zeroed because the canvas layout has none either. */
.lf-ripple-panel h1 { font-size: calc(var(--text-md) * 1.6); margin: 0; line-height: 1.45; font-weight: inherit; }
.lf-ripple-panel h2 { font-size: calc(var(--text-md) * 1.35); margin: 0; line-height: 1.45; font-weight: inherit; }
.lf-ripple-panel h3 { font-size: calc(var(--text-md) * 1.18); margin: 0; line-height: 1.45; font-weight: inherit; }
.lf-ripple-panel h4 { font-size: calc(var(--text-md) * 1.05); margin: 0; line-height: 1.45; font-weight: inherit; }
.lf-ripple-panel h5,
.lf-ripple-panel h6 { font-size: var(--text-md); margin: 0; line-height: 1.45; font-weight: inherit; }
.lf-ripple-panel p { margin: 0; }
/* Middle ripple panel (Row 3, narrow column) needs more room — text wraps more. */
.lf-row--three .lf-ripple-panel { min-height: 380px; }
.lf-ripple__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

@media (max-width: 768px) {
  .lf-ripple-panel { font-size: var(--text-sm); min-height: 180px; }
}

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

/* --------------------------------------------------------------------------
   Blocks — Homepage
   -------------------------------------------------------------------------- */

.lf-block {
  padding: var(--space-xl) 0;
  position: relative;
}

/* --------------------------------------------------------------------------
   Homepage Grid — Rows
   -------------------------------------------------------------------------- */

.lf-homepage {
  border: 2px solid rgba(7, 7, 183, 0.25);
  max-width: var(--container-max);
  margin: var(--space-md) auto;
}

@media (max-width: 1232px) {
  .lf-homepage {
    margin-left: var(--space-lg);
    margin-right: var(--space-lg);
  }
}

.lf-row {
  display: grid;
  grid-template-columns: 1fr 2fr;
  align-items: stretch;
}

.lf-row + .lf-row {
  border-top: 2px solid rgba(7, 7, 183, 0.25);
}

.lf-row--three {
  grid-template-columns: 1fr 1.5fr 1fr;
}

.lf-row--full {
  grid-template-columns: 1fr;
}

/* On tablet, 2-col rows become stacked */
@media (max-width: 768px) {
  .lf-row,
  .lf-row--three,
  .lf-row--stippling {
    grid-template-columns: 1fr;
  }

  .lf-row .lf-block + .lf-block {
    border-top: 2px solid rgba(7, 7, 183, 0.25);
    border-left: 0;
  }
}

/* Blocks: only vertical dividers between siblings */
.lf-row .lf-block {
  padding: var(--space-lg);
  background: var(--color-bg);
  min-width: 0;
  overflow: hidden;
}

@media (min-width: 769px) {
  .lf-row .lf-block + .lf-block {
    border-left: 2px solid rgba(7, 7, 183, 0.25);
  }
}

.lf-block__inner {
  position: relative;
}

.lf-block__title {
  font-size: var(--text-xl);
  font-weight: 400;
  margin-bottom: var(--space-md);
}

.lf-block__title--clickable {
  cursor: pointer;
  transition: color 0.2s ease;
}
.lf-block__title--clickable:hover,
.lf-block__title--clickable:focus-visible {
  color: var(--color-hover);
  outline: none;
}

.lf-block--meditation-player .lf-block__body {
  margin-bottom: var(--space-xl);
}
.lf-block--meditation-player .lf-block__body .kg-audio-card {
  display: none;
}

.lf-block__expand {
  position: absolute;
  top: calc(var(--space-lg) * -1 + var(--space-xs));
  right: calc(var(--space-lg) * -1 + var(--space-xs));
  font-family: var(--font-sans);
  font-size: 1.75rem;
  font-weight: 500;
  color: var(--color-primary);
  cursor: pointer;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s ease;
  user-select: none;
}

.lf-block__expand:hover {
  color: var(--color-hover);
}

/* Postcard Club's "+" is decorative only (feature is post-launch).
   Cancel the cursor and the gold hover so it doesn't look interactive. */
.lf-block--postcard-club .lf-block__expand {
  cursor: default;
}
.lf-block--postcard-club .lf-block__expand:hover {
  color: var(--color-primary);
}

.lf-block__body {
  line-height: 1.7;
}

/* Center any Koenig image card sitting inside a block body. Koenig's
   <figure class="kg-image-card"> defaults to margin:0 (left-aligned)
   inside narrow containers — these auto margins re-center it. */
.lf-block__body .kg-image-card,
.lf-block__body figure {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.lf-block__body .kg-image-card img,
.lf-block__body figure img {
  margin-left: auto;
  margin-right: auto;
  display: block;
}

/* --------------------------------------------------------------------------
   Meditations homepage block — horizontal album strip
   -------------------------------------------------------------------------- */

.lf-vinyl-icon {
  display: block;
  width: 100%;
  height: 100%;
}

/* Animated turntable: vinyl record + tonearm.
   - Three angle anchors (rest / play-start / play-end) are CSS variables so
     they can be tuned live in DevTools without re-editing.
   - Tonearm pivot is at (72%, 14.2%) of its source PNG (computed via centroid
     of the top-band opaque pixels). Image is positioned so that pivot point
     lands at (--tonearm-pivot-x, --tonearm-pivot-y) within the stage.
   - Vinyl record image (1920×1080, disc centered) is sized so the disc fits
     the stage; the surrounding transparent margins overflow the stage and are
     hidden via the stage's overflow:hidden. The tonearm is allowed to
     overflow visibly upward / rightward.
   - JS writes --tonearm-angle for tonearm rotation, --record-angle for the
     vinyl spin (driven by a per-card rAF loop). Transitions are CSS-only on
     the tonearm (smooth ease for needle drop / lift); the vinyl runs without
     transition and JS sets the angle each frame. */
.lf-vinyl-stage {
  --rest-angle: -20deg;
  /* play-start-angle: needle on outer groove. Geometric solve put the
     headshell centroid exactly at disc-edge at -13°, but the visible needle
     TIP is slightly past the centroid, so it read as "outside the vinyl."
     -10° brings the centroid 0.18rem inside the edge and the tip onto the
     outer groove. */
  --play-start-angle: -10deg;
  /* play-end-angle: needle stops short of the inner label, leaving a small
     gap between needle and label (mimicking the lead-out region on a real
     LP). Inner label edge measured at radius 110px in the source PNG;
     stopping the needle at radius ~140px gives ~30px (0.2rem) of visible
     gap. +8° puts the headshell roughly at that radius. */
  --play-end-angle: 8deg;
  --tonearm-angle: var(--rest-angle);
  --record-angle: 0deg;
  --tonearm-pivot-x: 92%;
  --tonearm-pivot-y: 6%;

  position: relative;
  width: 100%;
  height: 100%;
  /* overflow:visible is safe here — the vinyl image's surrounding margins
     are fully transparent (alpha=0), so they don't paint anything outside
     the disc. Visibility lets the tonearm's pivot ring render freely past
     the stage edges (it sits in the upper-right corner and would otherwise
     clip a few pixels at top and right). */
  overflow: visible;
}

.lf-vinyl-stage__record {
  position: absolute;
  /* Record image is 1920×1080. The visible disc is centered VERTICALLY at
     ~50.04% but offset HORIZONTALLY: its centroid is at (48.68%, 50.04%) of
     the image, not (50%, 50%). Translate and transform-origin both use those
     coordinates so the disc is centered on the stage AND rotates around its
     own visual center.
     Disc fills 34.4% of source image width. Display width 220% of stage
     gives a disc diameter ≈ 4.55rem in a 6rem stage (good margin for the
     tonearm pivot in the upper-right and visible cream around the disc). */
  width: 220%;
  height: auto;
  left: 50%;
  top: 50%;
  transform-origin: 48.68% 50.04%;
  transform: translate(-48.68%, -50.04%) rotate(var(--record-angle));
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

.lf-vinyl-stage__tonearm {
  position: absolute;
  width: 2.2rem;            /* tonearm display width — sized so shaft length
                               ≈ 1.6 × disc-radius, matching the original SVG */
  height: auto;             /* preserves 326:638 native aspect */
  /* Position the IMG so its pivot point lands at (--tonearm-pivot-x,
     --tonearm-pivot-y) of the stage. transform-origin matches the same
     internal point so rotation is around the visible pivot. */
  left: var(--tonearm-pivot-x);
  top: var(--tonearm-pivot-y);
  transform-origin: 72% 14.2%;
  transform: translate(-72%, -14.2%) rotate(var(--tonearm-angle));
  transition: transform 0.75s cubic-bezier(0.83, 0, 0.17, 1);
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* During audio playback, the rAF loop drives --tonearm-angle every frame
   from audio.currentTime. The CSS transition would add a ~750ms lag between
   the rAF target and the visible angle, which makes resume-after-pause land
   farther inward than where the user saw the needle at pause. Disabling the
   transition while sweeping keeps the visual angle exactly synchronised with
   audio progress; the transition is restored for the discrete drop/lift. */
.lf-vinyl-stage.is-sweeping .lf-vinyl-stage__tonearm {
  transition: none;
}


/* Layout: chevrons are flex siblings of the scrolling list, NOT absolutely
   positioned over it. The list has no padding — overflow-x:auto clips
   cleanly at the list's right edge. No peek possible.
       Strip width  = 100%
       Chevron      = 2.5rem each (× 2 = 5rem)
       Gap chevron↔list = 1.5rem each (× 2 = 3rem)
       List width   = 100% - 8rem
       Cards        = (list width - inter-card gaps) / N */
.lf-album-strip {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  margin-top: var(--space-md);
}

.lf-album-strip__list {
  flex: 1;
  min-width: 0;
  list-style: none;
  margin: 0;
  /* padding-top gives the tonearm's pivot ring breathing room above each
     card — overflow-y:hidden (required because overflow-x:auto can't pair
     with overflow-y:visible) would otherwise clip the few pixels of ring
     that extend above the 6rem vinyl box. */
  padding: 0.5rem 0 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 2rem) / 3);
  gap: 1rem;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.lf-album-strip__list::-webkit-scrollbar {
  display: none;
}

/* Chevron prev/next — flex siblings, no absolute positioning. JS toggles
   disabled at scroll boundaries. */
.lf-album-strip__nav {
  flex-shrink: 0;
  appearance: none;
  background: var(--color-bg);
  border: 1.5px solid var(--color-primary);
  border-radius: 50%;
  width: 2.5rem;
  height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  /* Active sits near 0.35 — same visual weight as the block border so the
     chevron doesn't out-shout its container. Hover bumps to full opacity
     for clear affordance. Disabled drops to 0.12 so inactive < active. */
  opacity: 0.35;
  transition: opacity 0.15s ease, background-color 0.2s ease, color 0.2s ease;
}
.lf-album-strip__nav:hover {
  opacity: 1;
  background: var(--color-primary);
  color: var(--color-bg);
}
.lf-album-strip__nav:disabled {
  opacity: 0.12;
  cursor: default;
  pointer-events: none;
}
.lf-album-strip--no-overflow .lf-album-strip__nav { display: none; }

/* Tablet: 2 cards visible. List = 100% - 8rem (chevrons + gaps).
   Cards = (list - 1 × 1rem) / 2 = (100% - 1rem) / 2. */
@media (max-width: 1023px) {
  .lf-album-strip__list {
    grid-auto-columns: calc((100% - 1rem) / 2);
  }
}


/* Each card is a 2-column / 2-row grid:
       │  Vinyl spans both rows (takes the full card height) │  Title    │
       │                                                     │  Player   │
   Title and Player divide the right column equally so each takes half
   the vinyl's height. The link wraps vinyl + title and uses display:
   contents so its children participate directly in the grid (button
   can't be nested inside an anchor, so the player sits outside). */
.lf-album-strip__item {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: 1fr 1fr;
  column-gap: var(--space-md);
  scroll-snap-align: start;
  min-width: 0;
}
.lf-album-strip__link {
  display: contents;
  text-decoration: none;
  color: inherit;
}
.lf-album-strip__link:hover .lf-album-strip__title {
  color: var(--color-hover);
}
.lf-album-strip__vinyl {
  grid-row: 1 / 3;
  width: 6rem;
  height: 6rem;
  cursor: pointer;
}
.lf-album-strip__title {
  grid-row: 1;
  grid-column: 2;
  align-self: center;
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.2;
  word-break: break-word;
  cursor: pointer;
}
.lf-album-strip__item > .lf-album__intro-source {
  display: none;
}
.lf-album-strip__item > .lf-player--strip {
  grid-row: 2;
  grid-column: 2;
  align-self: center;
  margin-top: 0;
}

/* Mobile: 1 card visible. List = 100% - 8rem. Card fills the list.
   Card collapses to a single-column stack: title, Play Intro player, then
   the turntable animation underneath (centered horizontally so the prev/next
   chevrons — flex-centered vertically — bracket it visually). This media
   block sits AFTER the base .lf-album-strip__* rules so its overrides win on
   source order; placing it earlier silently lost to the later base rules. */
@media (max-width: 640px) {
  .lf-album-strip__list {
    grid-auto-columns: 100%;
  }
  .lf-album-strip__item {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    row-gap: var(--space-sm);
  }
  .lf-album-strip__title,
  .lf-album-strip__item > .lf-player--strip,
  .lf-album-strip__vinyl {
    grid-column: 1;
  }
  .lf-album-strip__title { grid-row: 1; }
  .lf-album-strip__item > .lf-player--strip { grid-row: 2; }
  .lf-album-strip__vinyl {
    grid-row: 3;
    justify-self: center;
    margin-top: var(--space-sm);
  }
}

/* Strip player — just play/pause icon + "Play Intro" label, no progress
   bar or duration. */
.lf-player--strip {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.lf-player--strip .lf-player__play {
  appearance: none;
  background: transparent;
  border: 1.5px solid var(--color-primary);
  border-radius: 50%;
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  color: var(--color-primary);
  transition: background-color 0.2s ease, color 0.2s ease;
}
.lf-player--strip .lf-player__play:hover {
  background: var(--color-primary);
  color: var(--color-bg);
}
.lf-player--strip .lf-player__icon-play,
.lf-player--strip .lf-player__icon-pause {
  font-size: 0.7em;
  line-height: 1;
}
.lf-player--strip .lf-player__icon-pause { display: none; }
.lf-player--strip.lf-player--playing .lf-player__icon-play { display: none; }
.lf-player--strip.lf-player--playing .lf-player__icon-pause { display: inline; }
.lf-album-strip__intro-label {
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   Teaser image used by the About blocks (and any future block that wants
   a feature-image hero). Iara sets the page's Feature image in Ghost
   admin and the block crops it gently.
   -------------------------------------------------------------------------- */
.lf-block__image {
  display: block;
  width: 100%;
  max-height: 280px;
  object-fit: cover;
  margin-bottom: var(--space-md);
  border-radius: 2px;
}

.lf-block__hint {
  font-size: var(--text-sm);
  color: var(--color-disabled);
  font-style: italic;
}

/* Block preview items (field notes, meditations) */
.lf-block__preview {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.lf-block__item-link {
  display: block;
  padding: var(--space-xs) 0;
}

.lf-block__item-link:visited {
  color: var(--color-primary);
}

.lf-block__item-title {
  font-size: var(--text-base);
}

.lf-block__item-excerpt {
  font-size: var(--text-sm);
}

.lf-block__item-link--locked,
.lf-block__item-link--locked:visited {
  color: var(--color-disabled);
}

.lf-block__item-link--locked .lf-block__item-title {
  color: var(--color-disabled);
}

.lf-block__item-link--locked:hover {
  color: var(--color-hover);
}

/* Decorative blocks */
.lf-block--decorative {
  display: flex;
  align-items: center;
  justify-content: center;
}

.lf-block--decorative .lf-block__inner {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lf-zmap {
  position: relative;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  overflow: hidden;
}

/* Stippling animation block — locks the BLOCK's aspect to the current SVG's
   viewBox exactly. On desktop, the row gives this column 25% more width than
   the default 1fr 2fr so both dimensions grow 25% while aspect stays true to
   the image. On narrow viewports the rule is dropped so the row collapses to
   a single column like the other rows. */
@media (min-width: 769px) {
  .lf-row--stippling {
    grid-template-columns: 1.25fr 1.75fr;
  }
}

.lf-block--stippling {
  --stippling-aspect-w: 1;
  --stippling-aspect-h: 1;
  padding: 0 !important;
  aspect-ratio: var(--stippling-aspect-w) / var(--stippling-aspect-h);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--color-bg);
}

.lf-block--stippling .lf-stippling {
  width: 100%;
  height: 100%;
}

.lf-stippling__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.lf-zmap__static {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  display: block;
  object-fit: contain;
}

.lf-zmap__canvas {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* --------------------------------------------------------------------------
   Post & Page Headers
   -------------------------------------------------------------------------- */

.lf-post__header,
.lf-page__header {
  margin-bottom: 0;
  padding-bottom: var(--space-md);
}

.lf-post__title,
.lf-page__title {
  font-size: var(--text-xl);
  margin: 0;
}

.lf-post__tag {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  display: block;
  margin-bottom: var(--space-sm);
}

.lf-post__date {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--color-disabled);
  display: block;
}

.lf-post .lf-reading,
.lf-page .lf-reading {
  padding: var(--space-md) 0;
}

/* --------------------------------------------------------------------------
   Tag Page (Level 1)
   -------------------------------------------------------------------------- */

.lf-tag-page,
.lf-custom-page,
.lf-explore-page,
.lf-sessions-play,
.lf-post,
.lf-page,
.lf-error {
  border: 2px solid rgba(7, 7, 183, 0.25);
  max-width: var(--container-max);
  margin: var(--space-md) auto;
  padding: var(--space-lg);
  /* Position context for the absolutely-positioned .lf-collapse button
     in the top-right of every page frame. */
  position: relative;
}

@media (max-width: 1232px) {
  .lf-tag-page,
  .lf-custom-page,
  .lf-explore-page,
  .lf-sessions-play,
  .lf-post,
  .lf-page,
  .lf-error {
    margin-left: var(--space-lg);
    margin-right: var(--space-lg);
  }
}

.lf-tag-page {
  padding: var(--space-lg);
}

.lf-tag-page__header {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-md);
  margin-bottom: 0;
  padding-bottom: var(--space-md);
}
.lf-tag-page__header-text {
  min-width: 0;
}
.lf-tag-page__actions {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.lf-tag-page__title {
  font-size: var(--text-xl);
  margin: 0;
}

.lf-tag-page__description,
.lf-page__description,
.lf-block__description {
  margin-top: var(--space-xs);
  /* Bound to the Meta text role from theme design settings (Ghost admin
     → Settings → Design → Customize → Meta), so Iara controls font /
     style / weight / color of all "subtitle under title" copy in one
     place. */
  font-family: var(--meta-font);
  font-style: var(--meta-style);
  font-weight: var(--meta-weight);
  color: var(--meta-color);
  /* Honour line breaks the editor put in the description / excerpt in
     admin — Ghost stores them as plain text, so render newlines as
     <br>-equivalent. */
  white-space: pre-line;
}

.lf-item {
  padding: var(--space-md) 0;
  border-bottom: 1px solid rgba(7, 7, 183, 0.1);
}

.lf-item:last-child {
  border-bottom: none;
}

.lf-item__link {
  display: block;
}

.lf-item__link:visited {
  color: var(--color-primary);
}

.lf-item__title {
  font-size: var(--text-lg);
  font-weight: 400;
  margin-bottom: var(--space-xs);
}

.lf-item__date {
  font-size: var(--text-sm);
  color: var(--color-disabled);
  display: block;
}

/* --------------------------------------------------------------------------
   Item — Locked State
   -------------------------------------------------------------------------- */

.lf-item__link--locked,
.lf-item__link--locked:visited {
  color: var(--color-disabled);
}

.lf-item__link--locked .lf-item__title {
  color: var(--color-disabled);
}

.lf-item__link--locked:hover {
  color: var(--color-hover);
}

/* --------------------------------------------------------------------------
   Meditation Albums (Level 1 Meditations page) — two-level hierarchy:
   each album has a title, description, intro audio player (always playable),
   and a list of its meditations beneath.
   -------------------------------------------------------------------------- */

.lf-album {
  padding: var(--space-lg) 0;
  border-bottom: 1px solid rgba(7, 7, 183, 0.15);
}
.lf-album:last-child { border-bottom: none; }
/* Tighten the gap between the page-frame header and the very first album
   on tag-style L1 pages (Meditations) — about 30% smaller than the
   between-album spacing. */
.lf-album:first-of-type {
  padding-top: var(--space-sm);
}

.lf-album__header {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-lg);
  margin-bottom: var(--space-md);
}
.lf-album__title {
  font-size: var(--text-xl);
  font-weight: 400;
  margin: 0;
}
/* Title link — visually identical to the H2 text but with a hover hint
   that signals it navigates to the L2 album page. */
.lf-album__title-link {
  color: inherit;
  text-decoration: none;
}
.lf-album__title-link:hover {
  color: var(--color-hover);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
/* On phone, break "Album N:" onto its own line so the album name can take
   the full available width. Inline on desktop where there's room for both. */
@media (max-width: 640px) {
  .lf-album__title-prefix {
    display: block;
  }
}
.lf-album__description {
  font-size: var(--text-md);
  color: var(--color-primary);
  opacity: 0.8;
  margin: 0;
  /* No max-width — the page-frame already constrains line length via the
     container border. Capping at 60ch forced the album description to
     wrap mid-line even when the block had plenty of horizontal room. */
}

.lf-album__intro {
  margin: var(--space-md) 0 var(--space-lg) 0;
  max-width: 32rem;
}

.lf-album__list {
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: album-track;
}
.lf-album__item {
  counter-increment: album-track;
  padding: var(--space-sm) 0;
  border-top: 1px solid rgba(7, 7, 183, 0.1);
}
.lf-album__item:first-child { border-top: none; }
.lf-album__item-link {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  text-decoration: none;
}
.lf-album__item-link:visited { color: var(--color-primary); }
.lf-album__item-link::before {
  content: counter(album-track, decimal-leading-zero);
  font-size: var(--text-sm);
  color: var(--color-disabled);
  font-variant-numeric: tabular-nums;
  min-width: 1.6em;
}
.lf-album__item-title {
  font-size: var(--text-lg);
  font-weight: 400;
  flex: 1;
}
.lf-album__item-date {
  font-size: var(--text-sm);
  color: var(--color-disabled);
}
/* Inert row variant — used for Intro and Letter, which are queueable
   tracks (via the select-circle) but not navigable destinations. The
   `::before` counter still increments because it's keyed on the
   .lf-album__item-link class. */
.lf-album__item-link--inert {
  cursor: default;
  color: inherit;
}
.lf-album__item-link--inert:hover { color: inherit; }

.lf-album__item-link--locked,
.lf-album__item-link--locked:visited {
  color: var(--color-disabled);
}
.lf-album__item-link--locked .lf-album__item-title {
  color: var(--color-disabled);
}
.lf-album__item-link--locked:hover { color: var(--color-hover); }

/* Collapsible track list — toggle lives on the right of the album title */
.lf-album__tracks-toggle {
  background: none;
  border: none;
  padding: var(--space-xs) var(--space-sm);
  cursor: pointer;
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-sm);
  flex: 0 0 auto;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-primary);
  user-select: none;
}
.lf-album__tracks-toggle:hover { color: var(--color-hover); }
.lf-album__tracks-toggle:focus-visible {
  outline: 1px solid var(--color-primary);
  outline-offset: 2px;
}
.lf-album__tracks-toggle-arrow {
  display: inline-block;
  font-size: 2.25rem;
  line-height: 1;
  transform: translateY(0.1em);
  transition: transform 0.2s ease;
}
.lf-album--expanded .lf-album__tracks-toggle-arrow {
  transform: translateY(0.1em) rotate(180deg);
}
.lf-album__list {
  margin-top: var(--space-md);
}

/* --------------------------------------------------------------------------
   Simple inline audio player (used for album intros — no ambience controls).
   Inherits the existing .lf-player play button / progress / time styling.
   -------------------------------------------------------------------------- */
.lf-player--simple {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* L1 album-intro player uses the simple variant. Match the play-button
   size to the compact player on L2 + the homepage strip (36×36) so the
   site reads one play-button size across surfaces. */
.lf-player--simple .lf-player__play {
  width: 36px;
  height: 36px;
}

.lf-item__excerpt {
  font-size: var(--text-sm);
  color: var(--color-disabled);
  margin-top: var(--space-xs);
  line-height: 1.5;
}

/* --------------------------------------------------------------------------
   Pagination
   -------------------------------------------------------------------------- */

.lf-pagination {
  padding-top: var(--space-xl);
  text-align: center;
}

.lf-pagination__more {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* --------------------------------------------------------------------------
   Paywall
   -------------------------------------------------------------------------- */

/* Hide the meditation player widget on gated posts by default. The
   the-gate-stream.js script removes the `lf-post--gated` class when it
   confirms ownership via /api/access, which un-hides the player so the
   owner can stream their purchased track. */
.lf-post--gated .lf-player--compact {
  display: none;
}

.lf-post--gated .lf-post__content {
  position: relative;
}

.lf-post--gated .lf-post__content::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 200px;
  background: linear-gradient(to bottom, rgba(248, 245, 240, 0), rgba(248, 245, 240, 0.95));
  pointer-events: none;
}

/* Inline paywall (renders inside post.hbs when {{#if access}} = false).
   Visually re-uses the gate-card layout so the paywall reads as part of the
   same monetization surface as /the-gate/. The wrapper just centers the
   card inside the article width. */
.lf-paywall {
  display: flex;
  justify-content: center;
  padding: var(--space-2xl) var(--space-lg);
  background: rgba(248, 245, 240, 0.85);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.lf-gate-card--paywall {
  max-width: 24rem;
  width: 100%;
  text-align: center;
  background: var(--color-bg);
}

/* Inside the paywall context, the copy reads as the lede (italic serif,
   slightly larger than card-default body) since there's no card title
   above it. */
.lf-gate-card--paywall .lf-paywall__copy {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-md);
  line-height: 1.55;
  opacity: 1;
}

.lf-gate-card--paywall .lf-gate-card__cta {
  /* Two CTAs stacked inside a single card — give each its own block-level
     centering with a meaningful gap so the buttons don't read as one
     control. Use :last-child (not :last-of-type) below because the two
     CTAs are different element types (<a> and <button>) — :last-of-type
     would match BOTH and zero out the gap. */
  margin-bottom: var(--space-md);
}
.lf-gate-card--paywall .lf-gate-card__cta:last-child {
  margin-bottom: 0;
}

/* "Already a member? Sign in." link — appears only for non-members on a
   paywall, below the two buy/walk-in CTAs. Visually subordinate: smaller
   italic serif in muted color; the "Sign in." span carries the gold
   underline so the eye lands there. */
.lf-gate-card--paywall .lf-gate-card__signin {
  display: block;
  margin-top: var(--space-md);
  text-align: center;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-sm);
  color: var(--color-disabled);
  text-decoration: none;
}
.lf-gate-card--paywall .lf-gate-card__signin span {
  color: var(--color-hover);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.lf-gate-card--paywall .lf-gate-card__signin:hover span,
.lf-gate-card--paywall .lf-gate-card__signin:focus-visible span {
  color: var(--color-primary);
}

/* Overlay variant needs extra top padding so the body copy doesn't crowd
   the absolute-positioned close X in the top-right corner. Compound
   selector (.lf-gate-card AND .lf-gate-card--paywall-overlay on the same
   element) bumps specificity to 2 classes — required because the base
   `.lf-gate-card { padding: var(--space-lg) }` rule appears LATER in the
   file and would otherwise reset padding-top via the shorthand. */
.lf-gate-card.lf-gate-card--paywall-overlay {
  padding-top: calc(var(--space-2xl) + var(--space-xs));
}

/* Suppress Ghost Portal's built-in paywall CTA */
.gh-post-upgrade-cta,
.gh-post-upgrade-cta-content {
  display: none !important;
}

/* --------------------------------------------------------------------------
   Paywall Overlay (in-page, triggered by locked links)
   -------------------------------------------------------------------------- */

.lf-paywall-overlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1000;
  align-items: center;
  justify-content: center;
}

.lf-paywall-overlay--visible {
  display: flex;
}

.lf-paywall-overlay__backdrop {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Gold-frame retired 2026-05-16 — paywall overlay now uses the gate-card
   layout. The .lf-paywall-overlay__content class is preserved as a
   fallback containing block for any legacy overlay markup; the new
   markup uses .lf-gate-card--paywall-overlay directly. */
.lf-paywall-overlay__content {
  position: relative;
  text-align: center;
  max-width: 480px;
  padding: var(--space-xl) var(--space-2xl);
  background: var(--color-bg);
  border: 1px solid rgba(7, 7, 183, 0.18);
}

.lf-gate-card--paywall-overlay {
  position: relative;
  max-width: 26rem;
  width: calc(100% - 2 * var(--space-lg));
  margin: 0 var(--space-lg);
  box-shadow: 0 10px 40px rgba(7, 7, 183, 0.12);
}

.lf-paywall-overlay__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  font-size: 1.75rem;
  font-weight: 300;
  color: var(--color-primary);
  cursor: pointer;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s ease;
}

.lf-paywall-overlay__close:hover {
  color: var(--color-hover);
}

.lf-paywall-overlay__message {
  font-size: var(--text-lg);
  font-style: italic;
  line-height: 1.6;
  margin-bottom: var(--space-xl);
  color: var(--color-primary);
}

/* Legacy .lf-paywall-overlay__action* rules retired 2026-05-16; the new
   overlay markup uses .lf-gate-card__cta inside .lf-gate-card--paywall-overlay.
   Keep the close button rule (it's still markup-side). */

/* --------------------------------------------------------------------------
   Graph View
   -------------------------------------------------------------------------- */

.lf-graph-view {
  width: 100%;
  min-height: 300px;
  position: relative;
  flex: 1 1 auto;
}

/* On the homepage, let the graph block grow with its row so the live
   canvas fills any extra height a tall neighbor gives it (instead of
   leaving an invisible cropped frame at 300px). Scoped so other places
   that use .lf-graph-view aren't affected. */
.lf-block--graph-view .lf-block__inner {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.lf-graph-view canvas {
  display: block;
  max-width: 100%;
}

.lf-graph-view--full {
  height: 70vh;
  flex: none;
}

.lf-explore-page .lf-container {
  padding: 0;
}

.lf-explore-page__header {
  margin-bottom: var(--space-lg);
}

.lf-explore-page__title {
  font-size: var(--text-xl);
}

/* --------------------------------------------------------------------------
   Audio Player
   -------------------------------------------------------------------------- */

.lf-player {
  margin-top: var(--space-md);
}

.lf-player__track-title {
  font-size: var(--text-lg);
  font-style: italic;
  margin-bottom: var(--space-md);
}

.lf-player__controls {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.lf-player__play {
  background: none;
  border: 1px solid var(--color-primary);
  color: var(--color-primary);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: color 0.2s ease, border-color 0.2s ease;
  font-size: var(--text-sm);
}

.lf-player__play:hover {
  color: var(--color-hover);
  border-color: var(--color-hover);
}

.lf-player__icon-pause {
  display: none;
  font-size: 0.7rem;
  letter-spacing: 2px;
}

.lf-player--playing .lf-player__icon-play {
  display: none;
}

.lf-player--playing .lf-player__icon-pause {
  display: inline;
}

.lf-player__time {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--color-disabled);
  white-space: nowrap;
}

.lf-player__sep {
  margin: 0 2px;
}

.lf-player__progress {
  flex: 1;
  height: 2px;
  background: rgba(7, 7, 183, 0.15);
  cursor: pointer;
  position: relative;
}

.lf-player__progress-fill {
  height: 100%;
  background: var(--color-primary);
  width: 0%;
  transition: width 0.1s linear;
}

/* Ambient controls */
.lf-player__ambient {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid rgba(7, 7, 183, 0.1);
}

.lf-player__ambient-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-disabled);
  margin-bottom: var(--space-sm);
}

.lf-player__ambient-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

.lf-player__ambient-options + .lf-player__ambient-options {
  margin-top: var(--space-sm);
}

/* Compact + Sessions players: ambient controls flow as a single
   flex-wrap row instead of the base hard-coded 2-row + mix-row stack
   used by the homepage "A Meditation" block. The wrap layout
   accommodates phone widths gracefully. */
.lf-player--compact .lf-player__ambient,
.lf-player--sessions .lf-player__ambient {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
}

.lf-player--compact .lf-player__ambient-label,
.lf-player--sessions .lf-player__ambient-label {
  margin-bottom: 0;
}

.lf-player--compact .lf-player__ambient-options,
.lf-player--sessions .lf-player__ambient-options {
  margin-top: 0;
}

.lf-player--compact .lf-player__ambient-options + .lf-player__ambient-options,
.lf-player--sessions .lf-player__ambient-options + .lf-player__ambient-options {
  margin-top: 0;
}

.lf-player--compact .lf-player__ambient-mix,
.lf-player--sessions .lf-player__ambient-mix {
  margin-top: 0;
}

.lf-player__ambient-btn,
.lf-block__cta-btn {
  background: none;
  border: 1px solid rgba(7, 7, 183, 0.2);
  color: var(--color-primary);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--space-xs) var(--space-sm);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.lf-block__cta-wrap {
  text-align: center;
  margin: var(--space-md) 0;
}

.lf-block__cta-btn {
  /* Asymmetric padding for optical vertical centering of all-caps text.
     With line-height: 1, Inter's line-box leaves more empty space below
     the baseline than above the cap-line, so the text reads "too high"
     with symmetric padding — compensate by adding more padding on top. */
  padding: 0.45rem calc(var(--space-sm) * 1.5) 0.3rem;
  line-height: 1;
}

.lf-block__cta-btn:visited {
  color: var(--color-primary);
}

.lf-player__ambient-btn:hover,
.lf-block__cta-btn:hover {
  border-color: var(--color-hover);
  color: var(--color-hover);
}

.lf-player__ambient-btn--active {
  border-color: var(--color-hover);
  color: var(--color-hover);
  background: rgba(176, 143, 61, 0.08);
}

.lf-player__ambient-btn--loading {
  opacity: 0.6;
  animation: lf-ambient-pulse 1.1s ease-in-out infinite;
}

@keyframes lf-ambient-pulse {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 0.85; }
}

.lf-player__ambient-mix {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-sm);
}

.lf-player__ambient-mix-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-disabled);
}

.lf-player__ambient-volume {
  -webkit-appearance: none;
  appearance: none;
  width: 120px;
  height: 2px;
  background: rgba(7, 7, 183, 0.15);
  outline: none;
  cursor: pointer;
}

.lf-player__ambient-volume::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  background: var(--color-primary);
  border: none;
  cursor: pointer;
}

.lf-player__ambient-volume::-moz-range-thumb {
  width: 12px;
  height: 12px;
  background: var(--color-primary);
  border: none;
  border-radius: 0;
  cursor: pointer;
}

/* Compact variant (post pages) */
.lf-player--compact {
  margin-bottom: var(--space-xl);
}

.lf-player--compact .lf-player__controls {
  gap: var(--space-sm);
}

.lf-player--compact .lf-player__play,
.lf-player--sessions .lf-player__play {
  width: 36px;
  height: 36px;
}

/* Phone layout for the in-controls progress bar.
   On narrow viewports the controls row crowds the progress bar between
   the buttons and the timer — on the sessions player especially, it
   compresses to ~90px and is hard to scrub. Wrap the progress bar to its
   own full-width row beneath the buttons + timer (via flex-wrap + an
   order shunt so it lands last), and bump its height so it's actually
   grabbable by a fingertip. */
@media (max-width: 640px) {
  .lf-player--compact .lf-player__controls,
  .lf-player--sessions .lf-player__controls {
    flex-wrap: wrap;
    row-gap: var(--space-sm);
  }
  .lf-player--compact .lf-player__progress,
  .lf-player--sessions .lf-player__progress {
    flex-basis: 100%;
    order: 99;
    height: 6px;
    margin-top: 5px;
  }
}

/* Meditation post layout: tight header, generous space before player */
.lf-post--meditation .lf-post__header {
  margin-bottom: var(--space-md);
  padding-bottom: 0;
}

.lf-post--meditation .lf-post__content .kg-audio-card {
  display: none;
}

.lf-post--meditation .lf-player--compact {
  margin-top: var(--space-2xl);
}

/* --------------------------------------------------------------------------
   Error Page
   -------------------------------------------------------------------------- */

.lf-error .lf-container {
  text-align: center;
  padding: var(--space-4xl) 0;
}

.lf-error__code {
  font-size: var(--text-hero);
  opacity: 0.15;
  line-height: 1;
}

.lf-error__message {
  font-size: var(--text-2xl);
  margin-top: var(--space-md);
}

.lf-error__link {
  display: inline-block;
  margin-top: var(--space-xl);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

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

.lf-footer {
  padding: var(--space-md) 0 var(--space-lg);
}

.lf-footer__inner {
  text-align: center;
}

.lf-footer__links {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.lf-footer__sep {
  color: var(--color-disabled);
}

.lf-footer__copy {
  margin-top: var(--space-lg);
  font-size: var(--text-xs);
  color: var(--color-disabled);
}

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

.lf-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   Page Transitions
   -------------------------------------------------------------------------- */

body {
  transition: opacity 0.25s ease;
}

body.lf-transitioning-out {
  opacity: 0;
}

body.lf-transitioning-in {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  body,
  body.lf-transitioning-out,
  body.lf-transitioning-in {
    transition: none;
    opacity: 1;
  }
}

/* --------------------------------------------------------------------------
   Collapse Button (Level 1 pages — return to homepage)
   -------------------------------------------------------------------------- */

/* Collapse button is absolutely positioned in the top-right of the page
   frame so it doesn't push the title down. Top offset matches the page
   frame's padding so the button sits flush with the inner content area.
   Inside the 40×40 hit area, the "−" glyph is pushed to the top edge
   (align-items: flex-start + line-height: 1) so it visually top-aligns
   with the page title's cap-height instead of sitting centered ~20px
   below it. The hit area itself stays full-size for easy tapping. */
.lf-collapse {
  position: absolute;
  top: calc(var(--space-lg) - 8px);
  right: var(--space-lg);
  z-index: 5;
}

.lf-collapse__btn {
  font-family: var(--font-sans);
  font-size: 1.75rem;
  font-weight: 500;
  line-height: 0.7;
  color: var(--color-primary);
  cursor: pointer;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  transition: color 0.2s ease;
  user-select: none;
  background: none;
  border: none;
  padding: 0;
}

.lf-collapse__btn:hover {
  color: var(--color-hover);
}

/* --------------------------------------------------------------------------
   Ghost Koenig Editor — Required Card Styles
   -------------------------------------------------------------------------- */

.kg-width-wide {
  max-width: 1040px;
  margin-left: auto;
  margin-right: auto;
}

.kg-width-full {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

/* Regular-width Koenig images on Pages render at 50% of the content
   column — Ghost's Regular size felt too large for portraits/about
   imagery. Wide and Full options still apply their own sizing.
   Scoped to .lf-page__content so Posts (meditations/field-notes) are
   unaffected. */
.lf-page__content .kg-image-card:not(.kg-width-wide):not(.kg-width-full) {
  max-width: 50%;
  margin-left: auto;
  margin-right: auto;
}

.kg-gallery-container {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.kg-gallery-row {
  display: flex;
  gap: 0.5rem;
}

.kg-gallery-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kg-bookmark-card {
  width: 100%;
  margin-bottom: var(--space-lg);
}

.kg-bookmark-container {
  display: flex;
  border: 1px solid var(--color-primary);
  text-decoration: none;
  color: var(--color-primary);
  overflow: hidden;
}

.kg-bookmark-content {
  flex: 1;
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
}

.kg-bookmark-title {
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  font-weight: 500;
  line-height: 1.3;
}

.kg-bookmark-description {
  font-size: var(--text-sm);
  margin-top: var(--space-xs);
  opacity: 0.8;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.kg-bookmark-metadata {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: auto;
  padding-top: var(--space-sm);
  font-size: var(--text-xs);
}

.kg-bookmark-icon {
  width: 20px;
  height: 20px;
}

.kg-bookmark-author,
.kg-bookmark-publisher {
  opacity: 0.7;
}

.kg-bookmark-thumbnail {
  width: 180px;
  min-height: 120px;
  flex-shrink: 0;
}

.kg-bookmark-thumbnail img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Sessions feature — Phase A
   Selection circles on Level 1, inline Begin button, Player page.
   -------------------------------------------------------------------------- */

/* Selection circle — used on album titles and individual tracks. Empty by
   default (outlined ring), filled when --on. Album circles get a smaller
   inner dot when --partial (some but not all tracks selected). The same
   class is rendered as both <button> (selectable) and <span> (locked
   variant) — hence display: inline-block so spans honor width/height,
   and box-sizing: border-box so the 1.5px border doesn't change size. */
.lf-select-circle {
  appearance: none;
  background: transparent;
  border: 1.5px solid var(--color-primary);
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  display: inline-block;
  box-sizing: border-box;
  /* Anchor em-resolution at 1rem so button-element bullets (which inherit
     a slightly reduced font-size from the browser default) end up the same
     visual size as span-element bullets in the locked variant. Without
     this, the unlocked button rendered ~15% smaller than the locked span
     in the album track list. */
  font-size: 1rem;
  line-height: 1;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.lf-select-circle:focus-visible {
  outline: 1px solid var(--color-hover);
  outline-offset: 2px;
}
.lf-select-circle:hover {
  border-color: var(--color-hover);
}
.lf-select-circle--on {
  background: var(--color-primary);
  border-color: var(--color-primary);
}
.lf-select-circle--on:hover {
  background: var(--color-hover);
  border-color: var(--color-hover);
}
.lf-select-circle--partial {
  background: radial-gradient(circle, var(--color-primary) 0 35%, transparent 36%);
}
/* Locked circle — rendered as a span on paid-only tracks for free users.
   Inert (no cursor change, no hover), drawn in the muted role color. */
.lf-select-circle--locked {
  border-color: var(--color-disabled);
  cursor: default;
}
.lf-select-circle--locked:hover {
  border-color: var(--color-disabled);
}
/* Album circle sits next to the album h2 inside the .lf-album__header flex
   row (which is `align-items: baseline`). Letting the button baseline-align
   means its bottom edge meets the title's text baseline — the circle then
   sits visually inside the cap height of the title, which reads as aligned. */
/* Unified bullet size — album, unlocked track, locked track all read the
   same visual size. Target is a discreet small dot that sits inside the
   text cap-height (per Leonardo's red-mark on the 11.51 AM screenshot).
   Baseline alignment is set on the PARENT flex container (album header
   and track row both use `align-items: baseline`), so the bullet inherits
   it like the album-title bullet always did. Setting it on the child
   alone produced an empty-inline-block baseline trap (the bullet's
   baseline = its bottom edge, which dragged the whole flex line
   baseline up and pushed the text under the bullet). */
.lf-select-circle--album,
.lf-select-circle--track {
  width: 0.7em;
  height: 0.7em;
}

/* Track row is a flex container so the selection circle sits left of the
   existing link layout (which has its own internal track-number counter).
   `align-items: baseline` so the bullet sits on the same baseline as the
   text — matching the album header's alignment, which is what Leonardo
   wants across all bullet rows. */
.lf-album__item {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
}
.lf-album__item .lf-album__item-link {
  flex: 1;
}
.lf-album__item .lf-track-source {
  display: none;
}

/* Inline Begin button — lives in the .lf-tag-page__header flex row, right
   of the page title/description. Hidden until at least one track is
   selected. Padlocked for non-paid members so the click fires the paywall
   overlay via the existing data-lf-locked path in blocks.js. */
.lf-session-begin {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-lg);
  background: var(--color-bg);
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  border-radius: 999px;
  text-decoration: none;
  font-family: var(--meta-font);
  font-size: var(--text-sm);
  line-height: 1;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  flex-shrink: 0;
  transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
/* Disabled state: paid user with nothing to play (no current selection
   AND no saved sessions). Sessions.js applies/removes this class as
   selection state and saved-sessions count change. */
.lf-session-begin--disabled {
  border-color: var(--color-disabled);
  color: var(--color-disabled);
  cursor: default;
}
/* Base hover only fires when the button isn't in --disabled state, so the
   blue invert doesn't flash on a non-clickable Begin. */
.lf-session-begin:not(.lf-session-begin--disabled):hover {
  background: var(--color-primary);
  color: var(--color-bg);
  transform: translateY(-1px);
}
.lf-session-begin[hidden] {
  display: none;
}
.lf-session-begin__glyph {
  font-size: 1.1em;
  line-height: 1;
}
.lf-session-begin__count {
  font-variant-numeric: tabular-nums;
  min-width: 1ch;
  text-align: center;
}
.lf-session-begin__count:empty {
  display: none;
}
.lf-session-begin .lf-lock-icon {
  width: 0.85em;
  height: 0.85em;
  margin-left: 0.2em;
}

/* Surprise Me — pill button next to Begin in the page header. Same
   shape as Begin so the two read as a pair of session-entry actions. */
.lf-session-surprise {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-lg);
  background: var(--color-bg);
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  border-radius: 999px;
  text-decoration: none;
  font-family: var(--meta-font);
  font-size: var(--text-sm);
  line-height: 1;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  flex-shrink: 0;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.lf-session-surprise:hover {
  background: var(--color-primary);
  color: var(--color-bg);
  transform: translateY(-1px);
}
.lf-session-surprise__glyph {
  font-size: 1.1em;
  line-height: 1;
}
.lf-session-surprise .lf-lock-icon {
  width: 0.85em;
  height: 0.85em;
  margin-left: 0.2em;
}

/* Continue Listening — banner above the album list. Hidden by default;
   sessions.js reveals it once /api/continue returns a non-empty state. */
.lf-continue {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "main    dismiss"
    "resume  resume";
  column-gap: var(--space-md);
  row-gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-xl);
  background: rgba(7, 7, 183, 0.06);
  border: 1px solid rgba(7, 7, 183, 0.18);
  border-radius: 4px;
}
.lf-continue[hidden] { display: none; }
.lf-continue__main {
  grid-area: main;
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  flex-wrap: wrap;
}
.lf-continue__resume {
  grid-area: resume;
  justify-self: start;
}
.lf-continue__dismiss {
  grid-area: dismiss;
  align-self: start;
}
.lf-continue__label {
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.lf-continue__title {
  font-size: var(--text-base);
}
.lf-continue__pos {
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}
.lf-continue__resume {
  appearance: none;
  background: var(--color-bg);
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  border-radius: 999px;
  padding: var(--space-xs) var(--space-md);
  font-family: var(--meta-font);
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.lf-continue__resume:hover {
  background: var(--color-primary);
  color: var(--color-bg);
}
.lf-continue__dismiss {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--color-disabled);
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  padding: var(--space-xs) var(--space-sm);
}
.lf-continue__dismiss:hover { color: var(--color-hover); }

/* Player page at /sessions/play/ — uses the standard page-block frame
   from the .lf-tag-page selector group above (border, max-width, padding).
   Page title and track names sized to match block titles (text-xl) so the
   Player page reads at the same scale as the rest of the site's blocks. */
.lf-sessions-play__header {
  margin-bottom: var(--space-xl);
}
.lf-sessions-play__title {
  font-size: var(--text-xl);
  margin: 0 0 var(--space-xs) 0;
}
.lf-sessions-play__hint {
  font-size: var(--text-sm);
  margin: 0;
}
.lf-sessions-play__empty {
  padding: var(--space-2xl) 0;
}
.lf-sessions-play__now {
  margin-bottom: var(--space-xl);
}
.lf-sessions-play__now-title {
  font-size: var(--text-base);
  margin-bottom: var(--space-xs);
  min-height: 1.4em;
}
.lf-sessions-play__now-description {
  font-size: var(--text-base);
  margin: 0 0 var(--space-md) 0;
}
.lf-sessions-play__now-description[hidden] { display: none; }

/* Sessions player variant. Inherits most styling from .lf-player but adds
   prev/next buttons in the controls strip. */
.lf-player--sessions .lf-player__controls {
  gap: var(--space-sm);
}
.lf-player__prev,
.lf-player__next {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--color-primary);
  cursor: pointer;
  font-size: var(--text-sm);
  padding: var(--space-xs) var(--space-sm);
  letter-spacing: 0.1em;
}
.lf-player__prev:hover,
.lf-player__next:hover {
  color: var(--color-hover);
}

/* Queue list */
.lf-sessions-play__queue {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid rgba(7, 7, 183, 0.12);
}
.lf-sessions-queue__item {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-xs);
  border-bottom: 1px solid rgba(7, 7, 183, 0.1);
  cursor: pointer;
  background: var(--color-bg);
  transition: background-color 0.15s ease;
}
.lf-sessions-queue__item:hover {
  background: rgba(7, 7, 183, 0.04);
}
.lf-sessions-queue__item--current {
  background: rgba(7, 7, 183, 0.08);
}
.lf-sessions-queue__item--current .lf-sessions-queue__title {
  color: var(--color-hover);
}
.lf-sessions-queue__item--dragging {
  opacity: 0.85;
  box-shadow: 0 6px 18px rgba(7, 7, 183, 0.25);
  position: relative;
  z-index: 10;
  cursor: grabbing;
  transition: none;
}
.lf-sessions-queue__handle {
  font-size: var(--text-lg);
  color: var(--color-disabled);
  cursor: grab;
  user-select: none;
  touch-action: none;
  padding: 0 var(--space-xs);
  line-height: 1;
}
.lf-sessions-queue__handle:active {
  cursor: grabbing;
}
.lf-sessions-queue__num {
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  min-width: 1.6em;
}
.lf-sessions-queue__title {
  flex: 1;
  font-size: var(--text-base);
}
.lf-sessions-queue__remove {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--color-disabled);
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  padding: var(--space-xs) var(--space-sm);
}
.lf-sessions-queue__remove:hover {
  color: var(--color-hover);
}

/* Locked queue row — informational only, click opens the paywall overlay.
   Greyed out title + visible padlock signal "buy/subscribe to unlock." */
.lf-sessions-queue__item--locked {
  cursor: pointer;
  background: rgba(7, 7, 183, 0.02);
}
.lf-sessions-queue__item--locked:hover {
  background: rgba(7, 7, 183, 0.05);
}
.lf-sessions-queue__item--locked .lf-sessions-queue__title,
.lf-sessions-queue__item--locked .lf-sessions-queue__num {
  color: var(--color-disabled);
  font-style: italic;
}
.lf-sessions-queue__item--locked .lf-lock-icon {
  color: var(--color-disabled);
  margin-left: var(--space-xs);
  flex: 0 0 auto;
}
.lf-sessions-play__complete {
  margin-top: var(--space-xl);
  padding: var(--space-lg) 0;
  text-align: center;
  font-size: var(--text-lg);
  color: var(--color-primary);
}
.lf-sessions-play__gate {
  padding: var(--space-2xl) 0;
}

/* Save form — appears below the queue on the Player page. */
.lf-sessions-save {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid rgba(7, 7, 183, 0.12);
}
.lf-sessions-save__label {
  display: block;
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: var(--space-xs);
}
.lf-sessions-save__row {
  display: flex;
  gap: var(--space-sm);
  align-items: stretch;
}
.lf-sessions-save__input {
  flex: 1;
  font-family: var(--body-font);
  font-size: var(--text-base);
  color: var(--color-primary);
  background: var(--color-bg);
  border: 1.5px solid rgba(7, 7, 183, 0.25);
  border-radius: 4px;
  padding: var(--space-sm) var(--space-md);
}
.lf-sessions-save__input:focus {
  outline: none;
  border-color: var(--color-primary);
}
.lf-sessions-save__button {
  appearance: none;
  background: var(--color-bg);
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  border-radius: 999px;
  padding: var(--space-sm) var(--space-lg);
  font-family: var(--meta-font);
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.lf-sessions-save__button:hover {
  background: var(--color-primary);
  color: var(--color-bg);
}
.lf-sessions-save__status {
  display: inline-block;
  margin-top: var(--space-sm);
  font-size: var(--text-sm);
}
/* State colors override role for explicit feedback. */
.lf-sessions-save__status--ok { color: var(--color-primary); }
.lf-sessions-save__status--error { color: var(--color-hover); }

@media (max-width: 768px) {
  .lf-sessions-save__row {
    flex-direction: column;
  }
  .lf-sessions-save__button {
    align-self: center;
  }
}

/* Your Sessions list — section below the player block. */
.lf-sessions-saved {
  margin-top: var(--space-2xl);
  padding-top: var(--space-lg);
  border-top: 2px solid rgba(7, 7, 183, 0.18);
}
.lf-sessions-saved__title {
  font-size: var(--text-xl);
  margin: 0 0 var(--space-md) 0;
}
.lf-sessions-saved__list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.lf-sessions-saved__item {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid rgba(7, 7, 183, 0.1);
}
.lf-sessions-saved__item:last-child { border-bottom: none; }
.lf-sessions-saved__name {
  flex: 1;
  font-size: var(--text-base);
}
.lf-sessions-saved__count {
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}
.lf-sessions-saved__load {
  appearance: none;
  background: var(--color-bg);
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  border-radius: 999px;
  padding: var(--space-xs) var(--space-md);
  font-family: var(--meta-font);
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.lf-sessions-saved__load:hover {
  background: var(--color-primary);
  color: var(--color-bg);
}
.lf-sessions-saved__delete {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--color-disabled);
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  padding: var(--space-xs) var(--space-sm);
}
.lf-sessions-saved__delete:hover {
  color: var(--color-hover);
}
.lf-sessions-saved__empty {
  margin: 0;
}

/* --------------------------------------------------------------------------
   Guidebook L1 — three paths (PDF / print / flipbook)
   Sits below the page body (Iara's hero copy). Three cards in a row on
   desktop, stacked on tablet/mobile. Title uses list_title role; body copy
   uses list_description role; CTA mirrors the lf-paywall__action pattern
   (small uppercase tracked link).
   -------------------------------------------------------------------------- */

.lf-guidebook-paths {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-xl);
  margin-top: var(--space-xl);
}

@media (max-width: 900px) {
  .lf-guidebook-paths {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }
}

.lf-guidebook-path {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-lg);
  background: var(--color-bg);
}

.lf-guidebook-path__title {
  font-family: var(--list-title-font);
  font-style: var(--list-title-style);
  font-weight: var(--list-title-weight);
  color: var(--list-title-color);
  font-size: var(--text-2xl);
  margin: 0;
}
/* Card title is clickable — same href + behavior as the bottom CTA, gold
   on hover. Anchor wraps the h3 so the entire heading becomes the hit
   area without changing the visual layout. */
.lf-guidebook-path__title-link {
  text-decoration: none;
  color: inherit;
}
.lf-guidebook-path__title-link:hover .lf-guidebook-path__title {
  color: var(--color-hover);
}

.lf-guidebook-path__copy {
  font-family: var(--list-description-font);
  font-style: var(--list-description-style);
  font-weight: var(--list-description-weight);
  color: var(--list-description-color);
  font-size: var(--text-base);
  line-height: 1.6;
  margin: 0;
  flex: 1;
}

.lf-guidebook-path__cta {
  align-self: flex-start;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-primary);
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  text-decoration: none;
}
.lf-guidebook-path__cta:hover {
  color: var(--color-hover);
}

/* --------------------------------------------------------------------------
   Guidebook thank-you page
   -------------------------------------------------------------------------- */

.lf-guidebook-thanks__linkbox {
  margin: var(--space-xl) 0;
  padding: var(--space-lg);
  background: var(--color-bg-alt);
  text-align: center;
}

.lf-guidebook-thanks__download {
  display: inline-block;
  font-family: var(--list-title-font);
  font-size: var(--text-xl);
  color: var(--color-primary);
  text-decoration: none;
  border-bottom: 2px solid currentColor;
  padding-bottom: 4px;
}
.lf-guidebook-thanks__download:hover {
  color: var(--color-hover);
}

.lf-guidebook-thanks__note {
  color: var(--color-disabled);
  font-size: var(--text-sm);
  margin-bottom: var(--space-2xl);
}

.lf-guidebook-thanks__resend {
  margin: var(--space-xl) 0;
  border-top: 1px solid rgba(7, 7, 183, 0.15);
  padding-top: var(--space-lg);
}
.lf-guidebook-thanks__resend > summary {
  cursor: pointer;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-disabled);
  list-style: none;
  margin-bottom: var(--space-md);
}
.lf-guidebook-thanks__resend > summary::-webkit-details-marker { display: none; }
.lf-guidebook-thanks__resend > summary:hover {
  color: var(--color-primary);
}
.lf-guidebook-thanks__resend-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 400px;
}
.lf-guidebook-thanks__resend-form label {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  font-size: var(--text-sm);
  color: var(--color-disabled);
}
.lf-guidebook-thanks__resend-form input[type="email"] {
  font-family: var(--body-font);
  font-size: var(--text-base);
  color: var(--color-primary);
  background: var(--color-bg);
  border: 1px solid rgba(7, 7, 183, 0.25);
  padding: var(--space-sm) var(--space-md);
}
.lf-guidebook-thanks__resend-form input[type="email"]:focus {
  outline: none;
  border-color: var(--color-primary);
}
.lf-guidebook-thanks__resend-form button {
  align-self: flex-start;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
}
.lf-guidebook-thanks__resend-form [data-lf-resend-status] {
  font-size: var(--text-sm);
  color: var(--color-disabled);
  margin: 0;
}
.lf-guidebook-thanks__back {
  margin-top: var(--space-xl);
}

/* --------------------------------------------------------------------------
   Guidebook L2 — flipbook viewport + dual CTA (persistent + amplified)
   -------------------------------------------------------------------------- */

/* Flipbook viewport — middle row of the L2 page's three-row layout.
   The horizontal dividers (border-bottom on row 1 and row 2, plus the
   outer page-frame border) form the visible boundary that frames the
   inevitable animation clipping at the canvas edges. Height gives the
   canvas internal room for the page-flip lift and cast-shadow fall. */
.lf-flipbook-frame {
  position: relative;
  background: transparent;
  width: 100%;
  height: 88vh;
}

.lf-flipbook {
  width: 100%;
  height: 100%;
  position: relative;
}

/* Hide DFlip's navigation arrows (prev/next/alt). Everybody knows that's how
   it goes — clicking either side of the spread or dragging the corner does
   the same job. */
.lf-flipbook .df-ui-prev,
.lf-flipbook .df-ui-next,
.lf-flipbook .df-ui-altprev,
.lf-flipbook .df-ui-altnext {
  display: none !important;
}

/* Replace DFlip's bundled loading.gif with La Flora's four-leaf clover,
   rotating via CSS keyframes. Compound selector (no descendant space)
   because DFlip adds .df-container to the same element that already has
   .lf-flipbook — they are NOT in a descendant relationship. */
.lf-flipbook.df-container.df-loading:after {
  background-image: url('/assets/images/laflora_four_leaf_clover.png') !important;
  background-size: contain !important;
  animation: lf-flipbook-loader-spin 1.6s linear infinite;
  will-change: transform;
}
@keyframes lf-flipbook-loader-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* L2 flipbook page is a three-row layout (head, flipbook, CTA).
   Horizontal lines between rows match the outer page-frame border so the
   layout reads as three stacked blocks sharing one frame. The
   .lf-container's horizontal padding is removed so the dividers reach
   the page-frame's inner edge; each row reapplies its own horizontal
   inset via padding so the content keeps breathing room. */
.lf-custom-page--guidebook-flipbook {
  padding: 0;
}
.lf-custom-page--guidebook-flipbook .lf-container {
  padding-left: 0;
  padding-right: 0;
}
.lf-custom-page--guidebook-flipbook .lf-flipbook-head,
.lf-custom-page--guidebook-flipbook .lf-flipbook-frame,
.lf-custom-page--guidebook-flipbook .lf-flipbook-cta {
  padding-left: var(--space-lg);
  padding-right: var(--space-lg);
}
/* Row 1: title + intro body together inside lf-flipbook-head; divider
   below the whole block, not between the title and the description. */
.lf-custom-page--guidebook-flipbook .lf-flipbook-head {
  padding-top: var(--space-lg);
  padding-bottom: var(--space-md);
  border-bottom: 2px solid rgba(7, 7, 183, 0.25);
}
.lf-custom-page--guidebook-flipbook .lf-flipbook-head .lf-page__header {
  margin: 0;
  padding: 0;
  border: none;
}
.lf-custom-page--guidebook-flipbook .lf-flipbook-head .lf-page__content {
  margin: var(--space-xs) 0 0;
}
.lf-custom-page--guidebook-flipbook .lf-page__title {
  margin: 0;
}
/* Row 2: flipbook viewport — same calculated height as the previous
   bordered "floating" version (book aspect 882/666 capped at 88vh) so
   the canvas has the same animation room. */
.lf-custom-page--guidebook-flipbook .lf-flipbook-frame {
  height: auto;
  aspect-ratio: 882 / 666;
  max-height: 88vh;
  border-bottom: 2px solid rgba(7, 7, 183, 0.25);
}
.lf-custom-page--guidebook-flipbook .lf-flipbook-cta {
  padding-top: var(--space-md);
  padding-bottom: var(--space-md);
}
/* The optional intro body slot above the flipbook (Iara's editable
   paragraph). Tighter than a full body block because the flipbook follows
   immediately. */
.lf-page__content--flipbook-intro {
  margin: var(--space-sm) 0 var(--space-md);
}
.lf-page__content--flipbook-intro p:last-child {
  margin-bottom: 0;
}

/* Loading + error overlays sit centered on the empty viewport before
   StPageFlip takes over. */
.lf-flipbook__loading,
.lf-flipbook__error {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-lg);
  color: var(--color-disabled);
  font-family: var(--meta-font);
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  pointer-events: none;
}

/* Persistent dual CTA below the flipbook. Always visible; amplified when
   the reader reaches the last preview page (handled by guidebook-flipbook.js).
   No background or border in resting state — sits as flat copy on the page. */
.lf-flipbook-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md) 0;
  margin-top: 0;
  text-align: center;
  background: transparent;
  border: none;
  transition: background-color 0.45s ease, border-color 0.45s ease, transform 0.45s ease;
}

.lf-flipbook-cta__copy {
  font-family: var(--body-font);
  font-style: var(--body-style);
  color: var(--color-disabled);
  font-size: var(--text-base);
  line-height: 1.5;
  margin: 0;
  max-width: 520px;
}

/* Center the L2 CTA action button — overrides .lf-guidebook-path__cta's
   left-aligned default (which is correct for the L1 cards but wrong here). */
.lf-flipbook-cta__action {
  align-self: center;
}

/* Amplified state — brand gold accent, soft lift, copy color brought
   forward. Triggered by the page-15 hook in guidebook-flipbook.js. */
.lf-flipbook-cta--amplified {
  background: rgba(176, 143, 61, 0.08);
  border-color: var(--color-hover);
  transform: scale(1.02);
}

.lf-flipbook-cta--amplified .lf-flipbook-cta__copy {
  color: var(--color-primary);
  font-style: italic;
}

.lf-flipbook-cta--amplified .lf-flipbook-cta__action {
  color: var(--color-hover);
  border-bottom-color: var(--color-hover);
}

/* --------------------------------------------------------------------------
   La Flora Tarot Deck clover (The Deck block) — default textured clover
   with HOPE / LOVE / FAITH / LUCK baked in; mousing over each leaf swaps
   that quadrant to the crisp hover version. Each quadrant is a link to
   the L1 page.
   -------------------------------------------------------------------------- */

.lf-tarot-clover {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  margin: var(--space-md) auto 0;
  background-image: url("../images/laflora_tarot_default.png");
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}

.lf-tarot-clover__quadrant {
  position: absolute;
  width: 50%;
  height: 50%;
  /* Cream BG-color sits BEHIND the hover PNG and shows through its
     transparent corners — when this quadrant fades in, the cream
     covers the underlying default-image's leaf in this quadrant, and
     the crisp hover leaf paints on top. Effect: clean per-quadrant
     swap, no preprocessing of the PNG needed. */
  background-color: var(--color-bg);
  background-image: url("../images/laflora_tarot_hover.png");
  background-size: 200% 200%;   /* full hover image, scaled so each quadrant shows ¼ */
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 0.18s ease;
  /* The whole quadrant is a clickable <a>. */
  cursor: pointer;
}

.lf-tarot-clover__quadrant--tl { top: 0;    left: 0;   background-position: 0%   0%;   }
.lf-tarot-clover__quadrant--tr { top: 0;    right: 0;  background-position: 100% 0%;   }
.lf-tarot-clover__quadrant--bl { bottom: 0; left: 0;   background-position: 0%   100%; }
.lf-tarot-clover__quadrant--br { bottom: 0; right: 0;  background-position: 100% 100%; }

.lf-tarot-clover__quadrant:hover,
.lf-tarot-clover__quadrant:focus-visible {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Row — Public Strip (Public Player + Letters)
   -------------------------------------------------------------------------- */

.lf-row--public-strip {
  /* Public Player narrow left, Letters wider right. */
  grid-template-columns: minmax(220px, 320px) 1fr;
}

@media (max-width: 768px) {
  .lf-row--public-strip {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   Public Player (compact meditation-player + Letter swap surface)
   -------------------------------------------------------------------------- */

/* Title margin-bottom inherits from the default .lf-block__title rule
   (var(--space-md)) — matches Field Notes / Guidebook standard. */

.lf-public-player__excerpt {
  /* Inherits font + color from .lf-block__description (Meta role).
     No font-size override — matches Field Notes / Guidebook description sizing. */
  margin-bottom: var(--space-md);
}

/* Shift Public Player content down a touch using the room freed by the
   tighter content + larger row height. The block was previously hugging
   the top edge; this pushes the title down so the content sits more
   balanced vertically. */
.lf-block--public-player {
  padding-top: calc(var(--space-lg) + var(--space-md));
}

/* Public Player play/pause button compacted to match the Stop button (36×36)
   so the controls strip stays tidy in the narrow column. */
.lf-block--public-player .lf-player__play {
  width: 36px;
  height: 36px;
}

/* Public Player body — shows the meditation's description text in the
   default state. Hidden in Letter mode (the Letter's full prose lives in
   the Letters block expansion instead). Audio Card inside is hidden via
   the .lf-block--meditation-player .lf-block__body .kg-audio-card rule
   elsewhere in this file. */
.lf-public-player--letter-mode .lf-public-player__body {
  display: none;
}

/* Public Player Letter-mode: subtle indigo accent on the title to signal
   "this is the playing Letter," logarithmic-eased fade on content swaps. */
.lf-public-player__title,
.lf-public-player__excerpt {
  transition: opacity 0.35s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.lf-public-player--swapping .lf-public-player__title,
.lf-public-player--swapping .lf-public-player__excerpt {
  opacity: 0;
}

/* Stop button — visible only in Letter mode. */
.lf-player__stop {
  background: transparent;
  border: 1px solid var(--color-primary);
  color: var(--color-primary);
  cursor: pointer;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-right: var(--space-sm);
  transition: color 0.2s ease, border-color 0.2s ease;
}

.lf-player__stop:hover,
.lf-player__stop:focus-visible {
  color: var(--color-hover);
  border-color: var(--color-hover);
  outline: none;
}

.lf-player__icon-stop {
  font-size: 0.85rem;
  line-height: 1;
}

/* Disabled ambient mixer — visible but non-selectable. */
.lf-player__ambient--disabled {
  pointer-events: none;
  opacity: 0.55;
}

.lf-player__ambient--disabled .lf-player__ambient-btn {
  cursor: not-allowed;
  color: var(--color-disabled);
  border-color: var(--color-disabled);
}

.lf-player__ambient--disabled .lf-player__ambient-btn:hover {
  color: var(--color-disabled);
  border-color: var(--color-disabled);
  background: transparent;
}

.lf-player__ambient--disabled .lf-player__ambient-volume {
  cursor: not-allowed;
}

.lf-player__ambient--disabled .lf-player__ambient-label,
.lf-player__ambient--disabled .lf-player__ambient-mix-label {
  color: var(--color-disabled);
}

/* --------------------------------------------------------------------------
   Letters Block — vertical list + expand-in-place + arrow scroll
   -------------------------------------------------------------------------- */

.lf-block--letters .lf-block__inner {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.lf-letters {
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
  /* No margin-top — the description's default margin-bottom already
     provides the gap. Adding margin-top here was producing double
     spacing relative to the Public Player block, where the excerpt's
     margin-bottom is the only space before the player controls. */
  gap: var(--space-sm);
}

/* Right-edge column holding up/down scroll triangles, vertically split
   (up at top, down at bottom). Same glyph + size as the Level 1
   Meditations track-toggle chevron (▾ at 2.25rem). */
.lf-letters__nav {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  width: 2.5rem;
  padding: var(--space-xs) 0;
}

.lf-letters__nav-btn {
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--color-primary);
  /* Browsers reset <button> font-family to the system UI font by default —
     setting it explicitly here so the inner ▾ glyph renders in Inter, the
     same as the .lf-album__tracks-toggle-arrow chevron on /meditations/. */
  font-family: var(--font-sans);
  user-select: none;
  transition: color 0.2s ease, opacity 0.2s ease;
}

/* Inner arrow span mirrors the Level 1 album track-toggle chevron exactly
   (font-size 2.25rem, line-height 1, translateY 0.1em). The up button just
   rotates 180° around that same baseline. */
.lf-letters__nav-arrow {
  display: inline-block;
  font-size: 2.25rem;
  line-height: 1;
  transform: translateY(0.1em);
  transition: transform 0.2s ease;
}

.lf-letters__nav-btn--up .lf-letters__nav-arrow {
  transform: translateY(0.1em) rotate(180deg);
}

.lf-letters__nav-btn:hover:not(:disabled),
.lf-letters__nav-btn:focus-visible:not(:disabled) {
  color: var(--color-hover);
  outline: none;
}

.lf-letters__nav-btn:disabled {
  color: var(--color-disabled);
  opacity: 0.35;
  cursor: default;
}

.lf-letters__viewport {
  position: relative;
  overflow: hidden;
  flex: 1 1 auto;
  min-height: 0;
}

.lf-letters__list {
  list-style: none;
  margin: 0;
  padding: 0;
  /* Transform-based scroll — the viewport clips, this list slides via
     translate3d updated by letters.js. Subpixel motion is GPU-composited
     and smooth at any rate, including the slow teleprompter pace. */
  will-change: transform;
  transform: translate3d(0, 0, 0);
}

.lf-letters__item {
  border-top: 1px solid rgba(7, 7, 183, 0.18);
}

.lf-letters__item:first-child {
  border-top: none;
}

.lf-letters__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-md);
  align-items: center;
  padding: var(--space-sm) 0;
}

.lf-letters__triangle {
  background: transparent;
  border: none;
  color: var(--color-primary);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: var(--space-xs);
  transition: color 0.2s ease;
}

.lf-letters__triangle-icon {
  display: inline-block;
  transition: transform 0.35s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.lf-letters__item--open .lf-letters__triangle-icon {
  transform: rotate(90deg);
}

.lf-letters__triangle:hover,
.lf-letters__triangle:focus-visible {
  color: var(--color-hover);
  outline: none;
}

.lf-letters__heading {
  min-width: 0;
}

.lf-letters__title {
  font-family: var(--list-title-font);
  font-style: var(--list-title-style);
  font-weight: var(--list-title-weight);
  color: var(--list-title-color);
  font-size: var(--text-lg);
  margin: 0;
}

.lf-letters__excerpt {
  font-family: var(--list-description-font);
  font-style: var(--list-description-style);
  font-weight: var(--list-description-weight);
  color: var(--list-description-color);
  font-size: var(--text-sm);
  margin: 0;
}

.lf-letters__play {
  background: transparent;
  border: 1px solid var(--color-primary);
  color: var(--color-primary);
  cursor: pointer;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-left: 2px; /* optical centering of the play glyph */
  transition: color 0.2s ease, border-color 0.2s ease;
}

.lf-letters__play:hover:not(:disabled),
.lf-letters__play:focus-visible:not(:disabled) {
  color: var(--color-hover);
  border-color: var(--color-hover);
  outline: none;
}

.lf-letters__icon-play {
  font-size: 0.85rem;
  line-height: 1;
}

/* Placeholder Letters — Coming Soon, no audio. JS adds the modifier when the
   Letter post has no Audio Card. */
.lf-letters__item--placeholder .lf-letters__play {
  cursor: not-allowed;
  color: var(--color-disabled);
  border-color: var(--color-disabled);
  opacity: 0.6;
}

.lf-letters__item--placeholder .lf-letters__excerpt::after {
  content: " — Coming Soon";
  color: var(--color-disabled);
  font-style: italic;
}

.lf-letters__item--placeholder .lf-letters__triangle {
  cursor: not-allowed;
  color: var(--color-disabled);
  opacity: 0.6;
}

/* Letter body — expanded reading surface. Holds the prose + the Ghost Audio
   Card (hidden via CSS — letters.js extracts its src for the Public Player). */
.lf-letters__body {
  padding: 0 0 var(--space-md);
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.45s cubic-bezier(0.215, 0.61, 0.355, 1),
              padding 0.45s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.lf-letters__body[hidden] {
  display: block !important;
  max-height: 0;
  padding: 0;
}

.lf-letters__item--open .lf-letters__body {
  max-height: var(--lf-letter-body-height, 4000px);
  padding-bottom: var(--space-md);
}

.lf-letters__body .kg-audio-card,
.lf-letters__body .kg-file-card {
  display: none;
}

/* End-of-Letter CTA — renders inline below the body when its item is
   --open. Uses the same .lf-block__cta-btn shape as the Field Notes
   block CTA for visual consistency on the homepage. */
.lf-letters__cta[hidden] {
  display: none;
}
.lf-letters__item--open .lf-letters__cta {
  display: block;
  text-align: center;
  padding: var(--space-md) 0 var(--space-lg);
}
.lf-letters__cta-text {
  font-style: italic;
  color: var(--color-primary);
  opacity: 0.78;
  font-size: var(--text-md);
  margin: 0 0 var(--space-md);
}

/* End-of-Field-Note CTA — same shape + tone as the end-of-Letter CTA. */
.lf-post__field-note-cta {
  text-align: center;
  padding: var(--space-2xl) 0 var(--space-lg);
  margin-top: var(--space-xl);
  border-top: 1px solid rgba(7, 7, 183, 0.12);
}
.lf-post__field-note-cta-text {
  font-style: italic;
  color: var(--color-primary);
  opacity: 0.78;
  font-size: var(--text-md);
  margin: 0 0 var(--space-md);
}

.lf-letters__body p,
.lf-letters__body div {
  font-family: var(--body-font);
  font-style: var(--body-style);
  font-weight: var(--body-weight);
  color: var(--body-color);
  font-size: var(--text-base);
  line-height: 1.7;
}
.lf-letters__body em { font-style: italic; }
.lf-letters__body strong { font-weight: bold; }

.lf-letters__body p {
  margin-bottom: var(--space-md);
}

.lf-letters__body p:last-child {
  margin-bottom: 0;
}

/* Line-highlight overlay for audio-text sync. letters.js wraps each visual
   line in a span on init (recomputed on resize); the active span gets
   --color-disabled (Muted) with a logarithmic-eased fade in/out. */
.lf-letters__line {
  display: inline;
  color: inherit;
  transition: color 0.35s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.lf-letters__line--active {
  color: var(--color-disabled);
}

/* --------------------------------------------------------------------------
   Public Strip — fixed row height (override stretch behavior)
   Without a cap, the Letters block would stretch the whole row to fit an
   expanded Letter body. Cap to ~340px on desktop; ~3 list items fit, the
   arrow scroll handles overflow including expanded Letters.
   -------------------------------------------------------------------------- */

.lf-row--public-strip {
  height: 460px;
}

@media (max-width: 768px) {
  .lf-row--public-strip {
    height: auto;
  }
  .lf-row--public-strip .lf-block--public-player,
  .lf-row--public-strip .lf-block--letters {
    max-height: 560px;
  }
}

/* Letters block — tighter top/bottom padding so the first/last list items
   sit closer to the block edges (per Iara's earlier spacing call). */
.lf-block--letters {
  padding-top: calc(var(--space-lg) / 2);
  padding-bottom: calc(var(--space-lg) / 2);
}

/* Letters description sits in a flex container (.lf-block__inner is
   display:flex / flex-direction:column for the viewport-fills-remaining
   layout). Flex prevents adjacent margin collapse, so the
   .lf-block__title margin-bottom + .lf-block__description margin-top
   sum (~20px) is 4px more than the equivalent normal-flow gap in the
   Public Player block (where the two collapse to ~16px). Zeroing the
   description margin-top closes that 4px and aligns the Letters
   description with "Experience La Flora" in the Public Player.
   Leonardo flagged 2026-05-16. */
.lf-block--letters .lf-block__description {
  margin-top: 0;
}

/* No extra margin between the block description and the list — match
   the Public Player's tighter description→content spacing. The
   description's default margin-bottom is the only gap. */
.lf-block--letters .lf-letters {
  margin-top: 0;
}

/* Ripple #1 (full-width row 2) — compact height (was 275 / 225, now 70%
   per Leonardo 2026-05-16). The text-ripple.mjs JS sets inline
   `style.minHeight` to fit all text content, so plain CSS gets
   overridden. !important on min-height + a forced block height keeps
   the block compact even when JS tries to grow it. Iara may rewrite
   the copy to be longer later; when she does, raise these values. */
.lf-row--full .lf-block--ripple {
  height: 178px !important;
  min-height: 178px !important;
  max-height: 178px;
}

.lf-row--full .lf-block--ripple .lf-block__inner,
.lf-row--full .lf-block--ripple .lf-ripple-panel {
  min-height: 0 !important;
  height: 100% !important;
  overflow: hidden;
}

@media (max-width: 768px) {
  .lf-row--full .lf-block--ripple {
    height: 143px !important;
    min-height: 143px !important;
    max-height: 143px;
  }
}

/* ==========================================================================
   The Gate — /the-gate/ monetization decision page
   ========================================================================== */

.lf-the-gate__header {
  text-align: center;
  max-width: 38rem;
  margin: 0 auto var(--space-xl);
}
.lf-the-gate__title {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 4vw, 3rem);
  color: var(--color-primary);
  margin: 0 0 var(--space-md);
  letter-spacing: 0.01em;
}
.lf-the-gate__lede {
  font-family: var(--font-sans);
  font-size: var(--text-md);
  color: var(--color-primary);
  opacity: 0.85;
  margin: 0;
}

.lf-the-gate__row {
  margin: 0 0 calc(var(--space-xl) * 1.25);
}
.lf-the-gate__row-title {
  font-family: var(--font-serif);
  font-size: var(--text-md);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--color-primary);
  opacity: 0.65;
  text-align: center;
  margin: 0 0 var(--space-lg);
  font-weight: 500;
}

.lf-the-gate__cards {
  display: grid;
  gap: var(--space-lg);
  max-width: 60rem;
  margin: 0 auto;
}
.lf-the-gate__cards--3 {
  grid-template-columns: repeat(3, 1fr);
}
.lf-the-gate__cards--2 {
  grid-template-columns: repeat(2, minmax(0, 18rem));
  justify-content: center;
}

.lf-gate-card {
  background: var(--color-bg);
  border: 1px solid rgba(7, 7, 183, 0.18);
  border-radius: 4px;
  padding: var(--space-lg);
  display: flex;
  flex-direction: column;
  text-align: center;
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.lf-gate-card:hover {
  border-color: var(--color-hover);
}
.lf-gate-card header {
  margin-bottom: var(--space-md);
}
.lf-gate-card__title {
  font-family: var(--font-serif);
  font-size: 1.375rem;
  color: var(--color-primary);
  margin: 0 0 var(--space-xs);
  letter-spacing: 0.01em;
}
.lf-gate-card__price {
  display: inline-flex;
  align-items: baseline;
  gap: 0.15em;
  color: var(--color-primary);
}
.lf-gate-card__amount {
  font-family: var(--font-serif);
  font-size: 2rem;
  line-height: 1;
}
.lf-gate-card__period {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  opacity: 0.75;
}
.lf-gate-card__copy {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--color-primary);
  opacity: 0.88;
  margin: 0 0 var(--space-md);
  flex: 1 1 auto;
}
.lf-gate-card__tag {
  font-family: var(--font-sans);
  font-style: italic;
  font-size: var(--text-sm);
  color: var(--color-primary);
  opacity: 0.65;
  margin: 0 0 var(--space-md);
}
.lf-gate-card__slots {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-hover);
  margin: 0 0 var(--space-sm);
  min-height: 1em;
}
.lf-gate-card__cta {
  display: inline-block;
  background: none;
  border: 1px solid rgba(7, 7, 183, 0.3);
  color: var(--color-primary);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 0.6rem var(--space-md) 0.45rem;
  cursor: pointer;
  text-decoration: none;
  line-height: 1;
  transition: border-color 0.2s ease, color 0.2s ease, background-color 0.2s ease;
  align-self: center;
  margin-bottom: var(--space-sm);
}
.lf-gate-card__cta:hover,
.lf-gate-card__cta:focus-visible {
  border-color: var(--color-hover);
  color: var(--color-hover);
  outline: none;
}
.lf-gate-card__cta--paid {
  border-color: var(--color-primary);
}
.lf-gate-card__cta--paid:hover {
  background-color: rgba(176, 143, 61, 0.06);
}
.lf-gate-card__fine {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--color-primary);
  opacity: 0.55;
  margin: 0;
}
.lf-gate-card__fine a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.18em;
}
.lf-gate-card__fine a:hover {
  color: var(--color-hover);
  opacity: 1;
}

/* Album-list expansion — vertical row layout scales to N albums without
   redesign. Hidden by default; toggled by the Pick-your-albums button. */
.lf-album-list {
  max-width: 50rem;
  margin: var(--space-lg) auto 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.lf-album-list[hidden] { display: none; }
.lf-album-list__empty {
  text-align: center;
  font-family: var(--font-sans);
  font-style: italic;
  color: var(--color-primary);
  opacity: 0.6;
}
.lf-album-row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  background: var(--color-bg);
  border: 1px solid rgba(7, 7, 183, 0.12);
  border-radius: 3px;
  transition: border-color 0.2s ease;
}
.lf-album-row:hover {
  border-color: rgba(7, 7, 183, 0.32);
}
.lf-album-row__meta {
  flex: 1 1 auto;
  min-width: 0;
}
.lf-album-row__title {
  font-family: var(--font-serif);
  font-size: 1.125rem;
  color: var(--color-primary);
  margin: 0 0 0.15rem;
}
.lf-album-row__excerpt {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--color-primary);
  opacity: 0.78;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.lf-album-row__buy {
  flex: 0 0 auto;
  background: none;
  border: 1px solid var(--color-primary);
  color: var(--color-primary);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  padding: 0.55rem 1rem 0.4rem;
  cursor: pointer;
  line-height: 1;
  transition: border-color 0.2s ease, color 0.2s ease, background-color 0.2s ease;
}
.lf-album-row__buy:hover,
.lf-album-row__buy:focus-visible {
  border-color: var(--color-hover);
  color: var(--color-hover);
  background-color: rgba(176, 143, 61, 0.06);
  outline: none;
}

@media (max-width: 768px) {
  .lf-the-gate__cards--3 { grid-template-columns: 1fr; }
  .lf-the-gate__cards--2 { grid-template-columns: 1fr; }
  .lf-album-row { flex-direction: column; align-items: stretch; text-align: center; }
}

/* ==========================================================================
   My Library — /my-library/ member surface
   ========================================================================== */

.lf-my-library {
  padding: var(--space-xl) 0;
}

.lf-my-library__header {
  text-align: center;
  margin-bottom: var(--space-xl);
}

.lf-my-library__title {
  font-size: var(--text-3xl);
  font-weight: 400;
  color: var(--color-primary);
  margin-bottom: var(--space-xs);
}

.lf-my-library__intro {
  font-size: var(--text-lg);
  color: var(--color-disabled);
  font-style: italic;
}

.lf-my-library__section {
  margin-bottom: var(--space-xl);
}

.lf-my-library__section-title {
  font-size: var(--text-xl);
  font-weight: 400;
  color: var(--color-primary);
  margin-bottom: var(--space-md);
  letter-spacing: 0.02em;
}

/* Subscription card — single panel showing tier, status, manage CTA. */
.lf-my-library__sub-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  align-items: flex-start;
  padding: var(--space-lg);
  background: var(--color-bg-alt);
  border: 1px solid rgba(7, 7, 183, 0.15);
}

.lf-my-library__sub-tier {
  font-family: var(--font-serif);
  font-size: var(--text-xl);
  color: var(--color-primary);
}

.lf-my-library__sub-status {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-hover);
}

.lf-my-library__sub-manage {
  margin-top: var(--space-sm);
}

/* Owned albums grid — responsive cards. */
.lf-my-library__albums {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-md);
}

.lf-my-library__album-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-lg);
  background: var(--color-bg-alt);
  border: 1px solid rgba(7, 7, 183, 0.15);
  color: var(--color-primary);
  text-decoration: none;
  transition: border-color 0.2s ease, transform 0.2s ease;
  min-height: 160px;
}

.lf-my-library__album-card:hover,
.lf-my-library__album-card:focus-visible {
  border-color: var(--color-hover);
  transform: translateY(-2px);
  outline: none;
}

.lf-my-library__album-title {
  font-size: var(--text-xl);
  font-weight: 400;
  margin: 0;
  color: var(--color-primary);
}

.lf-my-library__album-link-text {
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  color: var(--color-hover);
}

.lf-my-library__loading,
.lf-my-library__empty-text {
  color: var(--color-disabled);
  font-style: italic;
  font-size: var(--text-lg);
  margin-bottom: var(--space-md);
}

.lf-my-library__empty {
  text-align: center;
  padding: var(--space-xl) 0;
}

.lf-my-library__signin {
  text-align: center;
  padding: var(--space-xl) 0;
}

.lf-my-library__signin-text {
  font-size: var(--text-lg);
  color: var(--color-primary);
}

.lf-my-library__signin-text a {
  color: var(--color-hover);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

@media (max-width: 768px) {
  .lf-my-library__albums {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   Refund Policy page (custom-refund-policy.hbs)
   Narrow prose column for readability — same chrome as other custom pages.
   -------------------------------------------------------------------------- */

.lf-refund-policy__content {
  max-width: 720px;
  margin: 0 auto;
}

/* The global h2/h3 in style.css are hero-sized (text-4xl) because most
   pages have at most one heading. The refund policy has 7+ H2s, so
   scope them to body-text size here. */
.lf-refund-policy__content h2 {
  font-size: var(--text-xl);
  font-weight: 600;
  line-height: 1.3;
  margin-top: var(--space-xl);
  margin-bottom: var(--space-sm);
}

.lf-refund-policy__content h3 {
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.3;
  margin-top: var(--space-lg);
  margin-bottom: var(--space-xs);
}

.lf-refund-policy__content p,
.lf-refund-policy__content li {
  font-size: var(--text-base);
  line-height: 1.7;
}

.lf-refund-policy__content ul {
  list-style: disc;
  padding-left: var(--space-lg);
}

.lf-page__subtitle {
  font-size: var(--text-lg);
  color: var(--color-text-muted, #5e5e50);
  margin-top: var(--space-sm);
  max-width: 720px;
}
