/* Lab pages of the Mobile Development course (courses/mobile/labs/), shared by the six labs. Loaded after mobile.css,
   nav.css and present.css; course tokens only, so every component renders in light, in dark and on paper.
   Paper for reading; night for the machine (code, Android Studio captures, the phone), in both themes.
   One colour, one meaning, as everywhere in the course: your code amber (--you), the system and the phone sky (--os),
   done mint (--ok), interactive and "you are here" indigo (--accent). Android Studio itself is neutral.
   Markup of every component, the code panel contract and the i18n keys: docs/mobile/labs/lab1-java/page-kit.md.
   Behaviour (Copy, Whole file, callouts, Done ✕, the package field, the route): lab.js. */

/* ---------- 0. The page ---------- */
/* A lab page numbers its steps with discs: no "01 —" opener above its section titles (mobile.css's selector, raised). */
.module-main[data-kind="lab"] .prose > .slide:not(.card):not(.checkpoint):not(#answer):not(#recap) > h2::before { content: none; }
.module-main[data-kind="lab"] .prose > .slide:not(.card):not(.checkpoint):not(#answer):not(#recap) > h2 { counter-increment: none; }
.module-main[data-kind="lab"] .prose > .slide + .slide { margin-top: clamp(48px, 6vw, 80px); }
.module-main[data-kind="lab"] .prose > .lab-step + .lab-step { margin-top: clamp(56px, 6.5vw, 92px); }
.module-main[data-kind="lab"] .hero { padding-bottom: clamp(20px, 2.4vw, 32px); }
.module-main[data-kind="lab"] .hero__text .lede { max-width: 46ch; }

/* hidden means hidden, whatever a component's display. */
.module-main[data-kind="lab"] [hidden] { display: none !important; }
/* A link to a step lands it just under the header: html's scroll-padding alone (W9: with .slide's margin too, the step
   above showed its Stuck? fold first). */
.module-main[data-kind="lab"] .slide { scroll-margin-top: 0; }
/* The steps keep the biggest titles of a part: a reading section between them (3's four layouts, 7's two ways) is no
   new chapter (W9). */
.module-main[data-kind="lab"]:has(.lab-step) section.slide:not(.lab-step):not(.hero):not(.lab-recap) > h2 { font-size: clamp(1.3rem, 1.12rem + .7vw, 1.6rem); }
/* A table in a step: its head in the body font, under the action's title (Playfair read like a heading, W9); it fits
   its column from 481 px (7.2's result column was cut at 683). */
.module-main[data-kind="lab"] .lab-step .data-table thead th { font: 600 .8rem/1.35 var(--font-body); letter-spacing: 0; color: var(--ink-2); }
@media (min-width: 481px) { .module-main[data-kind="lab"] .lab-step .table-wrap .data-table { min-width: 0; } }

/* Small mono kicker, the course's .try__k look. */
.lab-k { display: block; margin: 0 0 6px !important; font: 600 .68rem/1.3 var(--font-mono) !important; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }

/* ---------- 1. Icons (CSS masks: no markup, no JS) ---------- */
:root {
  --lab-i-studio: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.4'%3E%3Crect x='1.5' y='2.5' width='13' height='11' rx='2'/%3E%3Cpath d='M1.5 5.5h13M5 5.5v8'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-xml: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 4.5 1.8 8 5 11.5M11 4.5 14.2 8 11 11.5M9.2 3.5 6.8 12.5'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-res: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.4'%3E%3Crect x='2' y='2' width='12' height='12' rx='3.5'/%3E%3Ccircle cx='6' cy='6' r='1.4' fill='%23000'/%3E%3Cpath d='M2.5 11.5 6.5 8l3 2.5 2-1.5 2.2 1.8'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-java: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.4' stroke-linejoin='round'%3E%3Cpath d='M3 1.5h6.5l3.5 3.5v9.5H3z'/%3E%3Cpath d='M9.5 1.5V5H13'/%3E%3Cpath d='M9 7.5v3.6a1.6 1.6 0 0 1-3.2 0' stroke-linecap='round'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-gradle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.4' stroke-linejoin='round'%3E%3Cpath d='M8 1.8 14 5v6l-6 3.2L2 11V5z'/%3E%3Cpath d='M2 5l6 3.2L14 5M8 8.2v6'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-phone: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.4'%3E%3Crect x='4' y='1.5' width='8' height='13' rx='2'/%3E%3Cpath d='M7 12.5h2'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-log: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'%3E%3Cpath d='M2.5 4h11M2.5 8h8M2.5 12h10'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.5'%3E%3Crect x='5' y='5' width='9' height='9' rx='2'/%3E%3Cpath d='M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-dl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v8M4.5 6.8 8 10.3l3.5-3.5M2.5 13.5h11'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-zoom: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round'%3E%3Ccircle cx='7' cy='7' r='4.5'/%3E%3Cpath d='m10.5 10.5 3.5 3.5M5 7h4M7 5v4'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5 6.5 12 13 4.5' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --lab-i-cross: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 4l8 8M12 4l-8 8' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  --lab-i-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='6'/%3E%3Cpath d='M8 4.6V8l2.3 1.6'/%3E%3C/g%3E%3C/svg%3E");
  --lab-i-home: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 7.5 8 2.8l5.5 4.7V13a.5.5 0 0 1-.5.5H9.6V10H6.4v3.5H3a.5.5 0 0 1-.5-.5z' fill='none' stroke='%23000' stroke-width='1.4' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.lab-ico, .place::before, .code__file::before, .lab-btn::before, .lab-dl::before, .as-shot__zoom::before {
  content: ""; display: inline-block; flex: none; width: 15px; height: 15px; background: currentColor;
  -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat;
}

/* ---------- 2. Place chips: where you work (c) ---------- */
.lab-where { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; margin-bottom: 2px; padding: 0 !important; list-style: none; }
.lab-where > li { margin: 0 !important; }
.place {
  --c: var(--ink-2); --ico: var(--lab-i-studio);
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-height: 28px; padding: 3px 10px 3px 8px;
  border-radius: 999px; font: 600 .76rem/1.3 var(--font-body); color: var(--ink); vertical-align: middle;
  background: var(--surface); border: 1px solid color-mix(in srgb, var(--c) 45%, var(--rule));
}
.place::before { color: var(--c); }
.place small { font: 500 .7rem/1.25 var(--font-mono); color: var(--ink-3); padding-left: 7px; border-left: 1px solid var(--rule-strong); overflow-wrap: anywhere; }
.place code { font-size: .92em; padding: 0; border: 0; background: none; white-space: normal; overflow-wrap: anywhere; }
.place--studio { --c: var(--ink-2); --ico: var(--lab-i-studio); border-color: var(--rule-strong); }
.place--layout { --c: var(--you); --ico: var(--lab-i-xml); }
.place--manifest { --c: var(--you); --ico: var(--lab-i-xml); }
.place--res { --c: var(--you); --ico: var(--lab-i-res); }
.place--java { --c: var(--you); --ico: var(--lab-i-java); }
.place--gradle { --c: var(--you); --ico: var(--lab-i-gradle); }
.place--emu { --c: var(--os); --ico: var(--lab-i-phone); }
.place--logcat { --c: var(--os); --ico: var(--lab-i-log); }
.place--home { --c: var(--ink-2); --ico: var(--lab-i-home); border-color: var(--rule-strong); }

/* ---------- 3. Android Studio's words: menu paths and keys (d) ---------- */
.ui { font-weight: 700; color: var(--ink); }
/* The › is drawn; a screen reader hears a comma between the items ("New, Android Resource File"), in EN and FR. */
.ui > span + span::before { content: "\203A"; content: "\203A" / ", "; margin: 0 .3em; font-weight: 500; color: var(--ink-3); }
.lab-kind {
  display: inline-block; margin-right: 6px; padding: 1px 7px 0; border-radius: 6px; vertical-align: .1em;
  font: 700 .62rem/1.55 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; white-space: nowrap;
  color: var(--ink-2); background: var(--surface-2); border: 1px solid var(--rule-strong);
}
.lab-kind--type { color: var(--you); background: var(--you-soft); border-color: color-mix(in srgb, var(--you) 42%, transparent); }
/* A short chip that must not break (<code class="nb">&lt;!--</code>): mobile.css lets inline code break anywhere under 480 px. */
code.nb { white-space: nowrap !important; overflow-wrap: normal !important; }
/* A path chip with <wbr> joints breaks at them in every browser (Firefox ignores <wbr> inside mobile.css's nowrap chips). */
main[data-kind="lab"] :not(pre) > code:has(wbr) { white-space: normal; }
.lab-kind--paste { color: var(--you); background: transparent; border: 1px dashed color-mix(in srgb, var(--you) 55%, transparent); }

/* ---------- 4. The code panel (a): file bar, ownership in the gutter, diff first, Whole file, Copy ----------
   <figure class="code" data-at data-path data-action="new|replace|add|read"> … (written by tools/code-panel.py) */
.code {
  margin: 14px 0 12px; border-radius: 14px; overflow: hidden; min-width: 0; color-scheme: dark;
  background: var(--code-bg); border: 1px solid var(--code-rule);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 18px 36px -26px rgba(12, 14, 30, .75);
}
.code__bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; min-height: 44px; padding: 6px 6px 6px 12px; border-bottom: 1px solid var(--code-rule); background: rgba(255, 255, 255, .025); }
.code__file { --ico: var(--lab-i-xml); display: inline-flex; align-items: center; gap: 7px; min-width: 0; font: 600 .76rem/1.3 var(--font-mono); color: var(--code-ink); overflow-wrap: anywhere; }
.code__file::before { color: #fbbf24; }
.code__file--res { --ico: var(--lab-i-res); } .code__file--java { --ico: var(--lab-i-java); } .code__file--gradle { --ico: var(--lab-i-gradle); }
.code__dir { color: var(--code-dim); font-weight: 500; }
.code__name { overflow-wrap: normal; }   /* the folder path may wrap; the file name never breaks inside a word */
.code__act { padding: 2px 8px; border-radius: 999px; font: 700 .6rem/1.45 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; color: #fbbf24; border: 1px solid rgba(251, 191, 36, .45); }
.code__act--new { color: #5fd3a0; border-color: rgba(95, 211, 160, .45); }
.code__act--replace { color: #c9c6ff; border-color: rgba(168, 163, 255, .45); }
.code__act--read { color: var(--code-dim); border-color: var(--code-rule); }
.code__act--edit { color: #7cc4ff; border-color: rgba(124, 196, 255, .45); }
@media (max-width: 360px) { .code__act { white-space: normal; } }   /* a French badge in a 172 px Start-from panel */
.code__btns { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.code__btn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 5px 10px; border-radius: 8px; cursor: pointer;
  border: 1px solid #343a50; background: transparent; color: var(--code-ink); font: 600 .72rem/1.2 var(--font-body); text-align: left;
}
.code__btn:hover { border-color: #a8a3ff; color: #fff; }
.code__btn[aria-pressed="true"] { background: rgba(168, 163, 255, .14); border-color: rgba(168, 163, 255, .6); }
.code__btn.lab-btn--copy { --ico: var(--lab-i-copy); }
.code__btn.lab-btn--copy::before { content: ""; width: 13px; height: 13px; background: currentColor; -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat; }
.code__btn.is-done { color: #5fd3a0; border-color: rgba(95, 211, 160, .5); max-width: 100%; }
/* No ligatures: -> and >= show as the two keys the student types (the font shorthand would turn them back on). */
.code__pre {
  position: relative; margin: 0; padding: 10px 0 12px; overflow-x: auto; -webkit-overflow-scrolling: touch;
  font: 500 .84rem/1.6 var(--font-mono); font-variant-ligatures: none; color: var(--code-ink); white-space: pre; tab-size: 4; background: none; border: 0;
}
main[data-kind="lab"] pre.expect { font-variant-ligatures: none; }
.code__pre:focus-visible { outline: 2px solid var(--code-focus); outline-offset: -2px; border-radius: 10px; }
.code__pre.is-clipped { -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 40px), rgba(0, 0, 0, .2)); mask-image: linear-gradient(90deg, #000 calc(100% - 40px), rgba(0, 0, 0, .2)); }
.code__pre > code { display: block; min-width: max-content; font: inherit; color: inherit; background: none; border: 0; padding: 0; white-space: inherit; }
.ln { display: block; position: relative; min-height: 1.6em; padding: 0 18px 0 64px; }
/* Line numbers at 4.5:1 or more on the panel (the steps say "After line 13"). */
.ln::before { content: attr(data-n); position: absolute; left: 0; width: 38px; text-align: right; color: #80869e; -webkit-user-select: none; user-select: none; }
.ln::after { position: absolute; left: 46px; top: 0; font-weight: 700; -webkit-user-select: none; user-select: none; }
/* A marked line: an opaque band and its 3 px stripe drawn as one background (an inset shadow or a see-through band
   leaves 1 px seams between rows in Firefox and WebKit whenever the page is scaled). A screen reader hears "to add". */
.ln--add { background: linear-gradient(#fbbf24, #fbbf24) 0 0 / 3px 100% no-repeat, color-mix(in srgb, #fbbf24 10%, var(--code-bg)); }
.ln--add::before { color: #fbbf24; }
.ln--add::after { content: "+"; content: "+" / "to add"; color: #fbbf24; }
:lang(fr) .ln--add::after { content: "+"; content: "+" / "à ajouter"; }
/* Lines Android Studio wrote: grey, with a grey edge and a dot that tell them from a diff's plain context lines. The
   selector is as strong as .code__pre .t below: it lost to it, and the "grey lines" showed in full colour (W8). */
.code__pre .ln--ide { color: #9aa0b6; background: linear-gradient(#6b7089, #6b7089) 0 0 / 3px 100% no-repeat; }
.code__pre .ln--ide :is(.t, .a, .s, .k, .n) { color: inherit; }
.ln--ide::after { content: "·"; content: "·" / ""; color: #9aa0b6; }
.ln--del { color: #8d93a8; text-decoration: line-through; text-decoration-color: rgba(255, 138, 128, .7); background: color-mix(in srgb, #ff8a80 6%, var(--code-bg)); }
.ln--del::after { content: "\2212"; content: "\2212" / "to delete"; color: #ff8a80; }
:lang(fr) .ln--del::after { content: "\2212"; content: "\2212" / "à supprimer"; }
.ln--note { background: linear-gradient(#a8a3ff, #a8a3ff) 0 0 / 3px 100% no-repeat, color-mix(in srgb, #a8a3ff 10%, var(--code-bg)); }
/* The diff view: what the step changes, its context dimmed, the rest folded. Without JS the whole file shows. */
.code.js-ready:not(.is-whole) .ln--out, .code.js-ready:not(.is-whole) .ln--del[hidden] { display: none; }
.code.is-diff:not(.is-whole) .ln:not(.ln--add):not(.ln--del):not(.ln--edit) { color: #8d93a8; }
.code.is-diff:not(.is-whole) .ln:not(.ln--add):not(.ln--edit) :is(.t, .a, .s, .k, .n) { color: inherit; }
/* An edit panel (code-panel.py --action edit, W8): the file as the IDE holds it after the drags, element by element (a
   label row each), every line marked by what to do with it: ✎ change the struck part, − delete the line, + type it.
   The numbers are the step's own (a − line has none): worked from top to bottom, each is the line Android Studio shows
   at that moment (Ctrl+G), as in the other panels (the A/B test asked for them back). */
.code__legend { display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0 !important; padding: 7px 14px; border-bottom: 1px solid var(--code-rule); font: 500 .8rem/1.45 var(--font-body) !important; color: var(--code-dim); }
.code__lg { display: inline-flex; align-items: baseline; gap: 6px; }
.code__lg::before { font: 700 .84rem/1 var(--font-mono); }
.code__lg--edit::before { content: "✎"; content: "✎" / ""; color: #7cc4ff; }
.code__lg--del::before { content: "\2212"; content: "\2212" / ""; color: #ff8a80; }
.code__lg--add::before { content: "+"; content: "+" / ""; color: #fbbf24; }
.code__lg--any::before { content: "…"; content: "…" / ""; padding: 0 3px; outline: 1px dashed rgba(255, 138, 128, .9); outline-offset: -1px; color: #ff9a8f; }
.code__lg--order::before { content: "↓"; content: "↓" / ""; color: var(--code-dim); }
figure.code[data-action="edit"] .ln, figure.code[data-action="edit"][data-copy="none"] .ln { padding-left: calc(64px + var(--ind, 0) * 1ch); }
/* A note on the very line it is about (3.3: the closing tag the IDE adds). */
.code__tip { display: block; margin: 2px 14px 6px 64px; padding: 4px 10px; border-radius: 6px; border-left: 3px solid #7cc4ff; background: rgba(124, 196, 255, .1); font: 500 .8rem/1.45 var(--font-body); color: var(--code-ink); white-space: normal; -webkit-user-select: none; user-select: none; }
.code__tip code { white-space: nowrap; color: var(--code-ink); background: rgba(255, 255, 255, .07); border-color: #343a50; }
/* A narrow edit panel wraps between attributes, never inside one: a long attribute scrolls sideways instead. */
figure.code[data-action="edit"][data-copy="none"] .code__pre { overflow-wrap: normal; }
figure.code[data-action="edit"][data-copy="none"] .code__pre > code { min-width: min-content; }
figure.code[data-action="edit"][data-copy="none"] .code__pre .s { white-space: nowrap; }   /* Firefox broke after a "/" */
/* A phone: the value to type must show without scrolling sideways, so a line wraps anywhere there. */
@media (max-width: 640px) {
  figure.code[data-action="edit"][data-copy="none"] .code__pre { overflow-wrap: anywhere; }
  figure.code[data-action="edit"][data-copy="none"] .code__pre > code { min-width: 0; }
  figure.code[data-action="edit"][data-copy="none"] .code__pre .s { white-space: normal; }
  /* a wrapped value hangs deeper than its attribute, so it never reads as a line of its own */
  figure.code[data-action="edit"][data-copy="none"] .ln { padding-left: calc(50px + var(--ind, 0) * .5ch + 4ch); text-indent: -4ch; }
  figure.code[data-action="edit"] .ln::after, figure.code[data-action="edit"] .ln::before { text-indent: 0; }
  /* a value to change stays whole: the line breaks before or after it, never inside */
  figure.code[data-action="edit"] :is(.ln__old, .ln__new) { white-space: nowrap; }
  .code__tip { margin-left: 50px; }
}
/* Way B's panels sit two cards deep: a wrapped rest hangs deeper than its attribute, and they wrap anywhere at every
   width (B2's inputType line scrolled at 720; W9: its line 85 still overflowed by 11 px from 900 to 1440 px); a value
   to change stays whole. */
@media (min-width: 641px) {
  details.lab-way figure.code[data-action="edit"][data-copy="none"] .ln { padding-left: calc(64px + var(--ind, 0) * 1ch + 4ch); text-indent: -4ch; }
  details.lab-way figure.code[data-action="edit"] .ln::after, details.lab-way figure.code[data-action="edit"] .ln::before { text-indent: 0; }
  details.lab-way figure.code[data-action="edit"][data-copy="none"] .code__pre { overflow-wrap: anywhere; }
  details.lab-way figure.code[data-action="edit"][data-copy="none"] .code__pre > code { min-width: 0; }
  details.lab-way figure.code[data-action="edit"][data-copy="none"] .code__pre .s { white-space: normal; }
  details.lab-way figure.code[data-action="edit"] :is(.ln__old, .ln__new) { white-space: nowrap; }
}
/* On a slide, an edit panel keeps only what changes and each element's opening line: the rest is on the page. */
:root.is-presenting figure.code[data-action="edit"]:not(.is-whole) .ln:not(.ln--add):not(.ln--del):not(.ln--edit):not(.ln--open) { display: none; }
.ln--edit { background: linear-gradient(#7cc4ff, #7cc4ff) 0 0 / 3px 100% no-repeat, color-mix(in srgb, #7cc4ff 9%, var(--code-bg)); }
.ln--edit::after { content: "✎"; content: "✎" / "to change"; color: #7cc4ff; }
:lang(fr) .ln--edit::after { content: "✎"; content: "✎" / "à modifier"; }
.ln__old { color: #ff9a8f; text-decoration: line-through 2px rgba(255, 138, 128, .9); background: rgba(255, 138, 128, .1); border-radius: 3px; }
/* "Whatever your drop wrote here" (a tools: position, a size from the drop point): a dashed box, not a strike on one dot. */
.ln__old--any { text-decoration: none; padding: 0 3px; margin-right: 2px; outline: 1px dashed rgba(255, 138, 128, .9); outline-offset: -1px; }
.ln__old :is(.t, .a, .s, .k, .n) { color: inherit; }
.ln__new { text-decoration: none; color: #fff; font-weight: 600; background: rgba(124, 196, 255, .2); box-shadow: inset 0 0 0 1px rgba(124, 196, 255, .55); border-radius: 3px; padding: 0 1px; }
.ln__empty { font: italic 500 .76rem/1.6 var(--font-body); color: var(--code-dim); -webkit-user-select: none; user-select: none; }
.code__el { display: block; width: fit-content; margin: 10px 14px 4px 64px; padding: 1px 8px; border-radius: 999px; border: 1px solid var(--code-rule); background: rgba(255, 255, 255, .04); font: 500 .72rem/1.5 var(--font-body); color: var(--code-dim); white-space: normal; -webkit-user-select: none; user-select: none; }
.code__el .t { font-family: var(--font-mono); }
.code__el:first-child { margin-top: 2px; }
.code__el b { color: var(--code-ink); font-weight: 700; font-family: var(--font-mono); }
@media (max-width: 640px) {
  figure.code[data-action="edit"] .ln { padding-left: calc(50px + var(--ind, 0) * .5ch); }
  .code__el { margin-left: 50px; }
  /* A phone (W9): the legend in one compact block, its line-number note once a step (the step's first edit panel). */
  figure.code[data-action="edit"] .code__legend { gap: 2px 12px; padding: 5px 10px; font-size: .74rem !important; }
  ol.lab-do--g > li:has(figure.code[data-action="edit"]) ~ li figure.code[data-action="edit"] .code__lg--order { display: none; }
}
/* The legend stays in view at the top of a long edit panel (B3: a panel taller than the screen). */
figure.code[data-action="edit"] { overflow: clip; overflow-clip-margin: 0; }
figure.code[data-action="edit"] .code__legend { position: sticky; top: 64px; z-index: 2; background: color-mix(in srgb, var(--code-bg) 94%, #fff); }
:root.is-presenting figure.code[data-action="edit"] .code__legend { position: static; }
.code__fold { display: none; }
.code.js-ready:not(.is-whole) .code__fold {
  display: flex; align-items: center; gap: 8px; width: calc(100% - 58px); min-width: 0; margin: 3px 12px 3px 46px; padding: 2px 10px;
  border-radius: 6px; border: 1px dashed #343a50; background: rgba(255, 255, 255, .03); color: var(--code-dim);
  font: 500 .74rem/1.6 var(--font-body); cursor: pointer; text-align: left; white-space: normal;
}
.code__fold:hover { color: var(--code-ink); border-color: #565c74; }
/* Where each group of added lines goes (lab.js writes it on an "add" panel). */
.code__hunk { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin: 8px 12px 4px 46px; font: 600 .72rem/1.4 var(--font-body); color: #fbbf24; white-space: normal; }
.code__hunk .code__btn { min-height: 28px; padding: 3px 9px; }
/* The whole file (W9): a group's row stays ("Copy 15 lines" is still where the gesture says), and the bar follows the
   reader down a long file, with its name, Only the change and Copy. */
:root:not(.is-presenting) figure.code.is-whole { overflow: clip; overflow-clip-margin: 0; }
:root:not(.is-presenting) figure.code.is-whole > .code__bar { position: sticky; top: 64px; z-index: 3; background: color-mix(in srgb, var(--code-bg) 97%, #fff); }
:root:not(.is-presenting) figure.code[data-action="edit"].is-whole .code__legend { position: static; }
/* A paste whose marked lines are not typed (code-panel.py --summary, 3.5 A): the page shows its bar and its foot until
   Whole file (W9: eleven amber + lines between fold rows read as eleven lines to type). A slide and paper as before. */
@media screen { :root:not(.is-presenting) figure.code[data-view="summary"]:not(.is-whole) .code__pre { display: none; } }
/* A whole file in a Stuck? fold or the Start-from box: shut until "Show the file" (lab.js; without it, it shows). */
.code.is-shut .code__pre, .code.is-shut .code__foot { display: none; }
.code.is-shut > .code__bar { border-bottom: 0; }
.code__pre .t { color: #82cfff; } .code__pre .a { color: #f3c58a; } .code__pre .s { color: #a5e3a1; }
.code__pre .k { color: #c792ea; } .code__pre .n { color: #f9c56b; } .code__pre .c { color: #8e93ab; font-style: italic; }
.code__foot { margin: 0 !important; padding: 9px 14px 11px; border-top: 1px solid var(--code-rule); font: 500 .8rem/1.5 var(--font-body) !important; color: var(--code-dim); }
.code__foot :is(b, strong) { color: var(--code-ink); }
.code__foot code { color: var(--code-ink); background: rgba(255, 255, 255, .07); border-color: #343a50; }
/* A key on a night surface (a code foot, a capture's legend or caption): the page's white key would hide its own word. */
.code__foot kbd, .as-shot__legend kbd, .as-shot__cap kbd { color: var(--night-ink); background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .22); }
.code .pkg { color: inherit; }
@media (max-width: 640px) {
  .code__pre { font-size: .76rem; }
  .ln { padding-left: 50px; padding-right: 14px; }
  .ln::before { width: 28px; }
  .ln::after { left: 35px; }
  .code.js-ready:not(.is-whole) .code__fold { margin-left: 34px; width: calc(100% - 46px); }
  .code__hunk { margin-left: 34px; }
  /* A phone: the folder path wraps as one unit above the file name; Copy goes under "After line k", inside the panel. */
  .code__file { flex-wrap: wrap; row-gap: 0; }
  .code__hunk { flex-direction: column; align-items: flex-start; gap: 4px; }
}
/* A Type panel (no Copy) and a panel of a pair wrap a long line at every width: the student reads the whole line
   (6.3's inflate call, a drawable's gradient line in a half-width column); Copy reads the lines, not the wrap. */
:is(figure.code[data-copy="none"], .code-pair .code) .code__pre { white-space: pre-wrap; overflow-wrap: anywhere; }
:is(figure.code[data-copy="none"], .code-pair .code) .code__pre > code { min-width: 0; }
/* Where a panel wraps, the indent leaves the flow (span.ln__ind and --ind, written by code-panel.py, else by lab.js: the
   span at font-size 0, no break inside, so a hand copy keeps its spaces) and comes back as padding (--ind), so a long
   line keeps its code on its numbered row and hangs under its own indent; no numbered empty row, no code at column 0. */
:is(figure.code[data-copy="none"], .code-pair .code) .ln, :root.is-presenting .code .ln { padding-left: calc(64px + var(--ind, 0) * 1ch); }
:is(figure.code[data-copy="none"], .code-pair .code) .ln > .ln__ind, :root.is-presenting .code .ln > .ln__ind { font-size: 0; white-space: pre; }
@media (max-width: 640px) { :is(figure.code[data-copy="none"], .code-pair .code) .ln { padding-left: calc(50px + var(--ind, 0) * .5ch); } }
/* A Copy panel in a step wraps too (W9: 34 marked lines were cut at 683 px, 7 still at 1280); a wrapped rest hangs 4 ch
   deeper than its line, so it never reads as a line of its own. Copy reads the lines, not the wrap. The hang is for
   screens: paper pads its lines with !important, and a text-indent there would undo their indent. */
.lab-step figure.code:not([data-copy="none"]) .code__pre { white-space: pre-wrap; overflow-wrap: anywhere; -webkit-mask-image: none; mask-image: none; }
.lab-step figure.code:not([data-copy="none"]) .code__pre > code { min-width: 0; }
.lab-step figure.code:not([data-copy="none"]) .ln > .ln__ind { font-size: 0; white-space: pre; }
@media screen {
  .lab-step figure.code:not([data-copy="none"]) .ln { padding-left: calc(64px + var(--ind, 0) * 1ch + 4ch); text-indent: -4ch; }
  .lab-step figure.code:not([data-copy="none"]) .ln::before, .lab-step figure.code:not([data-copy="none"]) .ln::after,
  .lab-step figure.code:not([data-copy="none"]) .ln :is(.code-notes__badge, .code__tip) { text-indent: 0; }
}
/* A phone (W9): the indent counts half (2 ch a level still reads as structure), and a panel or a capture of an action
   takes the action's whole width, under its letter (way B already does: .lab-ways). */
@media screen and (max-width: 640px) {
  .lab-step figure.code:not([data-copy="none"]) .ln { padding-left: calc(50px + var(--ind, 0) * .5ch + 4ch); }
  .lab-step > ol.lab-do--g > li > figure.code { margin-left: -38px; }
  .lab-step > ol.lab-do--g > li > figure.as-shot,
  .lab-step > ol.lab-do--g > li > .lab-act__body > figure.as-shot { margin-left: -38px; max-width: calc(100% + 38px); }
}

/* Two panels side by side (F8, Way 1 vs Way 2), stacked under 760 px and on paper. */
.code-pair { display: grid; gap: 14px; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 16px 0; }
.code-pair > div { min-width: 0; }
.code-pair .code { margin: 6px 0 0; }
/* A half-width bar: the folder path stays one unit and the file name goes under it whole. */
.code-pair .code__file { flex-wrap: wrap; row-gap: 0; }
.code-pair__k { margin: 0 !important; font: 600 .74rem/1.4 var(--font-body) !important; color: var(--ink-2); }
.code-pair__k b { color: var(--ink); }
@media (max-width: 760px) { .code-pair { grid-template-columns: minmax(0, 1fr); } }

/* Annotated code (h, F10): numbered notes on lines of a read-only panel. */
.code-notes { margin: 16px 0; }
.code-notes .code { margin-bottom: 0; }
.code-notes__badge { position: absolute; left: 42px; top: .2em; display: inline-grid; place-items: center; width: 17px; height: 17px; border-radius: 50%; font: 700 .62rem/1 var(--font-mono); color: #fff; background: var(--wire-deep); }
/* What a hand selection copies is the code only: not a note's number, a fold's "⋯ lines 1–10" or a group's row. */
.code-notes__badge, .code__fold, .code__hunk { -webkit-user-select: none; user-select: none; }
@media (max-width: 640px) { .code-notes__badge { left: 31px; } }   /* between the numbers (end at 28 px) and the code (from 50 px) */
.code-notes .ln--note::after { content: none; }
.code-notes__list { margin: 12px 0 0 !important; padding: 0 !important; list-style: none; display: grid; gap: 8px; counter-reset: note; }
.code-notes__list > li { counter-increment: note; position: relative; max-width: 72ch; margin: 0 !important; padding: 2px 0 2px 34px; font-size: .95rem; line-height: 1.5; color: var(--ink-2); }
.code-notes__list > li::before { content: counter(note); position: absolute; left: 0; top: 2px; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font: 700 .72rem/1 var(--font-mono); color: #fff; background: var(--wire-deep); }
.code-notes__list code { white-space: normal; }

/* ---------- 5. Android Studio captures (b): night frame, locator map, HTML callouts, translated legend ---------- */
/* The frame takes the capture's own width (its width attribute, ≤ 640 for a crop): 1 CSS px per logical px, never blurred up.
   The img keeps its width/height attributes (no CSS width), so its box is reserved before it loads. */
.as-shot { width: fit-content; max-width: 100%; margin: 14px 0 8px; border-radius: 16px; overflow: hidden; background: var(--night); border: 1px solid var(--code-rule); box-shadow: 0 22px 44px -28px rgba(8, 10, 24, .8); color-scheme: dark; }
.as-shot__bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; min-height: 44px; padding: 6px 8px 6px 10px; border-bottom: 1px solid var(--code-rule); color: var(--night-ink-2); font: 600 .74rem/1.3 var(--font-mono); }
.as-shot__map { width: 46px; height: 29px; flex: none; }
.as-shot__map .w { fill: none; stroke: #6b7089; stroke-width: 1; }
.as-shot__map .p { fill: #262b3d; }
.as-shot__map .hit { fill: rgba(122, 92, 255, .4); stroke: #a8a3ff; stroke-width: 1.2; }
.as-shot__where { min-width: 0; }
.as-shot__where > span::before { content: "· "; color: var(--night-ink-3); }
.as-shot__where b { color: var(--night-ink); font-weight: 700; overflow-wrap: normal; }
.as-shot__zoom { --ico: var(--lab-i-zoom); margin-left: auto; display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 10px; border-radius: 8px; border: 1px solid var(--code-rule); color: var(--night-ink-2); text-decoration: none; font: 600 .72rem/1 var(--font-body); white-space: nowrap; }
.as-shot__zoom::before { width: 13px; height: 13px; }
.as-shot__zoom:hover { color: #fff; border-color: #a8a3ff; }
/* The callouts are placed in % of this box: it hugs the image, even when the bar's words make the frame wider. */
.as-shot__img { position: relative; width: fit-content; max-width: 100%; margin-inline: auto; line-height: 0; overflow: hidden; background: #1e1f22; }
.as-shot__img img { display: block; max-width: 100%; height: auto; }
/* A loop of a gesture (W8): a muted video in the capture's frame; its button plays or pauses it. */
.as-shot__img video { display: block; max-width: 100%; height: auto; background: #1e1f22; }
.as-clip__btn { --ico: var(--lab-i-zoom); margin-left: auto; display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 10px; border-radius: 8px; border: 1px solid var(--code-rule); background: transparent; color: var(--night-ink-2); font: 600 .72rem/1 var(--font-body); white-space: nowrap; cursor: pointer; }
.as-clip__btn::before { content: ""; width: 0; height: 0; border-style: solid; border-width: 5px 0 5px 8px; border-color: transparent transparent transparent currentColor; }
.as-clip__btn.is-playing::before { width: 8px; height: 10px; border: 0; background: linear-gradient(90deg, currentColor 0 3px, transparent 3px 5px, currentColor 5px 8px); }
.as-clip__btn:hover { color: #fff; border-color: #a8a3ff; }
.as-shot__legend, .as-shot__cap { max-width: 100%; }
.as-shot__ring { position: absolute; left: calc(var(--x) * 1%); top: calc(var(--y) * 1%); width: calc(var(--w) * 1%); height: calc(var(--h) * 1%); border-radius: 8px; border: 2px solid #a8a3ff; box-shadow: 0 0 0 3px rgba(122, 92, 255, .25); pointer-events: none; transition: box-shadow .2s ease, opacity .2s ease; }
.as-shot__img.is-spot .as-shot__ring { opacity: .2; }
.as-shot__img.is-spot .as-shot__ring.is-on { opacity: 1; box-shadow: 0 0 0 3px rgba(122, 92, 255, .35), 0 0 0 2000px rgba(5, 6, 14, .55); }
/* The disc stays whole inside its capture: its centre is kept half a disc from each edge (it moves a few px at most). */
.as-shot__mark { position: absolute; z-index: 2; left: clamp(13px, calc(var(--x) * 1%), calc(100% - 13px)); top: clamp(13px, calc(var(--y) * 1%), calc(100% - 13px)); transform: translate(-50%, -50%); width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font: 700 .76rem/1 var(--font-mono); color: #fff; background: var(--wire-deep); border: 2px solid #fff; box-shadow: 0 4px 12px rgba(0, 0, 0, .45); pointer-events: none; }
.as-shot__legend { margin: 0 !important; padding: 10px 12px 12px !important; list-style: none; display: grid; gap: 4px; counter-reset: m; background: var(--night-2); border-top: 1px solid var(--code-rule); }
.as-shot__legend > li { counter-increment: m; position: relative; min-width: 0; overflow-wrap: anywhere; margin: 0 !important; padding: 5px 8px 5px 38px; border-radius: 8px; color: var(--night-ink); font-size: .92rem !important; line-height: 1.45; }
.as-shot__legend > li::before { content: counter(m); position: absolute; left: 6px; top: 5px; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font: 700 .72rem/1 var(--font-mono); color: #fff; background: var(--wire-deep); }
.as-shot__legend > li[tabindex]:hover { background: rgba(168, 163, 255, .12); }
.as-shot__legend > li:focus-visible { background: rgba(168, 163, 255, .12); outline: 2px solid var(--code-focus); outline-offset: -2px; }
.as-shot__legend :is(b, .ui) { color: #fff; }
.as-shot__legend code { color: var(--night-ink); background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .14); }
.as-shot__cap { margin: 0 !important; padding: 8px 14px 11px; border-top: 1px solid var(--code-rule); font: 500 .8rem/1.5 var(--font-body) !important; color: var(--night-ink-3); }
@media (max-width: 640px) {
  .as-shot__mark { width: 22px; height: 22px; font-size: .66rem; border-width: 1.5px; left: clamp(11px, calc(var(--x) * 1%), calc(100% - 11px)); top: clamp(11px, calc(var(--y) * 1%), calc(100% - 11px)); }
  .as-shot__where > span { display: none; }
}
/* Callouts numbered as the gesture lines they show (lab.js sets is-g when each has its own data-g, W9); an item that only
   said its gesture again (data-same) leaves the legend, and a legend left empty goes. */
.as-shot__legend.is-g > li[data-g]::before { content: attr(data-g); }
.as-shot__legend.is-g > li[data-same] { display: none; }
.as-shot__legend.is-g:not(:has(> li:not([data-same]))) { display: none; }
/* Beside the gesture lines the legend is a quiet key (W9: it read as strong as the gestures, which stay the reference);
   a slide keeps it as it was. The bar keeps one row: the window's name, and Full size or the loop's button as an icon
   (their words stay their accessible names and their tooltips). */
@media screen {
  :root:not(.is-presenting) .lab-do--g .as-shot__legend { gap: 0; padding: 5px 10px 7px !important; }
  :root:not(.is-presenting) .lab-do--g .as-shot__legend > li { padding: 2px 6px 2px 30px; font-size: .84rem !important; line-height: 1.4; color: var(--code-dim); }
  :root:not(.is-presenting) .lab-do--g .as-shot__legend > li :is(b, .ui) { color: var(--night-ink); }
  :root:not(.is-presenting) .lab-do--g .as-shot__legend > li::before { width: 20px; height: 20px; left: 4px; top: 2px; font-size: .66rem; }
  @container lab-do (min-width: 620px) {
    :root:not(.is-presenting) .lab-act__body:not(.lab-act__body--under) > .as-shot :is(.as-shot__map, .as-shot__where > span) { display: none; }
    :root:not(.is-presenting) .lab-act__body:not(.lab-act__body--under) > .as-shot :is(.as-shot__zoom, .as-clip__btn) { font-size: 0; gap: 0; width: 34px; padding: 0; justify-content: center; }
    /* a tall picture (8.1 e's preview, 691 px beside two gestures) at most 62 % of the screen: its box still reserved */
    :root:not(.is-presenting) .lab-act__body:not(.lab-act__body--under) > .as-shot .as-shot__img img { max-width: min(100%, calc(min(62vh, 480px) * var(--ar, 9))); }
  }
}
@media screen and (max-width: 640px) {
  .as-shot__map { display: none; }
  .as-shot :is(.as-shot__zoom, .as-clip__btn) { font-size: 0; gap: 0; width: 34px; padding: 0; justify-content: center; }
}
/* A phone: smaller discs, so two neighbours do not overlap. */
@media (max-width: 420px) { .as-shot__mark { width: 16px; height: 16px; font-size: .6rem; left: clamp(8px, calc(var(--x) * 1%), calc(100% - 8px)); top: clamp(8px, calc(var(--y) * 1%), calc(100% - 8px)); } }

/* ---------- 6. The phone (a capture in the course's bezel), its 1:1 crops, a before/after pair ---------- */
.lab-phone { --pw: 236px; position: relative; width: var(--pw); max-width: 100%; margin: 0; flex: none; }
.lab-phone img {
  display: block; width: 100%; height: auto; border-radius: 22px; border: 5px solid #0b0d15; background: #0b0d15;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .06), 0 0 0 1.5px rgba(22, 22, 31, .18), var(--shadow-lift);
}
.lab-phone figcaption, .lab-crop figcaption { margin-top: 10px; text-align: center; font: 600 .64rem/1.35 var(--font-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.lab-crop { margin: 12px 0 0; width: fit-content; max-width: 100%; }
.lab-crop img { display: block; max-width: 100%; height: auto; border-radius: 12px; border: 3px solid #0b0d15; background: #0b0d15; box-shadow: 0 0 0 1px rgba(255, 255, 255, .06), var(--shadow-sm); }
.lab-crop figcaption { text-align: left; letter-spacing: .08em; }
.lab-phones { display: flex; flex-wrap: wrap; align-items: center; gap: 18px 22px; margin: 14px 0; }
.lab-phones .lab-phone { --pw: 180px; }
.lab-phones__arrow { font: 600 .72rem/1.3 var(--font-mono); color: var(--ink-3); text-align: center; }
.lab-phones__arrow::before { content: "\2192"; display: block; font-size: 1.6rem; line-height: 1; color: var(--accent); }

/* ---------- 7. The step: disc and kicker, Goal, places, actions a/b/c, proof, You should see, Done, Stuck? ---------- */
.lab-step { position: relative; }
.lab-step__head { display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; column-gap: 14px; align-items: start; }
.lab-step__disc {
  width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; font: 700 .86rem/1 var(--font-mono); letter-spacing: -.02em;
  color: var(--accent); background: var(--surface); border: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 0 5px var(--bg); transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}
.lab-step:has(.lab-done input:checked) .lab-step__disc { color: #fff; background: var(--ok); border-color: var(--ok); }
:root[data-theme="dark"] .lab-step:has(.lab-done input:checked) .lab-step__disc { color: #0b1a14; }
@media (prefers-color-scheme: dark) { :root:not([data-theme]) .lab-step:has(.lab-done input:checked) .lab-step__disc { color: #0b1a14; } }
.lab-step__k { margin: 3px 0 2px !important; font: 600 .68rem/1.3 var(--font-mono) !important; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.lab-step h2 { margin: 0 !important; font-size: clamp(1.4rem, 1.15rem + 1vw, 1.75rem) !important; line-height: 1.2 !important; }
.lab-step__time { --ico: var(--lab-i-clock); display: inline-flex; align-items: center; gap: 5px; margin-top: 6px; padding: 3px 9px 3px 7px; border-radius: 999px; font: 500 .7rem/1.3 var(--font-mono); color: var(--ink-3); background: var(--surface-2); border: 1px solid var(--rule); white-space: nowrap; }
.lab-step__time::before { content: ""; width: 12px; height: 12px; background: currentColor; -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat; }
/* A phone: the minutes go under the title, which keeps the whole row ("20 min + download" would squeeze it to a few letters). */
@media (max-width: 520px) { .lab-step__head { grid-template-columns: 46px minmax(0, 1fr); } .lab-step__time { grid-column: 2; justify-self: start; white-space: normal; } }
@media (min-width: 761px) { .lab-step > :not(.lab-step__head) { margin-left: 60px; } }
.lab-step > :is(p, ul, .predict, .lab-break, details:not(.lab-stuck)) { max-width: 680px; }
.lab-goal { margin-top: 14px; margin-bottom: 0; padding: 10px 14px; border-radius: 12px; font-size: 1rem !important; line-height: 1.5; color: var(--ink); background: var(--accent-soft); border-left: 3px solid var(--accent); }
.lab-goal__k { margin-right: 8px; font: 600 .66rem/1.3 var(--font-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--accent); }
ol.lab-do { margin-top: 18px; margin-bottom: 0; padding: 0 !important; list-style: none; counter-reset: act; }
ol.lab-do > li { counter-increment: act; position: relative; padding-left: 34px; margin: 0 0 18px !important; }
ol.lab-do > li:last-child { margin-bottom: 0 !important; }
ol.lab-do > li::before {
  content: counter(act, lower-alpha); position: absolute; left: 0; top: 2px; width: 23px; height: 23px; border-radius: 7px; display: grid; place-items: center;
  font: 700 .72rem/1 var(--font-mono); color: var(--ink-2); background: var(--surface-2); border: 1px solid var(--rule-strong);
}
/* Each action's letter from its place in the list, not from the counter: presenting, present.js hides the actions of
   the other pages, and a hidden item does not count, so the third action would read "a" on its own page. */
ol.lab-do > li:nth-child(1)::before { content: "a"; } ol.lab-do > li:nth-child(2)::before { content: "b"; } ol.lab-do > li:nth-child(3)::before { content: "c"; }
ol.lab-do > li:nth-child(4)::before { content: "d"; } ol.lab-do > li:nth-child(5)::before { content: "e"; } ol.lab-do > li:nth-child(6)::before { content: "f"; }
ol.lab-do > li > p { margin: 0 0 8px !important; max-width: 680px; }
ol.lab-do > li > :last-child { margin-bottom: 0 !important; }
ol.lab-do .code, ol.lab-do .as-shot { margin-top: 10px; }
/* A gesture list (W8; the P3 pilot, ol.lab-do--g): an action is a short title (p.lab-act), then one IDE gesture per
   numbered line, each with its own verb, place and values; its capture sits beside the lines when the column has room
   (620 px), under them otherwise. The action's letter is the strongest mark of the list. */
ol.lab-do--g { container: lab-do / inline-size; }
ol.lab-do--g > li { padding-left: 38px; margin-bottom: 26px !important; }
ol.lab-do--g > li::before { top: 0; width: auto; min-width: 26px; height: 26px; padding: 0 5px; border-radius: 8px; font-size: .8rem; color: var(--accent); background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
ol.lab-do--g > li > p.lab-act { margin-bottom: 4px !important; font-weight: 650; line-height: 1.45; color: var(--ink); }
ol.lab-gest { margin: 0 !important; padding: 0 !important; list-style: none; counter-reset: g; max-width: 680px; }
ol.lab-gest > li { counter-increment: g; position: relative; margin: 0 !important; padding: 7px 0 7px 32px; border-top: 1px solid var(--rule); line-height: 1.55; }
ol.lab-gest > li:first-child { border-top: 0; }
ol.lab-gest > li::before { content: counter(g); position: absolute; left: 1px; top: 9px; width: 21px; height: 21px; border-radius: 50%; display: grid; place-items: center; font: 600 .68rem/1 var(--font-mono); color: var(--ink-2); background: var(--surface); border: 1px solid var(--rule-strong); }
.lab-act__body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px 26px; align-items: start; }
.lab-act__body > .as-shot { margin-top: 6px; }
@container lab-do (min-width: 620px) {
  .lab-act__body:has(> .as-shot) { grid-template-columns: minmax(0, 1fr) auto; }
  .lab-act__body > .as-shot { margin-top: 2px; max-width: min(360px, 46cqi); }
  /* The capture runs down beside the gestures; a table (3.3 c) goes under them, across the action until the gestures'
     column holds it whole (800 px of list), then in that column. */
  .lab-act__body:has(> .as-shot) > ol.lab-gest { grid-column: 1; grid-row: 1; }
  .lab-act__body:has(> .as-shot) > .as-shot { grid-column: 2; grid-row: 1 / span 2; }
  .lab-act__body:has(> .as-shot) > .table-wrap { grid-column: 1 / -1; grid-row: 3; }
}
@container lab-do (min-width: 800px) { .lab-act__body:has(> .as-shot) > .table-wrap { grid-column: 1; grid-row: 2; } }
@container lab-do (min-width: 620px) { .lab-act__body:has(> .table-wrap) { grid-template-rows: auto 1fr; } }
@container lab-do (min-width: 620px) and (max-width: 799.98px) {
  .lab-act__body:has(> .table-wrap) { grid-template-columns: minmax(0, 1fr); }
  .lab-act__body:has(> .table-wrap) > .table-wrap { grid-column: 1; grid-row: 2; }
  .lab-act__body:has(> .table-wrap) > .as-shot { grid-column: 1; grid-row: 3; }
}
/* A dense window (a list of rows, a form: Part 0's dialogs) reads only near its real size: on the page it goes under its
   gestures (a slide keeps it beside them, where it fits). */
@container lab-do (min-width: 620px) {
  :root:not(.is-presenting) .lab-act__body--under:has(> .as-shot) { grid-template-columns: minmax(0, 1fr); }
  :root:not(.is-presenting) .lab-act__body--under:has(> .as-shot) > .as-shot { grid-column: 1; grid-row: auto; max-width: none; margin-top: 6px; }
}
/* A phone: an id stays whole (it is what the student types); the long cells wrap between words. */
@media (max-width: 640px) {
  .lab-act__body > .table-wrap :is(th, td) { padding-inline: 6px; }
  .lab-act__body > .table-wrap td code { white-space: nowrap; padding-inline: 3px; }
  .lab-act__body > .table-wrap th.data-table__n { width: 1.6em; padding-inline: 4px; }
}
/* On a slide, a capture beside the gestures is at most half the screen tall: the callouts follow (they are placed in % of
   the image's box), and a tall one (3.3 c) no longer pushes the page into scrolling. */
/* At most 403 px tall: 56vh of 720, in the slide's own px, so a 1080p projector composes it the same (W9). Its width
   comes from its width and height attributes (lab.js copies them to --pw and --ar), so a picture still on its way has
   its box already (width: auto gave 0 × 0 until it arrived, and the slide was measured without it, W10). A loop's file
   is larger than its attributes (clip-b3: 446 × 540 for 255 × 309): it takes the 403 px height, within its column. */
:root.is-presenting .lab-act__body > .as-shot .as-shot__img img { max-height: 403px; width: min(var(--pw, 100%), calc(403px * var(--ar, 1.6))); }
:root.is-presenting .lab-act__body > .as-shot .as-shot__img video { max-height: 403px; width: calc(403px * var(--ar, 1.6)); max-width: 100%; }
/* On a slide, a fold row of a long panel takes a thin line (3.5's file: eleven of them). */
:root.is-presenting .code.js-ready:not(.is-whole) .code__fold { margin-block: 1px; padding-block: 0; font-size: .66rem; line-height: 1.5; }
:root.is-presenting details.lab-path .code__foot { display: none; }   /* 3.5 A's file fits a 1280 × 720 slide; the note stays on the page */
/* A table of views to drop (3.3 c): the routine once above it, one row per view, across the whole action. */
.lab-act__body > .table-wrap { grid-column: 1 / -1; margin: 6px 0 0; max-width: 680px; }
.lab-act__body > .table-wrap .data-table { min-width: 0; }
/* Two ways to the same file (3.5, W8): the choice first, as two cards; the chosen one opens (one at a time). */
.lab-paths { display: grid; gap: 12px; max-width: 760px; margin-top: 18px; }
details.lab-path { border-radius: var(--r); border: 1.5px solid var(--rule-strong); background: var(--surface); padding: 0 16px; }
details.lab-path[open] { border-color: color-mix(in srgb, var(--accent) 55%, var(--rule-strong)); padding-bottom: 16px; }
details.lab-path > summary { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-height: 58px; padding: 10px 0; cursor: pointer; list-style: none; }
details.lab-path > summary::-webkit-details-marker { display: none; }
details.lab-path > summary > b { flex: none; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 9px; font: 700 .9rem/1 var(--font-mono); color: var(--accent); background: var(--accent-soft); }
details.lab-path[open] > summary > b { color: var(--on-accent); background: var(--accent); }
details.lab-path > summary > span { font-weight: 650; color: var(--ink); }
details.lab-path > summary > small { margin-left: auto; font: 500 .74rem/1.35 var(--font-mono); color: var(--ink-3); }
details.lab-path > summary:hover > span { color: var(--accent); }
details.lab-path > .lab-note:first-of-type { margin-top: 0 !important; }
/* After the two ways, the action that serves both: an arrow, not a letter (way A's own list starts at a). */
ol.lab-do.lab-do--then > li:nth-child(1)::before { content: "\2192"; }
/* Way B's parts: each part's letters carry its name (B1a), and a tick that is the part's own (not the step's Done). */
details.lab-way ol.lab-do > li:nth-child(1)::before { content: var(--p, "") "a"; } details.lab-way ol.lab-do > li:nth-child(2)::before { content: var(--p, "") "b"; }
details.lab-way ol.lab-do > li:nth-child(3)::before { content: var(--p, "") "c"; } details.lab-way ol.lab-do > li:nth-child(4)::before { content: var(--p, "") "d"; }
details.lab-way ol.lab-do > li:nth-child(5)::before { content: var(--p, "") "e"; } details.lab-way ol.lab-do > li:nth-child(6)::before { content: var(--p, "") "f"; }
details.lab-way ol.lab-do--g > li { padding-left: 46px; }
details.lab-way figure.code[data-action="edit"] { margin-inline: -12px; }
.lab-way__tick { display: inline-flex; align-items: center; gap: 8px; margin-top: 12px; min-height: 40px; padding: 4px 12px; border-radius: 10px; border: 1px solid var(--rule-strong); background: var(--surface); font-weight: 600; font-size: .92rem; color: var(--ink-2); cursor: pointer; }
.lab-way__tick input { width: 18px; height: 18px; accent-color: var(--ok); }
.lab-way__tick:has(input:checked) { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 50%, transparent); }
details.lab-way:has(.lab-way__tick input:checked) > summary > b { color: var(--ok); }
details.lab-way:has(.lab-way__tick input:checked) > summary > b::after { content: " ✓"; }
.lab-see, .lab-why { margin-top: 16px; margin-bottom: 0; padding: 10px 14px; border-radius: 12px; font-size: .97rem !important; line-height: 1.55; color: var(--ink-2); background: var(--surface-2); border-left: 3px solid var(--rule-strong); }
.lab-why { background: transparent; border-left-color: var(--accent); padding-block: 4px; }
.lab-see .lab-k, .lab-why .lab-k { margin-bottom: 3px !important; color: var(--ink-2); }
.lab-note { margin: 6px 0 0 !important; font-size: .86rem !important; color: var(--ink-3); }
@media (min-width: 761px) { .lab-step > .lab-note { margin-left: 60px !important; } }   /* a Logcat note right in a step: the step's indent */
/* The result: the phone beside the text and the Done row (wide); a compact row with a 150 px phone (under 860 px). */
.lab-result { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "text phone"; gap: 18px 26px; align-items: start; margin-top: 18px; }
.lab-result > .lab-phone { grid-area: phone; --pw: 236px; }
.lab-result__text { grid-area: text; min-width: 0; }
.lab-result__text > :first-child { margin-top: 0 !important; }
@media (max-width: 859px) {
  .lab-result { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "phone text"; gap: 14px 16px; }
  .lab-result > .lab-phone { --pw: 150px; }
  .lab-result > .lab-phone img { border-width: 4px; border-radius: 17px; }
}
@media (max-width: 480px) { .lab-result > .lab-phone { --pw: 112px; } .lab-result > .lab-phone img { border-radius: 14px; } }
/* Done: I see X. ✓ ticks it (label.check, stored in mob-checks by mobile.js); ✕ opens the step's Stuck? fold. */
.lab-done { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin: 16px 0 0; padding: 12px 14px; border-radius: 14px; background: var(--surface); border: 1px solid var(--rule); box-shadow: var(--shadow-sm); transition: border-color .2s ease, background-color .2s ease; }
.lab-done:has(input:checked) { border-color: color-mix(in srgb, var(--ok) 55%, var(--rule)); background: color-mix(in srgb, var(--ok) 6%, var(--surface)); }
.lab-done__t { flex: 1 1 230px; margin: 0 !important; font-size: .97rem !important; line-height: 1.5; font-weight: 600; color: var(--ink); }
.lab-done__t .lab-k { display: inline; margin: 0 8px 0 0 !important; color: var(--ok); }
.lab-done__btns { display: flex; flex-wrap: wrap; gap: 8px; }
.lab-done .check, .lab-done__no {
  position: relative; display: inline-flex; align-items: center; gap: 7px; min-height: 40px; width: auto; padding: 6px 14px 6px 11px;
  border-radius: 999px; border: 1px solid var(--control); background: var(--surface); color: var(--ink-2); cursor: pointer;
  font: 600 .86rem/1.2 var(--font-body);
}
.lab-done .check { grid-template-columns: none; column-gap: 0; }
.lab-done .check > input[type="checkbox"] { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; border: 0; background: none; box-shadow: none; }
.lab-done .check::before, .lab-done__no::before { content: ""; width: 15px; height: 15px; flex: none; background: currentColor; -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat; }
.lab-done .check { --ico: var(--lab-i-check); }
.lab-done__no { --ico: var(--lab-i-cross); }
.lab-done .check:hover { border-color: var(--ok); color: var(--ok); }
.lab-done__no:hover { border-color: var(--no); color: var(--no); }
.lab-done .check:has(> input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.lab-done .check:has(> input:checked) { color: var(--surface); background: var(--ok); border-color: var(--ok); }
.lab-done .check > input:checked + span { color: inherit; }
/* Without lab.js, ✕ would do nothing: it shows only when the script runs (✓ is a plain check box either way). */
:root:not(.lab-js) .lab-done__no { display: none; }
.lab-done__no[aria-expanded="true"] { color: var(--no); border-color: var(--no); background: color-mix(in srgb, var(--no) 7%, var(--surface)); }
/* Stuck?: closed; 2–4 real symptoms, then the files at the end of the step. Open on paper. */
details.lab-stuck { margin: 12px 0 0; border-radius: 14px; border: 1px solid var(--rule); background: color-mix(in srgb, var(--surface) 70%, transparent); }
details.lab-stuck > summary { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; min-height: 44px; padding: 8px 14px; cursor: pointer; list-style: none; border-radius: inherit; font: 600 .95rem/1.3 var(--font-body); color: var(--ink-2); }
details.lab-stuck > summary::-webkit-details-marker { display: none; }
details.lab-stuck > summary::before { content: "?"; flex: none; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center; font: 700 .72rem/1 var(--font-mono); color: var(--no); border: 1.5px solid var(--no); }
details.lab-stuck > summary:hover { color: var(--ink); }
details.lab-stuck > summary small { margin-left: auto; font: 500 .7rem/1.3 var(--font-mono); letter-spacing: .04em; color: var(--ink-3); }
details.lab-stuck[open] > summary { border-bottom: 1px dashed var(--rule-strong); border-radius: 14px 14px 0 0; color: var(--ink); }
details.lab-stuck > :not(summary) { margin-inline: 14px; }
details.lab-stuck > :last-child:not(summary) { margin-bottom: 14px; }
ul.lab-stuck__list { margin: 4px 14px 0 !important; padding: 0 !important; list-style: none; }
ul.lab-stuck__list > li { margin: 0 !important; padding: 10px max(0px, calc(100% - 72ch)) 10px 0; border-bottom: 1px dashed var(--rule); font-size: .93rem !important; line-height: 1.5; color: var(--ink-2); }   /* the text at the reading measure, the dashes full width */
ul.lab-stuck__list > li:last-child { border-bottom: 0; }
.lab-sym { display: block; margin-bottom: 2px; font-weight: 600; color: var(--ink); }
.lab-sym code { white-space: normal; overflow-wrap: anywhere; font-weight: 500; }
.lab-stuck__files { margin: 6px 14px 0 !important; font-size: .9rem !important; color: var(--ink-3); }
.lab-stuck__more { margin: 10px 14px 0 !important; font-size: .9rem !important; }   /* to #fix (lab.js, W9) */
details.lab-stuck .code { margin-top: 8px; }

/* ---------- 8. Part start: objectives, where you start, the Start-from box (e), the package field (i) ---------- */
.lab-start { padding: clamp(18px, 2.6vw, 26px); border-radius: var(--r-xl); background: var(--surface); border: 1px solid var(--rule); box-shadow: var(--shadow); }
.lab-start__grid { display: grid; grid-template-columns: 170px minmax(0, 1fr); gap: 22px 26px; align-items: start; }
.lab-start h2, .lab-end h2 { margin: 0 0 8px !important; font-size: clamp(1.3rem, 1.12rem + .7vw, 1.6rem) !important; }
.lab-start__shot { margin: 0; }
.lab-start__shot figcaption { margin-top: 10px; font: 600 .64rem/1.35 var(--font-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); text-align: center; }
.lab-start__shot .as-shot { margin: 0; border-radius: 14px; }
.lab-start__shot .as-shot__img img { width: 100%; }
.lab-start__shot .lab-phone { --pw: 150px; margin-inline: auto; }
.lab-can { margin: 6px 0 12px !important; padding: 0 !important; list-style: none; }
.lab-can > li { position: relative; margin: 6px 0 !important; padding-left: 26px; font-size: .98rem; line-height: 1.5; }
/* A dot, not an empty box: nothing to tick here (W9: it read as a dead checkbox); the end's ticked discs are the payoff. */
.lab-can > li::before { content: ""; position: absolute; left: 5px; top: .62em; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.lab-can--done > li::before { left: 1px; top: .32em; border: 0; background: var(--ok); border-radius: 50%; width: 16px; height: 16px; }
.lab-can--done > li::after { content: ""; position: absolute; left: 6px; top: .62em; width: 6px; height: 3px; border: solid var(--surface); border-width: 0 0 2px 2px; transform: rotate(-45deg); }
.lab-start .lab-where { margin-top: 4px !important; }
@media (max-width: 640px) { .lab-start__grid { grid-template-columns: minmax(0, 1fr); } .lab-start__shot { max-width: 240px; } }
/* The start as a pair (W8, the P3 pilot): where you start → where you arrive, the arrival's parts named under the two. */
.lab-start__grid:has(> .lab-start__pair) { grid-template-columns: auto minmax(0, 1fr); }
.lab-start__pair { display: grid; grid-template-columns: auto auto auto; align-items: center; gap: 4px 8px; align-self: start; }
.lab-start__pair .lab-phone { --pw: 116px; display: block; }
.lab-start__pair .lab-phone img { border-width: 4px; border-radius: 15px; }
.lab-start__arrow { font-size: 1.3rem; color: var(--ink-3); }
.lab-start__parts { grid-column: 1 / -1; max-width: 280px; margin: 6px 0 0 !important; padding: 0 !important; list-style: none; font-size: .86rem; line-height: 1.45; color: var(--ink-2); }
.lab-start__parts > li { margin: 2px 0 !important; }
.lab-start__parts b { display: inline-block; min-width: 2.4em; font: 600 .74rem/1 var(--font-mono); color: var(--accent); }
@media (max-width: 640px) { .lab-start__grid:has(> .lab-start__pair) { grid-template-columns: minmax(0, 1fr); } .lab-start__pair { justify-self: center; } }
/* Start from: one procedure for every part (blueprint 2.4), closed until needed. */
details.lab-from { margin: 18px 0 0; border-radius: 16px; border: 1px dashed var(--rule-strong); background: var(--surface-2); }
details.lab-from > summary { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-height: 48px; padding: 10px 16px; cursor: pointer; list-style: none; border-radius: inherit; font: 600 .97rem/1.35 var(--font-body); color: var(--ink); }
details.lab-from > summary::-webkit-details-marker { display: none; }
details.lab-from > summary::before { content: ""; flex: none; width: 22px; height: 22px; border-radius: 7px; border: 1px solid var(--control); background: linear-gradient(var(--accent), var(--accent)) 50% 50% / 10px 2px no-repeat, linear-gradient(var(--accent), var(--accent)) 50% 50% / 2px 10px no-repeat, var(--surface); }
details.lab-from[open] > summary::before { background: linear-gradient(var(--accent), var(--accent)) 50% 50% / 10px 2px no-repeat, var(--surface); }
details.lab-from > summary small { margin-left: auto; font: 500 .7rem/1.3 var(--font-mono); color: var(--ink-3); }
details.lab-from[open] > summary { border-bottom: 1px dashed var(--rule-strong); }
ol.lab-from__steps { margin: 14px 16px 16px !important; padding: 0 !important; list-style: none; counter-reset: f; }
ol.lab-from__steps > li { counter-increment: f; position: relative; padding-left: 34px; margin: 0 0 14px !important; font-size: .96rem; line-height: 1.55; }
ol.lab-from__steps > li:last-child { margin-bottom: 0 !important; }
ol.lab-from__steps > li::before { content: counter(f); position: absolute; left: 0; top: 1px; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font: 700 .72rem/1 var(--font-mono); color: var(--accent); background: var(--surface); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); }
ol.lab-from__steps > li > p { margin: 0 0 6px !important; }
ol.lab-from__steps .code { margin: 8px 0; }
/* Start of session (P1 and P5): three lines. */
.lab-session { margin: 0 0 18px; padding: 12px 16px; border-radius: 14px; background: var(--os-soft); border: 1px solid color-mix(in srgb, var(--os) 30%, var(--rule)); }
.lab-session .lab-k { color: var(--os); }
.lab-session ol { margin: 4px 0 0 !important; padding-left: 1.3em !important; font-size: .95rem; }
.lab-session li { margin: 3px 0 !important; }
/* The package field: one per page at most is enough; every code panel, Copy and path chip follow it. */
.lab-pkg { margin: 14px 0 0; padding: 14px 16px; border-radius: 14px; background: var(--surface); border: 1px solid var(--rule); }
.lab-pkg__label { display: block; margin: 0 0 8px; font-weight: 600; color: var(--ink); }
.lab-pkg__row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.lab-pkg input { flex: 1 1 240px; min-width: 0; min-height: 44px; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--control); background: var(--bg); color: var(--ink); font: 500 .95rem/1.2 var(--font-mono); }
.lab-pkg input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lab-pkg input::placeholder { color: var(--ink-3); opacity: 1; }   /* the example at 4.5:1 or more, in every engine */
.lab-pkg input[aria-invalid="true"] { border-color: var(--no); }
.lab-pkg__msg { margin: 8px 0 0 !important; font-size: .88rem !important; line-height: 1.45; color: var(--ink-3); }
.lab-pkg__msg.is-ok { color: var(--ok); }
.lab-pkg__msg.is-bad { color: var(--no); }
.lab-pkg__nojs { margin: 8px 0 0 !important; font-size: .88rem !important; color: var(--ink-3); }
.lab-js .lab-pkg__nojs { display: none; }
.lab-pkg:not(.is-ready) .lab-pkg__row { display: none; }
/* Reset sits on the page, not on a night panel: the page's own button colours. */
.lab-pkg__reset { min-height: 44px; padding: 6px 14px; color: var(--ink-2); background: var(--surface); border-color: var(--control); }
.lab-pkg__reset:hover { color: var(--ink); border-color: var(--accent); }
/* Inside the Start-from box the step's own line names the field: no second label, no box in the box. */
.lab-from .lab-pkg { margin: 8px 0 0; padding: 0; border: 0; background: none; }
.lab-from .lab-pkg__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
/* A file to download (res packs, lab1-final.zip). */
.lab-dl { --ico: var(--lab-i-dl); display: inline-flex; align-items: center; gap: 9px; min-height: 44px; padding: 8px 14px 8px 12px; border-radius: 12px; background: var(--surface); border: 1px solid var(--control); color: var(--ink); text-decoration: none; font: 600 .9rem/1.25 var(--font-body); box-shadow: var(--shadow-sm); }
.lab-dl::before { color: var(--accent); }
.lab-dl:hover { color: var(--ink); border-color: var(--accent); }
.lab-dl small { font: 500 .7rem/1 var(--font-mono); color: var(--ink-3); }

/* ---------- 9. Part end: the objectives ticked, the recap, your app now ---------- */
.lab-end { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 22px 28px; align-items: center; padding: clamp(18px, 2.6vw, 26px); border-radius: var(--r-xl); background: radial-gradient(70% 110% at 100% 0%, var(--glow-2), transparent 62%), var(--surface); border: 1px solid var(--rule); box-shadow: var(--shadow); }
.lab-end .lab-phone { --pw: 160px; }
.lab-recap { margin: 0 0 10px !important; font-size: 1.04rem !important; line-height: 1.55; color: var(--ink); }
@media (max-width: 640px) { .lab-end { grid-template-columns: minmax(0, 1fr); } .lab-end .lab-phone { --pw: 140px; justify-self: center; } }

/* ---------- 10. Now you, If it doesn't work, Predict, Break it, answers ---------- */
.lab-now, .lab-fix { padding: clamp(18px, 2.6vw, 24px); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--rule); }
.lab-now { border-left: 3px solid var(--you); }
.lab-now .lab-k { color: var(--you); }
.lab-now > p { margin: 0 0 6px !important; }
.lab-fix h2, .lab-now h2 { margin: 0 0 10px !important; font-size: clamp(1.2rem, 1.08rem + .5vw, 1.42rem) !important; }
ul.lab-fixes { margin: 0 !important; padding: 0 !important; list-style: none; }
ul.lab-fixes > li { margin: 0 !important; padding: 11px 0; border-top: 1px dashed var(--rule); font-size: .95rem !important; line-height: 1.55; color: var(--ink-2); }
ul.lab-fixes > li:first-child { border-top: 0; padding-top: 2px; }
.predict { position: relative; margin: 18px 0 14px; padding: 14px 16px 14px 18px; border-radius: var(--r); background: var(--surface-2); border: 1px solid var(--rule); }
.predict::before { content: ""; position: absolute; left: 0; top: 12px; bottom: 12px; width: 3px; border-radius: 0 3px 3px 0; background: var(--accent); }
.predict__k { display: block; margin: 0 0 4px; font: 600 .68rem/1.3 var(--font-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--accent); }
.predict__q { margin: 0 !important; font-weight: 600; color: var(--ink); line-height: 1.55; }
.predict__opts { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 0; }
.predict__opt { min-height: 40px; padding: 6px 14px; border-radius: 12px; border: 1px solid var(--control); background: var(--surface); color: var(--ink); cursor: pointer; font: 500 .9rem/1.3 var(--font-body); text-align: left; }
.predict__opt:hover { border-color: var(--accent); }
.predict__opt[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--accent-soft); font-weight: 600; }
.predict__opt.is-right { border-color: var(--ok); color: var(--ok); }
.predict__opt.is-wrong { border-color: var(--no); color: var(--no); }
.predict details.lab-sol { margin-top: 10px; }
.lab-break { position: relative; margin: 18px 0 0; padding: 12px 16px 12px 18px; border-radius: var(--r); background: color-mix(in srgb, var(--no) 7%, var(--surface)); border: 1px solid color-mix(in srgb, var(--no) 28%, var(--rule)); }
.lab-break::before { content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 3px; border-radius: 0 3px 3px 0; background: var(--no); }
.lab-break__k { display: block; margin: 0 0 4px; font: 600 .68rem/1.3 var(--font-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--no); }
.lab-break p { margin: 0 !important; }
details.lab-sol { margin: 12px 0 0; border: 1px dashed var(--rule-strong); border-radius: var(--r); padding: 0 16px; background: color-mix(in srgb, var(--surface) 60%, transparent); }
details.lab-sol > summary { min-height: 44px; display: flex; align-items: center; gap: 10px; padding: 10px 0; cursor: pointer; list-style: none; font-weight: 600; color: var(--ink-2); }
details.lab-sol > summary::-webkit-details-marker { display: none; }
details.lab-sol > summary::before { content: ""; flex: none; width: 20px; height: 20px; border-radius: 6px; border: 1px solid var(--control); background: linear-gradient(var(--accent), var(--accent)) 50% 50% / 9px 2px no-repeat, linear-gradient(var(--accent), var(--accent)) 50% 50% / 2px 9px no-repeat; }
details.lab-sol[open] > summary::before { background: linear-gradient(var(--accent), var(--accent)) 50% 50% / 9px 2px no-repeat; }
details.lab-sol > summary:hover { color: var(--accent); }
details.lab-sol[open] { padding-bottom: 14px; }
details.lab-sol > :not(summary) { margin-top: 0; }
details.lab-sol > p { margin: 0 0 8px !important; }
details.lab-sol pre.expect { margin: 4px 0 10px; white-space: pre-wrap; overflow-wrap: anywhere; }   /* a crash line reads whole in a fold */
/* P3 3.5 way B: a part's actions use the fold's full width on a phone; the letter floats before the kind */
@media (max-width: 760px) {
  .lab-ways { margin-left: -34px; }
  details.lab-path .lab-ways { margin-left: 0; }
  details.lab-way { padding: 0 10px; }
  details.lab-way ol.lab-do > li { padding-left: 0; }
  details.lab-way ol.lab-do > li::before { position: static; float: left; margin: 1px 8px 0 0; }
  details.lab-way .code { margin-inline: -10px; }
}
details.lab-way > details.lab-stuck { margin-top: 12px; }   /* `details.lab-sol > :not(summary)` sets 0 */
details.lab-way > summary > small { flex: none; margin-left: auto; white-space: nowrap; }   /* "8 min" never splits on a phone */

/* ---------- 11. Figures: a flow of places (F1, F2 …) ---------- */
.lab-fig { margin: 18px 0 8px; }
.lab-fig > figcaption { max-width: 72ch; margin: 10px 2px 0; font-size: .86rem; line-height: 1.5; color: var(--ink-3); }
ol.lab-flow { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 26px; margin: 0 !important; padding: 0 !important; list-style: none; counter-reset: flow; }
ol.lab-flow > li {
  --c: var(--ink-2); --ico: var(--lab-i-studio);
  position: relative; margin: 0 !important; padding: 12px 12px 13px; border-radius: 14px; background: var(--surface); min-width: 0;
  border: 1px solid color-mix(in srgb, var(--c) 40%, var(--rule)); box-shadow: var(--shadow-sm); font-size: .88rem; line-height: 1.45; color: var(--ink-2);
}
ol.lab-flow > li > b { display: flex; align-items: center; gap: 7px; margin-bottom: 4px; font: 600 .86rem/1.3 var(--font-body); color: var(--ink); }
ol.lab-flow > li > b::before { content: ""; width: 16px; height: 16px; flex: none; background: var(--c); -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat; }
ol.lab-flow > li + li::before { content: "\2192"; position: absolute; left: -22px; top: 50%; margin-top: -.6em; width: 18px; text-align: center; font: 600 1rem/1.2 var(--font-body); color: var(--ink-3); }
ol.lab-flow code { font-size: .84em; white-space: normal; }
.lab-flow__n--you { --c: var(--you) !important; --ico: var(--lab-i-xml) !important; }
.lab-flow__n--java { --c: var(--you) !important; --ico: var(--lab-i-java) !important; }
.lab-flow__n--gradle { --c: var(--you) !important; --ico: var(--lab-i-gradle) !important; }
.lab-flow__n--os { --c: var(--os) !important; --ico: var(--lab-i-phone) !important; }
.lab-flow__n--log { --c: var(--os) !important; --ico: var(--lab-i-log) !important; }
.lab-flow__n--studio { --c: var(--ink-2) !important; --ico: var(--lab-i-studio) !important; }
@media (max-width: 899px) {
  ol.lab-flow:has(> li:nth-child(4)) { grid-auto-flow: row; gap: 22px; }
  ol.lab-flow:has(> li:nth-child(4)) > li + li::before { content: "\2193"; left: 18px; top: -21px; margin-top: 0; }
}
@media (max-width: 700px) {
  ol.lab-flow { grid-auto-flow: row; gap: 22px; }
  ol.lab-flow > li + li::before { content: "\2193"; left: 18px; top: -21px; margin-top: 0; }
}

/* ---------- 12. The hub: hero on night glass (two phones), facts, the route filmstrip (f), rules, extensions ---------- */
.lab-stage { display: grid; place-items: center; align-self: stretch; padding: clamp(22px, 3vw, 34px) clamp(14px, 2.4vw, 26px) clamp(18px, 2.4vw, 26px); }
.lab-stage__row { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; gap: clamp(10px, 2vw, 22px); }
.lab-stage .lab-phone { --pw: clamp(120px, 15vw, 186px); }
@media (max-width: 899px) { .lab-stage .lab-phone { --pw: clamp(120px, 26vw, 200px); } }   /* one column: the stage is wide, the screens can be read */
.lab-stage .lab-phone figcaption { color: var(--night-ink-3); }
.lab-stage__arrow { display: grid; justify-items: center; gap: 4px; font: 600 .68rem/1.2 var(--font-mono); letter-spacing: .06em; color: var(--night-ink-3); }
.lab-stage__arrow::before { content: "\2192"; font-size: 1.5rem; line-height: 1; color: #a8a3ff; }
.lab-stage__cap { position: relative; z-index: 1; margin: 18px 0 0 !important; max-width: 40ch; text-align: center; font-size: .86rem !important; line-height: 1.5; color: var(--night-ink-2); }
.lab-facts { display: flex; flex-wrap: wrap; gap: 8px; margin: 22px 0 0 !important; padding: 0 !important; list-style: none; }
.lab-facts > li { display: inline-block; margin: 0 !important; padding: 6px 12px 6px 10px; border-radius: 999px; font-size: .84rem; font-weight: 500; color: var(--ink-2); background: var(--surface-glass); border: 1px solid var(--rule-strong); }
.lab-facts > li::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px; vertical-align: .12em; border-radius: 50%; background: var(--wire-deep); }
.lab-facts b { color: var(--ink); font-weight: 600; }
.lab-tested { margin: 14px 0 0 !important; font: 500 .76rem/1.5 var(--font-mono); letter-spacing: .02em; color: var(--ink-3); }
/* A student back on the hub: where they stopped, one click away (lab.js, W9). */
.lab-continue { margin: 18px 0 0 !important; }
.lab-continue a { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px 18px; border-radius: 999px; font-weight: 600; line-height: 1.3; color: var(--on-accent); background: var(--accent); text-decoration: none; box-shadow: var(--shadow-sm); }
.lab-continue a:hover { color: var(--on-accent); filter: brightness(1.08); }
.lab-continue a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* The route: nine frames, the app growing; lit as far as the Done ticks reach (lab.js sets is-done / is-here). */
ol.lab-route { position: relative; display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 10px; margin: 24px 0 8px !important; padding: 0 !important; list-style: none; }
ol.lab-route::before { content: ""; position: absolute; left: 5%; right: 5%; top: 186px; height: 2px; background: repeating-linear-gradient(90deg, var(--rule-strong) 0 4px, transparent 4px 9px); }
ol.lab-route::after { content: ""; position: absolute; left: 5%; top: 186px; width: var(--lit, 0%); height: 2px; background: var(--wire); }
ol.lab-route > li { position: relative; z-index: 1; margin: 0 !important; display: flex; flex-direction: column; align-items: center; text-align: center; min-width: 0; }
.lab-route__shot { position: relative; width: 76px; height: 169px; border-radius: 13px; border: 3px solid #0b0d15; background: #0b0d15; overflow: hidden; box-shadow: var(--shadow-sm); }
.lab-route__shot img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top; }
.lab-route__shot--crop { background: #fff8f1; }   /* a 1:1 detail (P7): the app's paper around it, not a black void */
.lab-route__shot--crop img { object-fit: contain; object-position: center; padding: 3px; }
.lab-route li.is-ahead .lab-route__shot { opacity: .55; }
.lab-route__node { width: 18px; height: 18px; margin: 8px 0 8px; border-radius: 50%; background: var(--bg); border: 2px solid var(--rule-strong); display: grid; place-items: center; }
.lab-route li.is-done .lab-route__node { background: var(--ok); border-color: var(--ok); }
.lab-route li.is-done .lab-route__node::after { content: ""; width: 7px; height: 4px; border: solid var(--bg); border-width: 0 0 2px 2px; transform: translateY(-1px) rotate(-45deg); }
.lab-route li.is-here .lab-route__node { border-color: var(--accent); box-shadow: 0 0 0 5px var(--accent-soft); }
.lab-route li.is-here .lab-route__node::after { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
.lab-route__n { font: 600 .64rem/1.3 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.lab-route__n > .lab-route__m { display: block; margin-top: 1px; text-transform: none; letter-spacing: .02em; }
.lab-route__t { margin: 3px 0 2px !important; font: 600 .84rem/1.3 var(--font-body) !important; color: var(--ink); text-wrap: balance; }
.lab-route__t a { color: inherit; text-decoration: none; }
.lab-route__t a::after { content: ""; position: absolute; inset: 0; }
.lab-route li:hover .lab-route__t a { color: var(--accent); }
.lab-route__t a:focus-visible { outline: none; }
.lab-route li:has(a:focus-visible) { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 12px; }
.lab-route__m { font: 500 .68rem/1.3 var(--font-mono); color: var(--ink-3); }
.lab-route__can { margin: 6px 0 0 !important; font-size: .76rem !important; line-height: 1.4; color: var(--ink-2); text-wrap: pretty; }
.lab-route__count { display: block; margin-top: 4px; font: 600 .64rem/1.2 var(--font-mono); color: var(--ok); }
/* Night tiles drawn in HTML for the parts whose frame is not a phone screen (P1 Gradle, P5 Logcat). */
.lab-tile { display: flex; flex-direction: column; justify-content: center; gap: 5px; width: 100%; height: 100%; padding: 8px 5px; background: radial-gradient(90% 60% at 20% 0%, rgba(122, 92, 255, .32), transparent 70%), #0c0f1a; font: 600 .5rem/1.35 var(--font-mono); color: var(--night-ink-2); text-align: left; overflow: hidden; }
.lab-tile b { color: #fbbf24; font-weight: 600; }
.lab-tile i { font-style: normal; color: #5fd3a0; }
.lab-tile span { display: block; white-space: nowrap; overflow: hidden; }
.lab-tile__k { color: var(--night-ink-3); letter-spacing: .08em; text-transform: uppercase; font-size: .46rem; }
@media (max-width: 899px) {
  ol.lab-route { grid-template-columns: minmax(0, 1fr); gap: 0; margin-top: 18px !important; }
  ol.lab-route::before, ol.lab-route::after { left: 75px; right: auto; top: 30px; bottom: 30px; width: 2px; height: auto; }
  ol.lab-route::before { background: repeating-linear-gradient(180deg, var(--rule-strong) 0 4px, transparent 4px 9px); }
  ol.lab-route::after { bottom: auto; height: var(--lit-v, 0%); background: var(--wire-v); }
  ol.lab-route > li { display: grid; grid-template-columns: 52px 20px minmax(0, 1fr); grid-template-areas: "shot node n" "shot node t" "shot node can" "shot node cnt"; column-gap: 14px; align-items: center; text-align: left; padding: 9px 0; }
  .lab-route__shot { grid-area: shot; width: 52px; height: 116px; border-width: 2px; border-radius: 9px; }
  .lab-route__count { grid-area: cnt; margin-top: 2px; }
  .lab-route__node { grid-area: node; margin: 0; }
  .lab-route__n { grid-area: n; align-self: end; }
  .lab-route__t { grid-area: t; margin: 1px 0 !important; font-size: .95rem !important; }
  .lab-route__t a::after { content: none; }
  .lab-route__can { grid-area: can; align-self: start; margin: 0 !important; font-size: .86rem !important; }
  .lab-route__n > .lab-route__m { display: inline; margin: 0; }
  .lab-route__n > .lab-route__m::before { content: " · "; }
  .lab-tile { font-size: .38rem; padding: 5px 2px; gap: 3px; }   /* "targetSdk 37" whole in a 52 px frame */
  .lab-tile__k { font-size: .36rem; }
  .lab-tile span:nth-child(n+5) { display: none; }
}
.lab-legend { margin: 26px 0 0; }
.lab-legend > .lab-k { margin-bottom: 10px !important; }
/* The three rules, and the before-you-come cards. */
ul.lab-rules { display: grid; gap: 10px; margin: 16px 0 0 !important; padding: 0 !important; list-style: none; }
ul.lab-rules > li { position: relative; max-width: 72ch; margin: 0 !important; padding: 10px 14px 10px 16px; border-radius: 12px; background: var(--surface); border: 1px solid var(--rule); font-size: .97rem; line-height: 1.5; }
ul.lab-rules > li .lab-kind { margin-right: 8px; }
/* P0's shortcut list: two columns from 720 px, one on a phone. */
ul.lab-rules.lab-rules--keys { grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); }
/* French: no automatic hyphen inside a package name or a route title (mobile.css hyphenates French prose). */
:root:lang(fr) .prose p:is(.lab-pkg__msg, .lab-route__t) { hyphens: manual; -webkit-hyphens: manual; }
/* An input table (P7): the empty corner of the head row on the head's surface; the row number a narrow row header. */
.data-table--rows thead td { background: var(--surface-2); border-bottom-color: var(--rule-strong); }
.data-table tbody th.data-table__n { width: 2.5em; min-width: 0; }
/* Under 760 px the table scrolls sideways and its row numbers stay (mobile.css): the empty corner above them stays too,
   so each heading slides under it and stays above its own column. */
@media (max-width: 760px) { .data-table--rows thead td:first-child { position: sticky; left: 0; z-index: 2; background: var(--surface-2); box-shadow: 1px 0 0 var(--rule); } }
.lab-cards { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); margin: 18px 0 0; }
.lab-card { position: relative; display: flex; flex-direction: column; gap: 6px; padding: 16px 18px 18px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--rule); box-shadow: var(--shadow-sm); min-width: 0; }
.lab-card h3 { margin: 0 !important; font: 600 1.12rem/1.3 var(--font-display) !important; color: var(--ink); }
.lab-card h3 a { color: inherit; text-decoration: none; }
.lab-card h3 a:hover { color: var(--accent); }
.lab-card > p:not(.lab-k) { margin: 0 !important; font-size: .94rem !important; line-height: 1.5; color: var(--ink-2); }
.lab-cards--rows { grid-template-columns: minmax(0, 1fr); }
.lab-card details.lab-sol[open] { padding-bottom: 6px; }
.lab-card details.lab-sol .code { margin-inline: -8px; }
.lab-card .lab-k { margin: 0 !important; color: var(--accent); }
.lab-card details.lab-sol { margin-top: 6px; }
.lab-card--go { border: 1.5px solid transparent; background: linear-gradient(var(--surface), var(--surface)) padding-box, var(--wire-deep) border-box; }
.lab-card--go h3 a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.lab-card--go:has(a:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
.lab-card--go h3 a:focus-visible { outline: none; }

/* ---------- 13. Presenting (present.js) and paper ---------- */
:root.is-presenting .lab-done__btns, :root.is-presenting .as-shot__zoom { display: none !important; }
/* The Copy buttons the gesture lines name show on a slide too (W9: "Click Copy the file, top right" pointed at an empty
   corner); Whole file and Show the file stay on the page. A group's row is thin there, so 7.2 a still fits. */
:root.is-presenting .code__btns :is(.lab-btn--whole, .lab-btn--shut) { display: none !important; }
:root.is-presenting .code__bar { flex-wrap: nowrap; }
:root.is-presenting .code__hunk { margin-block: 4px 2px; }
:root.is-presenting .code__hunk .code__btn { min-height: 0; padding: 0 8px; line-height: 1.4; }
/* A file's notes on a slide: one tight list under it (3.1 b, its action now a title and a gesture line, W9). */
:root.is-presenting .code-notes__list { margin-top: 6px !important; gap: 2px; }
:root.is-presenting .code-notes__list > li { font-size: .88rem; line-height: 1.4; }
:root.is-presenting details.lab-stuck, :root.is-presenting details.lab-from { display: none; }
:root.is-presenting .as-shot__bar:not(:has(.as-shot__where)) { display: none; }   /* P2's start capture: its bar holds only Full size */
/* On the projector an IDE capture grows to a fixed height (lab.js writes --ar = width / height on its img), so a dialog
   stays legible from the back of the room and the step still fits one slide at 1280 × 720. */
:root.is-presenting .as-shot__img img { width: calc(var(--pp-shot-h, 430px) * var(--ar, 1.6)); max-width: 100%; height: auto; }
/* A projector cannot scroll a panel sideways: on a slide a long code line wraps (at the gutter), as on paper. */
:root.is-presenting .code__pre { white-space: pre-wrap; -webkit-mask-image: none; mask-image: none; }
:root.is-presenting .code__pre > code { min-width: 0; }
:root.is-presenting .ln { overflow-wrap: anywhere; }
/* A code pair of one or two panels (Way 1 / Way 2) is one column on a slide, each panel at the slide's width; with
   data-pp-groups="1,1" on a .code-pair that is a child of the step, each panel gets its own presentation page (what comes
   before the pair shows with the first, what follows it with the second). Three or more small files (the drawables)
   keep their two columns. */
:root.is-presenting .code-pair:not(:has(> :nth-child(3))) { grid-template-columns: minmax(0, 1fr); }
/* A step whose pair holds three or more small files takes the figures' width on a slide (1120 px): two columns of
   about 520 px, where a drawable's lines fit whole. */
:root.is-presenting .lab-step:has(.code-pair > :nth-child(3)) { --bw: 1120px; }
/* The smallest words of a slide (step kicker, minutes, Click / Type / Paste, the panel's action, small kickers, phone
   captions) keep about 8.7 px at the smallest slide scale (0.7) instead of 6.7 to 7.6 px. */
:root.is-presenting :is(.lab-step__k, .lab-step__time, .code__act, .lab-kind, .lab-k, .lab-goal__k, .lab-phone figcaption, .lab-crop figcaption) { font-size: .78rem !important; }
@media print {
  .code__btns, .code__hunk .code__btn, .as-shot__zoom, .lab-done__btns, .lab-pkg, ol.lab-from__steps > li:has(.lab-pkg) { display: none !important; }
  .as-shot__bar:not(:has(.as-shot__where)) { display: none !important; }
  .code, .as-shot { background: #fff !important; border-color: #bbb !important; box-shadow: none !important; }
  .code__bar, .as-shot__bar, .as-shot__legend, .code__foot { background: #fff !important; color: #16161f !important; border-color: #ccc !important; }
  .code__file, .code__pre, .code__dir, .as-shot__legend > li, .as-shot__where b { color: #16161f !important; }
  .as-shot__legend :is(b, .ui, code), .code__foot :is(b, code) { color: #16161f !important; background: none !important; border-color: #bbb !important; }
  /* A key on a night surface turns white on paper: its word must turn dark with it. */
  .code__foot kbd, .as-shot__legend kbd, .as-shot__cap kbd { color: #16161f !important; background: #fff !important; border-color: #bbb !important; }
  /* Paper keeps one grey (6.6:1) for what is dimmed: a capture's caption, the IDE's lines, a diff's context lines. */
  .as-shot__cap { color: #5c5c6a !important; }
  .code__pre .ln--ide, .code.is-diff:not(.is-whole) .ln:not(.ln--add):not(.ln--del):not(.ln--edit) { color: #5c5c6a !important; }
  /* An edit panel on paper: what to type stays dark and boxed, what goes is struck in red (white on white before, W8). */
  .ln--edit { background: #e8f2fc !important; box-shadow: inset 3px 0 0 #0b5394 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .ln__new { color: #16161f !important; font-weight: 700; background: none !important; box-shadow: inset 0 0 0 1px #0b5394 !important; }
  .ln__old { color: #b3261e !important; text-decoration-color: #b3261e !important; background: none !important; }
  .ln__old--any { outline-color: #b3261e !important; }
  .ln--edit::after, .code__lg--edit::before { color: #0b5394 !important; }
  .ln--del::after, .code__lg--del::before { color: #b3261e !important; }
  .code__lg--add::before, .ln--add::after { color: #8a4b00 !important; }
  .code__legend, .code__el { color: #16161f !important; border-color: #ccc !important; }
  .code__act { color: #5c5c6a !important; border-color: #bbb !important; }
  .code__pre .t { color: #0b5394 !important; } .code__pre .a { color: #8a4b00 !important; } .code__pre .s { color: #1b6e2a !important; }
  .code__pre .k { color: #6a1b9a !important; } .code__pre .n { color: #8a4b00 !important; } .code__pre .c { color: #5c5c6a !important; }
  .ln::before { color: #888 !important; }
  .ln--add { background: #fff3d6 !important; box-shadow: inset 3px 0 0 #b26b00 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .code .ln--out, .code.js-ready .ln--out { display: block !important; }
  /* Paper cannot scroll: a long line wraps under its own indent instead of being cut at the edge. */
  .code__pre { white-space: pre-wrap !important; overflow: visible !important; -webkit-mask-image: none !important; mask-image: none !important; }
  .code__pre > code { min-width: 0 !important; }
  .ln { overflow-wrap: anywhere; padding-left: calc(64px + var(--ind, 0) * 1ch) !important; }
  .ln > .ln__ind { display: none !important; }
  .code__fold, .code__hunk { display: none !important; }
  /* The handout stays short: an "add" or "read" panel prints as on screen (its lines, their context, its folds, where
     they go); a code pair prints one panel under the other; the whole files of a Stuck? fold and of the Start-from box
     stay on the web page, where Copy is. */
  .code.js-ready:not(.is-whole)[data-action="add"] .ln--out { display: none !important; }
  .code.js-ready:not(.is-whole)[data-action="add"] .code__fold { display: flex !important; color: #5c5c6a !important; border-color: #bbb !important; background: none !important; }
  .code.js-ready:not(.is-whole)[data-action="add"] .code__hunk { display: flex !important; color: #8a4b00 !important; }
  .code.js-ready:not(.is-whole)[data-action="read"] .ln--out { display: none !important; }
  .code.js-ready:not(.is-whole)[data-action="read"] .code__fold { display: flex !important; color: #5c5c6a !important; border-color: #bbb !important; background: none !important; }
  .code.js-ready:not(.is-whole)[data-action="edit"] .ln--out { display: none !important; }
  .code.js-ready:not(.is-whole)[data-action="edit"] .code__fold { display: flex !important; color: #5c5c6a !important; border-color: #bbb !important; background: none !important; }
  .code[data-action="edit"] .ln { padding-left: calc(64px + var(--ind, 0) * 1ch) !important; }
  .code__tip code { color: #16161f !important; background: #fff !important; border-color: #bbb !important; }
  .code__tip { color: #16161f !important; background: #e8f2fc !important; border-color: #0b5394 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .code__legend { position: static !important; }
  .code-pair { grid-template-columns: minmax(0, 1fr) !important; }
  :is(details.lab-stuck, details.lab-from) .code:not([data-action="add"]), .lab-stuck__files { display: none !important; }
  /* P3 3.5's way b prints as its six titles, each with its plus, even with a part open on screen (lab.js leaves it
     open, so the reader keeps their place); a line says where the parts are. */
  details.lab-sol > summary::before { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  details.lab-way > :not(summary) { display: none !important; }
  details.lab-way[open] { padding-bottom: 0 !important; }
  details.lab-way[open] > summary::before { background: linear-gradient(var(--accent), var(--accent)) 50% 50% / 9px 2px no-repeat, linear-gradient(var(--accent), var(--accent)) 50% 50% / 2px 9px no-repeat; }
  .lab-ways::after { content: "Each part is on the web page, not on paper."; display: block; margin-top: 8px; font-size: .9rem; color: #5c5c6a; }
  :root:lang(fr) .lab-ways::after { content: "Chaque partie est sur la page web, pas sur papier."; }
  /* 3.5's two cards: the closed one says where it is (way B's parts sit inside it); the letters print dark. */
  details.lab-path:not([open]) > summary::after { content: "On the web page, not on paper."; flex-basis: 100%; font-size: .9rem; color: #5c5c6a; }
  :root:lang(fr) details.lab-path:not([open]) > summary::after { content: "Sur la page web, pas sur papier."; }
  details.lab-path > summary > b { color: #16161f !important; background: none !important; border: 1px solid #bbb; }
  /* Way A's whole file stays on the web page, where Copy is: paper says so (it printed 187 lines over 4 pages). */
  details.lab-path > ol.lab-do .code[data-action="replace"] { display: none !important; }
  details.lab-path > ol.lab-do > li:has(> .code[data-action="replace"])::after { content: "The file is on the web page, not on paper."; display: block; margin-top: 6px; font-size: .9rem; color: #5c5c6a; }
  :root:lang(fr) details.lab-path > ol.lab-do > li:has(> .code[data-action="replace"])::after { content: "Le fichier est sur la page web, pas sur papier."; }
  /* A Stuck? fold whose file stays on the web: paper says where it is ("Copy the file below" has nothing below). */
  details.lab-stuck:has(> figure.code:not([data-action="add"]))::after { content: "The code is on the web page, not on paper."; display: block; margin: 6px 14px 14px; font-size: .9rem; color: #5c5c6a; }
  :root:lang(fr) details.lab-stuck:has(> figure.code:not([data-action="add"]))::after { content: "Le code est sur la page web, pas sur papier."; }
  /* The same in the Start-from box: its Java item says "paste this file", and the file stays on the web page. */
  ol.lab-from__steps > li:has(> figure.code:not([data-action="add"]))::after { content: "The code is on the web page, not on paper."; display: block; margin-top: 4px; font-size: .9rem; color: #5c5c6a; }
  :root:lang(fr) ol.lab-from__steps > li:has(> figure.code:not([data-action="add"]))::after { content: "Le code est sur la page web, pas sur papier."; }
  .lab-step, .lab-start, .lab-end { break-inside: auto; }
  .as-shot, .code, .lab-phone, .lab-result, .lab-done, ul.lab-fixes > li, ul.lab-stuck__list > li { break-inside: avoid; }
  .lab-start, .lab-end, .lab-now, .lab-fix, .lab-done, .lab-card { box-shadow: none !important; background: #fff !important; }
  .lab-stage { background: #0c0f1a !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  ol.lab-route::after { display: none; }
}

/* The finished project, offered to compare (hub, end of Part 8). */
.lab-final { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; margin: 20px 0 0; }
.lab-final > p { flex: 1 1 280px; margin: 0 !important; font-size: .94rem !important; color: var(--ink-2); }
