{"id":"l-a11y-4-4","courseId":"web-accessibility","lang":"en","kind":"lesson","summary":"Write Ticketly’s text so more people understand it, and mark up language and direction so screen readers pronounce Arabic correctly and right-to-left layouts mirror properly.","html":"<p>Ticketly is adding an Arabic event this year: <strong>ليالي الطرب</strong> (Tarab Nights), with the venue name and description in Arabic on the otherwise English page. The first test with NVDA was a disaster: the English voice tried to pronounce Arabic letters one at a time. And the Arabic card’s icon, padding and text alignment were all on the wrong side. Words matter for accessibility in two ways: how easy they are to understand, and how correctly software can process them.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Plain language</h2>\n<p>People with intellectual and learning disabilities, dyslexia, brain injuries or memory loss, along with everyone reading in a second language or at the end of a long day, benefit from text that is easy to follow. WCAG’s only formal criterion on reading level, 3.1.5, is AAA, but plain language is still one of the most effective accessibility improvements you can make.</p>\n<p>Compare Ticketly’s refund policy before and after:</p>\n<blockquote>\n<p><strong>Before:</strong> Notwithstanding the foregoing, ticket holders who elect to request reimbursement subsequent to the 14-day pre-event threshold shall be ineligible for remuneration save in exceptional circumstances.</p>\n</blockquote>\n<blockquote>\n<p><strong>After:</strong> You can get a full refund until 14 days before the festival. After that, we only give refunds if the event is cancelled.</p>\n</blockquote>\n<p>The techniques are simple to state and take practice to apply:</p>\n<ul>\n<li><strong>Put the most important point first</strong>, in the heading and in the first sentence.</li>\n<li><strong>Use common words and short sentences.</strong> One idea per sentence.</li>\n<li><strong>Use the same name for the same thing</strong> everywhere: if it is a “pass” on the card, it isn’t a “ticket bundle” at checkout (3.2.4 Consistent Identification).</li>\n<li><strong>Write instructions that work without sight.</strong> “Press the green button on the right” relies on colour and position; “Press Continue” works for everyone (1.3.3 Sensory Characteristics).</li>\n<li><strong>Explain abbreviations</strong> the first time: “VIP lounge (the covered area beside the stage)”.</li>\n</ul>\n<h2 id=\"sec-2\" tabindex=\"-1\">Language of the page and its parts</h2>\n<p>Screen readers use the <code dir=\"ltr\">lang</code> attribute to choose a voice and pronunciation rules. Browsers also use it for hyphenation, font selection, spell-checking and translation. Two criteria apply:</p>\n<ul>\n<li><strong>3.1.1 Language of Page (A):</strong> <code dir=\"ltr\">&lt;html lang=&quot;en&quot;&gt;</code> (or <code dir=\"ltr\">ar</code>, <code dir=\"ltr\">fr</code>, and so on). A missing page language is one of the six most common failures on the web.</li>\n<li><strong>3.1.2 Language of Parts (AA):</strong> any passage in a different language gets its own <code dir=\"ltr\">lang</code>.</li>\n</ul>\n<p>Here is the Arabic card on the English page, with the title ليالي الطرب marked up as Arabic:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">ticketly/events.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\">html</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> lang</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"en\"</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:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</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\">\"card\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h3</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> lang</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"ar\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> dir</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"rtl\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>…&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">&#x3C;!-- the Arabic title --></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>An evening of classic Arabic music at the old harbour.&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<p>Now NVDA switches to an Arabic voice for the title and back to English for the description. You don’t need <code dir=\"ltr\">lang</code> on proper names or on words that have been absorbed into English, like “café”; it is for passages a reader would pronounce in the other language.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">Direction: rtl, auto and bdi</h2>\n<p>Arabic, Hebrew, Persian and Urdu are written right to left. The <code dir=\"ltr\">dir</code> attribute tells the browser the base direction of a block, which controls where the text starts, which side punctuation lands on, and how mixed-direction text is ordered.</p>\n<ul>\n<li><code dir=\"ltr\">dir=&quot;rtl&quot;</code> on <code dir=\"ltr\">&lt;html&gt;</code> for an Arabic page, or on an element for an Arabic part of an English page.</li>\n<li><code dir=\"ltr\">dir=&quot;auto&quot;</code> when you don’t know the direction in advance, such as user names, reviews and search fields. The browser looks at the first strong character.</li>\n<li><code dir=\"ltr\">&lt;bdi&gt;</code> isolates a short piece of user-generated text inside a sentence, so an Arabic username doesn’t reorder the English text around it: <code dir=\"ltr\">Review by &lt;bdi&gt;سارة&lt;/bdi&gt;, 5 stars</code>.</li>\n</ul>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><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\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Setting direction with CSS instead of markup</span></p>\n<p><code dir=\"ltr\">direction: rtl</code> in a stylesheet changes the visual layout, but the direction is part of the content’s meaning, not its style. If the CSS doesn’t load, or the text is copied, or a screen reader reads it, the information is lost. Put <code dir=\"ltr\">dir</code> in the HTML; use CSS for the layout that follows from it.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">Layout that mirrors itself</h2>\n<p>In a right-to-left layout, everything horizontal flips: the icon that sat on the left of the title belongs on its right, and padding that pushed text away from the left edge should push from the right. Physical properties such as <code dir=\"ltr\">margin-left</code> and <code dir=\"ltr\">text-align: left</code> don’t flip. <strong>Logical properties</strong> do:</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"Scrollable table\" tabindex=\"0\"><table><thead>\n<tr>\n<th>Physical</th>\n<th>Logical</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code dir=\"ltr\">margin-left</code></td>\n<td><code dir=\"ltr\">margin-inline-start</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">padding-right</code></td>\n<td><code dir=\"ltr\">padding-inline-end</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">left: 0</code></td>\n<td><code dir=\"ltr\">inset-inline-start: 0</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">text-align: left</code></td>\n<td><code dir=\"ltr\">text-align: start</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">border-left</code></td>\n<td><code dir=\"ltr\">border-inline-start</code></td>\n</tr>\n</tbody>\n</table></div><div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">ticketly/card.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\">.card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  padding-inline</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border-inline-start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> #5b3cc4</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  text-align</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">start</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:#0550AE;--shiki-dark:#79C0FF\">.badge</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  margin-inline-end</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* the gap after the icon, on whichever side that is */</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 200\" role=\"img\" aria-labelledby=\"l-a11y-4-4-t1\"><defs><marker id=\"arrow-l-a11y-4-4-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-a11y-4-4-t1\">An English card with the accent border and icon on the left and the gap after the icon on its right, next to an Arabic card where the border and icon are on the right and the gap is on the icon's left, both produced by the same logical CSS.</title>\n  <rect class=\"d-box\" x=\"20\" y=\"40\" width=\"300\" height=\"100\" rx=\"10\"/>\n  <rect class=\"d-box-primary\" x=\"20\" y=\"40\" width=\"10\" height=\"100\"/>\n  <circle class=\"d-dot\" cx=\"60\" cy=\"80\" r=\"12\"/>\n  <text class=\"d-label\" x=\"85\" y=\"86\">Harbour Lights</text>\n  <text class=\"d-label-muted\" x=\"45\" y=\"120\">inline-start = left</text>\n  <rect class=\"d-box\" x=\"360\" y=\"40\" width=\"300\" height=\"100\" rx=\"10\"/>\n  <rect class=\"d-box-primary\" x=\"650\" y=\"40\" width=\"10\" height=\"100\"/>\n  <circle class=\"d-dot\" cx=\"620\" cy=\"80\" r=\"12\"/>\n  <text class=\"d-label\" x=\"595\" y=\"86\" text-anchor=\"end\">ليالي الطرب</text>\n  <text class=\"d-label-muted\" x=\"635\" y=\"120\" text-anchor=\"end\">inline-start = right</text>\n  <text class=\"d-code\" x=\"340\" y=\"180\" text-anchor=\"middle\">border-inline-start · margin-inline-end</text>\n</svg><figcaption>The same card in both directions</figcaption></figure>\n<p>Not everything should mirror. Logos, photos, media player controls (play always points right) and numbers stay as they are. Arrows that mean “next” or “back” should flip; the <code dir=\"ltr\">:dir(rtl)</code> pseudo-class lets you target them without extra classes.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><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\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Test with real content</span></p>\n<p>Dummy Arabic filler text hides problems. Ask a native reader to check the content and listen to it with a screen reader set to Arabic. Most RTL bugs are found in the first two minutes of real use.</p>\n</aside>\n<p>That completes Section 4. Ticketly is now structured, operable, readable and correctly spoken. Section 5 turns to proving it: automated testing, manual testing with screen readers, and a full audit.</p>\n","toc":[{"id":"sec-1","text":"Plain language","level":2},{"id":"sec-2","text":"Language of the page and its parts","level":2},{"id":"sec-3","text":"Direction: rtl, auto and bdi","level":2},{"id":"sec-4","text":"Layout that mirrors itself","level":2}],"takeaways":["Plain language, short sentences and instructions that don’t depend on shape, colour or position help people with cognitive disabilities and everyone reading in a second language.","Set lang on the html element for the page and on any passage in another language, so screen readers switch voice and pronunciation.","Use dir=“rtl” for Arabic and Hebrew content and dir=“auto” for user-generated text whose direction you can’t know in advance.","CSS logical properties such as margin-inline-start and text-align start mirror automatically in right-to-left layouts."],"further":[{"title":"W3C: Understanding 3.1.2 Language of Parts","url":"https://www.w3.org/WAI/WCAG22/Understanding/language-of-parts.html"},{"title":"W3C Internationalization: Structural markup and right-to-left text in HTML","url":"https://www.w3.org/International/questions/qa-html-dir"},{"title":"MDN: CSS logical properties and values","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values"}],"quiz":[{"q":"<p>Ticketly’s English page shows the Arabic event title “ليالي الطرب” with no lang attribute. What does a screen reader set to English typically do?</p>","options":[{"text":"Detects the script and switches to an Arabic voice automatically, in every screen reader","why":"Some screen readers try to detect scripts, but behaviour varies widely and often fails. lang is the reliable signal WCAG requires."},{"text":"Skips the text, because it can’t be read","why":"The text is still in the tree. The problem is how it is spoken, not whether it is read."},{"text":"Reads it with English pronunciation rules or spells out characters, which is unintelligible","why":"Correct. Adding lang=“ar” (3.1.2 Language of Parts) lets the screen reader switch to an Arabic voice for that phrase."},{"text":"Translates it into English before reading","why":"Screen readers don’t translate content. They only choose a voice and pronunciation rules."}],"answer":2},{"q":"<p>Ticketly lets attendees post reviews, written in English or Arabic. Which markup handles direction best for each review’s text?</p>","options":[{"text":"<code dir=\"ltr\">&lt;p dir=&quot;rtl&quot;&gt;</code> on every review","why":"That would make English reviews right-to-left, putting full stops and parentheses in the wrong places."},{"text":"<code dir=\"ltr\">&lt;p dir=&quot;auto&quot;&gt;</code> on every review","why":"Correct. dir=“auto” sets the direction from the first strong character, so Arabic reviews become right-to-left and English ones left-to-right."},{"text":"No dir attribute; the page’s direction is enough","why":"The page is left-to-right, so Arabic reviews would be laid out with punctuation and numbers in the wrong positions."}],"answer":1},{"q":"<p>Which instruction meets 1.3.3 Sensory Characteristics?</p>","options":[{"text":"“Press the round green button on the right.”","why":"Shape, colour and position are meaningless to screen reader users and change on small screens."},{"text":"“Use the button below to continue.”","why":"The word “below” relies on visual position, which depends on layout and is unknown to screen reader users."},{"text":"“Press Continue to choose your seats.”","why":"Correct. It names the control by its visible label, which works for everyone, including voice control users."},{"text":"“Click the arrow icon.”","why":"The icon’s shape is a sensory characteristic, and “click” excludes keyboard and voice users."}],"answer":2},{"q":"<p>An icon badge sits before a card title with <code dir=\"ltr\">margin-right: 8px</code>. On Ticketly’s Arabic page, the gap ends up on the wrong side. What is the cleanest fix?</p>","options":[{"text":"Replace it with <code dir=\"ltr\">margin-inline-end: 8px</code>","why":"Correct. Inline-end is the right side in left-to-right text and the left side in right-to-left text, so one rule works for both."},{"text":"Add an <code dir=\"ltr\">[dir=&quot;rtl&quot;] .badge { margin-left: 8px; margin-right: 0; }</code> override","why":"It works, but you would need overrides like this for every directional property. Logical properties remove the duplication."},{"text":"Use <code dir=\"ltr\">transform: scaleX(-1)</code> on the Arabic page","why":"Mirroring with a transform also mirrors text and images, making them unreadable."}],"answer":0}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<article class=\"card\" id=\"card-en\">\n  <h3><span class=\"badge\" aria-hidden=\"true\">★</span>Harbour Lights</h3>\n  <p>Two nights of music on the old harbour wall.</p>\n</article>\n\n<article class=\"card\" id=\"card-ar\">\n  <h3><span class=\"badge\" aria-hidden=\"true\">★</span>ليالي الطرب</h3>\n  <p>أمسية من الموسيقى العربية الكلاسيكية في الميناء القديم.</p>\n  <p class=\"note\">An evening of classic Arabic music at the old harbour.</p>\n</article>\n\n<form class=\"review\">\n  <label for=\"reviewer\">Your name</label>\n  <input id=\"reviewer\" name=\"reviewer\">\n  <label for=\"review-text\">Your review</label>\n  <textarea id=\"review-text\" name=\"review\"></textarea>\n</form>","css":".card { border: 1px solid #c9c4dc; border-left: 4px solid #5b3cc4; border-radius: 8px; padding: 8px 12px; margin-block-end: 12px; text-align: left; }\n.card h3 { margin: 0 0 4px; }\n.card p { margin: 0 0 4px; }\n.badge { color: #5b3cc4; margin-right: 8px; }\n.note { color: #595959; font-size: 0.9rem; }\n.review { display: grid; gap: 4px; max-width: 320px; }\ninput, textarea { font: inherit; padding: 6px 8px; border: 1px solid #77708f; border-radius: 6px; }\n","js":""},"solution":{"html":"<article class=\"card\" id=\"card-en\">\n  <h3><span class=\"badge\" aria-hidden=\"true\">★</span>Harbour Lights</h3>\n  <p>Two nights of music on the old harbour wall.</p>\n</article>\n\n<article class=\"card\" id=\"card-ar\">\n  <div lang=\"ar\" dir=\"rtl\">\n    <h3><span class=\"badge\" aria-hidden=\"true\">★</span>ليالي الطرب</h3>\n    <p>أمسية من الموسيقى العربية الكلاسيكية في الميناء القديم.</p>\n  </div>\n  <p class=\"note\">An evening of classic Arabic music at the old harbour.</p>\n</article>\n\n<form class=\"review\">\n  <label for=\"reviewer\">Your name</label>\n  <input id=\"reviewer\" name=\"reviewer\" dir=\"auto\">\n  <label for=\"review-text\">Your review</label>\n  <textarea id=\"review-text\" name=\"review\" dir=\"auto\"></textarea>\n</form>","css":".card { border: 1px solid #c9c4dc; border-inline-start: 4px solid #5b3cc4; border-radius: 8px; padding: 8px 12px; margin-block-end: 12px; text-align: start; }\n.card h3 { margin: 0 0 4px; }\n.card p { margin: 0 0 4px; }\n.badge { color: #5b3cc4; margin-inline-end: 8px; }\n.note { color: #595959; font-size: 0.9rem; }\n.review { display: grid; gap: 4px; max-width: 320px; }\ninput, textarea { font: inherit; padding: 6px 8px; border: 1px solid #77708f; border-radius: 6px; }\n","js":""},"checks":[{"id":"arabic-lang","test":"const arabicEls = () => { const out = new Set(); const w = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT); let n; while ((n = w.nextNode())) { if (/[\\u0600-\\u06FF]/.test(n.textContent) && !n.parentElement.closest('script, style')) out.add(n.parentElement); } return [...out]; }; const els = arabicEls(); return els.length >= 2 && els.every((el) => { const l = el.closest('[lang]'); return l && /^ar\\b/i.test(l.getAttribute('lang')); });"},{"id":"arabic-dir","test":"const arabicEls = () => { const out = new Set(); const w = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT); let n; while ((n = w.nextNode())) { if (/[\\u0600-\\u06FF]/.test(n.textContent) && !n.parentElement.closest('script, style')) out.add(n.parentElement); } return [...out]; }; const els = arabicEls(); return els.length >= 2 && els.every((el) => getComputedStyle(el).direction === 'rtl' || el.matches(':dir(rtl)'));"},{"id":"english-stays","test":"const note = $('#card-ar .note'); const l = note.closest('[lang]'); const en = !l || /^en\\b/i.test(l.getAttribute('lang')); return document.documentElement.lang === 'en' && en && getComputedStyle(note).direction === 'ltr' && getComputedStyle($('#card-en h3')).direction === 'ltr';"},{"id":"user-text-auto","test":"return $('#reviewer').getAttribute('dir') === 'auto' && $('#review-text').getAttribute('dir') === 'auto';"},{"id":"logical-css","test":"const en = getComputedStyle($('#card-en .badge')); const ar = getComputedStyle($('#card-ar .badge')); const enCard = getComputedStyle($('#card-en')); const arCard = getComputedStyle($('#card-ar h3').closest('.card')); return parseFloat(en.marginRight) > 0 && parseFloat(en.marginLeft) === 0 && parseFloat(ar.marginLeft) > 0 && parseFloat(ar.marginRight) === 0;"}],"title":"Make the Arabic event card speak and sit right","prompt":"<p>The page is English (<code dir=\"ltr\">&lt;html lang=&quot;en&quot;&gt;</code> is already set). The second card’s title and description are Arabic, and reviewers may type in either language. Fix it:</p>\n<ol>\n<li>Mark every piece of Arabic text with <code dir=\"ltr\">lang=&quot;ar&quot;</code> and right-to-left direction.</li>\n<li>Keep the English note in that card (<code dir=\"ltr\">.note</code>) English and left-to-right.</li>\n<li>Let the reviewer name and review fields pick their direction from what is typed.</li>\n<li>Replace the physical CSS so the badge’s gap sits after the icon in both directions (on the right in English, on the left in Arabic).</li>\n</ol>\n","hints":["Wrap the Arabic h3 and p in one element with lang=“ar” dir=“rtl”, leaving .note outside it.","dir=“auto” on the input and the textarea handles user-generated text.","margin-right becomes margin-inline-end. While you are there, border-left can become border-inline-start and text-align: left can become start."],"explanation":"<p><code dir=\"ltr\">lang=&quot;ar&quot;</code> makes screen readers switch to an Arabic voice for the title and description (3.1.2 Language of Parts), and <code dir=\"ltr\">dir=&quot;rtl&quot;</code> gives that block a right-to-left base direction, so text starts on the right and punctuation lands correctly. The English note stays outside the wrapper and keeps the page’s language and direction. <code dir=\"ltr\">dir=&quot;auto&quot;</code> lets each form field follow its first strong character. Finally, <code dir=\"ltr\">margin-inline-end</code> puts the badge’s gap after the icon in both directions, and the other logical properties mirror the accent border and alignment too, all from a single set of rules.</p>\n","checkLabels":{"arabic-lang":"All Arabic text is inside an element with lang=“ar”","arabic-dir":"All Arabic text is laid out right to left","english-stays":"The page and the English note stay English and left-to-right","user-text-auto":"The name and review fields use dir=“auto”","logical-css":"The badge gap follows the icon in both English and Arabic cards"}},"words":816,"readMinutes":4}