/* ========================================================================
   Worlds stripe — book-binding / stripe-expand treatment.
   Each Shardworld renders as a tall book spine on a wooden shelf. Clicking
   a spine opens it: the spine compresses to a 44px strip (keeping gilt
   title + embossed sigil visible) while the paper "page" fades in with
   the world's onramp content.

   Timing is asymmetric on purpose — opening is a *substantial* gesture
   (480ms panel + 360ms padding + staggered content reveal), closing is
   *decisive* (300ms). See .planning/ notes for the per-property tuning.
   Tokens come from tokens.css; shelf-wood and gilt gold are local since
   they're specific to this book metaphor.
   ======================================================================== */

:root {
  /* Width of the compressed spine strip when a panel is open. */
  --spine-width: 44px;
  /* Easings — stronger than stock CSS easings. Local so this component
     can be lifted into any page without touching global tokens. */
  --ws-ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ws-ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  /* Gilt foil color used for spine titles and embossed sigils. */
  --ws-gilt: #f2d98a;
}

.worlds-stripe {
  display: flex;
  gap: 3px;
  height: clamp(520px, 62vh, 640px);
  border-radius: 2px;
  overflow: hidden;
  padding: 10px 10px 22px;
  /* Back panel of the shelving unit — stained walnut with layered grain:
     soft tonal figure, medium grain bands, tight hairlines. Each layer
     plays a different spatial frequency so the wood reads as organic
     rather than screen-perfect stripes. */
  background:
    /* Subtle knot/figure highlights — warm light glances off the wood
       asymmetrically, like a panel lit from upper-left. */
    radial-gradient(
      ellipse 60% 80% at 22% 28%,
      rgba(210, 145, 80, 0.10) 0%,
      transparent 60%
    ),
    radial-gradient(
      ellipse 40% 60% at 78% 66%,
      rgba(0, 0, 0, 0.18) 0%,
      transparent 70%
    ),
    /* Fine grain hairlines — tight period, low contrast — micro-texture. */
    repeating-linear-gradient(
      90deg,
      transparent 0,
      transparent 3px,
      rgba(0, 0, 0, 0.12) 3px,
      rgba(0, 0, 0, 0.12) 3.5px,
      transparent 3.5px,
      transparent 7px,
      rgba(140, 80, 45, 0.08) 7px,
      rgba(140, 80, 45, 0.08) 7.5px,
      transparent 7.5px,
      transparent 11px
    ),
    /* Medium grain bands — irregular spacing, variable darkness. */
    repeating-linear-gradient(
      90deg,
      transparent 0,
      transparent 24px,
      rgba(0, 0, 0, 0.48) 24px,
      rgba(0, 0, 0, 0.48) 25px,
      transparent 25px,
      transparent 47px,
      rgba(170, 100, 55, 0.22) 47px,
      rgba(170, 100, 55, 0.22) 48px,
      transparent 48px,
      transparent 79px,
      rgba(0, 0, 0, 0.38) 79px,
      rgba(0, 0, 0, 0.38) 80.5px,
      transparent 80.5px,
      transparent 113px,
      rgba(0, 0, 0, 0.22) 113px,
      rgba(0, 0, 0, 0.22) 113.8px,
      transparent 113.8px,
      transparent 137px,
      rgba(210, 140, 80, 0.14) 137px,
      rgba(210, 140, 80, 0.14) 138px,
      transparent 138px,
      transparent 163px,
      rgba(0, 0, 0, 0.55) 163px,
      rgba(0, 0, 0, 0.55) 164.5px,
      transparent 164.5px,
      transparent 191px
    ),
    /* Broad figure bands — low frequency tonal shifts, like a wide
       piece of wood where colour drifts across the surface. */
    repeating-linear-gradient(
      94deg,
      rgba(0, 0, 0, 0) 0,
      rgba(0, 0, 0, 0.12) 140px,
      rgba(0, 0, 0, 0) 260px,
      rgba(180, 110, 65, 0.08) 380px,
      rgba(0, 0, 0, 0) 520px
    ),
    /* Warm walnut base with vertical tonal shift — lighter at top so the
       strip above the books catches light. */
    linear-gradient(180deg, #5a3822 0%, #3a2412 45%, #20140a 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 200, 150, 0.10),
    inset 0 -8px 16px -8px rgba(0, 0, 0, 0.8),
    0 24px 60px -24px rgba(0, 0, 0, 0.4);
  position: relative;
}
/* Shelf plank — the wood the books sit on. Thicker and more detailed than
   the back panel because it's the surface the eye lingers on. Horizontal
   grain runs along the length of the shelf; a thin lighter edge along
   the top catches the light where the books meet the wood. */
.worlds-stripe::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 22px;
  background:
    /* Subtle horizontal figure — a long drifted light band near the top
       where the leading edge would catch the most light. */
    linear-gradient(
      180deg,
      rgba(240, 170, 110, 0.18) 0%,
      transparent 24%,
      transparent 100%
    ),
    /* Fine horizontal hairlines — tight grain detail. */
    repeating-linear-gradient(
      180deg,
      transparent 0,
      transparent 1.5px,
      rgba(0, 0, 0, 0.22) 1.5px,
      rgba(0, 0, 0, 0.22) 2px,
      transparent 2px,
      transparent 3.5px
    ),
    /* Medium horizontal grain streaks — varied opacity and hue for
       aged, organic wood figure. */
    repeating-linear-gradient(
      180deg,
      rgba(0, 0, 0, 0.5) 0,
      rgba(0, 0, 0, 0.5) 1px,
      transparent 1px,
      transparent 3px,
      rgba(90, 50, 25, 0.3) 3px,
      rgba(90, 50, 25, 0.3) 4.2px,
      transparent 4.2px,
      transparent 7.5px,
      rgba(0, 0, 0, 0.38) 7.5px,
      rgba(0, 0, 0, 0.38) 8.5px,
      transparent 8.5px,
      transparent 13px,
      rgba(170, 105, 60, 0.18) 13px,
      rgba(170, 105, 60, 0.18) 14px,
      transparent 14px,
      transparent 17.5px,
      rgba(0, 0, 0, 0.3) 17.5px,
      rgba(0, 0, 0, 0.3) 18.5px,
      transparent 18.5px,
      transparent 22px
    ),
    /* Rich walnut base, front edge darkens to suggest depth. */
    linear-gradient(180deg, #6a4428 0%, #4a2d18 40%, #20130a 100%);
  /* Crisp shadow at the wall/shelf junction + warm highlight where light
     catches the leading edge of the plank. */
  border-top: 1px solid rgba(0, 0, 0, 0.65);
  box-shadow:
    inset 0 1px 0 rgba(240, 170, 105, 0.3),
    inset 0 -2px 4px rgba(0, 0, 0, 0.55),
    0 6px 12px rgba(0, 0, 0, 0.5);
}

.world-panel {
  flex: 1 1 0;
  min-width: 0;
  position: relative;
  background: var(--c, var(--color-honor));
  color: #fff;
  cursor: pointer;
  text-decoration: none;
  overflow: hidden;
  /* Close transition: snappier than open — an exiting drawer shouldn't linger. */
  transition:
    flex-grow 300ms var(--ws-ease-drawer),
    transform 200ms var(--ws-ease-out),
    box-shadow 220ms var(--ws-ease-out),
    filter 220ms var(--ws-ease-out);
  display: flex;
  flex-direction: column;
  border-radius: 2px 2px 1px 1px;
  will-change: flex-grow, transform;
  /* Spine depth: inner shadows on the left and right suggest raised ridges
     where the cover meets the binding. */
  box-shadow:
    inset 3px 0 6px -2px rgba(0, 0, 0, 0.4),
    inset -3px 0 6px -2px rgba(0, 0, 0, 0.4),
    inset 0 2px 0 rgba(255, 255, 255, 0.08),
    inset 0 -2px 4px rgba(0, 0, 0, 0.3);
}
/* Raised bands — classic hardcover spine ridges across the height. */
.world-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent 70px,
    rgba(0, 0, 0, 0.18) 71px,
    rgba(0, 0, 0, 0.18) 88px,
    rgba(255, 255, 255, 0.06) 73px,
    rgba(255, 255, 255, 0.06) 74px,
    transparent 75px,
    transparent 140px
  );
  pointer-events: none;
  z-index: 1;
  clip-path: inset(0 0 0 0);
  transition: clip-path 300ms var(--ws-ease-drawer);
}

/* Spine layer — gilt title, embossed sigil, count chip. When closed the
   spine fills the whole card. When open it compresses to --spine-width
   and the title/chips fade out. */
.world-panel .world-panel__collapsed {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 32px 20px;
  transition:
    right 300ms var(--ws-ease-drawer),
    padding 220ms var(--ws-ease-out);
  z-index: 3;
}

/* World-symbol seal — foil-stamped in the same warm gold as the vertical
   title. Both pieces read as a single book-cover treatment: gilt sigil on
   top, gilt title running up the binding. */
.world-panel__seal {
  width: 36px;
  height: 36px;
  align-self: center;
  position: relative;
  z-index: 2;
  flex-shrink: 0;
  color: var(--ws-gilt);
  /* Raised-foil effect: rim light above + soft shadow below — the glyph
     reads as embossed, not merely printed. */
  filter:
    drop-shadow(0 -0.5px 0 rgba(255, 255, 255, 0.22))
    drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
  transition: opacity 220ms var(--ws-ease-out) 200ms;
}
.world-panel__seal svg {
  width: 100%;
  height: 100%;
  display: block;
  /* Bump stroke-based sigils (Hoid crest) so they read as gold foil at
     small sizes instead of disappearing into hairlines. */
  stroke-width: 4;
}

.world-panel__vertical {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(22px, 2vw, 30px);
  line-height: 1;
  letter-spacing: 0.01em;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: var(--ws-gilt);
  margin: 0 auto;
  text-wrap: nowrap;
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.5),
    0 -1px 0 rgba(255, 255, 255, 0.15);
  position: relative;
  z-index: 2;
  font-variation-settings: "opsz" 72;
  /* Close-state transition: delayed fade-in after spine re-expands. The
     delay means you never see the rotated text rendering inside a
     resizing container — that was the source of the jitter. */
  transition:
    filter 220ms var(--ws-ease-out),
    opacity 200ms var(--ws-ease-out) 320ms;
}

.world-panel__count-chip {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 230, 180, 0.7);
  align-self: center;
  position: relative;
  z-index: 2;
  transition: opacity 220ms var(--ws-ease-out) 160ms;
}

/* Expanded state: content flood on paper. */
.world-panel .world-panel__expanded {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 40px 36px 36px;
  padding-left: calc(var(--spine-width) + 36px);
  padding-right: 40px;
  padding-top: 44px;
  padding-bottom: 40px;
  color: var(--color-ink);
  opacity: 0;
  transition: opacity 200ms var(--ws-ease-out);
  pointer-events: none;
}

/* Paper page: always present so it can transition on open/close. The
   scaleX unfold from the spine edge makes the reveal feel like a page
   turning out rather than a block fading in. */
.world-panel::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: var(--spine-width);
  background: linear-gradient(180deg, #fbf5e7 0%, #f3ead3 100%);
  box-shadow:
    inset 8px 0 16px -8px rgba(0, 0, 0, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transform: scaleX(0.985);
  transform-origin: left center;
  transition:
    opacity 200ms var(--ws-ease-out),
    transform 260ms var(--ws-ease-out);
}

/* Compressed-spine open state — swap to open durations, fade chips/title. */
.world-panel.is-open .world-panel__collapsed {
  right: calc(100% - var(--spine-width));
  padding: 22px 8px;
  transition:
    right 480ms var(--ws-ease-drawer),
    padding 360ms var(--ws-ease-out);
}
.world-panel.is-open .world-panel__expanded {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 280ms var(--ws-ease-out) 200ms;
}
/* Spine is intentionally clean when open — no chips, no rotated title. */
.world-panel.is-open .world-panel__seal,
.world-panel.is-open .world-panel__count-chip,
.world-panel.is-open .world-panel__vertical {
  opacity: 0;
  transition: opacity 120ms var(--ws-ease-out);
}

/* Content groups — base transitions = close (fast, decisive). */
.wp-top,
.wp-planet,
.wp-name,
.wp-intent,
.wp-rows {
  opacity: 0;
  transform: translateY(6px);
  filter: blur(2px);
  transition:
    opacity 160ms var(--ws-ease-out),
    transform 200ms var(--ws-ease-out),
    filter 160ms var(--ws-ease-out);
}
.wp-cta {
  opacity: 0;
  filter: blur(2px);
  transition:
    opacity 160ms var(--ws-ease-out),
    filter 160ms var(--ws-ease-out),
    transform 160ms var(--ws-ease-out);
}

/* Open — longer durations + staggered delays land each group in rhythm
   after the paper page completes its unfold. */
.world-panel.is-open .wp-top,
.world-panel.is-open .wp-planet,
.world-panel.is-open .wp-name,
.world-panel.is-open .wp-intent,
.world-panel.is-open .wp-rows {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
  transition:
    opacity 240ms var(--ws-ease-out),
    transform 320ms var(--ws-ease-out),
    filter 240ms var(--ws-ease-out);
}
.world-panel.is-open .wp-top {
  transition-delay: 220ms;
}
.world-panel.is-open .wp-planet {
  transition-delay: 280ms;
}
.world-panel.is-open .wp-name {
  transition-delay: 280ms;
}
.world-panel.is-open .wp-intent {
  transition-delay: 320ms;
}
.world-panel.is-open .wp-rows {
  transition-delay: 360ms;
}
/* CTA keeps transform independent so hover/press stay instant. */
.world-panel.is-open .wp-cta {
  opacity: 1;
  filter: blur(0);
  transition:
    opacity 240ms var(--ws-ease-out) 400ms,
    filter 240ms var(--ws-ease-out) 400ms,
    transform 160ms var(--ws-ease-out);
}

.wp-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: auto;
  padding-bottom: 24px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.wp-glyph {
  width: 52px;
  height: 52px;
  color: var(--c, var(--color-honor));
  flex-shrink: 0;
}
.wp-glyph svg {
  width: 100%;
  height: 100%;
}
.wp-count {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
  text-align: right;
}
.wp-count strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 32px;
  line-height: 1;
  color: var(--color-core);
  margin-top: 4px;
  letter-spacing: -0.02em;
}
.wp-planet {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--c, var(--color-honor));
  margin: 28px 0 10px;
}
.wp-name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 3vw, 44px);
  line-height: 1.03;
  color: var(--color-core);
  letter-spacing: -0.02em;
  margin: 0 0 10px;
  max-width: 14ch;
}
.wp-intent {
  font-family: var(--font-body);
  font-style: italic;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--color-ink-soft);
  margin: 0 0 28px;
  max-width: 42ch;
}
.wp-rows {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 12px 24px;
  margin-bottom: 32px;
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 60ch;
}
.wp-rows dt {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c, var(--color-honor));
  padding-top: 3px;
}
.wp-rows dd {
  margin: 0;
  color: var(--color-ink);
}
.wp-rows dd em {
  font-style: italic;
  color: var(--color-core);
}
.wp-cta {
  margin-top: auto;
  align-self: flex-start;
  background: var(--c, var(--color-honor));
  color: #fff;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.02em;
  padding: 12px 22px;
  border-radius: 999px;
  text-decoration: none;
}
.wp-cta:hover {
  transform: translateY(-1px);
  filter: brightness(1.1);
}
.wp-cta:active {
  transform: translateY(0) scale(0.98);
  transition: transform 100ms var(--ws-ease-out);
}
.wp-cta::after {
  content: " →";
  display: inline;
}

/* Per-world accents — gradient binding color + --c custom prop for the
   expanded-page flourishes (planet eyebrow, row dt labels, CTA). */
.world-panel[data-accent="honor"] {
  --c: var(--color-honor);
  background: linear-gradient(160deg, #1b8b99 0%, #0f5a64 100%);
}
.world-panel[data-accent="crimson"] {
  --c: var(--color-crimson);
  background: linear-gradient(160deg, #c42d3a 0%, #801c24 100%);
}
.world-panel[data-accent="magenta"] {
  --c: var(--color-magenta);
  background: linear-gradient(160deg, #9b2fa5 0%, #601c66 100%);
}
.world-panel[data-accent="flame"] {
  --c: var(--color-flame);
  background: linear-gradient(160deg, #c76b1e 0%, #7e4212 100%);
}
.world-panel[data-accent="deep"] {
  --c: var(--color-deep);
  background: linear-gradient(160deg, #1e4a90 0%, #0a2454 100%);
}

/* Hover — book lifts off the shelf + gilt title catches light. */
@media (hover: hover) and (pointer: fine) {
  .world-panel:not(.is-open):hover {
    transform: translateY(-6px);
    box-shadow:
      inset 3px 0 6px -2px rgba(0, 0, 0, 0.4),
      inset -3px 0 6px -2px rgba(0, 0, 0, 0.4),
      inset 0 2px 0 rgba(255, 255, 255, 0.14),
      inset 0 -2px 4px rgba(0, 0, 0, 0.3),
      0 14px 28px -10px rgba(0, 0, 0, 0.65);
  }
  .world-panel:not(.is-open):hover .world-panel__vertical {
    filter: brightness(1.1);
  }
}
.world-panel:not(.is-open):active {
  transform: translateY(-2px) scale(0.995);
  transition: transform 100ms var(--ws-ease-out);
}

/* Open state locks in. */
.world-panel.is-open {
  flex-grow: 8;
  cursor: default;
  transform: none;
  transition:
    flex-grow 480ms var(--ws-ease-drawer),
    transform 200ms var(--ws-ease-out),
    box-shadow 220ms var(--ws-ease-out);
}
.world-panel.is-open::after {
  opacity: 1;
  transform: scaleX(1);
  transition:
    opacity 300ms var(--ws-ease-out) 160ms,
    transform 480ms var(--ws-ease-drawer) 80ms;
}
.world-panel.is-open::before {
  clip-path: inset(0 calc(100% - var(--spine-width)) 0 0);
  transition: clip-path 480ms var(--ws-ease-drawer);
}
.world-panel.is-open .world-panel__expanded {
  z-index: 2;
}

/* OS-level reduced-motion — state still swaps; transitions become instant. */
@media (prefers-reduced-motion: reduce) {
  .world-panel,
  .world-panel .world-panel__collapsed,
  .world-panel .world-panel__expanded,
  .world-panel::after,
  .world-panel::before,
  .world-panel__seal,
  .world-panel__count-chip,
  .wp-top,
  .wp-planet,
  .wp-name,
  .wp-intent,
  .wp-rows,
  .wp-cta {
    transition: none !important;
    filter: none !important;
    transform: none !important;
  }
  .world-panel.is-open .wp-top,
  .world-panel.is-open .wp-planet,
  .world-panel.is-open .wp-name,
  .world-panel.is-open .wp-intent,
  .world-panel.is-open .wp-rows,
  .world-panel.is-open .wp-cta {
    opacity: 1;
  }
}

/* Mobile: stack vertically, switch to height-based expansion. */
@media (max-width: 820px) {
  .worlds-stripe {
    flex-direction: column;
    height: auto;
    gap: 6px;
  }
  .world-panel {
    flex: 0 0 auto;
    height: 72px;
    transition: height 400ms var(--ws-ease-drawer);
  }
  /* Let the open panel grow to fit its content instead of clipping at a
     fixed height. The expanded block switches to static flow so the
     panel itself sizes to content; the spine column (.collapsed) stays
     absolutely positioned as a decorative strip. */
  .world-panel.is-open {
    height: auto;
  }
  .world-panel.is-open .world-panel__expanded {
    position: static;
    padding: 32px 20px 32px calc(var(--spine-width) + 18px);
  }
  .world-panel .world-panel__collapsed {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 14px;
    padding: 0 20px;
  }
  .world-panel__seal {
    width: 26px;
    height: 26px;
    align-self: center;
  }
  .world-panel__vertical {
    writing-mode: initial;
    transform: none;
    margin: 0;
    font-size: 18px;
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .world-panel__count-chip {
    align-self: center;
    flex-shrink: 0;
    font-size: 10px;
  }
  /* Tighten the content sizing so everything reads comfortably inside
     a phone-width panel. */
  .wp-top {
    gap: 16px;
    padding-bottom: 18px;
  }
  .wp-glyph {
    width: 42px;
    height: 42px;
  }
  .wp-count strong {
    font-size: 26px;
  }
  .wp-planet {
    margin: 22px 0 8px;
  }
  .wp-name {
    font-size: 28px;
    max-width: none;
  }
  .wp-intent {
    font-size: 15px;
    margin-bottom: 22px;
    max-width: none;
  }
  .wp-rows {
    gap: 10px 18px;
    font-size: 14px;
    margin-bottom: 24px;
    max-width: none;
  }
}

/* Cinematic variant — only on /worlds/ index. Full-bleed shelf sitting
   flush against the fixed nav, filling the remaining viewport height.
   Nav is fixed ~88px tall (22+20 padding + ~30px logo row). */
.worlds-section--cinematic {
  margin: 0;
}
.page-worlds main {
  padding-block-start: 88px;
}
.page-worlds .worlds-stripe {
  height: calc(100vh - 88px);
  max-height: none;
  border-radius: 0;
  padding: 12px 14px 26px;
}
@media (max-width: 820px) {
  .page-worlds .worlds-stripe {
    height: auto;
  }
}
