/* App and section pages in the homepage's world: the page's own ground and accent, the deck's copy anatomy in
   the hero, the app's playable demo beside it, then the page's own sections set in the same type system.
   Loaded after spectrum.css and common.css. Each page sets --bg and --accent on <body>. */
body.lab-app { --page: var(--bg); background: var(--bg); }
/* THE PAUSE CONTROL KEEPS ITS SPACE ON EVERY PAGE, WHETHER OR NOT IT IS SHOWN. It used to be display:none on a
   page with no looping demo, which took 91px out of the nav and slid every link right; the homepage reserved the
   box and showed nothing; a page with a demo reserved it and showed the pill. Three states, three different
   positions for the same menu, and the nav visibly jumped as you moved between pages. Hidden the way the base rule
   in deck.css hides it, by visibility, so the row is the same width everywhere. */
body.lab-app:not(.has-demos) #deck-pause { visibility: hidden; pointer-events: none; }

/* ---------- Hero ---------- */
.app-hero {
  position: relative; max-width: 96rem; margin: 0 auto;
  padding: calc(4.6rem + clamp(2.5rem, 7vh, 5rem)) var(--gx) clamp(2.5rem, 6vh, 4.5rem);
  display: grid; gap: clamp(2rem, 4vw, 5rem); align-items: start;   /* anchored, so a demo that grows never jumps */
}
.app-hero .sec-copy { display: grid; gap: 1rem; align-content: start; justify-items: start; padding-top: clamp(0rem, 4vh, 2.5rem); }
.app-hero .sec-fig { width: clamp(6rem, 9vw, 8.5rem); }
.app-hero .sec-name { font-size: clamp(3rem, 7vw, 6rem); }
.app-hero .sec-desc { max-width: 34rem; }
.app-note { font-size: 1.05rem; color: rgba(255,255,255,0.62); max-width: 34rem; }
.app-hero .sec-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin-top: 0.25rem; }
.app-hero .obj { justify-items: center; }
.app-hero .obj .demo { width: min(100%, 42rem); }
.app-hero .demo.is-playable { margin-top: 2.6rem; }   /* room for the sticker above the demo */
.app-hero .demo-chat.is-playable { margin-top: 0; }
.app-hero .obj .demo-chat { width: 100%; }
.app-hero .demo-chat .demo-badge { top: -1.4rem; bottom: auto; left: auto; right: 1rem; }
.app-hero .demo-chat .demo-badge::after { top: auto; bottom: -7px; left: 1rem; margin-top: 0; }
.app-hero .obj .demo-cull, .app-hero .obj .demo-lite { width: min(100%, 36rem); }
.btn-ghost { background: none; color: #fff; border: 2px solid rgba(255,255,255,0.35); }
.btn-ghost:hover { border-color: #fff; }
.btn-lg { font-size: 1.15rem; padding: 0.95rem 1.6rem; }
@media (min-width: 56rem) {
  .app-hero { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); min-height: 88svh; }
  .app-hero.is-solo { grid-template-columns: minmax(0, 1fr); min-height: 60svh; align-content: center; }
}
@media (max-width: 55.99rem) {
  .app-hero { padding-top: calc(4.6rem + 2rem); }
  .app-hero .obj { justify-items: stretch; }
  .app-hero .demo.is-playable { margin-top: 2.25rem; }
}

/* ---------- Body sections ---------- */
.app-body { max-width: 96rem; margin: 0 auto; padding: 1rem var(--gx) 4rem; display: grid; gap: clamp(3rem, 7vh, 5.5rem); }
.app-section { max-width: 62rem; }
.app-section.is-wide { max-width: none; }
.section-divider { display: none; }
.product-section-inner { display: grid; gap: 1.25rem; }
.product-section-label {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -0.025em; line-height: 1;
  font-size: clamp(1.9rem, 3.4vw, 2.8rem); color: var(--accent); margin-bottom: 0.25rem;
}
.product-text { display: grid; gap: 0.9rem; font-size: clamp(1.1rem, 1.35vw, 1.25rem); line-height: 1.6; color: rgba(255,255,255,0.88); max-width: 44rem; }
.product-text .highlight, p.highlight { font-family: var(--font-display); font-weight: 700; font-size: 1.35em; color: #fff; letter-spacing: -0.01em; }
.product-highlight { font-family: var(--font-display); font-weight: 700; font-size: clamp(1.3rem, 2vw, 1.7rem); color: #fff; letter-spacing: -0.01em; max-width: 40rem; }
.cost-big { font-family: var(--font-display); font-weight: 800; font-size: clamp(2.4rem, 5vw, 4rem); letter-spacing: -0.03em; line-height: 1; color: var(--accent); }
/* THE MARKER IS A MARKER, NOT A COMMA. Each row began with <span class="dash">, </span>: the class says dash, the
   character is a comma, and it rendered as a low amber comma floating before the line and read out as "comma,
   AssemblyAI, transcription". Left behind by the pass that took the em dashes out of the copy. The list draws its
   own marker now, in the page's accent. */
.cost-list { margin: 0; padding: 0 0 0 1.1rem; display: grid; gap: 0.5rem; font-size: 1.1rem; color: rgba(255,255,255,0.88); }
.cost-list li::marker { color: var(--accent); }
/* A LINK INSIDE A PARAGRAPH HAS TO BE VISIBLE AS ONE. The only live address on /projects/ sat in the Ask
   Champaign card with the paragraph's own colour, no underline and no weight change: identical to the text around
   it in every computed respect, which is WCAG 1.4.1 and, more plainly, unfindable. Every other card on that page
   carries a "Visit Site" button, so this was the one that needed the underline and did not have it. */
.project-card-desc a {
  /* NOT --accent. On /projects/ that token is #FEF3E8, the cream the cards are printed on, so an underline drawn
     with it came out at exactly 1.00:1 against the card: the rule shipped and changed nothing a visitor could see.
     A link's underline is a foreground, so it gets a foreground value of its own. */
  color: #9c3516; font-weight: 600; text-decoration: underline; text-decoration-thickness: 0.09em;
  text-underline-offset: 0.16em; text-decoration-color: currentColor;
}
.project-card-desc a:hover { text-decoration-thickness: 0.16em; }
.cost-list a, .product-text a, .dev-note a, .app-body a.text-rc-amber { color: var(--accent); text-decoration: underline; text-decoration-thickness: 0.08em; text-underline-offset: 0.12em; }
.text-rc-gray, .text-br-gray, .text-brs-gray, .text-muted, .text-muted-60 { color: rgba(255,255,255,0.72); }
.text-muted-40 { color: rgba(255,255,255,0.55); }
.text-rc-amber, .text-br-cyan, .text-brs-rose { color: var(--accent); }

/* steps and feature cards: the app's ground lifted a notch, with the accent as a rule */
/* THE CLASS, NOT THE TWO THAT OVERFLOWED. A repeat(auto-fit, minmax(X, 1fr)) track cannot shrink below X, so a
   container narrower than X is pushed sideways by its own grid and the whole page scrolls horizontally. At a 320px
   viewport the two 20rem grids made four pages 16px wider than the screen. min(X, 100%) keeps the intent, a column
   at least X wide where there is room, and lets the track give way where there is not. Every auto-fit grid here is
   written this way now, not only the two that happened to be measured over. */
.feature-steps { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); }
.feature-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); }
.feature-steps > div, .feature-grid > div {
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.08); border-radius: 14px; padding: 1.4rem 1.5rem 1.5rem;
  display: grid; gap: 0.5rem; align-content: start;
}
.feature-steps > div { border-left: 4px solid var(--accent); border-radius: 6px 14px 14px 6px; }
.feature-steps h3, .feature-grid h3 { font-family: var(--font-display); font-weight: 700; font-size: 1.25rem; letter-spacing: -0.01em; line-height: 1.15; }
.feature-steps p, .feature-grid p { font-size: 1.02rem; line-height: 1.5; color: rgba(255,255,255,0.8); }
.feature-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem 2rem; grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); font-size: 1.08rem; color: rgba(255,255,255,0.88); }
.feature-list li { position: relative; padding-left: 1.4rem; }
.feature-list li::before { content: ""; position: absolute; left: 0; top: 0.6em; width: 0.6rem; height: 0.6rem; border-radius: 50%; background: var(--accent); }

/* a note from the developer: a sheet of paper on the app's ground, like the stickers and the Lower Key card */
.dev-note {
  background: #efe8da; color: #1e2d40; border-radius: 6px; padding: clamp(1.5rem, 3vw, 2.25rem) clamp(1.5rem, 3vw, 2.5rem);
  max-width: 44rem; font-size: 1.1rem; line-height: 1.6; display: grid; gap: 0.9rem;
  box-shadow: 0 24px 50px -24px rgba(0,0,0,0.8); transform: rotate(-0.6deg);
}
.dev-note-title { font-family: var(--font-display); font-weight: 800; font-size: 1.5rem; letter-spacing: -0.02em; color: #1e2d40; }
.dev-note a { color: #a63a17; }
.dev-note-list { margin: 0; padding-left: 1.2rem; display: grid; gap: 0.5rem; }
.dev-note strong { font-weight: 700; }

/* requirements and the closing download */
.sys-req { border-top: 1px solid rgba(255,255,255,0.12); padding-top: 1.5rem; font-size: 1.05rem; color: rgba(255,255,255,0.68); max-width: 44rem; }
.download-cta { text-align: center; display: grid; gap: 1rem; justify-items: center; padding: clamp(2rem, 6vh, 4rem) 0 1rem; }
.download-cta p { font-size: 1.02rem; color: rgba(255,255,255,0.62); max-width: 36rem; }
.download-cta .btn { margin-bottom: 0.25rem; }
.app-body .guide-link { display: inline-flex; align-items: center; min-height: 44px; padding: 0.55rem 1.1rem; border-radius: 999px; border: 2px solid rgba(255,255,255,0.35); font-family: var(--font-display); font-weight: 700; color: #fff; }
.app-body .guide-link:hover { border-color: #fff; }

/* reveal on scroll, gently */
@media (max-width: 55.99rem) { .dev-note { transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); }
  /* Without a script nothing ever adds .visible, so every section stayed at zero: about 80% of each app page's copy
     was invisible, two links were invisible AND focusable, and the homepage's own no-script fallback was sending
     people to pages that could not show them anything. The rule this belongs to: NOTHING THAT JAVASCRIPT WILL
     REVEAL OR FILL MAY START LIFE INVISIBLE OR AS A FOCUSABLE LINK TO NOWHERE. tools/check-markup.mjs enforces it. */
  .no-js .reveal { opacity: 1; transform: none; }
  .reveal.visible { opacity: 1; transform: none; }
}

/* ---------- Utilities page ---------- */
.util-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); }
.util-card {
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1); border-radius: 18px; padding: clamp(1.25rem, 2.5vw, 2rem);
  display: grid; gap: 1rem; align-content: start;
}
.util-card .sec-fig { width: 5rem; margin: 0; }
.util-card h2 { font-family: var(--font-display); font-weight: 800; font-size: clamp(1.7rem, 3vw, 2.4rem); letter-spacing: -0.02em; line-height: 1; }
.util-card p { font-size: 1.08rem; line-height: 1.55; color: rgba(255,255,255,0.85); }
.util-card .demo { width: 100%; margin-top: 2.4rem; }
.util-card .sec-meta { margin-top: 0.25rem; }
.utilities-note { font-size: 1.1rem; line-height: 1.6; color: rgba(255,255,255,0.8); max-width: 44rem; }

/* ---------- Projects page ---------- */
body.page-projects { --bg: #c4471f; --accent: #fef3e8; }
.projects-grid { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); }
.project-card { background: #fef3e8; color: #1e2d40; border-radius: 6px; padding: 1.5rem 1.6rem; display: grid; gap: 0.75rem; align-content: start; box-shadow: 0 20px 40px -24px rgba(0,0,0,0.6); }
.project-card:nth-child(3n+1) { transform: rotate(-0.5deg); } .project-card:nth-child(3n+2) { transform: rotate(0.4deg); }
.project-card-header { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
.project-card-title { font-family: var(--font-display); font-weight: 800; font-size: 1.45rem; letter-spacing: -0.02em; line-height: 1.05; color: #1e2d40; }
.project-card-badge { font-family: var(--font-display); font-size: 0.8rem;   /* 12.8px: the site holds 12px everywhere else and this was 11.52 */ font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; border: 1px solid #1e2d40; border-radius: 999px; padding: 0.15rem 0.5rem; }
.project-card-desc { font-size: 1.02rem; line-height: 1.55; color: #33445a; }
/* The cards stretch to a common height and the link did not move with them: in one row of four the CTA sat 24px,
   25px and 150px from the card's floor. A column body with the link pushed to the bottom puts them on one line. */
.project-card-body { display: flex; flex-direction: column; height: 100%; }
.project-card-link { margin-top: auto; font-family: var(--font-display); font-weight: 700; color: #c4471f; align-self: start; min-height: 44px; display: inline-flex; align-items: center; }   /* the site floors every target at 44px; these were 23px, the only ones under */
.project-card-link:hover { text-decoration: underline; }
body.page-projects .app-hero .sec-name { color: #fff; }
body.page-projects .sec-desc { color: #fff; }   /* 0.92 white on the coral ground measured 4.40:1 */

/* ---------- 404 ---------- */
body.page-404 .app-hero { min-height: 80svh; }

/* Bubble Reel demo in the app hero: the same layout deck.css gives it inside the folder */
.app-hero .obj .demo-chat { width: 100%; margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 19rem); gap: 1.25rem; align-items: start; padding: 0; background: none; box-shadow: none; border-radius: 0; }
.app-hero .obj .demo-chat .phone { border-radius: 30px; box-shadow: 0 40px 80px -30px rgba(0,0,0,0.85), 0 0 0 10px #15171f, 0 0 0 11px rgba(255,255,255,0.12); margin: 11px; }
.app-hero .obj-chat { justify-items: stretch; }
/* Only how tall. The shape is common.css's business; these used to set the phone's height per size instead, and
   the more specific rule above them beat both anyway. */
/* THE BUDGET IS THE APP HERO'S, NOT THE DECK'S. This asked for 100svh minus --navh and two --rim, and both of
   those are declared on .sheets in deck.css, which no app page loads. An undefined var makes the whole calc
   invalid, so --phone-h was nothing, the phone had no height cap and no computed width, and all three export-ratio
   buttons did literally nothing on this page. Stated in the units this page actually has: the fixed nav, and room
   to breathe under it. */
.app-hero .obj .demo-chat { --phone-h: min(32rem, calc(100svh - 11rem)); }
.app-hero .obj .phone { transition: width 0.4s var(--ease), height 0.4s var(--ease); }
.app-hero .obj .demo-chat { --chat-phone-col: 19rem; grid-template-columns: minmax(0, var(--chat-phone-col)) minmax(0, 1fr); }   /* phone first, settings beside it, on the app page */
/* THE NUDGE IS MEASURED FROM WHICHEVER SIDE THE PHONE IS ON. In the deck the phone is the second column and the
   sticker is offset from the right; here it is the first, so that same rule put "Try it: type a reply" 724px away
   from the phone and up at the top of the demo, pointing at nothing at all. Measured from the left against the
   same column variable, so the two cannot drift. */
.app-hero .obj .demo-chat .demo-badge:not(.demo-badge-next) {
  /* The phone is at this page's left edge, so there is no room beside it the way there is in the deck. The nudge
     sits over the thread with its tail on the compose bar it names, which is what the deck already does whenever
     its own column gets too narrow to put it alongside. */
  right: auto; left: 0.6rem; top: auto; bottom: 4.6rem;
}
/* ONE COLUMN MEANS THE PHONE CAN HAVE THE ROOM. Stacked, the phone kept a height budget meant for a two-column
   hero, so at 768px it drew 146px wide with 200px of empty ground beside it and "what did you eat" wrapped over
   three lines: a demo whose whole job is to look like a phone, looking worst on a phone. It takes the height the
   column will give it now, capped so it still fits a short screen. */
@media (max-width: 55.99rem) {
  .app-hero .obj .demo-chat { grid-template-columns: 1fr; justify-items: center; }
  .app-hero .obj .demo-chat { --phone-h: min(30rem, calc(100svh - 14rem)); }
}

/* the footer as the homepage lays it out */
.lab-app .footer-copy { color: rgba(255,255,255,0.6); }
.lab-app .footer-inner { flex-wrap: wrap; row-gap: 1.25rem; }
.lab-app .footer-nav { order: -1; width: 100%; }

/* desktop: section titles in a left rail, the copy and cards on the right, so the body keeps the hero's two-column rhythm */
@media (min-width: 64rem) {
  .app-section { max-width: none; }
  .app-section .product-section-inner { grid-template-columns: minmax(11rem, 15rem) minmax(0, 1fr); column-gap: clamp(2rem, 4vw, 4rem); align-items: start; }
  .app-section .product-section-inner > * { grid-column: 2; }
  /* one row, so the label spans it without being told a number. "1 / span 30" cost 29 row gaps per section. */
  /* start, not stretch: stretched to the section's height a sticky label has nowhere to travel and never sticks */
  .app-section .product-section-inner > .product-section-label { grid-column: 1; grid-row: 1; position: sticky; top: calc(var(--nav-h, 4.6rem) + 4.2rem); margin: 0; align-self: start; }
}
/* the phone keeps its height on the app page too, so the receipt drops in over the thread instead of stretching it */
@media (min-width: 56rem) { .app-hero .obj .phone { height: min(32rem, calc(100svh - 4.6rem - 12rem)); } }
.app-hero .demo-chat .demo-badge-next { right: auto; left: 9.5rem; top: -2rem; }
@media (max-width: 55.99rem) { .app-hero .demo-chat .demo-badge-next { right: 1rem; left: auto; } }

/* the content that used to be a column of grid items is one item now; it keeps the rhythm they had between them */
.app-section .section-body > * + * { margin-top: 1.25rem; }


/* =====================================================================================================================
   THE PAGE IS THE FOLDER, OPENED (2026-09-18). On the homepage each app is a closed folder in a stack, with a tab that
   names it. The app page is that folder taken out and opened flat: the tab stays at the top, on the folder's rim,
   and follows the reader; inside are only the things a person keeps in a folder about an app. One accent per page.
   ================================================================================================================== */

/* ---------- The folder tab: the app's name and cut-out on the rim, then what is inside ---------- */
.folder-tab { position: sticky; top: var(--nav-h, 4.6rem); z-index: 6; margin-top: var(--nav-h, 4.6rem); background: var(--bg); }
.folder-tab ul {
  list-style: none; margin: 0 auto; padding: 0.7rem var(--gx) 0; max-width: 96rem;
  display: flex; align-items: flex-end; gap: 0.35rem;
}
.folder-tab::after { content: ""; display: block; height: 3px; background: var(--accent); }                 /* the rim, the tabs stand on it */
.folder-tab::before { content: ""; position: absolute; left: 0; right: 0; bottom: -10px; height: 10px; background: color-mix(in srgb, var(--accent) 30%, var(--bg)); }   /* the folder's edge, as the deck draws it */
.folder-tab a {
  position: relative; display: inline-flex; align-items: center; gap: 0.45rem; height: 2.2rem; padding: 0 0.8rem;
  font-family: var(--font-display); font-weight: 700; font-size: 0.92rem; white-space: nowrap;
  color: var(--accent); background: var(--bg);
  border: 2px solid var(--accent); border-bottom: 0; border-radius: 8px 8px 0 0;
  transition: color 0.2s, background-color 0.2s;
}
.folder-tab a::after { content: ""; position: absolute; left: 0; right: 0; top: -6px; bottom: -6px; }   /* a 44px target */
.folder-tab a:hover { background: color-mix(in srgb, var(--accent) 24%, var(--bg)); }
.folder-tab a[aria-current] { background: var(--accent); color: var(--bg); }
.folder-tab a:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.folder-tab .ft-name a { font-size: 1rem; padding-right: 1rem; }
.folder-tab .ft-name img { width: 1.5rem; height: 1.5rem; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.5)); }
.folder-tab .ft-dl { margin-left: auto; }
@media (max-width: 47.99rem) {
  .folder-tab .ft-in:not(.ft-dl) { display: none; }   /* a phone gets the folder's name and the way to the download */
}
.app-section[id] { scroll-margin-top: calc(var(--nav-h, 4.6rem) + 4.3rem); }
#note { scroll-margin-top: calc(var(--nav-h, 4.6rem) + 6.5rem); }   /* the cut-out stands above the section's box */
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* ---------- Hero: the folder's cover, sized to what is on it ---------- */
.app-hero.is-folder { padding-top: clamp(2.5rem, 6vh, 4.5rem); padding-bottom: clamp(2rem, 5vh, 3.5rem); }
.app-hero.is-folder .sec-copy { padding-top: 0; }
@media (min-width: 56rem) { .app-hero.is-folder { min-height: 0; } }

/* ---------- Inside the folder ---------- */
.app-body.is-folder { padding-top: clamp(1.5rem, 4vh, 3rem); }
.app-body.is-folder .app-section, .app-body.is-folder .product-section-inner, .app-body.is-folder .section-body, .index > li, .steps > li, .bill-beside, .bill-wrap { min-width: 0; }
.app-body.is-folder .section-body { display: grid; gap: 1.5rem; }
.app-body.is-folder .section-body > * + * { margin-top: 0; }
.how-sub { font-family: var(--font-display); font-weight: 700; font-size: 1.3rem; letter-spacing: -0.01em; color: #fff; margin-top: 0.5rem; }
.how-text { display: grid; gap: 0.9rem; font-size: clamp(1.1rem, 1.35vw, 1.25rem); line-height: 1.6; color: rgba(255,255,255,0.88); max-width: 44rem; }

/* the story: the page's own cover paragraph */
.story { display: grid; gap: 1rem; margin-bottom: 0.5rem; }
.story p { font-family: var(--font-body); font-size: clamp(1.25rem, 1.9vw, 1.65rem); line-height: 1.45; max-width: 44rem; text-wrap: pretty; color: rgba(255,255,255,0.88); }
.story p.story-mark { font-family: var(--font-display); font-weight: 800; font-size: clamp(1.6rem, 2.8vw, 2.4rem); line-height: 1.05; letter-spacing: -0.02em; color: var(--accent); margin-top: 0.3rem; }

/* ---------- Frames on a strip of film ---------- */
/* THE FILM IS GREY AND THE HOLES ARE HOLES. The first version was a dark band with grey dashes on it, which is a
   ribbon with a pattern. Film is the other way round, as the B-Roller icon draws it: a grey strip with sprocket
   holes punched through it, so the page shows through the holes, and the frames are the dark rectangles between
   the rows of holes. Wide, the strip runs left to right; on a phone the frames stack and the strip runs down, with
   the holes on its two long edges, as a strip held upright would. */
.steps {
  --film: #8b909e; --hole: var(--bg);
  list-style: none; margin: 0; padding: 20px 8px; counter-reset: step; position: relative;
  background: var(--film); border-radius: 4px;
  display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
}
.steps::before, .steps::after {
  content: ""; position: absolute; left: 12px; right: 12px; height: 9px; border-radius: 1px;
  background: repeating-linear-gradient(90deg, var(--hole) 0 14px, transparent 14px 34px);
}
.steps::before { top: 5px; } .steps::after { bottom: 5px; }
.steps li { counter-increment: step; background: #0b0d12; border-radius: 3px; padding: 1.3rem 1.4rem 1.4rem; display: grid; gap: 0.4rem; align-content: start; min-width: 0; }
.steps li::before { content: counter(step); font-family: var(--font-display); font-weight: 800; font-size: 2.2rem; line-height: 1; letter-spacing: -0.03em; color: var(--accent); margin-bottom: 0.3rem; }
.steps.is-choices li::before { content: none; }
.steps h3 { font-family: var(--font-display); font-weight: 700; font-size: 1.25rem; line-height: 1.15; letter-spacing: -0.01em; text-wrap: balance; color: #fff; }
.steps p { font-size: 1.02rem; line-height: 1.5; color: rgba(255,255,255,0.82); }
@media (max-width: 47.99rem) {
  .steps { padding: 8px 20px; }
  .steps::before, .steps::after { left: auto; right: auto; top: 12px; bottom: 12px; height: auto; width: 9px; background: repeating-linear-gradient(180deg, var(--hole) 0 14px, transparent 14px 34px); }
  .steps::before { left: 5px; } .steps::after { right: 5px; }
}

/* ---------- The film ---------- */
.tour-card {
  position: relative; display: grid; max-width: 52rem; border-radius: 12px; overflow: hidden; color: #fff;
  background: rgba(0,0,0,0.3); box-shadow: 0 30px 60px -30px rgba(0,0,0,0.9); isolation: isolate;
}
.tour-card img { display: block; width: 100%; height: auto; transition: transform 0.6s var(--ease); }
.tour-card-play {
  position: absolute; left: 50%; top: calc(50% - 1.9rem); z-index: 2; width: 5rem; height: 5rem; margin: -2.5rem 0 0 -2.5rem;
  border-radius: 50%; background: var(--accent); color: var(--bg); display: grid; place-items: center;
  box-shadow: 0 18px 40px -12px rgba(0,0,0,0.9); transition: transform 0.3s var(--ease);
}
.tour-card-play svg { width: 2.2rem; height: 2.2rem; fill: currentColor; margin-left: 0.2rem; }
.tour-card-cap { display: grid; grid-template-columns: auto 1fr auto; align-items: center; column-gap: 0.75rem; padding: 0.9rem 1.2rem; }
.tour-card-cap b { font-family: var(--font-display); font-weight: 800; font-size: 1.2rem; letter-spacing: -0.01em; }
.tour-card-cap > span:not(.tour-card-go) { font-size: 0.95rem; color: rgba(255,255,255,0.75); }
.tour-card-go { font-family: var(--font-display); font-weight: 700; font-size: 0.9rem; color: var(--bg); background: var(--accent); border-radius: 999px; padding: 0.45rem 0.9rem; }
.tour-card:hover img { transform: scale(1.03); }
.tour-card:hover .tour-card-play { transform: scale(1.08); }
.tour-card:focus-visible { outline: 3px solid #fff; outline-offset: 4px; }
@media (max-width: 47.99rem) { .tour-card-cap { grid-template-columns: 1fr auto; row-gap: 0.15rem; } .tour-card-cap > b, .tour-card-cap > span:not(.tour-card-go) { grid-column: 1; } .tour-card-go { grid-column: 2; grid-row: 1 / span 2; align-self: center; } }
@media (prefers-reduced-motion: reduce) { .tour-card img, .tour-card-play { transition: none; } .tour-card:hover img { transform: none; } }

/* ---------- One list of what it does, every line shown ---------- */
.index {
  list-style: none; margin: 0; padding: 0; counter-reset: idx;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr)); column-gap: clamp(2rem, 4vw, 4rem); row-gap: 0;
  align-items: start; border-bottom: 1px solid rgba(255,255,255,0.14);
}
.index > li { counter-increment: idx; border-top: 1px solid rgba(255,255,255,0.14); padding: 0.9rem 0 1rem 2.7rem; position: relative; }
.index > li::before { content: counter(idx, decimal-leading-zero); position: absolute; left: 0; top: 1.05rem; font-family: var(--font-display); font-weight: 800; font-size: 0.95rem; color: var(--accent); font-variant-numeric: tabular-nums; }
.index h3 { font-family: var(--font-display); font-weight: 700; font-size: 1.15rem; line-height: 1.2; letter-spacing: -0.01em; margin-bottom: 0.35rem; }
.index p { font-size: 1.02rem; line-height: 1.5; color: rgba(255,255,255,0.8); }
.index p + p { margin-top: 0.6rem; }
.index-more-h { font-family: var(--font-display); font-weight: 700; font-size: 0.85rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); margin-top: 0.5rem; }
.index-more { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem 2rem; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); font-size: 1.02rem; color: rgba(255,255,255,0.85); }
.index-more li { position: relative; padding-left: 1.2rem; }
.index-more li::before { content: ""; position: absolute; left: 0; top: 0.55em; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--accent); }

/* ---------- The bill: the one place cost and privacy live ---------- */
.cost-body { display: grid; grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); gap: clamp(2rem, 4vw, 4rem); align-items: start; }
@media (max-width: 63.99rem) { .cost-body { grid-template-columns: minmax(0, 1fr); } }
.bill-wrap { filter: drop-shadow(0 30px 40px rgba(0,0,0,0.55)); transform: rotate(0.6deg); }
.bill {
  --paper: #f6f1e6; --ink: #1e2d40;
  position: relative; background: var(--paper); color: var(--ink);
  padding: 1.5rem 1.5rem 3.4rem; font-family: var(--font-body); font-size: 1rem; line-height: 1.35;
  font-variant-numeric: tabular-nums;
  mask: conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) 50% / 16px 100%;   /* the torn edge */
}
.bill-head { display: grid; gap: 0.2rem; padding-bottom: 0.9rem; margin-bottom: 0.7rem; border-bottom: 2px dashed rgba(30,45,64,0.35); text-align: center; }
.bill-brand { font-family: var(--font-display); font-weight: 700; font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase; color: rgba(30,45,64,0.72); }
.bill-head b { font-family: var(--font-display); font-weight: 800; font-size: 1.5rem; letter-spacing: -0.02em; line-height: 1.1; }
.bill-sub { font-size: 0.85rem; color: rgba(30,45,64,0.75); }
.bill-lines, .bill-total { margin: 0; }
.bill-lines div, .bill-total div { display: flex; align-items: baseline; justify-content: space-between; gap: 1.25rem; padding: 0.3rem 0; }
.bill-lines div { border-bottom: 1px dotted rgba(30,45,64,0.28); }
.bill-lines dt { flex: 1 1 55%; min-width: 0; color: rgba(30,45,64,0.85); }
.bill-lines dd { margin: 0; flex: 0 1 auto; max-width: 55%; text-align: right; font-weight: 600; }
.bill-total { margin-top: 0.6rem; padding-top: 0.7rem; border-top: 2px dashed rgba(30,45,64,0.35); }
.bill-total dt { flex: 1 1 auto; font-family: var(--font-display); font-weight: 800; font-size: 1.15rem; letter-spacing: -0.01em; }
.bill-total dd { margin: 0; font-family: var(--font-display); font-weight: 800; font-size: 1.6rem; letter-spacing: -0.02em; line-height: 1; }
.bill-foot { margin: 0.9rem 3.2rem 0 0; text-align: left; font-size: 0.82rem; letter-spacing: 0.04em; color: rgba(30,45,64,0.7); }
.bill-stamp {
  position: absolute; right: 1.1rem; bottom: 1.3rem; width: 3.2rem; height: 3.2rem; border-radius: 50%;
  border: 3px solid var(--bg); color: var(--bg); display: grid; place-items: center; transform: rotate(-12deg); opacity: 0.85;
}
.bill-stamp svg { width: 1.9rem; height: 1.9rem; }
.bill-beside { display: grid; gap: 1rem; align-content: start; }
.bill-lead { font-family: var(--font-display); font-weight: 700; font-size: clamp(1.2rem, 1.8vw, 1.5rem); line-height: 1.3; color: #fff; letter-spacing: -0.01em; max-width: 34rem; }
.bill-beside p { font-size: 1.08rem; line-height: 1.55; color: rgba(255,255,255,0.85); max-width: 36rem; }
.bill-beside p[style] { font-family: var(--font-display); font-weight: 600; color: rgba(255,255,255,0.85); }
.bill-beside .cost-list { font-size: 1.05rem; }
.bill-note { font-size: 1rem !important; color: rgba(255,255,255,0.62) !important; }

/* ---------- The note: the cut-out in the label column, the paper in the body column ---------- */
.note-section .product-section-inner { align-items: start; }
.note-fig { display: grid; justify-items: start; }
.note-fig .sec-fig { width: clamp(6rem, 11vw, 10rem); margin: 0.5rem 0 0 0.5rem; transform: rotate(-8deg); }
.note-wrap .dev-note { max-width: 52rem; transform: rotate(0.4deg); }
@media (min-width: 64rem) { .note-section .product-section-inner > .note-fig { grid-column: 1; grid-row: 1; position: sticky; top: calc(var(--nav-h, 4.6rem) + 4.2rem); } }   /* outranks the rule that sends every child to column 2 */
@media (max-width: 63.99rem) { .note-fig .sec-fig { width: 5.5rem; margin: 0 0 0.5rem; } }

/* ---------- Under 64rem the rail layout goes single column; labels sit above their bodies ---------- */
@media (max-width: 63.99rem) { .app-body.is-folder .product-section-label { margin-bottom: 0.75rem; } }
.app-body.is-folder .download-cta { padding-top: clamp(1rem, 4vh, 2.5rem); }
