/* The middle of a case page, and nothing else. The header, compact logo, legal
   line, footer and Menu belong to the site (css/01-header.css, lab-chrome.css,
   14b-footer.css, footer-legal.css): no rule here reaches them. */
.case-story {
  --ground: #171719;
  --panel: #232325;
  --ink: #dee2e4;
  --body-ink: #bec4c9;
  --muted: #a9afb5;
  --line: rgba(222,226,228,.16);
  --silver: #e4e5e6;
  --gap: 12px;
  --radius: 12px;
  --card-padding: 24px;
  /* Text roles stay the same at every viewport width. */
  --text-body: 16px;
  --text-topic: 20px;
  --text-title: 36px;
  --text-small: 12px;
  /* The side gutter is the site's own, so the middle lines up with the header and footer. */
  padding: var(--hdr-h) var(--g) 0;
  color: var(--ink);
  font: 400 var(--text-body)/1.6 Inter, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}
:where(.case-story) a { color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
:where(.case-story) a:focus-visible { outline: 2px solid currentColor; outline-offset: 5px; }
:where(.case-story) :is(img, video) { display: block; max-width: 100%; }
:where(.case-story) svg { display: block; width: 24px; height: 24px; flex: none; }
.case-story ::selection { background: var(--silver); color: var(--ground); }

.case-topline { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin: 8px 2px 16px; color: var(--muted); font-size: var(--text-small); }
.case-topline a { display: flex; align-items: center; gap: 8px; color: var(--ink); }
.case-topline svg { width: 16px; height: 16px; transform: rotate(180deg); }
.case-topline a:hover { text-decoration: underline; text-underline-offset: 4px; }

.case-cover { margin-bottom: 24px; }
.case-visual { margin: 0; min-width: 0; overflow: hidden; border-radius: var(--radius); background: var(--field, var(--panel)); }
.case-visual img, .case-visual video { width: 100%; height: auto; }
/* A captioned frame has a dark underlay all the way through its rounded edge.
   Keep an explicit media field confined to the image row. */
.case-visual.has-field:not(.case-visual--hero):has(> figcaption) { display: grid; background: var(--panel); }
.case-visual.has-field:not(.case-visual--hero):has(> figcaption)::before { content: ""; grid-area: 1 / 1; background: var(--field); }
.case-visual.has-field:not(.case-visual--hero):has(> figcaption) > :is(img, video) { grid-area: 1 / 1; }
/* A cover on a plain field: it keeps its proportions and fits the first screen,
   and the field continues the media's own edge colour to both sides. The edges
   retain the complete artwork: no side mask may fade a device or its shadow. */
.case-visual--hero.has-field { position: relative; width: 100%; aspect-ratio: var(--ratio); max-height: clamp(340px, calc(100svh - var(--hdr-h) - 56px), 964px); }
.case-visual--hero.has-field > :is(img, video) { position: absolute; inset: 0; width: auto; height: 100%; max-width: 100%; margin: auto; object-fit: contain; mask-image: none; }
/* On a tall window the first screen ends right under the project title, so no line
   of the description shows in pieces (Alexa, 4.11.2026). 376 px is everything on the
   first screen but the cover: 131 above it, 233 from its edge to the title's end, 12
   of clearance. On lower windows the cover fills the first screen as above. */
@media (min-width: 1600px) and (min-height: 1200px) {
  .case-visual--hero.has-field { max-height: min(1200px, calc(100svh - 376px)); }
  /* A case without product sides has no tabs above the title: 76 px less (64 + 12). */
  .case-story:not(:has(.case-sides)) .case-visual--hero.has-field { max-height: min(1200px, calc(100svh - 300px)); }
}
/* The authored Classified cover (src/classified-cards.mjs) fills the frame: it is a
   photograph with no plain edge to continue, and a field beside it would draw a line. */
.case-visual--hero.is-classified > .cse-media--classified { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
/* The same for any cover with no plain edge (`"fill": true`): it fills the frame at its
   own proportions, trimmed only where the height limit applies. */
.case-visual--hero.is-fill > :is(img, video) { width: 100%; height: 100%; max-width: none; object-fit: cover; mask-image: none; }
/* Captioned media keeps its complete lower edge above the dark caption. */
.cover-caption { display: flex; justify-content: space-between; gap: 20px; margin: 14px 4px 0; color: var(--muted); font-size: var(--text-small); }
.cover-caption > span:first-child { color: var(--ink); }

.story-row { display: grid; grid-template-columns: minmax(0, 2fr) minmax(308px, 1fr); align-items: start; gap: var(--gap); margin-bottom: var(--gap); position: relative; }
.story-media { min-width: 0; display: grid; gap: var(--gap); align-items: start; }
/* Phone panels share one padding, so a phone alone and a phone in a pair come out
   the same size at every width of the two-column layout. Phones stand together as
   a group in the middle of the panel (Alexa, 4.11.2026). */
.story-media--pair, .story-media--trio, .story-media--portrait { --phone-gap: clamp(12px, 2vw, 32px); container-type: inline-size; background: var(--silver); border-radius: var(--radius); padding: clamp(16px, 3vw, 52px); justify-items: center; overflow: hidden; isolation: isolate; }
.story-media--pair { grid-template-columns: repeat(2, auto); justify-content: center; gap: 0; }
.story-media--trio { grid-template-columns: repeat(3, auto); justify-content: center; gap: 0; }
.story-media--wide .case-visual { width: 100%; }
.case-visual figcaption { padding: 14px 18px; background: var(--panel); color: var(--body-ink); font-size: var(--text-small); line-height: 1.5; text-align: center; }

/* A screen in the iPhone of the covers: the same LS.GRAPHICS body and shadow, at
   the geometry of healthcare-cover-2026-11-03/ae/build-three-iphones.jsx (body
   1612×3340, screen 1488.6×3234.9 at 62,51 with radius 200, shadow canvas
   2509×3779 with the body at 595,135). The phone fits the first screen. Shadows
   stay under every phone, whichever comes first. */
.phone { margin: 0; width: min(360px, calc((100cqw - var(--phone-gap)) / 2)); min-width: 0; }
.story-media--trio .phone { width: min(360px, calc((100cqw - 2 * var(--phone-gap)) / 3)); }
/* The distance between phones: 205 px when there is room, what is left when there
   is less, the minimum gap on narrow panels. It lives on the phone because a panel
   cannot measure itself in cqw. */
.story-media--pair .phone + .phone { margin-inline-start: clamp(var(--phone-gap), calc(100cqw - 720px), 205px); }
.story-media--trio .phone + .phone { margin-inline-start: clamp(var(--phone-gap), calc((100cqw - 1080px) / 2), 205px); }
.phone-device { position: relative; aspect-ratio: 1612 / 3340; }
.phone-shadow { position: absolute; left: -36.91%; top: -4.042%; width: 155.645%; height: 113.144%; max-width: none; }
.phone-body { position: absolute; z-index: 1; inset: 0; width: 100%; height: 100%; }
.phone-screen { position: absolute; z-index: 2; left: 3.846%; top: 1.527%; width: 92.345%; height: 96.853%; overflow: hidden; border-radius: 13.435% / 6.183%; }
.phone-screen > * { width: 100%; height: 100%; object-fit: cover; }
.phone figcaption { margin-top: 20px; color: #4d575f; font-size: var(--text-small); line-height: 1.5; text-align: center; text-wrap: balance; }

/* Sides of the product: the tabs are the site's own, only their place is ours. */
.case-sides.hs-nav { margin-top: 0; }
.case-story [data-side][hidden] { display: none; }

/* Every topic owns its panel. The collection itself has no background.
   Alexa, 5.11.2026: prose measure is 28% wider (42ch × 1.28), with the
   same font sizes and card grid. Available card width still caps it. */
.intro-topics { display: grid; gap: var(--gap); min-width: 0; }
.topic-card { padding: var(--card-padding); border-radius: var(--radius); background: var(--panel); min-width: 0; }
.topic-card p { max-inline-size: 53.76ch; margin: 0 0 16px; color: var(--body-ink); font-size: var(--text-body); line-height: 1.6; text-wrap: pretty; }
.topic-card > :last-child { margin-bottom: 0; }
.topic-title { max-inline-size: 28ch; margin: 0 0 12px; color: var(--ink); font-size: var(--text-topic); font-weight: 500; line-height: 1.3; letter-spacing: -.025em; text-wrap: balance; }
.case-title { margin: 0 0 16px; font-size: var(--text-title); font-weight: 450; line-height: 1.15; letter-spacing: -.045em; }
.section-label, .topic-card .section-label { margin: 0 0 16px; color: var(--muted); font-size: var(--text-small); font-weight: 400; line-height: 1.5; letter-spacing: .055em; text-transform: uppercase; }
.project-card > p:not(.section-label) { color: var(--ink); }
.project-card > p[data-side] { margin-bottom: 0; }
/* The chips themselves are the site's (css/05-services-row.css, css/95-chips.css).
   Their row brings its own distance from the heading. */
.topic-groups { display: grid; gap: var(--card-padding); }
.topic-groups .topic-title { margin-bottom: 0; }
/* css/05-services-row.css hides a sixth chip at some widths for its old fixed row.
   In a case every listed service and technology is a fact and must stay visible. */
.topic-groups .svc-chip:nth-child(6) { display: inline-flex; }
/* Sticky panels stop below the compact logo and action that replace the header. */
.story-copy { position: sticky; top: var(--clear); }
.story-intro { margin-bottom: 48px; }
.story-intro > .story-media { position: sticky; top: var(--clear); }
/* Keep the overview and lists alongside the introduction while its longer text
   scrolls. The column releases at the next chapter, without an empty area below. */
.intro-media-column { display: grid; gap: var(--gap); min-width: 0; position: sticky; top: var(--clear); }
/* A case with no visual of its own (NDA): the project card runs across the page and
   the facts stand in an equal row under it, so no card stays half empty. */
.story-intro--plain { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.story-intro--plain > .project-card { grid-column: 1 / -1; }
.story-intro--plain > .intro-topics { grid-column: 1 / -1; grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* The result stands on its own panel, the colour of the topic cards, as tall as its
   text plus 48 px above and below (Alexa, 5.11.2026). Columns and text keep the page's
   card grid, so the action lines up with the cards above it. */
.case-result { display: grid; grid-template-columns: minmax(0, 2fr) minmax(308px, 1fr); gap: var(--gap); margin: 48px 0; padding: 48px 0; border-radius: var(--radius); background: var(--panel); }
.case-result > div { padding: 0 var(--card-padding); }
.case-result h2 { max-inline-size: 18ch; font-size: var(--text-title); font-weight: 450; line-height: 1.15; letter-spacing: -.045em; margin: 0; text-wrap: balance; }
.result-detail p { max-inline-size: 53.76ch; color: var(--body-ink); margin: 0 0 24px; text-wrap: pretty; }
/* The buttons are the site's (.lab-btn in css/lab.css); only their row is ours. */
.result-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* Other cases: the row keeps the page gutter on the left and runs off the screen on
   the right. Cards use the catalogue's own surface and cover (.cse-link, .cse-media). */
.case-more { padding-bottom: 64px; }
.case-more-title { margin: 0 0 24px; padding-inline: var(--card-padding); font-size: var(--text-title); font-weight: 450; line-height: 1.15; letter-spacing: -.045em; }
.case-more-row { position: relative; margin-inline: calc(var(--g) * -1); }
.case-more-track { list-style: none; margin: 0; display: flex; gap: var(--gap); padding: 0 var(--g); overflow-x: auto; scroll-snap-type: x proximity; scroll-padding-inline: var(--g); scrollbar-width: none; }
.case-more-track::-webkit-scrollbar { display: none; }
.case-more-card { flex: 0 0 clamp(240px, 19vw, 400px); scroll-snap-align: start; }
/* A small card keeps the landscape cover on every screen; the catalogue's tall phone cover is for its big cards. */
.case-more-card .cse-media { aspect-ratio: 16 / 10; }
/* Fill the height shared with cards whose titles wrap, keeping every action at the bottom. */
.case-more-body { flex: 1 1 auto; padding: 14px 12px 12px; }
.case-more-name { margin: 0; color: var(--ink); font-size: var(--text-body); font-weight: 500; line-height: 1.3; }
.case-more-category { margin: 4px 0 0; color: var(--muted); font-size: var(--text-small); line-height: 1.5; }
.case-more-step { position: absolute; top: calc((clamp(240px, 19vw, 400px) - 8px) * .3125 + 4px); inset-inline-end: var(--g); display: flex; align-items: center; justify-content: center; width: 48px; height: 48px; padding: 0; border: 0; border-radius: 50%; background: var(--silver); color: #0d1015; cursor: pointer; transform: translateY(-50%); transition: background var(--lab-out) var(--lab-ease), color var(--lab-out) var(--lab-ease), opacity var(--lab-out) var(--lab-ease); }
.case-more-step:hover { background: #0d1015; color: var(--silver); transition-duration: var(--lab-in); }
.case-more-step:focus-visible { outline: 2px solid var(--silver); outline-offset: 3px; }
.case-more-step--prev { inset-inline-end: auto; inset-inline-start: var(--g); }
.case-more-step--prev svg { transform: rotate(180deg); }
[dir="rtl"] .case-more-step--prev svg { transform: none; }
[dir="rtl"] .case-more-step--next svg { transform: rotate(180deg); }
.case-more-row[data-at-end] .case-more-step--next, .case-more-row[data-at-start] .case-more-step--prev { opacity: 0; pointer-events: none; }
@media (hover: none) { .case-more-step { display: none; } }

/* The local list of all case pages: the same cards in a grid. */
.case-index { padding-top: 24px; }
.case-index-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr)); gap: var(--gap); }

/* Responsive rules change the composition and spacing, never text roles. */
@media (max-width: 767px) {
  .case-story { --gap: 8px; --card-padding: 22px; }
  .case-topline { margin: 6px 8px 12px; gap: 12px; }
  .case-topline > span { text-align: right; }
  .cover-caption { margin: 10px 8px 0; gap: 12px; }
  .cover-caption > span:last-child { text-align: right; }
  .story-row { grid-template-columns: 1fr; margin-bottom: 24px; }
  .story-row > .story-copy, .story-row > .intro-topics { grid-column: 1; grid-row: 1; position: static; }
  .story-row > .story-media { grid-column: 1; grid-row: 2; position: static; }
  .story-intro > .intro-media-column { grid-column: 1; grid-row: 2; position: static; }
  .story-row.story-intro--plain { grid-template-columns: 1fr; }
  .story-row.story-intro--plain > .project-card { grid-column: 1; grid-row: 1; }
  .story-row.story-intro--plain > .intro-topics { grid-column: 1; grid-row: 2; grid-template-columns: 1fr; }
  .story-media--pair, .story-media--trio, .story-media--portrait { --phone-gap: 12px; padding: 16px 12px; }
  .case-visual figcaption { padding: 10px; }
  .phone figcaption { margin-top: 12px; }
  /* On a phone the panel keeps the padding of the cards. */
  .case-result { grid-template-columns: 1fr; margin: 32px 0; padding: var(--card-padding) 0; gap: 24px; }
  .case-more { padding-bottom: 40px; }
}
/* On a phone a pair gets small, so a phone alone takes more room to stay readable.
   Three in a row would be unreadable, so they stack. */
@media (max-width: 519.98px) {
  .story-media--trio { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .story-media--trio .phone + .phone { margin-inline-start: 0; }
  .story-media--portrait .phone, .story-media--trio .phone { width: min(100%, 280px); }
  .result-actions .lab-btn { flex: 1 1 100%; display: flex; }
}
@media (max-width: 359px) {
  .case-story { --card-padding: 18px; }
  .case-topline > span { max-width: 140px; }
  .story-media--pair, .story-media--trio, .story-media--portrait { --phone-gap: 8px; padding: 12px 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .case-story *, .case-story *::before, .case-story *::after { transition: none !important; }
}

/* Other cases: grab the row without selecting text or lifting the image. */
.case-more-track { cursor: grab; user-select: none; -webkit-user-select: none; }
.case-more img { -webkit-user-drag: none; user-select: none; -webkit-user-select: none; }
.case-more-track.is-dragging { scroll-snap-type: none; scroll-behavior: auto; }
.case-more-track.is-dragging, .case-more-track.is-dragging * { cursor: grabbing; }
