{
 "site": "Büro (Bürocratik), Portugal",
 "slug": "burocratik",
 "urls": [
  "https://www.burocratik.com/",
  "https://www.burocratik.com/work",
  "https://www.burocratik.com/studios",
  "https://www.burocratik.com/recognition"
 ],
 "stack": {
  "framework": "Nuxt 2 static generation (Vue 2.7.16, vue-router 3.6.5, vue-meta 2.4.0, webpack 4); build id 1791840994 = 2026-10-12 21:36 UTC",
  "cms": "Sanity (cdn.sanity.io images, burocratik.sanity.studio in CSP frame-ancestors, ?preview plugin)",
  "animation": [
   "GSAP 3.12.2",
   "ScrollTrigger",
   "CustomEase (nine Material 3 m3.* easings)",
   "own SplitText Vue component (no GSAP SplitText)",
   "MotionPathPlugin",
   "Rive @rive-app/canvas 2.21.6",
   "Pizzicato.js (UI sound)"
  ],
  "scroll": "Lenis 1.0.42 on window, duration 1, wheelMultiplier 1.1; native unstyled page scrollbar, hidden only in the menu sheet (.no-scrollbar); data-lenis-prevent on the sheet",
  "three_d": "three.js r171 lazy chunk on /work (webglContainer + Words.worker), /recognition (full-viewport dot field, Points.worker) and /studios (Lines.worker); not on the homepage, whose hero is video",
  "fonts": [
   "Commercial Gräphik Web (Commercial Type Graphik, self-hosted variable woff2, upright and italic)"
  ],
  "evidence": [
   "the 25 vue-meta head tags (of 45 in the served HTML) carry data-n-head=\"ssr\"; window.__NUXT__ in /_nuxt/static/1791840994/state.js",
   "34b7000.js: Rr.version=\"2.7.16\", ee.version=\"3.6.5\", vue-meta version:\"2.4.0\", core-js 3.38.0",
   "e6fc914.js: GSAP .version=\"3.12.2\"; window.lenisVersion=\"1.0.42\"; @rive-app/canvas 2.21.6 package.json; Pizzicato Sound/Group/Effects",
   "f4b42a5.js: registerPlugin(CustomEase) + create(\"m3.emphasized\",...); registerPlugin(MotionPathPlugin)",
   "89d5fef.js: three.js const r=\"171\", THREE.WebGLRenderer strings",
   "response headers: server: Vercel, x-vercel-cache: HIT, x-vercel-id pdx1",
   "scripts: cloud.umami.is/script.js (Umami), googletagmanager gtag G-52YF8HGWG2 (GA4), /signature.js (console 'Made by Büro' badge only)",
   "probe: globals only __NUXT__; 1 backdrop-filter element; 0 url() cursors; 437 cursor:none elements on home; no view-transition CSS",
   "verifier 2026-10-22, at runtime: Vue 2.7.16, VueRouter 3.6.5, core-js 3.38.0, lenisVersion 1.0.42, gsap 3.12.2; window.__THREE__ \"171\" on /work, /recognition and /studios, unset on /; GSAP modules with \"3.12.2\": core, ScrollTrigger + Observer, CustomEase, MotionPathPlugin (no SplitText); the Rive module (@rive-app/canvas 2.21.6) also holds the uniform vec4 mat WebGL program"
  ]
 },
 "components": [
  {
   "name": "Persistent bottom bar with the menu sheet behind the plus",
   "owner_words": "you could hit the plus to expand it as a standard menu",
   "selectors": [
    "nav._navbar",
    "._navbar .navbar-background.blurred-background",
    "._navbar .persistent-bar",
    "._navbar .bot-container ._bot",
    "._bot .msg .active .m-t",
    "._bot .msg .aux .m-t",
    "._navbar .active-page ._root-page-name",
    "._navbar .open-close-button",
    "._open-close-icon",
    "._navbar .menu",
    "._navbar .menu-content",
    "._navbar .menu-pages ._navbar-page-link",
    "._page[data-blurred=true] > .page-content"
   ],
   "mechanism": "Fixed 46 px pill (10 of 24 grid columns, 575.5 px at 1440; 342.5 px on a 390 phone), radius 20, rgba(0,0,0,.85) over backdrop-filter blur(18px). The line is the top of a message stack ($bot): set({icon,message}) returns a remover; hover, intersection (rootMargin -70% 0% -25% 0%), window blur/focus and footer presets push messages; at rest it reads 'We are Büro'. Text swaps roll per word between .active and .aux layers inside overflow-hidden masks. The button's invisible span covers the whole bar, so any click opens the sheet and any hover says 'Open menu'. The sheet is the same skin growing in height out of the bar while the page behind recedes (scale 0.9755, opacity .667, rounded corners, inert, Lenis stopped). On load, the bar is lifted to the loader's greeting, the greeting docks into its message slot and both glide down to the bottom.",
   "libraries": [
    "GSAP 3.12.2",
    "CustomEase (m3 eases)",
    "Lenis 1.0.42"
   ],
   "states": [
    "rest: glyph + 'We are Büro' + page chip + plus",
    "hover anywhere on bar: '↑ Open menu', tilting-hand cursor",
    "section messages via intersection (e.g. 'That's Bach, btw!')",
    "footer preset message",
    "window-blur messages ('Take your time', ...)",
    "sheet opening",
    "sheet open (plus becomes minus)",
    "sheet closing",
    "bar as video controls (source only)",
    "phone: no chip, no hover messages"
   ],
   "timings": "Message swap: out 0.3 s power2.in (icon down, words up, stagger 0.03), in 0.5-0.6 s power2.out (stagger 0.1) after 0.2-0.23 s. Sheet open: skin height 0.65 s m3.emphasized; content opacity 0.23 s power3.in; page recede 0.6 s m3.standard after 0.05 s; dividers 2 s expo stagger 0.1 from 0.1 s; labels 0.6 s power3 stagger 0.05 from 0.3 s. Close: 0.52 s power3.inOut; message and chip back at 0.3 s (chip bg 1 s expo.out, label 0.55 s power3 after 0.225 s). Plus icon: rotate 90° 0.35 s cubic-bezier(.645,.045,.355,1) after 0.05 s. Load glide 0.65 s expo.out.",
   "shots": [
    "shots/bar-01-rest-eyes-over-hero.png",
    "shots/bar-02-pointer-on-bar.png",
    "shots/bar-03-hover-plus.png",
    "shots/bar-04-scrolled.png",
    "shots/bar-05-window-blur-message.png",
    "shots/bar-bot-roll-slowmo-strip.png",
    "shots/menu-01-open.png",
    "shots/menu-02-hover-work.png",
    "shots/menu-03-hover-child-branding.png",
    "shots/menu-04-closed.png",
    "shots/menu-open-slowmo-sheet.png",
    "shots/phone-01-bar-rest.png",
    "shots/phone-02-menu-open.png",
    "shots/phone-bar-rest-vs-long-message.png"
   ],
   "rebuild": "One fixed element sized from the grid: skin layer (dark 85% + backdrop blur 18 px, radius 20) and a row with mark, message slot, chip, plus. A say({icon,text}) -> undo stack wired to pointer hover, an IntersectionObserver band above the bar, window blur and page end. Roll words with two stacked span layers in overflow-hidden masks (GSAP, Motion or WAAPI with stagger). The sheet grows from the bar (height or clip-path) with content sliding up and labels staggered; recede the stage instead of blurring it. For ETS27 keep the plus and the ask field as separate hit areas, add aria-live to the message, focus styles and a reduced-motion path.",
   "confidence": "high"
  },
  {
   "name": "Newsletter in two sentences",
   "owner_words": "I want to copy it exactly",
   "selectors": [
    "footer._footer form._newsletter",
    ".submit-container > p.p-small",
    "._newsletter-email-field input[type=email]",
    "._newsletter-button[data-hidden]",
    "._form-checkbox-field.newsletter[data-hidden]"
   ],
   "mechanism": "Line 1 is a <p>, line 2 is the email input itself styled as text (no border, padding or outline, Graphik 17.575 px, line-height 1.2, letter-spacing -0.04em) with the sentence as placeholder in black at 50% opacity. Typing one character removes data-hidden from the Send button (with an underline) and the absolutely positioned consent line (fades 0.2 s). Strings are hard-coded in the component. Submit (source only, never triggered): console.log of the values and, after 2 s, the lines swap to 'I already have you mail' / 'Gotchaaa' for 4 s; no network request and the action prop is never called. Not present in the menu sheet.",
   "libraries": [
    "Vue 2 component",
    "GSAP (Send underline motion)"
   ],
   "states": [
    "before: two lines",
    "focus: no visible change",
    "typed: Send + consent visible",
    "error: red #dc3429 placeholder",
    "loading: inert, fields at 0.3 and Send at 0.4 opacity, underline loop (source)",
    "sent: 'I already have you mail' / 'Gotchaaa' for 4 s (source)",
    "phone: Send stacks under the address"
   ],
   "timings": "Consent opacity 0.2 s cubic-bezier(.215,.61,.355,1); Send appears without transition; Send hover underline out 0.6 s power3.in then clone in 0.8 s power3.out after 0.5 s (source, not seen in burst).",
   "shots": [
    "shots/nl-01-before.png",
    "shots/nl-02-focus.png",
    "shots/nl-03-typed.png",
    "shots/nl-states-crops.png",
    "shots/nl-send-hover-strip.png",
    "shots/phone-nl-01-before.png",
    "shots/phone-nl-02-typed.png"
   ],
   "rebuild": "Plain form: <p> plus <input type=email placeholder=...> styled with font: inherit, border 0, padding 0, transparent background, ::placeholder currentColor at .5 opacity; reveal Send and consent with input:placeholder-shown ~ sibling rules (no JS); add aria-label and a focus-visible cue Büro lacks; post to Zpryme's list for real.",
   "confidence": "high"
  },
  {
   "name": "Reactive custom cursor",
   "owner_words": "I like the custom cursors when you hover over certain things. Reactive custom cursors",
   "selectors": [
    "div._pointer[data-cursor]",
    "._pointer > [data-cursor=pointershift] svg",
    "._pointer > [data-cursor=eyes] svg .pupils",
    "._manifesto .accolades > a",
    "nav._navbar"
   ],
   "mechanism": "One fixed 48 x 48 px element (z 9999, pointer-events none, shown only on hover:hover and pointer:fine) moved every animation frame with translate3d from a rAF-throttled mousemove, no lag. It holds all states as inline SVGs; a stack set by the v-pointer directive (mouseenter push, mouseleave pop, click forwarded) names the visible one through data-cursor. Opted-in elements set cursor:none. States: pointer, pointershift (tilts with motion: rotateX 4dy, rotateY 4dx, rotateZ 5dx, dx and dy the movement since the previous frame clamped to ±5 px, settles after 100 ms), grab, eyes (pupils shift against the motion, blinks 1-4 s after the last move), tornado (motion-path spin on click), viewcase (trailing label). body:active swaps to the pressed drawing. The hand is a white glove with a 2.5 px black stroke plus a 20% stroke.",
   "libraries": [
    "GSAP 3.12.2 (quickTo, MotionPathPlugin)"
   ],
   "states": [
    "none (system cursor)",
    "pointer",
    "pointershift over the bar and the ranking cards",
    "grab over sliders",
    "eyes over the hero video",
    "tornado",
    "viewcase",
    "pressed (body:active)"
   ],
   "timings": "Position: every frame, no easing. Tilt 0.25 s power2.out, settle 0.5 s power4.out after 100 ms still. Pupils quickTo 0.25 s power2; blink scaleY .1 for 0.1 s each way, 1-4 s after the last mouse move (one wait in ten is 0-12.5 s). Tornado 0.4 s power2.out. Viewcase label 0.2 s power2.out; hand/inner scale transitions 0.3 s, inner delayed 0.15 s.",
   "shots": [
    "shots/cursor-01-hand-over-card.png",
    "shots/cursor-04-pressed-on-bar.png",
    "shots/cursor-hand-eyes-pressed-crops.png",
    "shots/bar-01-rest-eyes-over-hero.png",
    "shots/menu-02-hover-work.png"
   ],
   "rebuild": "Draw the states in the site's hand as inline SVGs in one fixed pointer-events:none element with planned hot spots; mark targets with data-cursor and give exactly those cursor:none; delegate pointerover/pointerout to a stack; move with translate3d per frame; small reactions from velocity (tilt, pupils, blink) with GSAP quickTo or Motion; gate on (hover:hover) and (pointer:fine) and prefers-reduced-motion.",
   "confidence": "high"
  }
 ],
 "transitions": [
  {
   "name": "Load: loader greeting docks into the bar",
   "from": "black loader ('Hello', then 'We are Büro')",
   "to": "page with the bar at the bottom",
   "layers": [
    "greeting text ('Hello' 0.6 s in, 0.4 s out, then 'We are Büro'; about 2.3 s before the handoff starts: 1.8 s of greeting motion, a 0.3 s pause and the handoff's 0.2 s delay; longer while assets load)",
    "navbar (lifted to the greeting's height, then glides down 0.65 s expo.out)",
    "greeting slides onto the bar's message slot (about 0.7 s expo.inOut)",
    "black curtain drops (y 101%, 0.95 s expo.inOut)",
    "page content fades and rises on inner pages (1.2 s expo.out)"
   ],
   "duration_ms": 1400,
   "shots": [
    "shots/intro-home-slowmo-sheet.png",
    "shots/intro-recognition-realtime-sheet.png"
   ]
  },
  {
   "name": "Bar message swap",
   "from": "'We are Büro'",
   "to": "'Open menu' or a section message",
   "layers": [
    "icon (down out, down in)",
    "word spans (up out, up in, staggered)"
   ],
   "duration_ms": 930,
   "shots": [
    "shots/bar-bot-roll-slowmo-sheet.png",
    "shots/bar-bot-roll-slowmo-strip.png"
   ]
  },
  {
   "name": "Menu sheet open",
   "from": "bar at rest",
   "to": "sheet open over a receded page",
   "layers": [
    "message and chip fade",
    "skin height grows from the bar",
    "menu content slides up",
    "page recedes (scale, opacity, corners)",
    "dividers draw",
    "labels rise"
   ],
   "duration_ms": 650,
   "shots": [
    "shots/menu-open-slowmo-sheet.png",
    "shots/menu-open-realtime-sheet.png",
    "shots/phone-menu-open-realtime-sheet.png"
   ]
  },
  {
   "name": "Menu sheet close",
   "from": "sheet open",
   "to": "bar at rest",
   "layers": [
    "content down and out",
    "skin shrinks into the bar",
    "page returns",
    "message and chip roll back"
   ],
   "duration_ms": 520,
   "shots": [
    "shots/menu-close-realtime-sheet.png",
    "shots/menu-close-run2-sheet.png"
   ]
  },
  {
   "name": "Page to page from the menu",
   "from": "/ (homepage)",
   "to": "/recognition or /studios",
   "layers": [
    "sheet closes into the bar",
    "old page pinned behind a black body",
    "new page slides up from the bottom",
    "chip rolls to the new name",
    "headings reveal line by line",
    "bar takes the new page's message"
   ],
   "duration_ms": 1000,
   "shots": [
    "shots/nav-to-recognition-slowmo-sheet.png",
    "shots/nav-to-recognition-slowmo-frames-01-04.png",
    "shots/nav-to-studios-realtime-sheet.png"
   ]
  }
 ],
 "not_confirmed": [
  "Old page during a page change: source defines a desktop 'fancy' leave (scale 0, rotate -20, 1.25 s power3.in) but 6% speed frames show the old page unchanged under the incoming page",
  "Send underline hover replay: in source, not visible in a 10-frame burst",
  "Newsletter submit: never submitted by rule; source shows console.log and a fake 'Gotchaaa' swap with no network request",
  "Exact Nuxt 2.x release (Vue 2.7.16 suggests 2.17)",
  "Bar morphing into video controls on Play: source only, not captured",
  "Reduced-motion behaviour: no rule found, not tested with emulation",
  "Page scrollbar appearance in a real browser: captures hide scrollbars by flag"
 ]
}