/* Event app demo (plan.md > Demo app).

   Ported from the finished event app's styles.css and kept in that app's
   own palette, not the virtualcorners.com brand (`vfid`). Every rule is
   scoped under .demo-app so the same views can sit inside the desktop
   phone mockup without touching style.css (`dscp`). .demo-app is also a
   size container, and the app's one width breakpoint queries it rather
   than the viewport, so the views respond to the phone box on the demo
   page and to the screen full-screen. The block at the end holds what the
   demo adds: the close X, the minimizing notice, the "On now" chip, dimmed
   finished items, the drawn business marks, the emulated-time footer,
   and the inline mode that runs the views inside the desktop mockup. */

.demo-app {
  --ink: #14181d;
  --ink-soft: #4a545f;
  --line: #d9dee4;
  --paper: #ffffff;
  --shade: #f4f6f8;
  --tap: 44px;
  --accent: #d62828;
  --accent-soft: #fdeceb;
  --link: #1d4ed8;
  --chip-bg: #ffc300;
  --chip-ink: #14181d;
  --header-bg: #00449e;
  --header-ink: #ffffff;
  --header-sub: #cfe0f5;
  --nav-ink: #cfe0f5;
  --nav-active: #ffc300;
}

.demo-app,
.demo-app *,
.demo-app *::before,
.demo-app *::after {
  box-sizing: border-box;
}

.demo-app {
  container: demo-app / inline-size;
  margin: 0;
  background: var(--shade);
  color: var(--ink);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

.demo-app .app-main {
  padding: 0.9rem 0.9rem 2.5rem;
  max-width: 40rem;
  margin: 0 auto;
}

/* Full-screen routes: the body fills the screen and the main grows, so on
   a short page the sticky clock bar still sits at the bottom edge. */
body.demo-app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

body.demo-app > .app-main {
  flex: 1 0 auto;
  width: 100%;
}

.demo-app header.site {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--header-bg);
  color: var(--header-ink);
  padding: 0.7rem 0.9rem 0;
}

.demo-app header.site .app-title {
  margin: 0;
  font-size: 1.15rem;
  line-height: 1.25;
}

.demo-app header.site p {
  margin: 0.1rem 0 0.5rem;
  font-size: 0.85rem;
  color: var(--header-sub);
}

.demo-app nav.tabs {
  display: flex;
  gap: 0.15rem;
  overflow-x: auto;
}

.demo-app nav.tabs a {
  flex: 0 0 auto;
  min-height: var(--tap);
  display: flex;
  align-items: center;
  padding: 0 0.7rem;
  color: var(--nav-ink);
  text-decoration: none;
  font-size: 0.9rem;
  border-bottom: 3px solid transparent;
}

@container demo-app (max-width: 359px) {
  .demo-app header.site {
    padding-left: 0.6rem;
    padding-right: 0.6rem;
  }
  .demo-app nav.tabs a {
    padding: 0 0.4rem;
    font-size: 0.85rem;
  }
}

.demo-app nav.tabs a.here {
  color: var(--nav-active);
  border-bottom-color: var(--nav-active);
  font-weight: 600;
}

.demo-app .notice {
  background: var(--accent);
  color: var(--paper);
  padding: 0.8rem 0.9rem;
  border-bottom: 4px solid var(--chip-bg);
}

.demo-app .notice > h2,
.demo-app .notice > .prose {
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
}

.demo-app .notice > h2 {
  margin: 0 0 0.3rem;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.demo-app .notice > .prose > p {
  margin: 0 0 0.5rem;
  font-size: 1rem;
  font-weight: 600;
}

.demo-app .notice > .prose > p:last-child {
  margin-bottom: 0;
}

.demo-app .notice > .prose > .prose-head {
  margin: 0.6rem 0 0.2rem;
  font-size: 1rem;
}

.demo-app .notice > .prose > .prose-list {
  margin: 0.3rem 0 0;
  padding-left: 1.1rem;
}

.demo-app .notice > .prose > .prose-list > li {
  margin: 0 0 0.25rem;
  font-weight: 600;
}

.demo-app .notice > .prose > .prose-list > li:last-child {
  margin-bottom: 0;
}

.demo-app .controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 0.6rem;
}

.demo-app .control {
  min-height: var(--tap);
  padding: 0 0.9rem;
  border: 1px solid var(--ink-soft);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  cursor: pointer;
}

.demo-app .control[aria-pressed='true'] {
  background: var(--header-bg);
  border-color: var(--header-bg);
  color: #fff;
}

.demo-app .control:active {
  transform: translateY(1px);
}

.demo-app .control:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 2px;
}

.demo-app h3.group {
  margin: 1.1rem 0 0.4rem;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.demo-app h3.group:first-of-type {
  margin-top: 0.2rem;
}

.demo-app h2.section {
  /* padding: 0 holds off style.css's sitewide .section band padding
     when the views run inside the demo page. */
  padding: 0;
  margin: 0.4rem 0 0.6rem;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* The schedule's day heading sticks under the app header and notice as
   the list scrolls (`tstk`). Their heights change with width (the title
   wraps at 320px) and with the notice's state, so demo-app.js measures
   them into --demo-header-height and --demo-notice-height on their scroll
   root. The fallbacks are the header at 390px and no stuck notice, as
   without JS. Padding replaces the margins so the shade covers rows
   sliding under. */
.demo-app h2.section.day {
  position: sticky;
  top: calc(var(--demo-header-height, 6.875rem) + var(--demo-notice-height, 0px) - 2px);
  z-index: 1;
  margin: 0;
  padding: 0.4rem 0 0.6rem;
  background: var(--shade);
}

/* On the schedule it also clears the stuck day heading. */
.demo-app ul.cards[data-schedule] > li[id] {
  scroll-margin-top: calc(var(--demo-header-height, 6.875rem) + var(--demo-notice-height, 0px) + 2.25rem);
}

.demo-app ul.cards {
  list-style: none;
  margin: 0;
  padding: 0;
}

.demo-app ul.cards > li {
  margin: 0 0 0.6rem;
}

.demo-app a.card,
.demo-app div.card {
  display: block;
  padding: 0.85rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  color: inherit;
  text-decoration: none;
}

.demo-app a.card {
  min-height: var(--tap);
}

.demo-app a.card:active {
  background: var(--shade);
}

.demo-app .card {
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
}

.demo-app a.card:focus-visible,
.demo-app nav.tabs a:focus-visible,
.demo-app .back a:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 2px;
}

.demo-app nav.tabs a:focus-visible {
  outline-color: var(--nav-active);
}

.demo-app .card h3,
.demo-app .card h4 {
  margin: 0 0 0.15rem;
  font-size: 1.05rem;
  line-height: 1.3;
}

.demo-app .card .when {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--accent);
}

.demo-app .card .where,
.demo-app .card .meta {
  margin: 0.15rem 0 0;
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.demo-app .card .blurb {
  margin: 0.3rem 0 0;
  font-size: 0.92rem;
}

.demo-app .empty {
  margin: 1.2rem 0;
  color: var(--ink-soft);
  font-size: 0.95rem;
}

/* A row a back link lands on clears the sticky header and notice, as
   demo-app.js measures them (`tstk`, `vntc`). */
.demo-app ul.cards > li[id] {
  scroll-margin-top: calc(var(--demo-header-height, 6.875rem) + var(--demo-notice-height, 0px) + 0.6rem);
}

.demo-app img {
  max-width: 100%;
  height: auto;
}

.demo-app .back {
  margin: 0 0 0.6rem;
}

.demo-app .back a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--link);
  font-size: 0.95rem;
}

.demo-app article.detail {
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  padding: 0.95rem 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}

.demo-app article.detail > .detail-head > h2 {
  margin: 0;
  font-size: 1.5rem;
  line-height: 1.2;
}

.demo-app article.detail > .detail-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0.2rem 0 0.3rem;
}

.demo-app article.detail > .where {
  font-size: 1rem;
  color: var(--ink);
}

.demo-app article.detail > .blurb {
  margin-top: 0.7rem;
}

.demo-app article.detail > .meta {
  margin: 0.2rem 0 0;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.demo-app article.detail > .meta a,
.demo-app article.detail > .meta .ext,
.demo-app article.detail > .blurb a {
  color: var(--link);
}

.demo-app article.detail > .prose > p {
  margin: 0 0 0.7rem;
}

.demo-app article.detail > .prose > p:last-child {
  margin-bottom: 0;
}

.demo-app article.detail > .prose > .prose-head {
  margin: 1.1rem 0 0.4rem;
  font-size: 1rem;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.demo-app article.detail > .prose > .prose-list {
  margin: 0 0 0.7rem;
  padding: 0;
  list-style: none;
}

.demo-app article.detail > .prose > .prose-list > li {
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--line);
}

.demo-app article.detail > .prose > .prose-list > li:last-child {
  border-bottom: 0;
}

.demo-app article.detail > .prose > .prose-list > li > a,
.demo-app article.detail > .prose > p > a {
  color: var(--link);
}

.demo-app article.detail > .meta a,
.demo-app article.detail > .meta .ext {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

.demo-app .card .code {
  display: inline-block;
  margin: 0.5rem 0 0;
  padding: 0.25rem 0.6rem;
  border-radius: 6px;
  background: var(--chip-bg);
  color: var(--chip-ink);
  font-weight: 700;
  letter-spacing: 0.04em;
}

.demo-app .card .terms {
  margin: 0.4rem 0 0;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.demo-app .card .window {
  display: inline-block;
  margin: 0.5rem 0 0;
  padding: 0.25rem 0.6rem;
  border-radius: 6px;
  background: var(--shade);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.9rem;
}

.demo-app .person {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
}

.demo-app .person .role {
  margin: 0.1rem 0 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink);
}

.demo-app ul.who {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
}

.demo-app ul.who > li {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.5rem;
  align-items: baseline;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
}

.demo-app ul.who > li:last-child {
  border-bottom: 0;
}

.demo-app ul.who > li > .who-name {
  font-weight: 600;
}

.demo-app ul.who > li > .who-role {
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.demo-app .card .face,
.demo-app .detail-head .face {
  position: relative;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--shade);
}

.demo-app .card .noface,
.demo-app .detail-head .noface {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  font-weight: 700;
  font-size: min(1.15rem, 22px);
  letter-spacing: 0.02em;
}

.demo-app .badge {
  display: inline-block;
  margin: 0.25rem 0 0;
  color: var(--header-bg);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Demo additions. */

.demo-app [hidden] {
  display: none !important;
}

.demo-app .site-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5rem;
}

/* `mxcl` - a plain link back to the demo page, 44px square. */
.demo-app .app-close {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  margin: -0.6rem -0.6rem -0.6rem 0;
  color: var(--header-ink);
}

.demo-app .app-close svg {
  width: 22px;
  height: 22px;
}

.demo-app .app-close:focus-visible,
.demo-app .notice-toggle:focus-visible {
  outline: 3px solid var(--nav-active);
  outline-offset: -3px;
}

/* `vntc` - with JS (.demo-js) the notice sticks under the app header,
   and it minimizes to a slim bar the whole of which reopens it.
   demo-app.js measures the header into --demo-header-height. Without JS
   it can't be minimized, so it stays in place rather than holding a
   third of a phone screen. */
.demo-app .notice {
  position: relative;
  padding-right: calc(var(--tap) + 0.5rem);
}

/* Each stuck layer tucks 1px under the one above it (header over notice
   over day heading), so subpixel rounding never opens a seam. */
.demo-js .demo-app .notice {
  position: sticky;
  top: calc(var(--demo-header-height, 6.875rem) - 1px);
  z-index: 2;
}

/* The toggle is a strip across the top of the notice: 44px tall open,
   with the chevron where the old close X sat, and the whole minimized bar
   once minimized, its 4px yellow border included (`vntc`). Minimized, the
   bar is 26px of red over the yellow border: a 30px target. */
.demo-app .notice-toggle {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: var(--tap);
  padding: 0 calc(0.2rem + (var(--tap) - 18px) / 2) 0 0;
  border: 0;
  background: transparent;
  color: var(--paper);
  cursor: pointer;
}

.demo-app .notice-toggle svg {
  width: 18px;
  height: 18px;
}

.demo-app .notice > h2 {
  line-height: 1.2rem;
}

/* The message folds to nothing through a one-row grid, so its height can
   animate without a fixed number. */
.demo-app .notice > .prose {
  display: grid;
  grid-template-rows: 1fr;
}

.demo-app .notice > .prose > p {
  min-height: 0;
  overflow: hidden;
}

.demo-notice-min .demo-app .notice {
  padding-top: calc((26px - 1.2rem) / 2);
  padding-bottom: calc((26px - 1.2rem) / 2);
}

.demo-notice-min .demo-app .notice > h2 {
  margin-bottom: 0;
}

.demo-notice-min .demo-app .notice > .prose {
  grid-template-rows: 0fr;
  opacity: 0;
}

.demo-notice-min .demo-app .notice-toggle {
  height: 30px;
}

.demo-notice-min .demo-app .notice-toggle svg {
  transform: rotate(180deg);
}

/* Opening and minimizing ease over 250ms instead of snapping. The list
   under a stuck notice holds still while it does: demo-app.js moves the
   scroll by each frame's height change, so the browser's own scroll
   anchoring is off here to keep it from moving the list twice. */
.demo-js .demo-app .notice,
.demo-js .demo-app .notice > h2,
.demo-js .demo-app .notice > .prose,
.demo-js .demo-app .notice-toggle,
.demo-js .demo-app .notice-toggle svg {
  transition-duration: 250ms;
  transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}

.demo-js .demo-app .notice {
  transition-property: padding;
}

.demo-js .demo-app .notice > h2 {
  transition-property: margin;
}

.demo-js .demo-app .notice > .prose {
  transition-property: grid-template-rows, opacity;
}

.demo-js .demo-app .notice-toggle {
  transition-property: height;
}

.demo-js .demo-app .notice-toggle svg {
  transition-property: transform;
}

body.demo-app,
.demo-app .demo-view {
  overflow-anchor: none;
}

@media (prefers-reduced-motion: reduce) {
  .demo-js .demo-app .notice,
  .demo-js .demo-app .notice > h2,
  .demo-js .demo-app .notice > .prose,
  .demo-js .demo-app .notice-toggle,
  .demo-js .demo-app .notice-toggle svg {
    transition: none;
  }
}

/* `tnow` - a live item carries the code chip's yellow. */
.demo-app .now {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.45rem;
  border-radius: 6px;
  background: var(--chip-bg);
  color: var(--chip-ink);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  vertical-align: 0.1em;
}

/* A finished item is dimmed by color, not opacity, so its text keeps AA
   contrast. No label. */
.demo-app .is-finished .card {
  background: var(--shade);
  color: var(--ink-soft);
}

.demo-app .is-finished .card .when {
  color: var(--ink-soft);
  font-weight: 600;
}

/* `vlog` - business marks drawn at build time. Partners get an inline SVG
   shape; everyone else gets a two-letter monogram on a colored circle. */
.demo-app .face svg {
  display: block;
  width: 100%;
  height: 100%;
}

.demo-app .face.tile {
  color: #ffffff;
}

.demo-app .face.tile-1 { background: #8a3b12; }
.demo-app .face.tile-2 { background: #2f5d8a; }
.demo-app .face.tile-3 { background: #4d6b2e; }
.demo-app .face.tile-4 { background: #6d3f7a; }
.demo-app .face.tile-5 { background: #9b2c48; }
.demo-app .face.tile-6 { background: #22636b; }

/* Website and phone render as text with no destination (`vext`). */
.demo-app article.detail > .meta .ext {
  color: var(--link);
  cursor: default;
}

/* Emulated-time footer: pinned to the bottom of the screen, so the fixed
   demo clock (`tnow`) stays in view on every view. Sticky rather than
   fixed: it is the last thing in the body, so it holds the bottom edge
   while the page scrolls (body.demo-app's min-height keeps it at the
   bottom on short pages), and it keeps working inside .demo-app's size
   container, which would turn a fixed footer into one pinned to the
   bottom of the page. */
.demo-app .clock-bar {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin: 0;
  padding: 0.45rem 0.9rem calc(0.45rem + env(safe-area-inset-bottom));
  background: var(--header-bg);
  color: var(--header-sub);
  font-size: 0.8rem;
  text-align: center;
}

/* Inline mode: the six views running inside the desktop phone mockup on
   /work/event-app/ (`dfrm`, `dtgt`, `dscp`).

   Every view is rendered in full (header, notice, content) as a section
   that scrolls on its own, so a view opens at its top with the header
   held in place, as on a phone. Only one shows at a time, chosen by CSS
   :target with no JS.

   The :target is an empty `hidden` anchor right before each section,
   not the section itself. Following a hash link scrolls the page to its
   target, so a visible section as the target would jump the page every
   time a view changed. A hidden element still matches :target but has no
   box to scroll to, so the page stays put. With no view in the hash, the
   schedule shows.

   The screen is a layout container, so anything fixed inside the app
   pins to the phone, not the browser window. */
.demo-app--inline {
  display: flex;
  flex-direction: column;
  height: 100%;
  contain: layout paint;
}

.demo-app--inline .demo-views {
  flex: 1;
  min-height: 0;
}

.demo-app--inline .demo-view {
  display: none;
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}

/* A phone shows no scrollbar gutter; the wheel and trackpad still scroll. */
.demo-app--inline .demo-view::-webkit-scrollbar {
  display: none;
}

.demo-app--inline .demo-anchor:target + .demo-view,
.demo-app--inline .demo-views:not(:has(.demo-anchor:target)) > .demo-view--home {
  display: block;
}

/* Browsers without :has() still open on the schedule. */
@supports not selector(:has(a)) {
  .demo-app--inline .demo-view--home {
    display: block;
  }
}
