[{"data":1,"prerenderedAt":719},["ShallowReactive",2],{"docs-navigation-flat":3,"\u002Fdocs\u002Finternals\u002Fextension":71,"\u002Fdocs\u002Finternals\u002Fextension-surround":714},[4,17,53],{"title":5,"path":6,"stem":7,"children":8,"icon":11},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started\u002F1.index",[9,12],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Quick start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002F1.getting-started\u002F2.quick-start","i-lucide-zap",{"title":18,"path":19,"stem":20,"children":21,"page":52},"Product","\u002Fdocs\u002Fproduct","docs\u002F2.product",[22,27,32,37,42,47],{"title":23,"path":24,"stem":25,"icon":26},"Workspaces","\u002Fdocs\u002Fproduct\u002Fworkspaces","docs\u002F2.product\u002F1.workspaces","i-lucide-users",{"title":28,"path":29,"stem":30,"icon":31},"Searches and stages","\u002Fdocs\u002Fproduct\u002Fsearches-and-stages","docs\u002F2.product\u002F2.searches-and-stages","i-lucide-git-branch",{"title":33,"path":34,"stem":35,"icon":36},"LinkedIn extension","\u002Fdocs\u002Fproduct\u002Flinkedin-extension","docs\u002F2.product\u002F3.linkedin-extension","i-lucide-panel-right",{"title":38,"path":39,"stem":40,"icon":41},"Dashboard","\u002Fdocs\u002Fproduct\u002Fdashboard","docs\u002F2.product\u002F4.dashboard","i-lucide-layout-dashboard",{"title":43,"path":44,"stem":45,"icon":46},"Billing","\u002Fdocs\u002Fproduct\u002Fbilling","docs\u002F2.product\u002F5.billing","i-lucide-credit-card",{"title":48,"path":49,"stem":50,"icon":51},"Boolean search","\u002Fdocs\u002Fproduct\u002Fboolean-search","docs\u002F2.product\u002F6.boolean-search","i-lucide-binary",false,{"title":54,"path":55,"stem":56,"children":57,"page":52},"Internals","\u002Fdocs\u002Finternals","docs\u002F3.internals",[58,63,68],{"title":59,"path":60,"stem":61,"icon":62},"App map","\u002Fdocs\u002Finternals\u002Fapp-map","docs\u002F3.internals\u002F1.app-map","i-lucide-map",{"title":64,"path":65,"stem":66,"icon":67},"Extension","\u002Fdocs\u002Finternals\u002Fextension","docs\u002F3.internals\u002F2.extension","i-lucide-puzzle",{"title":48,"path":69,"stem":70,"icon":51},"\u002Fdocs\u002Finternals\u002Fboolean-search","docs\u002F3.internals\u002F3.boolean-search",{"id":72,"title":64,"body":73,"description":707,"extension":708,"links":709,"meta":710,"navigation":711,"path":65,"seo":712,"stem":66,"__hash__":713},"docs\u002Fdocs\u002F3.internals\u002F2.extension.md",{"type":74,"value":75,"toc":688},"minimark",[76,85,90,114,117,142,152,156,215,219,225,230,304,330,334,417,424,427,454,461,465,472,489,493,565,575,579,603,639,643,667,671],[77,78,81],"callout",{"color":79,"icon":80},"warning","i-lucide-construction",[82,83,84],"p",{},"Living notes for builders. LinkedIn\u002FGoogle DOM details require ongoing spikes.",[86,87,89],"h2",{"id":88},"location","Location",[82,91,92,93,97,98,105,106,109,110,113],{},"The extension lives in ",[94,95,96],"code",{},"apps\u002Fmodri-extension\u002F"," and is built with ",[99,100,104],"a",{"href":101,"rel":102},"https:\u002F\u002Fwxt.dev\u002F",[103],"nofollow","WXT"," plus Vue 3 and Nuxt UI (",[94,107,108],{},"@nuxt\u002Fui\u002Fvite",", ",[94,111,112],{},"colorMode: false"," — theme is toggled manually).",[82,115,116],{},"Useful root scripts:",[118,119,120,127,136],"ul",{},[121,122,123,126],"li",{},[94,124,125],{},"pnpm extension:dev"," — local extension development",[121,128,129,132,133],{},[94,130,131],{},"pnpm extension:build"," — production build → ",[94,134,135],{},"apps\u002Fmodri-extension\u002Fdist\u002Fchrome-mv3",[121,137,138,141],{},[94,139,140],{},"pnpm extension:zip"," — zip for distribution",[82,143,144,145,147,148,151],{},"Load unpacked from ",[94,146,135],{}," (or the WXT ",[94,149,150],{},".output\u002F…"," path if your local scripts still point there).",[86,153,155],{"id":154},"relationship-to-the-web-app","Relationship to the web app",[118,157,158,172,175,178,181,197],{},[121,159,160,161,164,165,168,169],{},"Web app lives in ",[94,162,163],{},"apps\u002Fmodri"," (",[94,166,167],{},"@sourcing\u002Fmodri","); extension in ",[94,170,171],{},"apps\u002Fmodri-extension",[121,173,174],{},"One repository builds the website, dashboard, and extension",[121,176,177],{},"Supabase is the source of truth; the extension uses the same workspace + RLS model",[121,179,180],{},"Do not assume a shared UI package: Nuxt and WXT have different runtime and style-isolation constraints",[121,182,183,184,188,189,192,193,196],{},"Shared ",[185,186,187],"strong",{},"pure"," TypeScript lives under ",[94,190,191],{},"shared\u002F"," (URL + Boolean); shared Vue pieces under ",[94,194,195],{},"ui\u002F"," where needed",[121,198,199,200,203,204,164,207,210,211,214],{},"Both apps read the ",[185,201,202],{},"repo-root"," ",[94,205,206],{},".env",[94,208,209],{},"NUXT_*"," \u002F ",[94,212,213],{},"WXT_*",")",[86,216,218],{"id":217},"product-surface","Product surface",[82,220,221,222,224],{},"See ",[99,223,33],{"href":34}," for user-facing behavior.",[226,227,229],"h3",{"id":228},"entrypoints","Entrypoints",[231,232,233,246],"table",{},[234,235,236],"thead",{},[237,238,239,243],"tr",{},[240,241,242],"th",{},"Entrypoint",[240,244,245],{},"Role",[247,248,249,263,277,290],"tbody",{},[237,250,251,257],{},[252,253,254],"td",{},[94,255,256],{},"entrypoints\u002Fpopup\u002F",[252,258,259,260],{},"Sign-in, workspace glance; follows OS ",[94,261,262],{},"prefers-color-scheme",[237,264,265,270],{},[252,266,267],{},[94,268,269],{},"entrypoints\u002Fbackground.ts",[252,271,272,273,276],{},"Service worker — local ",[94,274,275],{},"chrome.history"," visit lookups for SERP badges",[237,278,279,284],{},[252,280,281],{},[94,282,283],{},"entrypoints\u002Flinkedin.content\u002F",[252,285,286,287],{},"Floating note + ProfileModal on ",[94,288,289],{},"\u002Fin\u002F{slug}",[237,291,292,297],{},[252,293,294],{},[94,295,296],{},"entrypoints\u002Fgoogle.content\u002F",[252,298,299,300,303],{},"FAB + right SERP overlay of ",[94,301,302],{},"\u002Fin\u002F"," results + local visit badges on organic hits",[82,305,306,307,164,310,313,314,317,318,321,322,325,326,329],{},"Both content scripts use WXT ",[94,308,309],{},"createShadowRootUi",[94,311,312],{},"cssInjectionMode: 'ui'","), anchored on ",[94,315,316],{},"html",", with ",[94,319,320],{},"pointer-events: none"," on ",[94,323,324],{},":host"," and ",[94,327,328],{},"pointer-events-auto"," on interactive UI.",[226,331,333],{"id":332},"auth-handoff","Auth handoff",[118,335,336,354,377,394,401],{},[121,337,338,339,164,342,345,346,349,350,353],{},"Signed-out LinkedIn\u002FGoogle panels and the popup show the shared ",[94,340,341],{},"AuthForm",[94,343,344],{},"UAuthForm",") — email sign-in\u002Fsign-up ",[185,347,348],{},"and"," Continue with Google — so the session lands in ",[94,351,352],{},"chrome.storage"," without leaving the page.",[121,355,356,357,360,361,364,365,368,369,372,373,376],{},"Google uses ",[94,358,359],{},"chrome.identity.launchWebAuthFlow"," in the background service worker, then ",[94,362,363],{},"supabase.auth.signInWithIdToken"," (requires ",[94,366,367],{},"identity"," + ",[94,370,371],{},"oauth2.client_id"," from ",[94,374,375],{},"WXT_GOOGLE_OAUTH_CLIENT_ID","). Register that Chrome Extension client ID in Supabase → Auth → Google → Client IDs.",[121,378,379,380,203,382,385,386,389,390,393],{},"Auth API errors (wrong password, etc.) render inline via the ",[94,381,344],{},[94,383,384],{},"#validation"," slot (",[94,387,388],{},"UAlert","), not only as toasts — content-script toasters also use ",[94,391,392],{},"portal: false"," so they stay in the shadow root.",[121,395,396,397,400],{},"Forgot password opens ",[94,398,399],{},"{WXT_SITE_URL}\u002Fforgot-password"," in a new tab.",[121,402,403,404,164,407,109,410,109,413,416],{},"Helpers: ",[94,405,406],{},"utils\u002FsiteUrl.ts",[94,408,409],{},"getSignupUrl",[94,411,412],{},"getLoginUrl",[94,414,415],{},"getForgotPasswordUrl",").",[226,418,420,421,214],{"id":419},"shared-contact-layer-appsmodri-extensioncontact","Shared contact layer (",[94,422,423],{},"apps\u002Fmodri-extension\u002Fcontact\u002F",[82,425,426],{},"Used by LinkedIn and Google UIs:",[118,428,429,438,448],{},[121,430,431,210,434,437],{},[94,432,433],{},"contactApi.ts",[94,435,436],{},"contactTypes.ts"," — load\u002Fcreate\u002Fupdate contacts, activity, statuses\u002Fpositions",[121,439,440,443,444,447],{},[94,441,442],{},"ProfileModal.vue"," — centered modal (notes, comments, activity); ",[94,445,446],{},":portal=\"false\""," so it stays in the shadow root",[121,449,450,453],{},[94,451,452],{},"useExtensionWorkspace.ts"," — workspace gate \u002F entitlement",[82,455,456,457,460],{},"Contacts are ",[185,458,459],{},"not"," upserted merely by opening the modal. The first write (status, position, note, or comment) creates the contact.",[226,462,464],{"id":463},"linkedin-url-identity","LinkedIn URL identity",[82,466,467,468,471],{},"Canonical identity for matching is the profile slug, normalized via ",[94,469,470],{},"shared\u002Fcontact\u002FlinkedinUrl.ts",":",[118,473,474,480,486],{},[121,475,476,477,214],{},"Unwrap Google redirect URLs (",[94,478,479],{},"\u002Furl?q=…",[121,481,482,483],{},"Accept country LinkedIn hosts → always ",[94,484,485],{},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002F{slug}",[121,487,488],{},"Used by Google SERP scraping and LinkedIn profile flows so the same person matches across surfaces",[226,490,492],{"id":491},"google-serp-panel","Google SERP panel",[118,494,495,504,517,520,527,530,549],{},[121,496,497,498,109,501,214],{},"Matches Google Search URLs (",[94,499,500],{},"*.google.com\u002Fsearch*",[94,502,503],{},"www.google.pl\u002Fsearch*",[121,505,506,368,509,512,513,516],{},[94,507,508],{},"scrapeGoogleSerp.ts",[94,510,511],{},"useGoogleSerp.ts"," — MutationObserver, de-dupe by canonical URL, ",[185,514,515],{},"current page only"," (no background pagination, no HTML upload, no LinkedIn Search scraping)",[121,518,519],{},"Rows show workspace status + position; avatar\u002Fname open ProfileModal; external link opens LinkedIn",[121,521,522,523,526],{},"Panel open state persists in ",[94,524,525],{},"sessionStorage"," across SERP pagination within the tab",[121,528,529],{},"FAB is draggable; the sidebar stays docked on the right",[121,531,532,164,535,368,538,541,542,544,545,548],{},[185,533,534],{},"Local visit badges",[94,536,537],{},"scrapeOrganicResults.ts",[94,539,540],{},"useVisitMarkers.ts","): lime chips next to organic result titles with last-visit time from ",[94,543,275],{}," only — never sent to Supabase. Requires the ",[94,546,547],{},"history"," permission; hover shows the exact timestamp.",[121,550,551,164,554,557,558,560,561,564],{},[185,552,553],{},"Inline LinkedIn controls",[94,555,556],{},"useSerpInlineLayouts.ts","): status + position selects and an Open profile button rendered under each ",[94,559,302],{}," card in the extension shadow UI (",[94,562,563],{},"position: fixed",") so Google SERP CSS cannot flip them.",[82,566,567,568,571,572,574],{},"Typical loop with product Boolean: build an X-ray string in ",[99,569,570],{"href":49},"\u002Fapp\u002Fboolean"," → paste into Google → use the overlay to triage ",[94,573,302],{}," hits.",[226,576,578],{"id":577},"host-color-mode","Host color mode",[82,580,581,582,585,586,210,589,592,593,595,596,321,599,602],{},"Nuxt UI dark tokens are class-based (",[94,583,584],{},".dark { --ui-* }","). ",[94,587,588],{},"UApp",[94,590,591],{},"ConfigProvider"," does ",[185,594,459],{}," render a DOM node, so ",[94,597,598],{},":class",[94,600,601],{},"\u003CUApp>"," is a no-op.",[118,604,605,615,636],{},[121,606,607,608,611,612],{},"Content scripts: ",[94,609,610],{},"useHostColorMode()"," + a real wrapper ",[94,613,614],{},"\u003Cdiv :class=\"{ dark: isDark }\">",[121,616,617,618,109,621,210,624,109,627,109,630,633,634],{},"Detection: LinkedIn ",[94,619,620],{},"theme--dark",[94,622,623],{},"data-color-scheme",[94,625,626],{},"data-theme",[94,628,629],{},"meta[name=color-scheme]",[94,631,632],{},"color-scheme",", background luminance, then ",[94,635,262],{},[121,637,638],{},"Popup: OS preference only",[86,640,642],{"id":641},"manifest-permissions","Manifest \u002F permissions",[82,644,645,646,649,650,109,653,109,655,657,658,661,662,372,664,666],{},"Configured in ",[94,647,648],{},"apps\u002Fmodri-extension\u002Fwxt.config.ts",": ",[94,651,652],{},"storage",[94,654,547],{},[94,656,367],{},", host permissions for LinkedIn, Google Search, Supabase, and Google accounts. Keep the surface narrow — no ",[94,659,660],{},"\u003Call_urls>",", no cookie\u002Fnetwork interception. Google OAuth needs ",[94,663,371],{},[94,665,375],{},".",[86,668,670],{"id":669},"related","Related",[118,672,673,678,682],{},[121,674,675],{},[99,676,677],{"href":69},"Boolean search (internals)",[121,679,680],{},[99,681,59],{"href":60},[121,683,684,685],{},"Repo technical notes: ",[94,686,687],{},"docs\u002Ftechnical\u002Farchitecture.md",{"title":689,"searchDepth":690,"depth":691,"links":692},"",1,2,[693,694,695,705,706],{"id":88,"depth":691,"text":89},{"id":154,"depth":691,"text":155},{"id":217,"depth":691,"text":218,"children":696},[697,699,700,702,703,704],{"id":228,"depth":698,"text":229},3,{"id":332,"depth":698,"text":333},{"id":419,"depth":698,"text":701},"Shared contact layer (apps\u002Fmodri-extension\u002Fcontact\u002F)",{"id":463,"depth":698,"text":464},{"id":491,"depth":698,"text":492},{"id":577,"depth":698,"text":578},{"id":641,"depth":691,"text":642},{"id":669,"depth":691,"text":670},"WXT Chrome extension — LinkedIn profile panel, Google SERP overlay, shared contact layer.","md",null,{},{"icon":67},{"title":64,"description":707},"PWTrvs93fXxhD0C36GsjqnkP89u32PSre60PtMu9bCw",[715,717],{"title":59,"path":60,"stem":61,"description":716,"icon":62,"children":-1},"Routes, layouts, shared modules, and Content collections in the Nuxt app.",{"title":48,"path":69,"stem":70,"description":718,"icon":51,"children":-1},"Generator, public vs workspace history, and how X-ray ties to the Google extension.",1786987724538]