2026-10-21 · read https://floema.com/en (home, desktop and phone) and https://floema.com/en/about (reached through the nav); the home HTML, its three linked stylesheets, the 16 preloaded JS chunks, four prefetched chunks and the home's image worker, each fetched once with a desktop User-Agent · serves inspiration row 16 (Floema's navigation), and through it the awake state of the bar in rows 6, 7 and 11.
In one paragraph. The "tissue" is drawn, not filtered. An SVG sits behind the four links with one rounded-rectangle path per pill and one path of metaball bridges between neighbours, and it is redrawn from the links' live boxes every time the row resizes. CSS does the moving: a hovered pill takes a 20 px margin each side, and an invisible 20 px halo around every pill makes that happen before the pointer touches it. The component is Büro's own (MetaRow, part of what their code calls "BuroCore"): Floema's site is made by Büro, the studio behind the bar of row 6 and the newsletter of row 15. This settles the open point in bar-stage-drawers.md ("Pills with tissue"), which guessed a blur-plus-contrast filter: there is no filter anywhere in the nav (the page's only filter-like property is a 2 px backdrop blur on the wishlist counter's background).
| Layer | What | Evidence |
|---|---|---|
| Framework | Nuxt 4.5.2 on Vue 3.5.42, server-rendered then hydrated (the brief said Nuxt 3; the bundle says 4) | header x-powered-by: Nuxt; versions:{get nuxt(){return "4.5.2"}} in /_nuxt/cgz0BpdW.js; "3.5.42" in /_nuxt/xJNWDYji.js; #__nuxt, a 1.48 MB inline __NUXT_DATA__, buildId 80e1cab8-9916-46f5-9e52-2a3b8880a36c |
| State, i18n | Pinia (a states store holds menuTheme); @nuxtjs/i18n 10.0.1, locales pt (default), en, es, fr |
payload key pinia; nuxtI18n version getter in the entry chunk B5Sj-0NH.js; inline window.__NUXT__.config |
| CMS | Sanity, project 535lnz3g, dataset production, API 2025-08-08, GROQ queries, portable text |
inline Nuxt config public.sanity; cdn.sanity.io preconnect and image URLs; chunk groq.CepGutwA.css; vue-portable-text component |
| Hosting, CDN | Vercel, edge-cached; images through Vercel image optimisation from the Sanity CDN | headers server: Vercel, x-vercel-cache: HIT, x-vercel-id: pdx1::iad1::…; image URLs /_vercel/image?url=https://cdn.sanity.io/…&w=…&q=100 |
| Animation | GSAP 3.13.0 with ScrollTrigger, SplitText and Observer, bundled as modules (no globals); CSS transitions for the nav itself | 3.13.0 and GreenSock in DKtYPyz8.js; SplitText in CHE2-zLL.js; probe: no animation globals |
| Scroll | Lenis 1.3.8 inside a Scroller component; ScrollTrigger pins and section triggers |
window.lenisVersion = "1.3.8" in Mqeh8a45.js |
| 3D | three.js r181 inside Büro's own OffscreenCanvas worker layer ("BüroGL"): the home's image tunnel (Images), product models (ModelView) and mouse-driven shadows (ShadowsPortal) each render in a module Worker |
__THREE__ = "181" in DVps963u.js and Images.worker-BIRhFE1x.js; errors prefixed "🍀 BüroGL" in DVps963u.js; new Worker(new URL("Images.worker-BIRhFE1x.js", …), {type: "module"}) in BLQV81Cv.js; probe: three canvases, none hands out a context (control transferred) |
| Vector animation | Rive, @rive-app/canvas 2.31.6, bundled for pictograms such as /rive/floema-picto-wishlist.riv (a default inside a generic button component); no Rive canvas was found on the home, and the nav's wishlist counter draws SVG icons |
the package.json string and the .riv path in Mqeh8a45.js; probe: no 2D canvas on the home |
| In-house code | Büro's "BuroCore" utilities, of which MetaRow is one | [BuroCore--utils] NaN in arguments. in Mqeh8a45.js; footer link "Made by Büro" to burocratik.com; PreLoader default title "Buro Preload"; the search reacts to "buro" or "burocratik" as an easter egg |
| Fonts | Zimula, one self-hosted variable TTF with a custom cnct axis beside wght (every text style sets "cnct" 1000); nav labels 12 px, weight 600, uppercase, letter-spacing -0.02em, line height 16.8 px |
@font-face{font-family:Zimula;src:url(./Zimula-Variable.Cb2n2uX-.ttf)} in entry.D9Lu-YTe.css; probe fonts: "Zimula" |
| Analytics, consent | Cookiebot (GTM implementation, consent mode), GTM GTM-TTGLTQDL with GA4 G-CSPJEQXC07, Plausible, Umami, Meta Pixel and Meta's CAPI parameter builder |
probe script list (sources/measurements.json, page_transition.probe_scripts); nuxt-scripts block in the inline config |
| Agent-readable | the home links a Markdown alternate of itself, <link rel="alternate" type="text/markdown" href="https://floema.com/en/home.md">, which suggests one per page (relevant to row 17) |
head of /en; the file itself was not fetched (section 7) |
| Absent | no view transitions, no CSS filter and no SVG filter (the page's one backdrop-filter is blur(2px) on the wishlist counter's .bg, collapsed while the wishlist is empty), no custom cursor; 19 scrollbar rules |
probe in sources/measurements.json (nav_states.probe, backdropFilterEls 1); the element named in shots/verify/meta.json (rest-checks); startViewTransition appears only in vue-router's RouterLink option code |
What it is, in pixels (1440 x 900 viewport). Four links, PRODUCTS 105.8, ABOUT 81.7, SUSTAINABILITY 134.2 and JOURNAL 97.7 px wide, all 36.8 px tall, touching (gap 0) in one 419.5 x 36.8 strip at y 24.6 whose right edge sits at x 1332.2. The white skin is not the links' background; it is an SVG behind them. Each pill is drawn as a rounded rectangle with radius 0.34 x height (12.51 px). At rest a one-pixel-wide bridge at each seam fills the middle 20.2 px of the height, so a notch 8.3 px deep stays at the top and the bottom of every seam: that is why the strip reads as one piece with soft waists rather than four buttons. Hovered, a pill gains a 20 px margin each side (JOURNAL, the last, only on its inner side; PRODUCTS, the first, on both sides, because the first-child rule never matches: the SVG is the row's first child), the strip grows 40 px to the left while its right edge stays put (20 px for JOURNAL; for PRODUCTS the extra 20 px is empty, so only one gap shows), and each opened 20 px gap is spanned by a bridge 22.1 px tall where it meets the pills and 13.0 px tall at its middle (35 % of the pill). Shots: shots/nav-states-sheet.png (rest, pointer at 120, 60, 20 and 10 px, each pill hovered).
DOM. The nav is rendered on the client only (it is absent from the server HTML). Trimmed from the dom step (full dump in sources/nav-dom.html):
<div class="g-col xxl-12 md-15 right navigation"> <!-- flex row, justify-content:flex-end, gap 16px -->
<div data-component="navigation" class="dark"> <!-- theme class: dark | light | fluor -->
<div class="menu-items">
<div class="meta-row-container" style="--gap: 0px;"> <!-- MetaRow, scope data-v-918604f1 -->
<svg viewBox="0 0 419.453125 36.796875" data-meta-row-shape>
<path data-meta-row-shape-bridges d=" M105.30 28.52 C105.56 28.11, 105.99 28.11, 106.26 28.52 L106.26 8.28 C… Z M187.02 … Z M321.22 … Z"/>
<path data-meta-row-rect="0" d="M0 12.51 A12.51 12.51 0 0 1 12.51 0 L93.32 0 A12.51 12.51 0 0 1 105.83 12.51 … Z"/>
<path data-meta-row-rect="1" d="…"/> <path data-meta-row-rect="2" d="…"/> <path data-meta-row-rect="3" d="…"/>
<defs>
<radialGradient id="metaGlow" cx="50%" cy="50%" r="50%">
<stop offset="20%" stop-color="#e9e77847"/><stop offset="100%" stop-color="#e9e77800"/>
</radialGradient>
<clipPath id="metaClip" clipPathUnits="userSpaceOnUse"><!-- copies of the bridges and rect paths --></clipPath>
</defs>
<g clip-path="url(#metaClip)">
<ellipse id="glow" cx="0" cy="0" rx="0" ry="0" fill="url(#metaGlow)" style="mix-blend-mode: difference;"/>
</g>
</svg>
<a href="/en/products" class="button link" data-component="hyperlink" aria-label="Products page link" data-meta-row-node="0">
<span class="-body-smaller-semibold">Products</span></a>
<!-- About (node 1), Sustainability (node 2), Journal (node 3) -->
</div>
</div>
</div>
<!-- then .bookmark-wrap (wishlist counter: two SVG icons, collapsed to width 0 while empty) and [data-component=language-selector] -->
</div>
Selectors: [data-component="menu"] (fixed bar, z-index 10), [data-component="navigation"], .meta-row-container, svg[data-meta-row-shape], [data-meta-row-shape-bridges], [data-meta-row-rect="n"], #glow, a.button.link[data-meta-row-node].
Styles that matter (computed values from the css and eval steps; rules in sources/navigation.css.txt):
.meta-row-container: display:flex; gap:var(--gap) = 0px; width:auto; position:relative; overflow:visible; filter none, backdrop-filter none, transform none.svg[data-meta-row-shape]: position:absolute; top:0; right:0; width:100%; height:100%; z-index:1; pointer-events:none; overflow:visible; fill:var(--btn-background-color,#fff), computed rgb(255, 255, 255); paths transition: fill 1s cubic-bezier(.19,1,.22,1); the fluor theme fills #e9e778.a.button.link: z-index:2; position:relative; display:flex; padding:10px 20px; border-radius:12px (unused visually: the background is transparent); uppercase; transition: margin .3s cubic-bezier(.19,1,.22,1); filter, backdrop-filter and transform all none.::before: empty, 145.8 x 76.8 px (100 % + 40 px), top and left -20 px: the invisible hit halo.::after: 4 x 4 px dot, #241f21, radius 30 px, bottom 5 px, opacity 0; opacity 1 on the current page's pill.:hover: margin:0 20px, transition: margin .5s cubic-bezier(.175,.885,.32,1.275). The CSS also has :hover:first-child{margin:0 20px 0 0} and :hover:last-child{margin:0 0 0 20px}, but only the last-child rule can match: the SVG is the row's first child, so hovered PRODUCTS computes 0px 20px (g-hover-products in sources/measurements.json, row 459.5 px wide) and the row carries an empty 20 px at its left edge. The current-page first-child rule misses the same way..router-link-active): the same margins permanently plus the dot. A neighbour hovered next to it drops the margin on the shared side (.router-link-active + .button:hover{margin-left:0} and .button:hover:has(+ .router-link-active){margin-right:0}), so gaps never double.Behaviour, states, timings, easings.
:hover; thanks to the halo it fires when the pointer is within 20 px of a pill. It is a switch, not a gradient: at 120 px and 60 px below the strip nothing moves (nav-02-pointer-120px.png, nav-02-pointer-060px.png); at 19.6 px the nearest pill opens (nav-02-pointer-020px.png). The sense that the pills part "as the pointer approaches" is the halo plus the overshoot.getBoundingClientRect relative to the row and rewrites the paths whenever its ResizeObserver fires, and again on document.fonts.ready, on a gap change and on a locale change. The row is width:auto, so an animating margin resizes it every frame and the ResizeObserver redraws the skin frame by frame. No JavaScript animation loop drives the separation.sources/metarow.js.txt). Per pill, a rounded rectangle from arcs (M … A r r 0 0 1 …). Per pair of neighbours, the metaball connector from the Paper.js metaball example (the version popularised by Varun Vachhar's "Metaballs" article): circles of radius h/2 at the facing end caps; no bridge if the centre distance exceeds the detach distance (30) plus both radii; spread v = 0.3 + 0.1 x centre distance / (30 + r1 + 0.2 x r2), not clamped (about 0.37 for touching 36.8 px pills and 0.41 across a 20 px gap); handle factor 1; the left pill's attach points shifted 2.5 px right and the right pill's 2.6 px left, both toward the seam; the bridge is M p1 C h1, h3, p3 L p4 C h4, h2, p2 Z.sources/measurements.json, nav_motion). Hover in: about 500 ms. The strip overshoots by 3.4 px on its 40 px change (8.5 %) around 330 ms, then settles; that is the CSS back-out curve. Release: about 250 ms to within 0.1 px, front-loaded (expo out). Sliding along the strip moves the opening from pill to pill: the old gap closes on the 0.3 s curve while the new one opens on the 0.5 s one (nav-04-glide-end.png: JOURNAL open, the earlier gaps closed).difference, clipped to the same skin. On mouseenter it grows to 30 x 30 (GSAP, 1 s, expo.out); while the pointer moves it stretches to 60 x 30 and returns to 30 x 30 after 500 ms of stillness; on mouseleave it shrinks to 0. Its centre follows the pointer with a 0.12 lerp per frame. It shows as a faint warm smudge under the pointer (nav-crop-hover-about-2x.png).menuTheme; ScrollTriggers set it from each section's data-section-intersect as the section passes under the bar (dark, light, fluor). Scrolling into the home's photo sections flips it to light: the logo turns ivory, the pills stay white (home-08-scrolled-1400.png).router-link-active, keeps its gaps and shows the dot (page-06-about-landed.png). While navigating, .is-navigating turns the pills' pointer events off with a progress cursor.Assets. No images and no filters: one inline SVG per row (a bridges path, one path per pill, a radial gradient, a clip path, one ellipse). The fill comes from --btn-background-color.
Phone. At 1023 px and below the app mounts MenuMobile instead of Menu (app.vue: width > sm (1023) ? Menu : MenuMobile; breakpoints {xxs:410, xs:743, sm:1023, md:1290, lg:1440, xl:1700, xxl:2000}), so phones and portrait tablets up to 1023 px wide never see the pills (a 1024 px wide portrait tablet, such as a 12.9-inch iPad Pro, gets the desktop Menu). The phone header is the logo, EN and one rounded menu-and-search button (phone-10-top.png; no wishlist counter shows, since it collapses while the wishlist is empty). A tap swaps it for a dark close button (0.2 s) and fades in a full-screen sheet: a tree-shadow background, big links, the support links at the foot (sheet opacity 0.6 s; the search field rising 12 px over 0.45 s, then the links rising 18 px over 0.5 s, staggered 0.06 s; closing fades everything up in 0.15 s, then the sheet in 0.25 s). The skin survives on the phone in two places: the CTA buttons (six on the home, each an icon square and a label touching at rest with the seam drawn; they never separate there, since their hover rules sit inside @media (hover:hover); shots/verify/phone/verify-04-phone-cta.png) and the sheet's search field, a two-node MetaRow (input and search icon, 8 px gap) joined by a still neck (phone-search-pill-crop.png; its placeholder reads "Procurar" in Portuguese on the English page). There is no tap behaviour for the pills. Their :hover rules are not inside @media (hover:hover) (the CTA buttons' rules are), so on a touch screen wider than 1023 px a tap would leave a sticky separation (read from the CSS, not captured).
Accessibility and reduced motion. Real links with aria-labels ("About page link"); the halo also enlarges each hit area. Keyboard focus gets no separation and no visible ring: there is no :focus or :focus-visible rule in the nav CSS, and a Tab onto ABOUT leaves every margin at 0 with a computed outline-style of none (shots/verify/verify-02-keyboard-focus.png). The current page's pill carries aria-current="page". Nothing in the nav respects prefers-reduced-motion; the home's three reduced-motion rules cover the wishlist toast's timer (groq.CepGutwA.css) and two collections pieces, the CTA section's scroll label and the overview's media wrapper (pages.B377k9ir.css). The glow's requestAnimationFrame loop starts on the first mouseenter and is never cancelled.
How to rebuild it for ETS27 (library-agnostic).
width:auto, position:relative) holding the items with transparent backgrounds, and one SVG behind them (absolute, full size, pointer-events:none, overflow:visible, filled with the skin colour) holding one path per item and one bridges path.::before halo at inset -20px; :hover, :focus-visible { margin: 0 20px } (inner side only for the ends, picked with :first-of-type/:last-of-type or a class, since :first-child misses when the SVG comes first, as it does on Floema); in 0.5s cubic-bezier(.175,.885,.32,1.275), out 0.3s cubic-bezier(.19,1,.22,1). The current item keeps its margin and a dot.pointerdown, before the tap resolves (the owner's "perhaps tap too"); Floema offers no answer here.difference blend, centre lerped at 0.12; any tween library (GSAP, Motion) or a CSS transition on r.Libraries: none are needed. GSAP or Motion only if the glow is tweened; Paper.js only as the reference for the connector. The usual alternative, an SVG goo filter (blur plus contrast) over the group, softens text and edges and filters every frame; the drawn bridges stay crisp and recolour with one fill transition (that is how the skin turns flour yellow in the fluor theme). For the bar of rows 6, 7 and 11, the nodes would be the mark, the menu word, the contact word and the ask field, with "awake" meaning the gaps are open. The marker look of row 8 can keep the same geometry and change only the fill (an SVG pattern, or a displacement filter on the skin alone, never on the text).
Gotchas.
justify-content:flex-end; whatever sits left of it needs 40 px of room.elementFromPoint returns SUSTAINABILITY and SUSTAINABILITY opens; shots/verify/verify-01-halo-overlap.png).SpecialButton (scope data-v-15ef4614), the CTAs such as "See Urban Products" and "Work with us", is a two-node MetaRow: a 44 x 44 icon square and a 166.6 x 41.8 label pill, touching at rest. On hover, only on devices that can hover, the square takes a 16 px right margin on the same back-out curve (0.5 s) and its icon scales to 1.07 on cubic-bezier(.12,1.2,.16,2.35); the neck across the 16 px gap measures 15.0 px of 44 (shots/cta-tissue-sheet.png). On the phone the same pairing joins the search input and its icon with a fixed 8 px gap. For ETS27 this is the shape of the ask field and its send button.
This is not a grid and not DOM. It is a three.js scene in a module Worker (OffscreenCanvas through BüroGL), drawn on a canvas placed absolutely behind the intro header, which ScrollTrigger pins (pointer-events:none; z-index:-1; height:100vh). The rule, from Images.worker-BIRhFE1x.js (sources/home-tunnel.js.txt):
Perspective is what scatters them: near planes sit at the screen edges and are large, far ones gather toward the centre, small and faded (nav-01-rest.png, home-07-settled.png). The DOM timeline in Intro still targets .slider-image img, which matches nothing now that the images live in WebGL; that is most likely the source of the two "GSAP target not found" console warnings.
Frame times below are when each screenshot call returned (capture.cjs stamps after the shot), so a frame shows the page up to one screenshot duration earlier (about 0.1 to 0.5 s); read them as upper bounds.
home-opening-sheet.png; frames home-burst-opening-00 to 15, about every 0.4 s from DOMContentLoaded). At 0.05 s a blank ivory screen (#f2efea; most likely the PreLoader, which removes itself once the page loader resolves, though the frame was not traced to it; the server HTML already holds the title). By 0.6 s the nav and the title stand on an empty stage. By 1.6 s the image tunnel and the Cookiebot dialog are in, and the tunnel keeps drifting. From source: the title splits into lines (SplitText) that drop in from -100 % (0.8 s, circ.out, 0.1 s stagger), and ScrollTrigger pins the intro header while the next section scrolls over it.home-08-scrolled-1400.png, home-09-scrolled-4000.png). The collections section is 900vh tall and sticky; full-bleed photos replace one another under a numbered caption and a pill CTA. The bar's theme flips to light over them: the logo turns ivory, the pills stay white.nav-approach-sheet.png, nav-leave-sheet.png). Screenshots on fsit2 come about every 150 ms with the WebGL tunnel running, so the bursts catch the opening mid-flight but miss most of the 250 ms release; the rAF curves are the timing evidence.page-to-about-sheet.png, frames page-burst-to-about-00 to 13, page-loading-bar-sheet.png). Click ABOUT at 0 s. The click's hover opens ABOUT's gaps (half open, and no dot yet, in the frame stamped 0.51 s); by the frame stamped 0.78 s the route is active, the gaps stay open and the dot shows. A 7 px flour-yellow bar (#e9e778, the Loading component's progress bar) runs along the top edge and restarts more than once in this capture: 433 px at 0.78 s, 1355 at 1.09 s, then 613 (a restart while the first pass was still fading out), none at 1.58 s, 43, 354, 878 and 1332, then full width and fading at 2.52 s. The home holds still until about 1.6 s, then the whole old page ([data-component=page]) slides down by the viewport height, accelerating: in these frames the title is 31 px lower at 1.77 s, 203 px lower at 1.90 s (the page's top edge shows as a straight cut) and gone at 2.01 s. The verifier's per-frame record, from a run where it began later, has translateY 0 at 1.93 s, 41 px at 2.24 s, 192 px at 2.36 s and 900 px at 2.51 s; the old page is then squashed to zero height below the fold and removed by 3.2 s. The About hero (a stone F in moss) rises from the bottom between 2.5 and 3.4 s, the Floema wordmark goes from grey to black by 3.4 s, and the side copy and the "Work with us" card arrive by 4.3 s. From source: the Loading bar goes 0 to 0.6 in 1.2 s (power1.inOut), then to full in 0.6 s and fades in 0.4 s. A separate 12 px Curtain (0 to 0.7 in 0.8 s, power1.out, then full in 0.4 s circ.inOut and a 0.4 s fade) is told to finish 2.2 s after the fonts load on the first visit (app.vue); it was not identified in the page-change frames, and the verifier's per-frame record shows it at scaleX 0 throughout: both bar passes are Loading's.phone-menu-sheet.png, frames phone-burst-menu-open-00 to 07). The round button becomes a dark close button and the full-screen sheet fades in, complete by about 1.25 s after the tap in this capture; closing returns to the home in under 0.9 s (phone-12-menu-closed.png).| File | What it shows | Device |
|---|---|---|
shots/nav-01-rest.png |
Home at rest after declining cookies: four pills touching, image tunnel, title | desktop 1440 x 900 |
shots/nav-02-pointer-120px.png, nav-02-pointer-060px.png |
Pointer 120 and 60 px below the strip: no change | desktop |
shots/nav-02-pointer-020px.png, nav-02-pointer-010px.png |
Pointer 19.6 and 9.6 px below the strip: ABOUT open, two necks | desktop |
shots/nav-03-hover-1-products.png to nav-03-hover-4-journal.png |
Each pill hovered (one neck at the ends, two in the middle) | desktop |
shots/nav-states-sheet.png |
The nine states above, cropped to the nav at 2x | desktop |
shots/nav-crop-rest-2x.png, nav-crop-pointer-020px-2x.png, nav-crop-hover-about-2x.png |
Rest notches, the halo trigger, a hover with the glow, at 2x | desktop |
shots/nav-burst-approach-00.png to -11.png, nav-approach-sheet.png |
Burst after the pointer arrives from 320 px away, about every 150 ms, and its sheet (nav crops) | desktop |
shots/nav-burst-leave-00.png to -09.png, nav-leave-sheet.png |
Burst after the pointer leaves; already at rest by the first frame | desktop |
shots/nav-04-glide-end.png |
After sliding along the strip: JOURNAL open, the glow stretched | desktop |
shots/cta-13-rest.png, cta-14-hover.png, cta-tissue-sheet.png |
"See Urban Products" CTA at rest and hovered; sheet cropped at 3x | desktop |
shots/home-07-settled.png |
Home settled with the tunnel | desktop |
shots/home-08-scrolled-1400.png, home-09-scrolled-4000.png |
Collections section, theme flipped to light (ivory logo, white pills) | desktop |
shots/home-burst-opening-00.png to -15.png, home-opening-sheet.png |
Arrival from DOMContentLoaded, about every 0.4 s | desktop |
shots/page-05-home-before-click.png |
Home just before clicking ABOUT | desktop |
shots/page-burst-to-about-00.png to -13.png, page-to-about-sheet.png |
Home to About through the nav, 0.5 to 5.0 s after the click | desktop |
shots/page-loading-bar-sheet.png |
Top 70 px of eight transition frames: the yellow bar's passes, the active pill and its dot | desktop |
shots/page-06-about-landed.png |
About landed: ABOUT open with the dot, wordmark, stone hero | desktop |
shots/phone-10-top.png |
Phone home: logo, round menu-and-search button, tunnel | phone 390 x 844 at 2x |
shots/phone-burst-menu-open-00.png to -07.png, phone-menu-sheet.png |
Tap on the menu button to the open sheet | phone |
shots/phone-11-menu-open.png, phone-search-pill-crop.png |
Open sheet; the search field's two nodes joined by a neck | phone |
shots/phone-12-menu-closed.png |
Sheet closed, back on the home | phone |
Existing screenshots reused for comparison: ../../floema/desktop-top.png (rest with the Cookiebot dialog) and ../../floema/nav-hover-owner-crop.png (the owner's crop of the hover state).
/_nuxt/entry.D9Lu-YTe.css, /_nuxt/groq.CepGutwA.css, /_nuxt/Icon.d6YlQgwF.css, /_nuxt/Images.B-BZxPRM.css, /_nuxt/ShadowsPortal.CgH3YUsE.css, /_nuxt/ModelView.CI1QsZ_0.css; the verifier also read /_nuxt/pages.B377k9ir.css, which the home adds at runtime (collections styles, two of the reduced-motion rules)./_nuxt/B5Sj-0NH.js; the preloads cgz0BpdW, xJNWDYji, HclGiUj8, Mqeh8a45 (components, MetaRow, Navigation, Menu, Lenis, Rive), hePW80VL, DKtYPyz8 (GSAP), DQ4Nlvfy, BKSz1Hp1 (breakpoints), BDNMzG2s, B8Og-qgs, ClQxUScS, vRsMQoAQ, C-pVJMYT (home page, Intro), CHE2-zLL (SplitText), CNs_Ozdc; the prefetches BLQV81Cv (Images), Dkne19dx (ModelView), DVps963u (three.js and BüroGL), cbd89rtv (ShadowsPortal); the worker /_nuxt/Images.worker-BIRhFE1x.js.sources/metarow.js.txt, sources/navigation.js.txt, sources/navigation.css.txt, sources/home-tunnel.js.txt, sources/nav-dom.html; measurements, curves and probe results in sources/measurements.json. In navigation.css.txt the rules printed after a one-line @media …{ … } belong inside that block (the 2000 px vw overrides, and the CTA hover rules inside @media (hover:hover)).design/tools/capture-remote.sh: steps/nav-states.json, steps/nav-motion.json, steps/page-transition.json, steps/home-opening.json, steps/phone-menu.json, steps/cta-tissue.json; the verifier's steps/verify-checks.json (results in shots/verify/) and steps/verify-phone.json (results in shots/verify/phone/).design/inspiration/INSPIRATION.md (row 16), bar-stage-drawers.md, components-to-copy.md, teardowns/_examples/*.json, floema/desktop-top.png, floema/nav-hover-owner-crop.png.Loading's progress bar and the Curtain stays at scaleX 0 (the verifier's per-frame record, shots/verify/meta.json, rec-exit): the bar's in and out timelines ran twice in one navigation, the second start falling inside the first pass's fade. What emits them twice was not traced. Would establish: logging the loading-transitionIn and loading-transitionOut events.page.tap or touchscreen.tap).pointerover timestamps in the recorder..three-container inside its header component (two more such canvases sit in intro and team; verifier's run), so it is drawn in WebGL; whether the stone is a ModelView model or a textured plane, and what ShadowsPortal draws (probably the leaf shadows on the menu sheet and the About background), stay open. Would establish: a DOM dump of the header and a read of ModelView.worker-BfUAvEv4.js./en/home.md). Not fetched under this run's HTML, CSS and JS rule. Would establish: one GET of the file.aria-current="page" (verifier); how the halo and the moving targets read with assistive tech was not checked.2026-10-22 · verifier pass over README.md and component.json (teardown of 2026-10-21) · every stack, mechanism, timing and measurement claim was checked against the folder's evidence, the live site's HTML, CSS and JS (each file read once with a desktop User-Agent, then deleted), two fresh captures on fsit2 and pixel measurements of the agent's own frames.
Result. 70 claims checked: 59 held, 11 were wrong or imprecise and are corrected in place, and 8 points stay unconfirmed. The core finding stands: the "tissue" is drawn, not filtered (one SVG of rounded rects plus metaball bridges, rewritten by a ResizeObserver while CSS animates the hovered link's margins). The errors were in the details around it: the first pill's margins, the page exit, the reduced-motion inventory, the phone's use of the skin, two constants of the bridge maths, the filter inventory and the click's timing.
README.md, component.json, the six steps files, sources/nav-dom.html, the three JS excerpts, sources/navigation.css.txt and sources/measurements.json. The agent's raw meta.json files are not in the folder; measurements.json is a trimmed copy of them (it says so), and it holds no captured hover-neck path and no phone search geometry, so those two figures were re-derived here.https://floema.com/en with its headers; entry.D9Lu-YTe.css, groq.CepGutwA.css, pages.B377k9ir.css, Images.B-BZxPRM.css; the chunks B5Sj-0NH, cgz0BpdW, xJNWDYji, Mqeh8a45, DKtYPyz8, CHE2-zLL, DVps963u, BLQV81Cv, C-pVJMYT, Dkne19dx, cbd89rtv and Images.worker-BIRhFE1x. The buildId in the HTML (80e1cab8-9916-46f5-9e52-2a3b8880a36c) matched the agent's, so the chunk names were still current. No media, fonts or Markdown were fetched.design/tools/capture-remote.sh (headless on fsit2; no CAPTCHA or wall):steps/verify-checks.json (desktop, 17 s; results in shots/verify/): whether PRODUCTS matches :first-child, elementFromPoint at x 1075, 1090 and 1105 on the strip, the hover a pointer at x 1090 produces, a keyboard Tab onto the nav, the page's backdrop-filter inventory, a per-frame record of the home-to-About change (old page transform, Loading bar, Curtain), then aria-current and canvases on /en/about.steps/verify-phone.json (phone 390 x 844, 13 s; results in shots/verify/phone/): the CTA buttons' skin and the menu sheet's search row.Ga in sources/metarow.js.txt) was re-implemented; it reproduces the captured CTA hover path (start point within 0.01 px), and was then run on the nav's rest and hover geometry.nav-states-sheet, nav-crop-rest-2x, nav-crop-hover-about-2x, nav-approach-sheet, nav-leave-sheet, nav-04-glide-end, nav-01-rest, home-07-settled, home-08-scrolled-1400, home-09-scrolled-4000, home-opening-sheet, page-to-about-sheet, page-loading-bar-sheet, page-burst-to-about-00, page-burst-to-about-06, frames 04, 05, 07 and 08 of the same burst, the nav strip of page-05, page-burst-to-about-00 to 03 and page-06 (2x crops), cta-tissue-sheet, phone-10-top, phone-menu-sheet, phone-search-pill-crop, and the verifier's four new shots.Stack (19 of 21). Nuxt 4.5.2 (nuxt(){return4.5.2} in cgz0BpdW.js; header x-powered-by: Nuxt) on Vue 3.5.42 (xJNWDYji.js); server-rendered then hydrated, with the nav absent from the server HTML (no data-component="menu" or "navigation" in it); __NUXT_DATA__ of 1,485,065 characters (1.50 MB as bytes) and the buildId; Pinia (pinia and menuTheme in the payload, the states store in source); @nuxtjs/i18n 10.0.1 with pt as default and en, es, fr; Sanity 535lnz3g, production, API 2025-08-08, cdn.sanity.io preconnect, portable text; Vercel (server: Vercel, x-vercel-cache: HIT, x-vercel-id: pdx1::iad1::…, /_vercel/image?…&q=100); GSAP 3.13.0 with ScrollTrigger, Observer and SplitText, no globals; Lenis 1.3.8; three.js r181 in DVps963u.js and the image worker; BüroGL ("🍀 BüroGL", "Using OffScreenCanvas") with module Workers for Images, ModelView (ModelView.worker-BfUAvEv4.js) and ShadowsPortal (Shadows.worker-uSX2yEWE.js, driven by window mousemove); the three canvases that give no context; BuroCore, the "Made by Büro" link, the PreLoader's "Buro Preload" title and the "buro"/"burocratik" search easter egg; Zimula variable TTF with every explicit text style on "cnct" 1000 and nav labels at 12 px, 600, uppercase, -0.02em, 16.8 px; the consent and analytics set (Cookiebot GTM implementation with consent mode, GTM-TTGLTQDL, GA4 G-CSPJEQXC07, Plausible, Umami, Meta Pixel, CAPI parameter builder); the Markdown alternate link; no view transitions; no custom cursor and 19 scrollbar rules.
Navigation pills (21 of 29). The strip's geometry (pill widths 105.8, 81.7, 134.2, 97.7, height 36.8, gap 0, 419.5 px at y 24.6 ending at x 1332.2; the fresh run read the same rects); the SVG behind the links and the DOM and selectors; radius 0.34 x height; the rest seam (bridge 0.96 px wide, 20.23 px tall, notches 8.28 px; recomputed); the 40 px leftward growth with the right edge fixed; the hover neck (recomputed 22.05 px at the pills, 13.01 px mid-gap); every quoted CSS value (row, skin, pill, ::before halo 145.8 x 76.8 at -20 px, ::after dot, current-page and neighbour rules, .is-navigating); the halo as a switch (nothing at 119.6 and 59.6 px, ABOUT open at 19.6 px); the redraw triggers and the absence of a JS loop for the separation; the connector's structure (end-cap circles of h/2, detach 30 plus both radii, handle factor 1, M p1 C … L … C … Z); hover in about 500 ms with a 3.4 px (8.5 %) overshoot about 330 ms after motion starts; release within 0.1 px between about 160 and 245 ms after motion starts (the recorder rounds to 0.1 px, so "about 250 ms" is the upper end); the glide (old gap on the 0.3 s curve, new on the 0.5 s one); the glow (gradient stops, difference, clip, GSAP 1 s expo.out to 30 x 30, 60 x 30 while moving, back after 500 ms, 0 on leave, 0.12 lerp, a rAF loop never cancelled); the theme store and its ScrollTriggers (the collections section carries data-section-intersect="light"); the phone menu's timings (close button 0.2 s, sheet 0.6 s, search 12 px over 0.45 s, links 18 px over 0.5 s at 0.06 s stagger, close 0.15 s then 0.25 s); the phone search row (gap: 8px in source and 8 px measured, still neck, "Procurar" on a page with lang="en"); the nav's :hover rules outside @media (hover:hover) and the CTA's inside it (read in the original CSS, not the excerpt); aria-labels, no focus separation and no reduced motion in the nav; the halo overlap (now confirmed, see below); the unused 12 px border radius. "Flour yellow" is Floema's own token name (--color-flourYellow: #e9e778), not a slip for the fluor theme.
CTA skin (3 of 3). Two-node MetaRow, 44 x 44 icon square and 166.6 x 41.8 label touching at rest; on hover a 16 px margin on the back-out curve and the icon at 1.07, only under @media (hover:hover) (confirmed in the server HTML's inline style); the neck 15.0 px (recomputed 14.99).
Image tunnel (7 of 7). All from the worker source: 46 planes from the formula, golden-angle ring of radius 10 with 2-unit spacing, short side 1.5 to 2.0 keeping aspect, fog 0 to 78 in 0xF3EFEA, camera fov 45 at z 5, 300 to 10 units/s over 1.1 s plus up to 40 with scroll, recycling; the canvas CSS (.three-container{pointer-events:none;z-index:-1;height:100vh;position:absolute} in Images.B-BZxPRM.css); the empty .slider-image img targets as the likely source of the two GSAP warnings (both runs logged exactly two).
Flow (8 of 9). The arrival frames (blank at 55 ms, nav and title by 635 ms, tunnel and Cookiebot by 1569 ms); the title's SplitText entrance from source; the 900vh collections section (style="height:900vh;" in the server HTML, its wrapper sticky at 101vh) with photos replacing one another under numbered captions and the bar turning light; bursts on fsit2 about every 150 ms; the bar widths (re-measured from pixels: 433, 1355, 617 faded, none, 43, 354, 877, 1332, then full width fading); the About entrance (hero rising 2.5 to 3.4 s, wordmark grey to black by 3.4 s, side copy by 3.4 s and the card by 4.3 s); the Loading and Curtain timings from source; the phone sheet complete by the frame stamped 1.25 s and closed within 0.9 s.
Cross-references (1 of 1). The owner's quote, rows 6, 7, 11, 15 and 16 of INSPIRATION.md, and the "Pills with tissue" note in bar-stage-drawers.md.
Each is corrected in place in README.md and, where it appeared, in component.json.
backdrop-filter; the fresh run names it: blur(2px) on the .bg of button-wishlist-counter, which is collapsed while the wishlist is empty. Now: no filter anywhere in the nav; no CSS filter and no SVG filter on the page; one backdrop blur on the counter..riv path is a default inside a generic button component, and the probe found no 2D canvas on the home. Now: SVG icons, collapsed to width 0 while empty; Rive bundled, no Rive canvas found on the home.0 20px 0 0" and "inner side only for the first and last". The SVG is the row's first child, so :hover:first-child never matches: hovered PRODUCTS computes 0px 20px (g-hover-products; glide curve at 461 px; fresh run: productsIsFirstChild: false, firstChildTag: svg). Visually still one gap, but the row grows 40 px with an empty 20 px at its left. Only the last-child rule works. The rebuild advice now says to pick the ends with :first-of-type/:last-of-type or a class.v mapped from 0.3 when touching to 0.4 at the detach distance". The source maps centre distance 0 to 0.3 and 30 + r1 + 0.2 x r2 to 0.4, unclamped: about 0.37 for touching 36.8 px pills, 0.41 across a 20 px gap, 0.43 at the detach limit.[data-component=page] translateY 0.1 px at 1.93 s, 41 at 2.24, 192 at 2.36 and 900 at 2.51 s; the old page is then squashed to zero height below the fold (scaleY to 0 about its bottom edge, invisible) and removed by 3.16 s.width > 1023, so a 1024 px wide portrait tablet (such as a 12.9-inch iPad Pro) gets the desktop Menu. Now: phones and portrait tablets up to 1023 px.phone-10-top.png shows the logo, EN and a rounded rectangle with the menu and search icons; no counter shows (it collapses while the wishlist is empty, the same code as on desktop).shots/verify/phone/verify-04-phone-cta.png); they never separate there because their hover rules sit inside @media (hover:hover). Now: two places, the CTAs (still) and the search row (open neck).groq.CepGutwA.css), the collections CTA's scroll label (animation:none) and the collections overview's media wrapper (transition:none), both in pages.B377k9ir.css and the inline server styles. The nav itself still has none.Also changed, as clarifications rather than errors: section 4 now says burst times are upper bounds (see the notes below); the sources list adds pages.B377k9ir.css and the verifier's steps files and warns about the excerpt's media blocks; the accessibility paragraph adds two verified facts (no visible focus ring: computed outline-style none after a Tab onto ABOUT, shots/verify/verify-02-keyboard-focus.png; aria-current="page" on the current pill); the bar paragraph names Loading as the drawer of both passes; the "Not confirmed" list drops the halo overlap (confirmed: elementFromPoint(1090, 43) returns SUSTAINABILITY and a pointer there opens it, shots/verify/verify-01-halo-overlap.png), narrows the bar, About and screen-reader items, and adds the arrival's blank frame.
Loading bar's second run. Both passes are Loading's progress bar and the Curtain stays at scaleX 0 (shots/verify/meta.json, rec-exit: a full pass by 0.93 s, a restart at 0.97 s hidden by the first pass's fade, a second full pass from 1.53 s, faded by 2.53 s); the events behind the double run were not traced.capture.cjs has no tap step..three-container inside the header component (with two more in intro and team); whether the stone is a ModelView model or a textured plane, and what ShadowsPortal draws, stay open./en/home.md): outside the HTML, CSS and JS rule, not fetched.capture.cjs stamps each burst frame after its screenshot returns, so a frame shows the page up to one screenshot duration earlier (the first page-change frame took 507 ms). README section 4 now says so.getContext throws (control transferred to an OffscreenCanvas) and when every context type is refused; with the worker code, transfer is the reading, but the probe alone cannot tell them apart.sources/navigation.css.txt flattens media blocks. Rules printed after a one-line @media …{ … } belong inside it: the 2000 px vw overrides, and the CTA hover rules inside @media (hover:hover). Read alone, the excerpt suggests the CTA hover is unconditional; the original CSS confirms the README.tmp/ (the verifier's scratch: live files read once, helper scripts, comparison crops) deleted; no tmp/ left.VERIFY.md, the two steps files, and shots/verify/ (three PNGs and meta.json) with shots/verify/phone/ (one PNG and meta.json).phone-menu-sheet.png 1.7 MB, page-to-about-sheet.png 1.2 MB); the largest other file is shots/verify/meta.json at 47 KB.