RA.
All projects
2026Live

KADI HSE Consultancy

Client work · Design & Engineering

A bilingual English and Arabic site for KADI HSE Consultancy in Muscat. A buyer arrives from a tender shortlist or a WhatsApp link with about ten seconds to decide, so every section on the page earns its place or goes. Client work, live and still moving.

Lighthouse desktop performance, EN / AR
100 / 99Lighthouse desktop performance, EN / AR
Layout shift, every Lighthouse run
0Layout shift, every Lighthouse run
Unit tests
141Unit tests
Contrast assertions
75Contrast assertions
Languages
2Languages
Build window
15 daysBuild window
  1. 01 / 07

    Ten seconds

    The brief set the whole design. A buyer lands here from a LinkedIn post, a WhatsApp link or a tender shortlist, and inside about ten seconds has to trust the company, understand the work, and be one tap from the founder. Everything on the page serves one of those three. Anything serving none of them does not belong.

    The rule explains the absences more than the features. No content system, no blog, no carousel of testimonials. The rule also picks out which reader the engineering answers to. Of the three the site expects, one is an owner with an inspection coming, reading Arabic on a phone on a poor connection. The Arabic side is built as hard as the English because of them.

  2. 02 / 07

    The font was never downloading

    The font stack led with the Latin face for both languages, on the reasonable-sounding grounds of a browser resolving fallbacks one glyph at a time. Browsers do. The problem was the face they resolved through first.

    The metric-adjusted fallback sits on Arial, and Arial carries a complete Arabic. So every Arabic letter found a home before the stack ever reached Thmanyah, and the licensed typeface the client pays for was never requested at all. The Arabic site had been shipping in Arial while looking approximately right, which is the worst kind of bug: nothing is broken on screen and the thing you bought is simply absent.

    The Arabic stack now leads with Thmanyah and is scoped to the Arabic document, so the single Arabic character on the language toggle never drags the face onto the English page. Anything holding the Latin voice is marked as English in the markup.

  3. 03 / 07

    The contrast suite disproved the review

    Colour was being checked by eye and against a token table, which is how a dark-theme form border shipped at 2.90 to 1 and a footer outline at 2.60. The suite caught both, and settled something larger: the brand's own leaf green is 2.85 to 1 on white and will never carry text, whatever a brand guide says.

    So the palette split in two. One green draws shapes, a darker one at 5.33 to 1 carries words, and the single green panel on the site sets its text in deep navy, because white on the green is the same 2.85 an instinct for "green panel, white text" walks straight into.

    The suite then found its own blind spot. Raw token pairs were being asserted, which is not what a reader sees, and a note at 65% opacity over a white button slipped a violation through the gap. Pairs now flatten their opacity and are asserted as the rendered colour, and the file reads the tokens out of the stylesheet itself, so editing a hex moves the assertion too.

    Contrast assertions
    75
    Brand green on white
    2.85:1
  4. 04 / 07

    A fixed sleep hid four failures

    Four accessibility tests failed on and off on the iPad and phone projects for weeks, and twice the evidence was destroyed by the hunt itself, because the test runner clears its results directory at the start of every run. When artefacts finally survived on a real CI machine, the message read: reveals never reached full opacity, for every element below the fold.

    The audit walked the page in steps of 80% of a viewport and slept 120 milliseconds between them. Under load, 120 milliseconds is less than one rendered frame. An element might enter and leave the viewport between two observer checks, and because reveals fire once, the element stayed invisible for good. Failure came only on the slowest engine on the busiest machine, which is why the whole thing read as flakiness instead of a bug.

    The walk now waits for rendering instead of for time: two animation frames, then a zero-delay task, then half-viewport steps, and anything still hidden is scrolled to on its own. The record keeps the first fix too, which was wrong: polling one kind of element left six CSS animations completely uncovered.

  5. 05 / 07

    A gate that measured the runner

    Mobile Lighthouse assertions kept failing in CI. On code differing only in a test file, total blocking time read 250 milliseconds, then 318, then 362, then 845 across consecutive runs. The same page on an idle machine reads 10 to 30. The runner is a shared two-core machine, also hosting the server being measured, and its timings swung by nearly three times between back-to-back runs of identical code.

    So the signal moved instead of disappearing. The three processor-bound mobile checks became warnings, still measured and still reported. Desktop stays a hard gate. The structural mobile checks stay hard too, layout shift among them, because none of those depends on how many cores the machine has. A gate unable to tell a slower codebase from a busier neighbour is worse than no gate at all.

  6. 06 / 07

    Arabic written, not translated

    The English is the company's own profile text. The Arabic is written natively in professional MSA, which is why the two sides read as two originals, not as a document and its translation. The client, a native speaker, signed the Arabic off line by line and sent three rounds of corrections, one of them about punctuation. There has been no separate editorial pass.

    Three corrections sit outside the utility layer so they outrank the utilities. Letter-spacing is forced to zero, because Arabic letters join and tracking pulls the joins apart into loose shapes. Capitalisation is disabled, because Arabic has no case. And the leading opens up while the display size steps down one notch, because a tight line height, assured in the Latin face, makes consecutive Arabic lines collide.

    The cost is named, not hidden. The Arabic page scores 87 to 88 on mobile against 92 to 94 for the English, and the gap is the licensed face on the path to first paint. Three alternatives were measured and each was worse. Loading the face for both languages taxes English readers for nothing, skipping the preload measured four seconds, and letting the browser drop the face renders an Arabic reader's first visit in a system font, which fails the brand and not the metric.

  7. 07 / 07

    Thirty-eight pixels of movement

    A client copy change lengthened the Arabic headline, and the line wrapped differently in the fallback face than in the real one. The swap moved the page 38 pixels, a layout shift of 0.0136, on a site whose whole claim is never moving. At exactly 390 pixels wide the buttons wrapped too, because the font was deciding where the line broke.

    The fix was a fallback face measured against the real one, weight by weight, so the two occupy the same space before and after the swap, and moving the buttons' breakpoint off the width where the font was making the decision. Zero movement across sixteen combinations of width and language, tested with the web fonts blocked and again with them loaded.

    Shift before
    0.0136
    Shift after
    0