{"checkpoints":{"s-css-1":[{"q":"<p>What color is the link?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@layer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> base</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">components</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@layer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> components</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .btn</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">white</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">blue</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"btn\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> href</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"#\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Buy tickets&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n","options":[{"text":"white, because <code dir=\"ltr\">components</code> is the last declared layer.","why":"Being the last named layer only beats other named layers; the unlayered rule outranks all of them."},{"text":"blue, because unlayered normal styles beat every layer.","why":"Correct. Unlayered styles sit in an implicit layer above all named ones, so the type selector wins despite its lower specificity."},{"text":"white, because a class is more specific than a type selector.","why":"Specificity is only compared within the same layer. Layer priority is settled first."},{"text":"The browser default link color, because the two rules cancel out.","why":"Rules never cancel each other; the cascade always picks one winner."}],"answer":1},{"q":"<p>Both rules target <code dir=\"ltr\">&lt;h3 class=&quot;title&quot;&gt;</code> inside <code dir=\"ltr\">.card</code>. Which color wins?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:where</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">green</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">red</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n","options":[{"text":"red, because both selectors score (0,1,0) and red comes later.","why":"Correct. <code dir=\"ltr\">:where()</code> contributes nothing, so the specificities tie and order of appearance decides."},{"text":"green, because it is more specific.","why":"<code dir=\"ltr\">:where(.card)</code> adds zero specificity, so green’s selector scores the same (0,1,0) as red’s."},{"text":"green, because descendant selectors beat single selectors.","why":"Combinators add no specificity; only the simple selectors count."},{"text":"Neither; <code dir=\"ltr\">:where()</code> makes the first rule invalid.","why":"<code dir=\"ltr\">:where()</code> is valid everywhere and still matches; it just weighs nothing."}],"answer":0},{"q":"<p>A card’s glow should grow on hover with <code dir=\"ltr\">transition: --glow 300ms</code>, using <code dir=\"ltr\">box-shadow: 0 0 var(--glow) violet</code>. The glow jumps instead of animating. What fixes it?</p>","options":[{"text":"Add <code dir=\"ltr\">transition-behavior: allow-discrete</code> so the custom property is allowed to transition.","why":"<code dir=\"ltr\">allow-discrete</code> lets a value that can’t be interpolated take part in a transition, but it still flips in one step, at the halfway point. The browser needs to know <code dir=\"ltr\">--glow</code> is a length to blend it."},{"text":"Move <code dir=\"ltr\">--glow</code> to <code dir=\"ltr\">:root</code> so it inherits.","why":"Where the property is defined doesn’t change whether it can be interpolated."},{"text":"Register <code dir=\"ltr\">--glow</code> with <code dir=\"ltr\">@property</code> using <code dir=\"ltr\">syntax: &quot;&lt;length&gt;&quot;</code> and an initial value.","why":"Correct. Once the browser knows <code dir=\"ltr\">--glow</code> is a length, it can interpolate it, and the shadow animates smoothly."},{"text":"Add <code dir=\"ltr\">will-change: --glow</code>.","why":"<code dir=\"ltr\">will-change</code> is a performance hint; it doesn’t make an untyped value animatable."}],"answer":2},{"q":"<p>The markup is <code dir=\"ltr\">&lt;label class=&quot;field&quot;&gt;Email &lt;input type=&quot;email&quot;&gt;&lt;/label&gt;</code>. Which selector styles the label while its input has focus?</p>","options":[{"text":"<code dir=\"ltr\">.field:focus</code>","why":"The label itself never receives focus; the input inside it does."},{"text":"<code dir=\"ltr\">input:focus + .field</code>","why":"The <code dir=\"ltr\">+</code> combinator looks for a following sibling, but the label is the input’s parent."},{"text":"<code dir=\"ltr\">.field &gt; input:focus</code>","why":"That selects the input, not the label."},{"text":"<code dir=\"ltr\">.field:has(input:focus)</code>","why":"Correct. The label matches when it contains a focused input. <code dir=\"ltr\">.field:focus-within</code> would also work here."}],"answer":3},{"q":"<p>Inside a nested <code dir=\"ltr\">.session-card</code> rule, which selector targets the card itself when it also has the class <code dir=\"ltr\">is-live</code>?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">  /* ??? */</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">border-color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">red</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">&amp; .is-live</code>","why":"The space makes it a descendant selector: an <code dir=\"ltr\">.is-live</code> element inside the card."},{"text":"<code dir=\"ltr\">.is-live</code>","why":"A nested selector without <code dir=\"ltr\">&amp;</code> is treated as a descendant, so this also means an element inside the card."},{"text":"<code dir=\"ltr\">&amp;:is-live</code>","why":"<code dir=\"ltr\">:is-live</code> isn’t a pseudo-class, so the selector is invalid."},{"text":"<code dir=\"ltr\">&amp;.is-live</code>","why":"Correct. With no space, <code dir=\"ltr\">&amp;</code> and <code dir=\"ltr\">.is-live</code> form one compound selector: <code dir=\"ltr\">.session-card.is-live</code>."}],"answer":3}],"s-css-2":[{"q":"<p>A page is <code dir=\"ltr\">display: flex</code> with a 16rem sidebar and a <code dir=\"ltr\">main</code> with <code dir=\"ltr\">flex: 1</code>. A wide data table inside <code dir=\"ltr\">main</code> pushes the page into horizontal scrolling. What’s the targeted fix?</p>","options":[{"text":"Add <code dir=\"ltr\">min-width: 0</code> to <code dir=\"ltr\">main</code> and let the table scroll inside its own <code dir=\"ltr\">overflow-x: auto</code> wrapper.","why":"Correct. <code dir=\"ltr\">main</code>’s automatic minimum width is its content width; removing it lets <code dir=\"ltr\">main</code> shrink and contains the overflow where it belongs."},{"text":"Add <code dir=\"ltr\">flex-shrink: 1</code> to <code dir=\"ltr\">main</code>.","why":"<code dir=\"ltr\">flex-shrink: 1</code> is already the default; shrinking stops at the automatic minimum anyway."},{"text":"Set <code dir=\"ltr\">overflow: hidden</code> on <code dir=\"ltr\">body</code>.","why":"That hides content users need and makes the table impossible to read on small screens."},{"text":"Change <code dir=\"ltr\">flex: 1</code> to <code dir=\"ltr\">flex: auto</code> on <code dir=\"ltr\">main</code>.","why":"<code dir=\"ltr\">auto</code> makes <code dir=\"ltr\">main</code> start from its content width, which makes the overflow worse, not better."}],"answer":0},{"q":"<p>A grid uses <code dir=\"ltr\">grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))</code> with no gap in a 500px container. How many columns are there, and how wide?</p>","options":[{"text":"Two columns of 200px and 100px of empty space.","why":"The <code dir=\"ltr\">1fr</code> maximum lets the tracks grow to share the leftover space."},{"text":"Two columns of 250px.","why":"Correct. Two 200px tracks fit and a third doesn’t, then the <code dir=\"ltr\">1fr</code> maximum shares the leftover 100px between the two."},{"text":"Three columns of about 167px.","why":"Each track has a 200px minimum, so three can’t fit in 500px."},{"text":"One column of 500px.","why":"<code dir=\"ltr\">auto-fill</code> creates as many tracks as fit at their minimum size, which is two here."}],"answer":1},{"q":"<p>A speaker sign-up form has three fieldsets, each with label and input pairs. The labels should form one column of equal width across all fieldsets. The form is a two-column grid. What do you add to each fieldset?</p>","options":[{"text":"<code dir=\"ltr\">display: grid; grid-template-columns: max-content 1fr;</code>","why":"Each fieldset sizes its own label column, so a long label in one fieldset doesn’t widen the others."},{"text":"<code dir=\"ltr\">display: contents;</code>","why":"That can align the fields, but it removes the fieldset’s box (and its border and legend layout), which breaks the grouping."},{"text":"<code dir=\"ltr\">display: grid; grid-column: span 2; grid-template-columns: subgrid;</code>","why":"Correct. Each fieldset spans both form columns and adopts them, so every label shares one column track."},{"text":"<code dir=\"ltr\">width: 100%;</code>","why":"Width doesn’t connect the fieldsets’ internal columns to each other."}],"answer":2},{"q":"<p>A session card sits in a 300px sidebar. Its layout switches with <code dir=\"ltr\">@container (width &gt; 400px)</code>, and the sidebar is the size container. The browser window is 1400px wide. Which layout does the card get?</p>","options":[{"text":"The narrow layout, because the query measures the 300px sidebar.","why":"Correct. Container queries ignore the viewport; the nearest size container is what’s measured."},{"text":"The wide layout, because the window is wider than 400px.","why":"That’s how a media query behaves. A container query measures the container."},{"text":"Neither; container queries need a container name to match.","why":"Unnamed queries use the nearest ancestor size container."},{"text":"It depends on the card’s own width.","why":"An element can’t query itself; the measurement is the sidebar container’s width."}],"answer":0},{"q":"<p>What width does <code dir=\"ltr\">width: clamp(280px, 50%, 600px)</code> produce inside a 400px-wide parent?</p>","options":[{"text":"280px","why":"Correct. 50% of 400px is 200px, which is below the 280px minimum, so the minimum wins."},{"text":"200px","why":"200px is the preferred value, but clamp() never goes below its minimum."},{"text":"400px","why":"The parent’s width isn’t one of the three values; clamp() returns min, preferred or max."},{"text":"600px","why":"The maximum only applies when the preferred value exceeds it."}],"answer":0}],"s-css-3":[{"q":"<p>A designer asks why the hero heading uses <code dir=\"ltr\">clamp(2rem, 1.2rem + 3vw, 3.5rem)</code> rather than <code dir=\"ltr\">clamp(32px, 3vw + 19px, 56px)</code>. What’s the best answer?</p>","options":[{"text":"The rem version scales with the user’s default font size and zoom; the px version locks the range to the designer’s settings.","why":"Correct. rem limits and a rem intercept keep user preferences in the calculation, which Resize Text depends on."},{"text":"The px version doesn’t work in Safari.","why":"Both are valid in every current browser; the difference is accessibility, not support."},{"text":"rem renders faster than px.","why":"There’s no rendering speed difference between the units."},{"text":"You can’t add px and vw inside clamp().","why":"Mixed units are allowed in math functions; <code dir=\"ltr\">3vw + 19px</code> is valid."}],"answer":0},{"q":"<p>A dismiss button is positioned with <code dir=\"ltr\">inset-inline-end: 8px</code>. The page is <code dir=\"ltr\">dir=&quot;rtl&quot;</code>. Which physical property does it map to?</p>","options":[{"text":"<code dir=\"ltr\">left: 8px</code>","why":"Correct. In right-to-left text, the inline end is on the left."},{"text":"<code dir=\"ltr\">right: 8px</code>","why":"That’s the mapping in left-to-right text, where lines end on the right."},{"text":"<code dir=\"ltr\">top: 8px</code>","why":"<code dir=\"ltr\">top</code> is a block-axis position; inline properties map to left and right in horizontal writing."},{"text":"It has no effect in RTL.","why":"Logical properties exist precisely to work in both directions."}],"answer":0},{"q":"<p>Which declaration gives a disabled button a grey with the same perceived lightness as the brand color?</p>","options":[{"text":"<code dir=\"ltr\">background: hsl(from var(--brand) h 0% l);</code>","why":"HSL lightness isn’t perceptual, so the grey’s apparent lightness won’t match the brand color."},{"text":"<code dir=\"ltr\">background: oklch(from var(--brand) l 0 h);</code>","why":"Correct. Setting chroma to 0 removes the colorfulness while keeping L, so the grey looks equally light."},{"text":"<code dir=\"ltr\">background: color-mix(in srgb, var(--brand), grey);</code>","why":"Mixing with grey keeps half the color and shifts lightness towards grey’s, not the brand’s."},{"text":"<code dir=\"ltr\">filter: grayscale(1);</code>","why":"The filter also greys out the text and any icons, and works in a non-perceptual space."}],"answer":1},{"q":"<p>The page is in dark mode, but a ‘print preview’ panel inside it should render with the light values of every <code dir=\"ltr\">light-dark()</code> token. What do you set on the panel?</p>","options":[{"text":"<code dir=\"ltr\">@media (prefers-color-scheme: light)</code> around the panel’s rules.","why":"That media query checks the user’s OS setting, which is still dark."},{"text":"<code dir=\"ltr\">data-theme=&quot;light&quot;</code> on the panel.","why":"The toggle rules in this course read <code dir=\"ltr\">data-theme</code> on the root, so the attribute on a panel does nothing unless CSS targets it."},{"text":"<code dir=\"ltr\">color-scheme: light;</code>","why":"Correct. <code dir=\"ltr\">light-dark()</code> resolves against each element’s used color scheme, which the panel’s descendants inherit."},{"text":"<code dir=\"ltr\">filter: invert(1);</code>","why":"Inverting flips images and brand colors too, and doesn’t touch the token values."}],"answer":2},{"q":"<p>Waypoint adds a sticky ‘cookie settings’ bar 56px tall at the bottom of the viewport. Keyboard users report that the focused link is sometimes hidden behind it. Which fix addresses WCAG’s Focus Not Obscured?</p>","options":[{"text":"<code dir=\"ltr\">:focus-visible { outline-offset: 56px; }</code>","why":"Offsetting the ring doesn’t move the element out from under the bar."},{"text":"<code dir=\"ltr\">.cookie-bar { opacity: 0.9; }</code>","why":"Slight transparency still obscures the element; the criterion is about it being hidden, not about the bar’s look."},{"text":"<code dir=\"ltr\">body { padding-top: 56px; }</code>","why":"The bar is at the bottom; top padding doesn’t change where focused elements land."},{"text":"<code dir=\"ltr\">html { scroll-padding-bottom: 56px; }</code>","why":"Correct. Scroll padding marks the bottom 56px as covered, so focus scrolling keeps the focused element above the bar."}],"answer":3}],"s-css-4":[{"q":"<p>Which pair of properties can a browser animate without re-running layout or paint on each frame?</p>","options":[{"text":"<code dir=\"ltr\">translate</code> and <code dir=\"ltr\">opacity</code>","why":"Correct. They change how an already-painted layer is composited, so the browser can skip layout and paint."},{"text":"<code dir=\"ltr\">width</code> and <code dir=\"ltr\">height</code>","why":"Both change geometry, so layout runs every frame."},{"text":"<code dir=\"ltr\">top</code> and <code dir=\"ltr\">left</code>","why":"Positions are geometry too; changing them triggers layout."},{"text":"<code dir=\"ltr\">background-color</code> and <code dir=\"ltr\">box-shadow</code>","why":"These skip layout but still repaint on every frame."}],"answer":0},{"q":"<p>During a view transition on the schedule, the sticky header crossfades along with the page, which looks like a flicker. How do you keep it still?</p>","options":[{"text":"Set <code dir=\"ltr\">position: fixed</code> on the header.","why":"Fixed elements are still captured in the root snapshot, so they crossfade too."},{"text":"Set <code dir=\"ltr\">z-index: 1000</code> on the header.","why":"Stacking order on the live page doesn’t matter during the transition; the header is still part of the root snapshot that crossfades."},{"text":"Give the header <code dir=\"ltr\">view-transition-name: header</code> and set <code dir=\"ltr\">animation: none</code> on <code dir=\"ltr\">::view-transition-group(header)</code>.","why":"Correct. Naming the header gives it its own group, separate from the root crossfade, and removing that group’s animation keeps it still."},{"text":"Add <code dir=\"ltr\">will-change: transform</code> to the header.","why":"That’s a rendering hint and has no effect on how the transition captures the header."}],"answer":2},{"q":"<p>A reading progress bar uses <code dir=\"ltr\">animation: grow ease both; animation-timeline: scroll(root);</code>. Halfway down the page, the bar is already 80% full. Why?</p>","options":[{"text":"<code dir=\"ltr\">scroll(root)</code> measures the viewport, not the document.","why":"<code dir=\"ltr\">scroll(root)</code> tracks the document scroller’s progress; the distortion comes from the easing."},{"text":"The fill mode <code dir=\"ltr\">both</code> makes the bar jump ahead.","why":"<code dir=\"ltr\">both</code> only applies the first and last keyframes outside the active range."},{"text":"Scroll timelines always run at double speed in the middle.","why":"Progress is proportional to scroll position; only the easing changes how it’s mapped to keyframes."},{"text":"The <code dir=\"ltr\">ease</code> timing curve maps scroll progress non-linearly; use <code dir=\"ltr\">linear</code> so the bar tracks scroll distance exactly.","why":"Correct. Timing functions still apply on scroll timelines, so a curve distorts the mapping."}],"answer":3},{"q":"<p>A new developer adds <code dir=\"ltr\">.session-card { margin-block-start: 24px; }</code> so cards in the sidebar don’t touch. What should the review suggest instead?</p>","options":[{"text":"Use <code dir=\"ltr\">margin-top</code> instead, for older browsers.","why":"Logical properties are supported everywhere; the problem is the component spacing itself."},{"text":"Add <code dir=\"ltr\">!important</code> so the margin survives other layouts.","why":"That makes the margin impossible to adjust per context, which is the opposite of what’s needed."},{"text":"Move the margin into the utilities layer.","why":"The card would still carry spacing everywhere; the sidebar is the place that needs it."},{"text":"Give the sidebar layout <code dir=\"ltr\">display: grid</code> (or flex) with a <code dir=\"ltr\">gap</code>, and keep the card free of outer margins.","why":"Correct. The context owns the spacing, so the card stays reusable in the grid, sidebar and carousel."}],"answer":3},{"q":"<p>You add <code dir=\"ltr\">content-visibility: auto</code> to each day section of a long schedule but nothing else. What do users notice?</p>","options":[{"text":"The scrollbar jumps as sections render, because skipped sections have no height until they’re laid out.","why":"Correct. <code dir=\"ltr\">contain-intrinsic-size: auto &lt;length&gt;</code> gives skipped sections a placeholder height and fixes the jumping."},{"text":"Off-screen sections disappear from find-in-page results.","why":"Content skipped by <code dir=\"ltr\">content-visibility: auto</code> remains searchable and accessible."},{"text":"Nothing changes, because content-visibility only works with JavaScript.","why":"It’s pure CSS and takes effect immediately."},{"text":"Every section renders twice, slowing the page down.","why":"The browser renders a section when it nears the viewport; it doesn’t render twice."}],"answer":0}]},"final":[{"q":"<p>What color is the paragraph?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"color: red\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Doors open at 08:30&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">blue</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> !important</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n","options":[{"text":"red, because inline styles always win.","why":"Inline styles beat normal stylesheet rules, but <code dir=\"ltr\">!important</code> is decided earlier in the cascade."},{"text":"red, because it is more specific.","why":"Inline styles aren’t compared by specificity; and importance is settled before either."},{"text":"blue, because stylesheet rules load after inline styles.","why":"Load order isn’t the reason; importance outranks the inline style."},{"text":"blue, because an important declaration beats a normal inline style.","why":"Correct. Importance is part of the first cascade criterion, which is checked before inline styles."}],"answer":3},{"q":"<p>An element has the <code dir=\"ltr\">hidden</code> attribute and the class <code dir=\"ltr\">card</code>. What is its display?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@layer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> reset</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">components</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@layer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> reset</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">hidden</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">none</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> !important</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; } }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@layer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> components</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> !important</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; } }</span></span></code></pre></div>\n","options":[{"text":"none, because important declarations in earlier layers win.","why":"Correct. For <code dir=\"ltr\">!important</code>, layer order reverses, so <code dir=\"ltr\">reset</code> beats <code dir=\"ltr\">components</code>."},{"text":"grid, because <code dir=\"ltr\">components</code> is the later layer.","why":"That’s true for normal declarations; important ones reverse the order."},{"text":"grid, because a class beats an attribute selector.","why":"Both score (0,1,0), and in any case layers are compared before specificity."},{"text":"The browser default for the element.","why":"Both rules apply; the cascade picks one of them."}],"answer":0},{"q":"<p><code dir=\"ltr\">--accent</code> is never defined anywhere. What does <code dir=\"ltr\">color: var(--accent, teal)</code> produce?</p>","options":[{"text":"The inherited color, because the declaration is invalid.","why":"The fallback exists for this case; the declaration is only invalid if there’s no usable fallback."},{"text":"black, the initial value of color.","why":"Even without a fallback, <code dir=\"ltr\">color</code> would inherit from the parent rather than reset to black; here the fallback applies anyway."},{"text":"teal","why":"Correct. An undefined custom property has the guaranteed-invalid value, so <code dir=\"ltr\">var()</code> uses its fallback."},{"text":"An empty string, so the text becomes transparent.","why":"Custom properties never produce transparency on their own; the fallback applies."}],"answer":2},{"q":"<p>A two-column grid uses <code dir=\"ltr\">grid-template-columns: 1fr 1fr</code>. A code sample with a very long line makes the first column much wider. Which change keeps the columns equal and lets the code scroll?</p>","options":[{"text":"<code dir=\"ltr\">grid-template-columns: repeat(2, auto)</code>","why":"<code dir=\"ltr\">auto</code> tracks size to content, so the long line makes things worse."},{"text":"<code dir=\"ltr\">grid-template-columns: minmax(0, 1fr) minmax(0, 1fr)</code> plus <code dir=\"ltr\">overflow-x: auto</code> on the code block.","why":"Correct. Removing the automatic minimum keeps the tracks equal; the code block handles its own overflow."},{"text":"<code dir=\"ltr\">white-space: nowrap</code> on the code block.","why":"That keeps the line from wrapping, which is already the problem."},{"text":"<code dir=\"ltr\">grid-auto-flow: column</code>","why":"That changes placement direction, not track sizing."}],"answer":1},{"q":"<p>A component uses <code dir=\"ltr\">font-size: clamp(1rem, 4cqi, 2rem)</code>, but on one page it isn’t inside any size container. What does <code dir=\"ltr\">4cqi</code> resolve against there?</p>","options":[{"text":"4% of the small viewport’s inline size, the fallback for container units.","why":"Correct. With no eligible container, container units fall back to the small viewport units, so the rule still works."},{"text":"Zero, so the font size sits at the 1rem minimum.","why":"Container units don’t resolve to zero; they fall back to viewport units."},{"text":"The parent element’s width.","why":"Only size containers count; an ordinary parent isn’t measured."},{"text":"The declaration is invalid and ignored.","why":"The value is valid; it just uses the viewport fallback."}],"answer":0},{"q":"<p>Which declaration centers a fixed-width block horizontally in both left-to-right and right-to-left pages?</p>","options":[{"text":"<code dir=\"ltr\">margin-inline-start: auto;</code>","why":"Only one side absorbs the space, so the block is pushed to the end, not centered."},{"text":"<code dir=\"ltr\">text-align: center;</code>","why":"That centers inline content inside the block, not the block itself."},{"text":"<code dir=\"ltr\">inset-inline: 0;</code>","why":"Inset properties only affect positioned elements, and they set positions, not centering margins."},{"text":"<code dir=\"ltr\">margin-inline: auto;</code>","why":"Correct. Both inline margins absorb the free space equally, whatever the direction."}],"answer":3},{"q":"<p>What does <code dir=\"ltr\">background: color-mix(in oklch, var(--brand), transparent 80%)</code> produce?</p>","options":[{"text":"The brand color at 20% opacity.","why":"Correct. Transparent takes 80% of the mix, so the brand color keeps 20% of its alpha."},{"text":"The brand color at 80% opacity.","why":"The 80% belongs to <code dir=\"ltr\">transparent</code>, the color it follows, so the brand only gets 20%."},{"text":"A grey, because mixing with transparent removes chroma.","why":"Transparent has no hue to pull towards, so the brand’s lightness, chroma and hue are kept."},{"text":"An invalid value, because transparent can’t be mixed.","why":"<code dir=\"ltr\">transparent</code> is a normal color in <code dir=\"ltr\">color-mix()</code> and is the standard way to add alpha."}],"answer":0},{"q":"<p>Your dark mode swaps every token correctly, but form <code dir=\"ltr\">&lt;select&gt;</code> menus and scrollbars stay bright white. What’s missing?</p>","options":[{"text":"Dark tokens for <code dir=\"ltr\">--select-bg</code> and <code dir=\"ltr\">--scrollbar-bg</code>.","why":"Browser-native UI doesn’t read your custom properties by default."},{"text":"A <code dir=\"ltr\">prefers-color-scheme</code> media query around the tokens.","why":"That changes your tokens, which already work; native controls still need <code dir=\"ltr\">color-scheme</code>."},{"text":"<code dir=\"ltr\">appearance: none</code> on every control.","why":"That throws away native styling and accessibility affordances to fix something one property handles."},{"text":"A <code dir=\"ltr\">color-scheme</code> declaration that includes <code dir=\"ltr\">dark</code>, so the browser renders its own UI in dark mode.","why":"Correct. Built-in controls and scrollbars follow <code dir=\"ltr\">color-scheme</code>, not your custom properties."}],"answer":3},{"q":"<p>A mouse user clicks a button and sees no focus ring; a keyboard user tabs to it and sees one. The CSS uses <code dir=\"ltr\">:focus-visible</code>. Is this a bug?</p>","options":[{"text":"Yes. The ring must appear for every user on every focus.","why":"WCAG requires a visible indicator for keyboard operation, which <code dir=\"ltr\">:focus-visible</code> provides."},{"text":"No. <code dir=\"ltr\">:focus-visible</code> uses browser heuristics to show the indicator for keyboard focus but not after a mouse click on a button.","why":"Correct. That’s the intended behaviour, and it satisfies Focus Visible for keyboard users."},{"text":"Yes. Programmatic focus is required for mouse users.","why":"Mouse users already see where they clicked; no programmatic focus is needed."},{"text":"No, but only because the button has no outline in the reset.","why":"The reset isn’t involved; the heuristics of <code dir=\"ltr\">:focus-visible</code> explain the behaviour."}],"answer":1},{"q":"<p>A dialog shown with <code dir=\"ltr\">showModal()</code> should fade in from opacity 0. The transition on <code dir=\"ltr\">opacity</code> never runs on open. What’s the fix?</p>","options":[{"text":"Increase the transition duration.","why":"The transition never starts, so its duration doesn’t matter."},{"text":"Add <code dir=\"ltr\">@starting-style { dialog[open] { opacity: 0; } }</code> so the first style has a starting value.","why":"Correct. Without a before-state, there’s nothing to transition from when the dialog first renders."},{"text":"Use <code dir=\"ltr\">animation-delay</code> instead of a transition.","why":"A delay doesn’t give the browser a starting style either."},{"text":"Set <code dir=\"ltr\">will-change: opacity</code> on the dialog.","why":"<code dir=\"ltr\">will-change</code> is a performance hint and doesn’t create a starting value."}],"answer":1},{"q":"<p>Speaker cards reveal with a scroll-driven animation inside <code dir=\"ltr\">@supports (animation-timeline: view())</code>. What does a visitor using stable Firefox in 2026 see?</p>","options":[{"text":"The cards fully visible, with no reveal animation.","why":"Correct. The <code dir=\"ltr\">@supports</code> block doesn’t apply, so the cards keep their normal, visible styles."},{"text":"Invisible cards, because the reveal starts at opacity 0.","why":"The opacity 0 keyframe is only used inside the <code dir=\"ltr\">@supports</code> block that Firefox skips."},{"text":"A time-based fade-in on page load.","why":"Nothing in the guarded block applies, so there’s no animation at all."},{"text":"An error overlay from the browser.","why":"Browsers silently skip CSS they don’t support."}],"answer":0},{"q":"<p>Fifty speaker cards transition <code dir=\"ltr\">box-shadow</code> on hover, and moving the mouse across the grid feels heavy. What’s a cheaper way to get the same look?</p>","options":[{"text":"Add <code dir=\"ltr\">will-change: box-shadow</code> to every card.","why":"Layer promotion doesn’t stop the shadow from repainting each frame, and fifty layers cost memory."},{"text":"Lower the transition duration to 50ms.","why":"Fewer frames of repaint is still repainting, and the effect becomes abrupt."},{"text":"Put the larger shadow on a <code dir=\"ltr\">::after</code> pseudo-element and transition its <code dir=\"ltr\">opacity</code> instead.","why":"Correct. The shadow is painted once; hovering only changes compositing, so no repaint runs per frame."},{"text":"Use <code dir=\"ltr\">filter: drop-shadow()</code> instead.","why":"Changing a filter’s shadow still requires repainting the filtered element each frame."}],"answer":2}],"glossary":[{"id":"cascade","term":"Cascade","definition":"The algorithm the browser uses to choose one value when several declarations target the same property on the same element: origin and importance, inline styles, layers, specificity, then order of appearance.","lesson":"l-css-1-1"},{"id":"inheritance","term":"Inheritance","definition":"When no declaration targets an inherited property such as <code dir=\"ltr\">color</code> or <code dir=\"ltr\">font-family</code>, the element takes its parent’s computed value; non-inherited properties fall back to their initial value instead.","lesson":"l-css-1-1"},{"id":"specificity","term":"Specificity","definition":"A selector’s weight, counted as three separate numbers (IDs; classes, attributes and pseudo-classes; types and pseudo-elements) and compared column by column, never added together.","lesson":"l-css-1-2"},{"id":"where-pseudo-class","term":":where()","definition":"A pseudo-class that matches like <code dir=\"ltr\">:is()</code> but always contributes zero specificity, which makes it ideal for resets and base styles that components should override easily.","lesson":"l-css-1-2"},{"id":"is-pseudo-class","term":":is()","definition":"A pseudo-class that matches any selector in its list and takes the specificity of its most specific argument; it uses a forgiving selector list, so one invalid argument doesn’t drop the rule.","lesson":"l-css-1-2"},{"id":"cascade-layer","term":"Cascade layer","definition":"A named group of rules created with <code dir=\"ltr\">@layer</code>. Later-declared layers beat earlier ones before specificity is compared, and unlayered styles beat all layers for normal declarations.","lesson":"l-css-1-3"},{"id":"custom-property","term":"Custom property","definition":"A property whose name starts with two dashes, such as <code dir=\"ltr\">--track-color</code>, read with <code dir=\"ltr\">var()</code>. It inherits by default and is substituted where it is used, at computed-value time.","lesson":"l-css-1-4"},{"id":"invalid-at-computed-value-time","term":"Invalid at computed-value time","definition":"What happens when a <code dir=\"ltr\">var()</code> substitution produces a value the property can’t use: the property behaves as unset, taking its inherited or initial value rather than an earlier declaration.","lesson":"l-css-1-4"},{"id":"at-property","term":"@property","definition":"An at-rule that registers a custom property with a syntax, an inheritance flag and an initial value, so the browser can validate it and interpolate it in transitions and animations.","lesson":"l-css-1-4"},{"id":"css-nesting","term":"CSS nesting","definition":"Native syntax for writing rules inside other rules, where <code dir=\"ltr\">&amp;</code> stands for the parent selector. It works on selectors, not text, so it can’t build BEM class names the way Sass does.","lesson":"l-css-1-5"},{"id":"has-pseudo-class","term":":has()","definition":"A relational pseudo-class that matches an element when the relative selector inside it finds a match, letting a parent or earlier sibling be styled by its descendants or later siblings.","lesson":"l-css-1-5"},{"id":"flex-basis","term":"flex-basis","definition":"The starting size of a flex item along the main axis, before leftover space is shared by <code dir=\"ltr\">flex-grow</code> or a shortfall is taken back by <code dir=\"ltr\">flex-shrink</code>.","lesson":"l-css-2-1"},{"id":"automatic-minimum-size","term":"Automatic minimum size","definition":"The default <code dir=\"ltr\">min-width: auto</code> of flex and grid items, which stops them shrinking below their content. Setting <code dir=\"ltr\">min-width: 0</code> lets long text truncate instead of overflowing.","lesson":"l-css-2-1"},{"id":"grid-template-areas","term":"grid-template-areas","definition":"A grid property that names regions of the grid with strings, one per row, so you can place items by name and rearrange the layout by redrawing the strings.","lesson":"l-css-2-2"},{"id":"auto-fit","term":"auto-fit","definition":"A keyword for <code dir=\"ltr\">repeat()</code> that creates as many tracks as fit and collapses the empty ones, so a few items stretch to fill the row; <code dir=\"ltr\">auto-fill</code> keeps empty tracks instead.","lesson":"l-css-2-2"},{"id":"subgrid","term":"Subgrid","definition":"The <code dir=\"ltr\">subgrid</code> value for <code dir=\"ltr\">grid-template-rows</code> or <code dir=\"ltr\">grid-template-columns</code>, which makes a nested grid use the tracks it spans in its parent, so content aligns across sibling components.","lesson":"l-css-2-3"},{"id":"fit-content","term":"fit-content","definition":"An intrinsic sizing keyword that sizes an element to its max-content width, capped at the available space, so a block can hug its content without overflowing.","lesson":"l-css-2-4"},{"id":"clamp","term":"clamp()","definition":"A math function that returns a preferred value held between a minimum and a maximum, written <code dir=\"ltr\">clamp(MIN, PREFERRED, MAX)</code>. It equals <code dir=\"ltr\">max(MIN, min(PREFERRED, MAX))</code>.","lesson":"l-css-2-4"},{"id":"container-query","term":"Container query","definition":"An <code dir=\"ltr\">@container</code> rule that applies styles based on the size or style of an ancestor container rather than the viewport, so a component adapts to the slot it sits in.","lesson":"l-css-2-5"},{"id":"container-units","term":"Container query units","definition":"Units such as <code dir=\"ltr\">cqi</code> and <code dir=\"ltr\">cqb</code> that equal 1% of the nearest size container’s inline or block size, falling back to small viewport units when no container exists.","lesson":"l-css-2-5"},{"id":"fluid-type","term":"Fluid type","definition":"Font sizes that change continuously with available width, usually written as <code dir=\"ltr\">clamp()</code> with a rem minimum, a linear preferred value combining rem and <code dir=\"ltr\">vw</code> or <code dir=\"ltr\">cqi</code>, and a rem maximum.","lesson":"l-css-3-1"},{"id":"logical-properties","term":"Logical properties","definition":"Properties named by text flow instead of physical sides, such as <code dir=\"ltr\">margin-inline-start</code> and <code dir=\"ltr\">inline-size</code>, so layouts mirror correctly in right-to-left languages like Arabic.","lesson":"l-css-3-2"},{"id":"oklch","term":"oklch()","definition":"A color function using perceptual lightness, chroma and hue, so colors with equal lightness look equally light. It can also express colors beyond the sRGB gamut.","lesson":"l-css-3-3"},{"id":"relative-color-syntax","term":"Relative color syntax","definition":"A way to derive a color from another by unpacking its channels with <code dir=\"ltr\">from</code>, as in <code dir=\"ltr\">oklch(from var(--brand) calc(l - 0.1) c h)</code>, and changing only what you need.","lesson":"l-css-3-3"},{"id":"light-dark","term":"light-dark()","definition":"A color function that returns its first value when the element’s used color scheme is light and its second when it’s dark. It needs <code dir=\"ltr\">color-scheme</code> to allow dark.","lesson":"l-css-3-4"},{"id":"focus-visible","term":":focus-visible","definition":"A pseudo-class that matches a focused element only when the browser judges a focus indicator useful, such as keyboard focus or any text field, but not a mouse click on a button.","lesson":"l-css-3-5"},{"id":"starting-style","term":"@starting-style","definition":"An at-rule that defines the styles an element transitions from when it is first rendered or goes from <code dir=\"ltr\">display: none</code> to shown, enabling entry transitions in CSS alone.","lesson":"l-css-4-1"},{"id":"view-transition","term":"View transition","definition":"An animation created by <code dir=\"ltr\">document.startViewTransition()</code>: the browser snapshots the old and new states of a DOM update and animates between them through pseudo-elements you can style.","lesson":"l-css-4-2"},{"id":"scroll-driven-animation","term":"Scroll-driven animation","definition":"A CSS animation whose progress follows a scroll timeline, set with <code dir=\"ltr\">animation-timeline: scroll()</code> or <code dir=\"ltr\">view()</code>, instead of elapsed time.","lesson":"l-css-4-3"},{"id":"compositing","term":"Compositing","definition":"The final rendering stage, where painted layers are assembled on the GPU. Changes to <code dir=\"ltr\">transform</code> and <code dir=\"ltr\">opacity</code> can often be handled here alone, skipping layout and paint.","lesson":"l-css-4-5"}]}