/* Intention detail page: ten layout options.

   THIS IS THE SONG DETAIL PAGE'S FAMILY, wearing a 9:16 card instead of a
   square one. assets/kc-song-detail.css owns .sd-hero, .sd-head, .sd-eyebrow,
   .sd-title, .sd-by, .sd-actions, .sd-play, .sd-iconbtn, .sd-mid, .sd-side,
   .sd-facts, .sd-shelf and .sd-strip, and none of them are redefined here.
   assets/kc-poster-detail.css is the precedent for exactly this file: a poster
   is a song page in a different world, and it carries only what a poster has
   and a song does not. This carries only what an Intention has and neither of
   them does.

   WHAT AN INTENTION HAS THAT THEY DO NOT. The art is not a still. It is a
   playing card: narration on a clock, with the video cutting on the sentence.
   So the "art column" holds a live element, the transcript can be a seek
   control, and the piece has a duration. Everything below exists because of
   one of those three.

   EVERY COLOR IS A --mus-* TOKEN, so these pages invert with the site theme
   toggle (html[data-mode="batman"]) rather than carrying a palette of their
   own. The card itself is dark in BOTH themes on purpose and says why in
   assets/css/kc-intentions.css: it is a lit screen over footage, and inverting
   it would put white text on white.

   FONT. body sets no font-family on this site, so anything that does not say
   so renders in Times. Every rule that draws text states it.

   FOCUS RINGS ARE SCOPED WITH A THIRD CLASS. .am-main button:focus-visible in
   v17.css is (0,2,1) and squares off every control inside it at radius 6px, so
   a bare .thing:focus-visible loses and round controls read as double
   outlined. Selectors here are .am-main .id-thing:focus-visible, which is
   (0,3,0) and wins. */

/* ---------- THE CARD ITSELF ----------

   Moved here from assets/css/kc-intentions.css on 2026-08-26. These ten pages
   are the only ones that mount it (kc-intention-detail-boot.js -> mountOne in
   assets/js/kc-intentions.js), and that file is loaded by 66 pages that do not.
   Kept ahead of the .id-* rules below, which override .kci-card per layout, so
   the cascade order is unchanged. .kci-bed stays in kc-intentions.css: the
   detail pages use that button too. */

/* ---------- the card ---------- */
.kci-card {
  position: relative;
  width: min(420px, calc(100vw - 32px));
  aspect-ratio: 9 / 16;
  border-radius: 18px;
  overflow: hidden;
  background: #10140f;
  color: #fffdf9;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .16), 0 24px 60px -28px rgba(0, 0, 0, .5);
  isolation: isolate;
  scroll-margin-top: 96px;
}

/* THE STAGE IS ALSO THE CAPTION'S RULER. container-type gives .kc-caps a cqw
   to size itself against, so one caption rule covers a 420px feed card, a
   300px card beside a detail page's title, and the same card blown up full
   screen, without three font sizes to keep in step. Containment is harmless
   here: the stage is already position:absolute, so it was already the
   containing block for the video pair and the caption inside it. */
.kci-stage { position: absolute; inset: 0; z-index: 0; container-type: inline-size; }

.kci-poster {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center bottom; /* portrait crops to the BOTTOM, house rule */
  background-repeat: no-repeat;
  filter: saturate(.92);
}

.kci-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center bottom;
  opacity: 0;
  transition: opacity .28s ease;
}
.kci-video.is-live { opacity: 1; }

/* Legibility floor. Text sits on unpredictable footage, so the scrim is not
   decoration, it is what keeps contrast above AA no matter which clip is up. */
.kci-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom, rgba(6, 10, 8, .58) 0%, rgba(6, 10, 8, .12) 22%, rgba(6, 10, 8, 0) 38%),
    linear-gradient(to top, rgba(6, 10, 8, .88) 0%, rgba(6, 10, 8, .62) 24%, rgba(6, 10, 8, .1) 52%, rgba(6, 10, 8, 0) 68%);
}

/* ---------- voice, top ---------- */
.kci-top {
  position: absolute; z-index: 3;
  top: 0; left: 0; right: 0;
  padding: 16px 18px;
  display: flex; align-items: center; justify-content: space-between;
}

.kci-voice { display: flex; align-items: center; gap: 11px; min-width: 0; }

.kci-voice-disc {
  width: 42px; height: 42px; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 253, 249, .16);
  border: 1.5px solid rgba(255, 253, 249, .62);
  backdrop-filter: blur(6px);
}
.kci-voice-initial {
  font-family: "Montserrat", system-ui, sans-serif;
  font-weight: 700; font-size: 17px; line-height: 1; color: #fffdf9;
}

.kci-voice-meta { display: flex; flex-direction: column; min-width: 0; }
.kci-voice-name {
  font-family: "Montserrat", system-ui, sans-serif;
  font-weight: 700; font-size: 15px; letter-spacing: .01em; color: #fffdf9;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
}
.kci-voice-sub {
  font-family: "Montserrat", system-ui, sans-serif;
  font-weight: 600; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255, 253, 249, .78);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
}

/* ---------- right rail ---------- */
.kci-rail {
  position: absolute; z-index: 4;
  right: 10px; bottom: 168px;
  display: flex; flex-direction: column; gap: 20px; align-items: center;
}

.kci-act {
  -webkit-appearance: none; appearance: none;
  background: none; border: 0; padding: 2px; margin: 0;
  color: #fffdf9;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  cursor: pointer;
  text-decoration: none;
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, .55));
  transition: transform .16s ease, color .16s ease;
}
.kci-act:hover { transform: translateY(-1px); }
.kci-act:active { transform: scale(.94); }
.kci-act.is-on { color: #ff6b8a; }
.kci-act.is-done { color: var(--wt-accent, #8fd0b4); }

.kci-act-label {
  font-family: "Montserrat", system-ui, sans-serif;
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em;
  color: rgba(255, 253, 249, .92);
}

/* ---------- captions ----------
   THE LOOK IS IN kc-intentions-feed.css, the one stylesheet both this page and
   /intentions/ load, because the same caption band runs on two unrelated cards.
   All that belongs here is where it sits on THIS one.

   It clears the right rail, and it only shows while the piece is playing, which
   is unchanged from the sentence line it replaces: before Play a feed card is
   showing its title and step in this same space. */
.kci-card .kc-caps { left: 18px; right: 78px; bottom: 150px; }

/* A BARE CARD IS THE VIDEO AND NOTHING ELSE, so the caption is not dodging a
   button rail or a transport and can use the full width, sitting where the
   exported video puts it: low, centred, clear of the bottom edge. */
.kci-card--bare .kc-caps { left: 14px; right: 14px; bottom: 9%; }

/* The captions switch in the rail. Off is a slash through the mark, not a
   colour change alone; disabled is while the full text is open below. */
.kci-cc .kci-cc__off { display: none; }
.kci-cc[aria-pressed="false"] .kci-cc__off { display: block; }
.kci-card .kci-cc[aria-pressed="false"] { color: rgba(255, 253, 249, .55); }
.kci-cc[disabled] { opacity: .38; cursor: default; }

/* ---------- caption, bottom left ---------- */
.kci-caption {
  position: absolute; z-index: 3;
  left: 18px; right: 78px; bottom: 92px;
  transition: opacity .3s ease;
}
.kci-card.is-playing .kci-caption { opacity: 0; pointer-events: none; }

.kci-title {
  font-family: "Montserrat", system-ui, sans-serif;
  margin: 0 0 6px;
  font-size: 21px; line-height: 1.25; font-weight: 700; letter-spacing: -.005em;
  color: #fffdf9;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .6);
  text-wrap: balance;
}

.kci-step {
  font-family: "Montserrat", system-ui, sans-serif;
  margin: 0;
  font-size: 15px; line-height: 1.5; font-weight: 500;
  color: rgba(255, 253, 249, .94);
  text-shadow: 0 1px 5px rgba(0, 0, 0, .6);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.kci-caption.is-open .kci-step { -webkit-line-clamp: unset; overflow: visible; }

.kci-more {
  -webkit-appearance: none; appearance: none;
  background: none; border: 0; padding: 3px 0 0; margin: 0;
  font-family: "Montserrat", system-ui, sans-serif;
  font-size: 13px; font-weight: 700; letter-spacing: .02em;
  color: rgba(255, 253, 249, .78);
  cursor: pointer;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .6);
}
.kci-more:hover { color: #fffdf9; }

.kci-tags {
  font-family: "Montserrat", system-ui, sans-serif;
  margin: 8px 0 0;
  font-size: 13px; font-weight: 600;
  color: rgba(255, 253, 249, .86);
  text-shadow: 0 1px 5px rgba(0, 0, 0, .6);
}

/* ---------- transport ---------- */
.kci-transport {
  position: absolute; z-index: 5;
  left: 0; right: 0; bottom: 0;
  padding: 14px 16px 18px;
  display: grid;
  grid-template-columns: auto auto 1fr auto auto;
  align-items: center;
  gap: 12px;
}

.kci-play {
  -webkit-appearance: none; appearance: none;
  width: 52px; height: 52px; flex: none;
  border-radius: 50%; border: 0; padding: 0;
  background: #fffdf9; color: #10140f;
  display: grid; place-items: center;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .4);
  transition: transform .16s ease;
}
.kci-play:hover { transform: scale(1.05); }
.kci-play:active { transform: scale(.95); }

.kci-mini {
  -webkit-appearance: none; appearance: none;
  background: none; border: 0; padding: 4px; margin: 0;
  color: rgba(255, 253, 249, .88); cursor: pointer;
  display: grid; place-items: center;
}
.kci-mini:hover { color: #fffdf9; }

.kci-time {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; font-variant-numeric: tabular-nums;
  color: rgba(255, 253, 249, .9);
  text-shadow: 0 1px 4px rgba(0, 0, 0, .6);
}

.kci-scrub {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; background: none; cursor: pointer; margin: 0;
}
.kci-scrub::-webkit-slider-runnable-track {
  height: 4px; border-radius: 999px; background: rgba(255, 253, 249, .34);
}
.kci-scrub::-moz-range-track {
  height: 4px; border-radius: 999px; background: rgba(255, 253, 249, .34);
}
.kci-scrub::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 13px; height: 13px; border-radius: 50%; border: 0;
  background: #fffdf9; margin-top: -4.5px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .5);
}
.kci-scrub::-moz-range-thumb {
  width: 13px; height: 13px; border-radius: 50%; border: 0; background: #fffdf9;
}

/* ---------- focus, on a dark card ---------- */
.kci-card :focus-visible {
  outline: 3px solid #fffdf9;
  outline-offset: 3px;
  border-radius: 6px;
}

/* ---------- reduced motion: no cutting at all ---------- */
@media (prefers-reduced-motion: reduce) {
  .kci-video { display: none; }
  .kci-act, .kci-play, .kci-video { transition: none; }
  .kc-caps, .kci-caption { transition: none; }
}

/* ---------- narrow phones ---------- */
@media (max-width: 430px) {
  .kci-card { width: calc(100vw - 20px); border-radius: 14px; }
  .kci-card .kc-caps { bottom: 146px; }
  .kci-title { font-size: 19px; }
  .kci-rail { bottom: 164px; gap: 17px; }
}

/* ---------- the card's own later fixes ----------
   These came after the block above in assets/css/kc-intentions.css and beat
   it on source order at equal specificity (.kci-scrim's gradient, the card
   radius, the caption backing). They travel with it, in the same order, or
   the base would start winning again. */

.kci-card a.kci-act { color: #fffdf9; }
.kci-card a.kci-act:hover { color: #fffdf9; }

/* ============================================================
   LEGIBILITY FIX 2026-08-20. Kao caught a title rendering as
   dark-on-bright over snow: unreadable, and on a wellness site
   that is a failure not a blemish.

   ROOT CAUSE. The card-wide scrim is a gradient anchored to the
   card's bottom edge. The caption block is tall and variable,
   so on a long title the top of the text sat ABOVE where the
   gradient still had any density, and text-shadow alone cannot
   rescue white type on a bright highlight.

   THE FIX. The caption owns its own backing. A gradient painted
   behind the caption block itself, sized to the caption, so it
   is always exactly as tall as the text is, whatever the text
   does. That is a guarantee rather than a gradient that happens
   to be in the right place. Contrast holds on the brightest
   frame in the library.
   ============================================================ */

.kci-caption { position: absolute; }

.kci-caption::before {
  content: "";
  position: absolute;
  left: -18px; right: -78px; top: -22px; bottom: -26px;
  z-index: -1;
  border-radius: 14px;
  background: linear-gradient(to top,
    rgba(6, 10, 8, .92) 0%,
    rgba(6, 10, 8, .86) 45%,
    rgba(6, 10, 8, .62) 78%,
    rgba(6, 10, 8, 0) 100%);
  pointer-events: none;
}

/* The scrim is now doing less work up top, so it can be gentler on the
   picture while the caption stays guaranteed-legible. */
.kci-scrim {
  background:
    linear-gradient(to bottom, rgba(6, 10, 8, .55) 0%, rgba(6, 10, 8, .1) 20%, rgba(6, 10, 8, 0) 36%),
    linear-gradient(to top, rgba(6, 10, 8, .82) 0%, rgba(6, 10, 8, .34) 30%, rgba(6, 10, 8, 0) 58%);
}

/* Text shadow stays as a second line of defense, not the first. */
.kci-title, .kci-step, .kci-tags { text-shadow: 0 1px 10px rgba(0, 0, 0, .85); }

.kci-voice .kc-av { width: 42px; height: 42px; }

/* RADIUS: every Intention card, at every size, matches the rest of the site. */
.kci-card { border-radius: 14px; }

/* ============================================================
   CARD TEXT COLOR IS NOT NEGOTIABLE.

   These pages generate inside the Manifest shell, so <div class="kcm-app"> is
   an ancestor, and kc-manifest-app.css carries:

       .kcm-app :is(h1, h2, h3, h4) { color: var(--kcm-ink); }

   That is 0,1,1 and beats .kci-title at 0,1,0. The card title is an <h2>, so in
   LIGHT mode it took the page's dark ink and rendered near-black on dark
   footage: the illegible copy Kao reported twice. A card face is a lit screen
   over video and is dark in BOTH themes, so its text is always near-white
   regardless of what the page around it is doing.

   Every selector below is 0,2,x so it wins outright rather than by load order.
   If you add text to a card, add it here too.
   ============================================================ */
.kci-card .kci-title,
.kci-card .kci-step,
.kci-card .kci-tags,
.kci-card .kci-more,
.kci-card .kci-voice-name { color: #fffdf9; }
.kci-card .kci-voice-sub { color: rgba(255, 253, 249, .82); }
.kci-card .kci-act,
.kci-card .kci-act-label { color: #fffdf9; }
.kci-card .kci-act.is-on { color: #ff6b8a; }

/* ---------- shared, all ten ---------- */

.id-page {
  font-family: "Montserrat", system-ui, -apple-system, sans-serif;
  color: var(--mus-ink);
  padding: 0 0 3rem;
}

.id-wrap { max-width: 1080px; margin: 0 auto; padding: 0 1.1rem; }

/* THE CARD COLUMN. A song's art is square at 260px and a poster's is 3:4 at
   300px; both land near 300-400px tall beside a 3rem title. A 9:16 card at
   300px is 533px tall, which is taller than either, and that is correct here
   rather than a mistake to correct: this one is not an illustration of the
   thing, it IS the thing, and it holds the play control. */
/* .id-mount IS THE ELEMENT THE SCRIPT FILLS, and it has to carry the width
   itself. It was a bare div inside a flex .id-art, so it shrank to its
   content, the card's width:100% resolved against zero, and the 9:16 ratio
   made that a 0x0 card. Sizing the mount and letting the card fill it keeps
   the ratio doing the work in every layout below, which only ever set a width.
   Measured 0x0 before, 300x533 after. */
/* width: 100% ON BOTH, and it is load bearing. Half the layouts below center
   the card with a flex parent (align-items: center, or justify-content:
   center), and a flex item does not stretch under either: .id-art shrank to
   its content, .id-mount's 100% resolved against zero, and the 9:16 ratio
   turned that into a 0x0 card sitting in a large empty panel. Measured on
   option 06 as 460x780 of stage holding a 0x0 card. Stating the width at every
   step keeps the chain from depending on what kind of box the layout wrapped
   it in; the centering is then the mount's job, not the parent's. */
.id-art { width: 100%; min-width: 0; }
.id-mount { width: 100%; min-width: 0; display: flex; justify-content: center; }
.id-art .kci-card, .id-mount > .kci-card { width: 100%; max-width: 420px; }
.id-hero { grid-template-columns: minmax(0, 300px) minmax(0, 1fr); }
@media (max-width: 720px) { .id-hero { grid-template-columns: 1fr; } }

/* A visible edge on every secondary control, the same correction
   kc-poster-detail.css makes and for the same reason: --mus-rule measures
   1.23:1 against the page in light and 1.37:1 in dark, and a control whose
   edge you cannot see is a control people miss. --mus-ink-quiet is the same
   hairline weight at 5.15:1 / 6.44:1, clearing 3:1 outright. */
.id-actions .sd-iconbtn { border-color: var(--mus-ink-quiet); }

/* THE ROW IS THE POSTER CARD'S CIRCLE. Kaʻo, layouts/DESIGN-NOTES.md section 1,
   2026-08-28: the one true circle is the eye / heart / share / tee row under a
   live poster card (.kc-pcard__icon, cdo-watchtower.css): a 1px ring in
   --wt-field-border on a transparent disc, and on hover the ring and the ink
   both take the accent with NO fill. kc-song-detail.css hovers .sd-iconbtn
   with a filled disc instead, which is the one thing here that did not match.
   The ring keeps --mus-ink-quiet above (5.15:1 light, 6.44:1 dark) rather
   than --wt-field-border (3.7:1 light), because the poster's ring sits on a
   card and this one sits on the page; both clear 3:1, this one by more. The
   heart hovers and holds red, exactly as the poster's heart does. */
.id-actions .sd-iconbtn:hover { background: transparent; border-color: var(--wt-accent, var(--mus-accent)); color: var(--wt-accent, var(--mus-accent)); }
.id-actions [data-kci-save]:hover,
.id-actions [data-kci-save][aria-pressed="true"] { border-color: #e23b54; color: #e23b54; }

/* THE MUSIC CIRCLE'S OFF STATE reads as off at a glance, not only as a
   quieter grey: the slash the icon carries (hidden while pressed) is drawn
   across the note, and the ink drops to the quiet tone. On is the plain note
   in the row's own ink, so the two states differ in shape, not just colour. */
.id-music .id-music__off { display: none; }
.id-music[aria-pressed="false"] { color: var(--mus-ink-quiet); }
.id-music[aria-pressed="false"] .id-music__off { display: block; }

/* The captions circle, the music circle's twin. Off is a slash through the
   mark; disabled is while the full text is open below it, where there is
   nothing for it to do. */
.id-caps .id-caps__off { display: none; }
.id-caps[aria-pressed="false"] { color: var(--mus-ink-quiet); }
.id-caps[aria-pressed="false"] .id-caps__off { display: block; }
.id-caps[disabled] { opacity: .4; cursor: default; }

/* Download the video. A link wearing the row's circle, so it sits with the
   music and captions switches rather than looking like a different species. */
.id-dl { text-decoration: none; }

.id-lede {
  margin: 0 0 1.2rem; max-width: 46ch;
  font-size: 1.06rem; line-height: 1.6; color: var(--mus-ink-soft);
}

.id-body { font-size: 1.12rem; line-height: 1.68; color: var(--mus-ink); }
.id-body p { margin: 0 0 1.05rem; max-width: 68ch; }

/* ---------- the full text opens and closes ----------
   Kaʻo, 2026-08-30: "when someone clicks more the full text should appear and
   the captions should disappear, then when hitting less everything reverts."

   A HEIGHT AND A FADE, NOT A LINE CLAMP: this is six paragraphs, and
   -webkit-line-clamp only ever counts one element's lines. The mask fades the
   last visible line out instead of guillotining it mid-x-height, which is what
   tells a reader there is more without a word of instruction.

   .is-clamped IS ADDED BY SCRIPT. The markup ships open, so a reader with no
   JavaScript gets the whole piece rather than a cropped one with a button that
   cannot move. See the note in scripts/build-intentions-pages.mjs. */
.id-body.is-clamped {
  max-height: 15.5em;
  overflow: hidden;
  /* The fade FINISHES inside the box, at 94%, rather than at its very edge.
     Ending on transparent exactly at the boundary leaves the last line still
     half visible where the button starts, and the two read as overlapping. */
  -webkit-mask-image: linear-gradient(to bottom, #000 56%, transparent 94%);
  mask-image: linear-gradient(to bottom, #000 56%, transparent 94%);
}

.id-more {
  -webkit-appearance: none; appearance: none;
  display: inline-block;
  background: none; border: 0; border-bottom: 2px solid currentColor;
  margin: .6rem 0 1.4rem 20px;          /* 20px matches .kci-body's own padding */
  padding: 2px 0 3px;
  font-family: "Montserrat", system-ui, sans-serif;
  font-size: 1rem; font-weight: 700; letter-spacing: .01em;
  color: var(--mus-ink);
  cursor: pointer;
}
.id-more:hover { color: var(--mus-accent, var(--wt-accent, #2c5f4e)); }
.id-more:focus-visible { outline: 3px solid currentColor; outline-offset: 4px; border-radius: 4px; }

.id-h2 { font-size: 1.25rem; margin: 0 0 .8rem; letter-spacing: -.01em; }

/* ---------- the step ----------
   An Intention's payload is one thing to do, so it gets a panel and not a
   sentence in the flow. Built on .sd-side's surface so it is the same object
   the song page's facts panel is. */
.id-step {
  background: var(--mus-surface); border: 1px solid var(--mus-rule);
  border-radius: var(--mus-radius); padding: 1.1rem 1.2rem;
}
.id-step__k {
  margin: 0 0 .35rem; font: 800 .68rem "Montserrat", system-ui, sans-serif;
  letter-spacing: .12em; text-transform: uppercase; color: var(--mus-ink-quiet);
}
.id-step__v { margin: 0; font-size: 1.08rem; line-height: 1.5; color: var(--mus-ink); }

/* ---------- the transcript as a seek control ----------
   Real buttons, so they are reachable by keyboard and announce themselves.
   The line being spoken carries aria-current="location" as well as .is-live,
   because the highlight is information and not decoration. */
.id-lines { list-style: none; margin: 0; padding: 0; }
.id-line {
  display: block; width: 100%; text-align: left;
  border: 0; background: none; cursor: pointer;
  font: 400 1.12rem/1.62 "Montserrat", system-ui, sans-serif;
  color: var(--mus-ink-soft);
  padding: .42rem .7rem; margin: 0 0 .1rem;
  border-radius: var(--mus-radius-sm);
  border-left: 3px solid transparent;
  transition: color 140ms ease, background-color 140ms ease, border-color 140ms ease;
}
.id-line:hover { color: var(--mus-ink); background: var(--mus-surface-2); }
/* The spoken line: full-strength ink plus an accent edge. Weight alone would
   reflow the column as it moved down the piece, so the shift is color and a
   border, both of which cost no layout. --mus-ink on --mus-bg is 12.4:1 light
   and 14.3:1 dark; the quiet lines around it are 5.2:1 and 6.4:1, so every
   state clears AA on its own before the highlight is considered. */
.id-line.is-live {
  color: var(--mus-ink); background: var(--mus-surface);
  border-left-color: var(--mus-accent);
}
.am-main .id-line:focus-visible { outline: 3px solid var(--mus-focus); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .id-line { transition: none; } }

.id-lines__hint {
  margin: 0 0 .7rem; font-size: .86rem; color: var(--mus-ink-quiet);
}

/* ---------- 01 Family Standard ----------
   The song detail page with a taller card. Nothing else. */
.idl-01 .id-mid { align-items: start; }

/* ---------- 02 Poster Twin ----------
   The poster page's shape: a wider art column, and the facts panel doing the
   work the poster page's does. */
.idl-02 .id-hero { grid-template-columns: minmax(0, 340px) minmax(0, 1fr); }
@media (max-width: 720px) { .idl-02 .id-hero { grid-template-columns: 1fr; } }

/* ---------- 03 Stage First ----------
   The game page's shape: the playable thing sits on its own stage across the
   full column, with a hint under it, and the reading follows below. */
.idl-03 .id-stage {
  background: var(--mus-surface); border: 1px solid var(--mus-rule);
  border-radius: var(--mus-radius); padding: 1.6rem 1rem 1.3rem;
  display: flex; flex-direction: column; align-items: center; gap: .9rem;
  margin: 0 0 1.6rem;
}
.idl-03 .id-stage .kci-card { width: min(360px, 100%); }
.idl-03 .id-hint { margin: 0; font-size: .92rem; color: var(--mus-ink-quiet); text-align: center; }
.idl-03 .id-head { text-align: center; margin: 0 0 1.4rem; }
.idl-03 .id-head .id-lede { margin-inline: auto; }
.idl-03 .id-actions { justify-content: center; }

/* ---------- 04 Sticky Companion ----------
   The card stays while the piece scrolls past it, and the line being spoken
   lights up in the column. position: sticky only, so nothing is pinned by
   script and nothing fights the browser's own scrolling. */
.idl-04 .id-two {
  display: grid; grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: 2.2rem; align-items: start;
}
@media (max-width: 860px) { .idl-04 .id-two { grid-template-columns: 1fr; } }
.idl-04 .id-sticky { position: sticky; top: 88px; }
/* Sticky is a scroll behavior, and a fixed panel that cannot be scrolled past
   is what reduced motion and short viewports both suffer from. Below the
   card's own height there is nothing to gain by pinning it. */
@media (max-height: 700px), (prefers-reduced-motion: reduce) {
  .idl-04 .id-sticky { position: static; }
}

/* ---------- 05 Transcript Karaoke ----------
   The words are the page. The card sits above them, centered, and every line
   is a way back into the audio. */
.idl-05 .id-top { display: flex; justify-content: center; margin: 0 0 1.8rem; }
.idl-05 .id-top .kci-card { width: min(330px, 100%); }
.idl-05 .id-reading { max-width: 60ch; margin: 0 auto; }
.idl-05 .id-line { font-size: 1.22rem; padding: .55rem .8rem; }

/* ---------- 06 Split Stage ----------
   The card takes one full half of the screen and bleeds to the edge; the words
   take the other. The most cinematic of the ten and the least like the rest.

   NOT 100vh: a viewport-height panel with a scrolling column inside it traps
   the reading on a short screen and on a phone with browser chrome. min-height
   with a cap lets long pieces simply grow. */
.idl-06 .id-split {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0;
  align-items: stretch; min-height: min(88vh, 780px);
}
.idl-06 .id-split__art {
  background: var(--mus-surface-2);
  display: flex; align-items: center; justify-content: center;
  padding: 2rem 1.4rem;
}
.idl-06 .id-split__art .kci-card { width: min(400px, 100%); }
.idl-06 .id-split__read {
  display: flex; flex-direction: column; justify-content: center;
  padding: 2.4rem clamp(1.1rem, 4vw, 3rem);
}
@media (max-width: 900px) {
  .idl-06 .id-split { grid-template-columns: 1fr; min-height: 0; }
  .idl-06 .id-split__read { padding: 1.8rem 1.1rem; }
}

/* ---------- 07 Color Field ----------
   The piece's own tone becomes the ground the card stands on. The wash is a
   --mus-accent tint rather than an arbitrary color, so it stays inside the
   site's palette and inverts with it.

   The text does NOT sit on the wash. Only the card does. That is the whole
   reason this is safe: a tint deep enough to read as a field is a tint that
   would take body copy under AA, and the card brings its own scrim. */
.idl-07 .id-field {
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--mus-accent) 22%, transparent) 0%, transparent 70%),
    var(--mus-surface-2);
  border-radius: var(--mus-radius);
  padding: 2.6rem 1.2rem 2.2rem;
  display: flex; flex-direction: column; align-items: center; gap: 1.4rem;
  margin: 0 0 2rem;
}
.idl-07 .id-field .kci-card { width: min(340px, 100%); }
.idl-07 .id-field__head { text-align: center; max-width: 44ch; }
.idl-07 .id-reading { max-width: 66ch; margin: 0 auto; }

/* ---------- 08 Quiet Reader ----------
   Text first, for the person who would rather read it. The card is a companion
   floated beside the column, not the headline.

   float, so the words wrap around it and the page reads as an article with an
   illustration rather than two columns pretending to be one. It unfloats on
   narrow screens, where a float is just a squeezed column. */
.idl-08 .id-reading { max-width: 72ch; margin: 0 auto; }
.idl-08 .id-aside {
  float: right; width: 260px; margin: .3rem 0 1.4rem 2rem;
}
.idl-08 .id-aside .kci-card { width: 100%; }
@media (max-width: 760px) {
  .idl-08 .id-aside { float: none; width: min(300px, 100%); margin: 0 auto 1.6rem; }
}
.idl-08 .id-title { font-size: clamp(1.7rem, 5vw, 2.6rem); }

/* ---------- 09 Step First ----------
   The Intention is a thing to DO, so the step is promoted into the hero beside
   the card and the writing supports it instead of leading to it. */
.idl-09 .id-step {
  background: var(--mus-accent); border-color: var(--mus-accent);
  color: var(--mus-accent-ink);
}
/* On the accent panel the quiet token would be a tint of the wrong ground.
   --mus-accent-ink on --mus-accent is 7.24:1 light and 10.50:1 dark; at 82%
   over the same accent it holds 5.4:1 and 7.6:1, both past AA. */
.idl-09 .id-step__k { color: color-mix(in srgb, var(--mus-accent-ink) 82%, transparent); }
.idl-09 .id-step__v { color: var(--mus-accent-ink); font-size: 1.24rem; font-weight: 600; }
.idl-09 .id-step { margin: 0 0 1.2rem; }

/* ---------- 10 Cinema ----------
   Lean back. The card is as large as the column allows and the spoken line
   runs under it as a caption track, which is the one layout where the live
   sentence is the point rather than a detail of the card.

   The card keeps its own live line as well; this is a second, larger read of
   the same event, styled as a subtitle. It is aria-hidden because the card's
   line already carries it and announcing every sentence twice is worse than
   not announcing it. */
.idl-10 .id-cinema {
  background: var(--mus-surface-2); border-radius: var(--mus-radius);
  padding: 2rem 1.2rem 1.6rem; margin: 0 0 1.8rem;
  display: flex; flex-direction: column; align-items: center; gap: 1.2rem;
}
.idl-10 .id-cinema .kci-card { width: min(420px, 100%); }
.idl-10 .id-caption {
  min-height: 3.2em; max-width: 46ch; margin: 0; text-align: center;
  font: 600 1.32rem/1.45 "Montserrat", system-ui, sans-serif;
  color: var(--mus-ink);
}
.idl-10 .id-caption:empty::before { content: "Press play"; color: var(--mus-ink-quiet); font-weight: 400; }
.idl-10 .id-reading { max-width: 64ch; margin: 0 auto; }

/* ---------- the chooser ----------
   The jumpoff page. Not a layout: the index of them. */
.ido-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1.2rem; padding: .4rem 0 2rem; list-style: none; margin: 0;
}
.ido-card {
  display: flex; flex-direction: column; gap: .7rem;
  background: var(--mus-surface); border: 1px solid var(--mus-rule);
  border-radius: var(--mus-radius); padding: 1rem 1rem 1.1rem;
  text-decoration: none; color: var(--mus-ink);
  transition: border-color 140ms ease, transform 140ms ease;
}
.ido-card:hover { border-color: var(--mus-accent); transform: translateY(-2px); }
.am-main .ido-card:focus-visible { outline: 3px solid var(--mus-focus); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .ido-card { transition: none; } .ido-card:hover { transform: none; } }

/* A drawn wireframe, not a screenshot. Screenshots of ten pages is a build
   step and a stale asset; boxes cost nothing and say the same thing, which is
   where the card sits relative to the words. */
.ido-wire {
  aspect-ratio: 4 / 3; border-radius: var(--mus-radius-sm);
  background: var(--mus-bg); border: 1px solid var(--mus-rule);
  padding: 8px; display: grid; gap: 5px;
}
.ido-wire i { display: block; border-radius: 3px; background: var(--mus-rule); }
/* The card is the filled block in every wireframe, so the eye can find it.
   .is-step is the one other block that carries color on its page (option 09's
   accent step panel), drawn at half strength so it reads as related to the
   card without being mistaken for a second one. */
.ido-wire i.is-card { background: var(--mus-accent); }
.ido-wire i.is-step { background: color-mix(in srgb, var(--mus-accent) 45%, transparent); }
.ido-legend {
  display: flex; flex-wrap: wrap; gap: 1rem; align-items: center;
  margin: 0 0 1.2rem; font-size: .86rem; color: var(--mus-ink-quiet);
}
.ido-legend span { display: inline-flex; align-items: center; gap: .4rem; }
.ido-legend b { width: 14px; height: 10px; border-radius: 3px; background: var(--mus-accent); display: inline-block; }
.ido-legend b.is-rest { background: var(--mus-rule); }
.ido-num {
  font: 800 .68rem "Montserrat", system-ui, sans-serif; letter-spacing: .12em;
  text-transform: uppercase; color: var(--mus-ink-quiet); margin: 0;
}
.ido-name { font: 700 1.06rem "Montserrat", system-ui, sans-serif; margin: 0; letter-spacing: -.01em; }
.ido-why { margin: 0; font-size: .92rem; line-height: 1.5; color: var(--mus-ink-soft); }
.ido-tag {
  align-self: flex-start; margin: 0;
  font: 700 .68rem "Montserrat", system-ui, sans-serif; letter-spacing: .1em;
  text-transform: uppercase; color: var(--mus-accent);
}

/* The strip that lets you walk 1 to 10 without going back to the index. */
.ido-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  padding: 1.4rem 0 0; margin: 2rem 0 0; border-top: 1px solid var(--mus-rule);
}
.ido-strip__k { font-size: .86rem; color: var(--mus-ink-quiet); margin: 0 .4rem 0 0; }
.ido-strip a, .ido-strip__here {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 .5rem; border-radius: 999px;
  font: 700 .88rem "Montserrat", system-ui, sans-serif; text-decoration: none;
  border: 1px solid var(--mus-ink-quiet); color: var(--mus-ink);
}
.ido-strip a:hover { background: var(--mus-surface-2); border-color: var(--mus-accent); }
.am-main .ido-strip a:focus-visible { outline: 3px solid var(--mus-focus); outline-offset: 2px; }
.ido-strip__here { background: var(--mus-accent); border-color: var(--mus-accent); color: var(--mus-accent-ink); }

/* ===========================================================================
   THE REBUILT INTENTION DETAIL PAGE  (Kaʻo picked layout 01, 2026-08-26)
   ===========================================================================
   Everything here serves one of the tweaks he listed on the winning layout.
   The classes it leans on (.sd-hero, .sd-actions, .sd-iconbtn, .sd-btn) are
   the site's own and are NOT redefined; only what this page adds is below. */

/* TOP ALIGNED, both columns. kc-song-detail.css already starts .sd-hero at the
   top; .id-mid is the writing beside the panel and needs the same. */
.idl-01 .id-mid { align-items: start; }
.id-aside { display: grid; gap: 1rem; align-content: start; }

/* PLAY IS A REAL PRIMARY BUTTON, and its ink is PAIRED with its background.

   Kaʻo: "Button should be Play (like song says Play)... button should follow
   standard - white on light green not legible."

   He is right, and it is not a small miss: measured, #ffffff on the dark
   theme's mint #8fd0b4 is 1.77:1, against a 4.5:1 floor for normal text. The
   fix is not a different white, it is never hard-coding one. --mus-accent-ink
   is the token that travels WITH --mus-accent (near-black #10140f on the mint,
   warm white #fffdf9 on the deep green), which measures 10.50:1 dark and
   7.24:1 light.

   The fallbacks matter as much as the token: if --mus-accent-ink is ever
   undefined on a page that loads this file without kc-music-engine.css, an
   unguarded `color` inherits the page's body ink, which on the dark theme is
   near-white, and the button silently returns to 1.77:1. So both sides fall
   back to a literal pair that is legible together. */
.id-actions .sd-btn--primary {
  background: var(--mus-accent, var(--wt-btn-bg, #2c5f4e));
  color: var(--mus-accent-ink, var(--wt-btn-ink, #fffdf9));
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .68rem 1.25rem;
}
.id-actions .sd-btn--primary:hover { background: var(--mus-accent-hover, var(--wt-btn-bg-hover, #1f4638)); }
.id-play__ico { font-size: .9em; line-height: 1; }

/* The clock the video no longer carries. */
.id-clock { margin: .55rem 0 0; font-size: .9rem; color: var(--mus-ink-quiet, var(--wt-ink-quiet, #5f6a60)); }
.id-clock .mono { font-variant-numeric: tabular-nums; }

/* ---- YOUR STEP, in the Quick Tips shape, above About this Intention ----
   Same card as the tips block he pointed at, with one emoji chosen from the
   step's own words (lib/intention-step-emoji.js). The emoji is aria-hidden and
   the sentence carries the meaning, so a screen reader hears the step and
   never "green circle". */
.kci-tipbox {
  border: 1px solid var(--mus-rule, var(--wt-rule, #e4ddcf));
  border-radius: 14px;
  padding: 1rem 1.1rem;
  background: var(--mus-surface-2, var(--wt-chip-bg, #ede7da));
}
.kci-tipbox .kci-eyebrow {
  margin: 0 0 .5rem; font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 700; color: var(--mus-ink-quiet, var(--wt-eyebrow, #5f6a60));
}
.kci-tip {
  margin: 0; display: flex; gap: .7rem; align-items: flex-start;
  font-size: 1.02rem; line-height: 1.55; color: var(--mus-ink, var(--wt-ink, #26302b));
}
.kci-tip__e { font-size: 1.25rem; line-height: 1.3; flex: none; }

/* ---- full screen ----
   A CSS overlay first, because iOS Safari has never supported the Fullscreen
   API on anything but <video>; requestFullscreen is the upgrade where it
   exists. A button that did nothing on a phone would be worse than none. */
.kci-card.is-fullscreen {
  position: fixed; inset: 0; z-index: 9999; max-width: none; width: 100vw; height: 100dvh;
  border-radius: 0; background: #000;
}
.kci-card.is-fullscreen .kci-stage { height: 100dvh; aspect-ratio: auto; }
body.kci-fullscreen-on { overflow: hidden; }

/* The transcript reads as prose, and each paragraph is a seek target, so it
   gets a pointer and a lit state rather than looking like dead text. */
.id-body p[data-kci-index] { cursor: pointer; }
.id-body p[data-kci-index].is-live { color: var(--mus-ink, var(--wt-ink, #26302b)); font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .kci-card.is-fullscreen { transition: none; } }

/* ---------- the detail card turns over ----------
   Kaʻo, 2026-08-26: "it is a flip the card button".

   The GEOMETRY IS NOT HERE. .kc-flip / .kc-flip__inner / .kc-flip__face carry
   the 3D and the 1.6s rotation in cdo-watchtower.css, .kif-lockup carries the
   poster's measured type in kc-intentions-feed.css, and .kc-bc__scrim is the
   card-back layer every poster on this site uses. This file only says how that
   machinery sits inside a 9:16 detail card, which is the one thing none of
   them knows. */
/* .kc-flip IS A SIZED COMPONENT, and it has to be un-sized here.
   cdo-watchtower.css:5827 gives it `width: 320px; max-width: 84vw;
   aspect-ratio: 3/4`, later overridden to 5/7, because everywhere else it IS
   the card: a poster on a wall sets its own size. Here it is a layer inside a
   9:16 card that is already sized by the layout, so those three have to go or
   the poster draws at 320x448 inside a 300x533 card and hangs over two edges.
   Measured exactly that before this rule.

   Scoped with the card class, not just .kci-flip: both are one class, and
   kc-intentions-feed.css loads AFTER this file, so at equal specificity the
   sized rule would win on order alone. */
.kci-card .kci-flip {
  position: absolute; inset: 0;
  width: auto; max-width: none; height: auto; aspect-ratio: auto;
  cursor: default;      /* the card is not click-to-flip; the row's button is */
}
.kci-flip .kc-flip__inner { width: 100%; height: 100%; }
/* Each face fills the card, and the stage inside the front keeps its own
   inset: 0 without a second positioning context to fight. */
.kci-flip .kc-flip__face { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.kci-back { background: #0a0e0c; }
/* The first frame under the scrim, for the same reason the feed's back has it:
   a card nobody has played must not turn over to a flat rectangle. Bottom
   crop, the house rule for portrait footage. */
.kci-back-poster {
  position: absolute; inset: 0;
  background: #0a0e0c center bottom / cover no-repeat;
}

/* The flip mark in the action row is a mask, so it has no intrinsic size the
   way the row's SVGs do. 19px matches .sd-iconbtn svg exactly, which is what
   keeps this button the same weight as Save, Share and the flag beside it. */
.id-flip__ic { width: 19px; height: 19px; }
