1import{j as e,r as s,R as t}from"./react-vendor-BR2bEzcq.js";import{G as a}from"./GuideCallout-CfyKpKJQ.js";import{G as r}from"./GuideDemoFrame-DyxETMxm.js";import{a as i,d as n,h as l}from"./MobileDemo-LSYJxnfm.js";import{G as o}from"./GuideLayout-ngyQaTpG.js";import{L as d}from"./layout-grid-CZwZJ9I-.js";import{l as c,Q as m,G as g,U as h,w as x,m as p,Z as y,K as u}from"./index-We6CJOzg.js";import{D as b}from"./database-D5jEPgJK.js";import{C as f}from"./cpu-BIJO1NLL.js";import{M as v}from"./message-square-4YQyNQjT.js";import{B as j}from"./brain--xKcjCKQ.js";import{P as N}from"./palette-DFcpaOU8.js";import{U as w}from"./user-cog-BVpogBeF.js";import{W as k}from"./wrench-CNcYFiNJ.js";import{M as C}from"./mic-OaWmVihB.js";import{I as T}from"./image-TK_6Ysaq.js";import{L as S}from"./lock-CBrxUhMm.js";import{E as A}from"./eye-BcoJl0Iv.js";import{H as I}from"./hash-BdyiKRBq.js";import{R}from"./radio-OwJybX8D.js";import{L}from"./link-HN96Wkn-.js";import"./GuideStep-CLlbqK_X.js";import"./share-2-DEVRy_sG.js";import"./axios-DY9rj2-D.js";const M=c("power",[["path",{d:"M12 2v10",key:"mnfbl"}],["path",{d:"M18.4 6.6a9 9 0 1 1-12.77.04",key:"obofu9"}]]),P=c("volume-2",[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["path",{d:"M16 9a5 5 0 0 1 0 6",key:"1q6k2b"}],["path",{d:"M19.364 18.364a9 9 0 0 0 0-12.728",key:"ijwkga"}]]),B=[{id:"battlenet",title:"Battle.net",icon:m,status:"configured",priority:"high",description:"Character lookups, armory data, guild roster sync"},{id:"warcraftlogs",title:"Warcraft Logs",icon:g,status:"configured",priority:"high",description:"Combat log imports, parse tracking, fight analysis"},{id:"ai",title:"AI Configuration",icon:f,status:"configured",priority:"high",description:"LLM model, temperature, image generation, memory"},{id:"discord",title:"Discord Channels",icon:v,status:"configured",priority:"medium",description:"Channel routing, response channels, DM settings"},{id:"raiderio",title:"Raider.io",icon:g,status:"not_configured",priority:"medium",description:"M+ scores, dungeon runs, raid progression"},{id:"wowaudit",title:"wowaudit",icon:b,status:"not_configured",priority:"medium",description:"Raids, signups, attendance, wishlists, loot history, vault data"},{id:"branding",title:"Guild Branding",icon:N,status:"configured",priority:"medium",description:"Colors, sidebar theme, background gradients"},{id:"roster",title:"Roster Sync",icon:h,status:"configured",priority:"medium",description:"Auto-sync from Battle.net, activity scores"},{id:"voice",title:"Voice",icon:C,status:"not_configured",priority:"low",description:"Speech-to-text and text-to-speech providers"}],D={configured:{dot:"bg-green-400",label:"Configured",textColor:"text-green-400"},not_configured:{dot:"bg-yellow-400",label:"Needs Setup",textColor:"text-yellow-400"},error:{dot:"bg-red-400",label:"Error",textColor:"text-red-400"}},O=[{type:"Watched",icon:A,color:"text-blue-400",desc:"Bot reads messages and can respond when mentioned or contextually relevant"},{type:"Response",icon:v,color:"text-green-400",desc:"Bot sends its replies here instead of the channel where it was triggered"},{type:"Ignored",icon:I,color:"text-gray-500",desc:"Bot completely ignores all messages in these channels"},{type:"Admin",icon:m,color:"text-purple-400",desc:"Restricted channels for admin commands and system notifications"},{type:"Mention-Only",icon:R,color:"text-orange-400",desc:"Bot only responds when directly @mentioned, ignores all other messages"},{type:"Calendar",icon:d,color:"text-cyan-400",desc:"Dedicated channel for event embeds and calendar notifications"}],E=[{key:"lastSeen",label:"Last Seen",weight:50,desc:"Days since last game activity"},{key:"raiderioScore",label:"Raider.io Score",weight:20,desc:"M+ score and participation"},{key:"guildRank",label:"Guild Rank",weight:15,desc:"Position within guild hierarchy"},{key:"lootActivity",label:"Loot Activity",weight:10,desc:"Recent raid loot acquisitions"},{key:"wclParses",label:"WCL Parses",weight:5,desc:"Parse percentile bonus"}
1],W=[{label:"Team & Periods",status:"success",ago:"12m ago"},{label:"Characters",status:"success",ago:"12m ago"},{label:"Raids & Signups",status:"success",ago:"13m ago"},{label:"Wishlists",status:"success",ago:"14m ago"},{label:"Loot History",status:"running",ago:"in progressâ¦"},{label:"Vault / Historical",status:"idle",ago:"pending"}],G={success:{dot:"bg-green-400",text:"text-green-400"},running:{dot:"bg-blue-400 animate-pulse",text:"text-blue-400"},error:{dot:"bg-red-400",text:"text-red-400"},idle:{dot:"bg-gray-500",text:"text-gray-500"}},U=[{title:"Settings Dashboard",shortTitle:"Dashboard",icon:d,description:"The Settings page uses a responsive masonry grid where each integration or configuration area is a card you can click to expand. Cards are sorted by priority â critical integrations like Battle.net and AI appear first. Four category tabs at the top let you filter: External Services (API keys), Character & Roster (armory sync), Discord & AI (bot config, MCP tools, voice), and Guild Management (branding, members, roster). Not all users see all sections â visibility is gated by your guild permissions.",tip:'Every setting is scoped to your guild. If you manage multiple guilds, switch guilds in the sidebar to configure each one independently. After saving any section you will see a toast in the top-right (visible for several seconds), and credential-bearing sections (Battle.net, Warcraft Logs) also show a persistent inline "Configuration saved" banner under their Save button until you make another edit.',component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Settings Dashboard",mobileContent:e.jsx(i,{items:B.map(e=>({label:e.title,desc:e.description,badge:D[e.status].label,badgeColor:"configured"===e.status?"bg-green-900/40 text-green-400":"bg-yellow-900/40 text-yellow-400"}))}),children:e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3",children:B.map((s,t)=>{const a=s.icon,r=D[s.status];return e.jsxs(p.div,{initial:{opacity:0,y:12,scale:.95},animate:{opacity:1,y:0,scale:1},transition:{delay:.05*t,type:"spring",stiffness:300,damping:25},className:"rounded-xl border border-gray-700/50 bg-gray-800/40 p-4 hover:border-gray-600/60 transition-colors",children:[e.jsxs("div",{className:"flex items-start justify-between mb-2",children:[e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx(a,{className:"h-5 w-5 text-(--theme-primary-color,#6366f1)"}),e.jsx("h3",{className:"text-sm font-semibold text-gray-100",children:s.title})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("div",{className:`w-2 h-2 rounded-full ${r.dot}`}),e.jsx("span",{className:`text-[10px] font-medium ${r.textColor}`,children:r.label})]})]}),e.jsx("p",{className:"text-xs text-gray-500 leading-relaxed",children:s.description})]},s.id)})})}),e.jsx(a,{type:"info",children:"All settings are scoped to your guild. Each guild you manage has its own independent configuration, so changes here only affect the currently selected guild."})]})},{title:"Battle.net Integration",shortTitle:"Battle.net",icon:m,description:"Battle.net powers character lookups, item data, account linking, and guild roster sync. Loothing is zero-cost BYOK, so each guild admin creates a Blizzard developer client in the Battle.net portal and pastes the Client ID and Client Secret into the Battle.net settings card. The setup flow now shows the exact Blizzard app values to use, including the required Redirect URL, Service URL, Web Application client type, and a copyable checklist. After saving, Loothing stores the secret securely and can verify the saved credentials with a connection test.",tip:'Use a Blizzard Web Application client, copy the exact Redirect URL and Service URL from the card, then save before testing. The saved connection test authenticates with Blizzard using the credentials already stored on the server, so any secret change must be saved first. After a successful save you will see a persistent green "Configuration saved at HH:MM" banner under the Save button in addition to the toast notification â both confirm the credentials reached the server, and the Test Saved Connection button enables immediately without a page refresh.',component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Battle.net Configuration",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border border-sky-500/20 bg-sky-900/10 p-3",children:[e.jsx("div",{className:"text-sm font-medium text-sky-300",children:"Bring Your Own Blizzard App"}),e.jsx("p",{className:"mt-1 text-xs leading-relaxed text-gray-400",children:"Loothing is zero-cost BYOK. Guild admins create a Blizzard Web Application client in the Battle.net developer portal, then paste the Client ID and Client Secret into Loothing."})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsxs("div",{className:"rounded-lg border border-gray-700/40 bg-gray-800/40 p-3",children:[e.jsx("div",{className:"text-[10px] font-semibold uppercase tracking-wide text-gray-500",children:"Redirect URL"}),e.jsx("div",{className:"mt-1 rounded-sm bg-gray-900/40 px-2 py-1.5 text-[11px] text-sky-200 break-all",children:"https://loothing.xyz/auth/battlenet/callback"})]}),e.jsxs("div",{className:"rounded-lg border border-gray-700/40 bg-gray-800/40 p-3",children:[e.jsx("div",{className:"text-[10px] font-semibold uppercase tracking-wide text-gray-500",children:"Service URL"}),e.jsx("div",{className:"mt-1 rounded-sm bg-gray-900/40 px-2 py-1.5 text-[11px] text-sky-200 break-all",children:"https://loothing.xyz"})]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Client ID"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"a1b2c3d4e5f6..."})]}),e.jsxs("div",{children:[e.jsxs("label",{className:"block text-xs font-medium text-gray-400 mb-1.5 flex items-center justify-between",children:[e.jsx("span",{children:"Client Secret"}),e.jsxs("span",{className:"text-green-400 text-[10px] flex items-center gap-1",children:[e.jsx(S,{className:"h-3 w-3"})," Configured"]})]}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-green-600/40 text-sm text-gray-500",children:"â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢"})]})]}),e.jsxs("div",{className:"rounded-lg border border-gray-700/40 bg-gray-800/30 p-3",children:[e.jsx("div",{className:"text-xs font-semibold text-gray-300",children:"Blizzard client checklist"}),e.jsxs("div",{className:"mt-2 grid grid-cols-1 gap-2 text-xs text-gray-400 sm:grid-cols-2",children:[e.jsxs("div",{children:["Client type: ",e.jsx("span",{className:"text-gray-300",children:"Web Application"})]}),e.jsxs("div",{children:["Name: ",e.jsx("span",{className:"text-gray-300",children:"Loothing"})]}),e.jsxs("div",{className:"sm:col-span-2",children:["Use case: ",e.jsx("span",{className:"text-gray-300",children:"Fetch item, player, and guild data for raid loot tracking"})]}),e.jsxs("div",{className:"sm:col-span-2",children:["Flow: ",e.jsx("span",{className:"text-gray-300",children:"Save configuration first, then run the saved connection test"})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Region"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"EU"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Locale"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"English (GB)"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Guild Region"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"EU"})]})]}),e.jsxs("div",{className:"border-t border-gray-700/50 pt-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(h,{className:"h-4 w-4 text-(--theme-primary-color,#6366f1)"}),e.jsx("span",{className:"text-sm font-medium text-gray-200",children:"Guild Roster Sync"}),e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded-sm bg-green-900/30 text-green-400 border border-green-500/30",children:"Enabled"})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-2 text-xs",children:[e.jsxs("div",{className:"p-2 rounded-sm bg-gray-800/50 border border-gray-700/40 min-w-0",children:[e.jsx("div",{className:"text-gray-500",children:"Guild"}),e.jsx("div",{className:"text-gray-300 font-medium truncate",children:"Loot Goblins"})]}),e.jsxs("div",{className:"p-2 rounded-sm bg-gray-800/50 border border-gray-700/40 min-w-0",children:[e.jsx("div",{className:"text-gray-500",children:"Realm"}),e.jsx("div",{className:"text-gray-300 font-medium truncate",children:"Silvermoon"})]}),e.jsxs("div",{className:"p-2 rounded-sm bg-gray-800/50 border border-gray-700/40 min-w-0",children:[e.jsx("div",{className:"text-gray-500",children:"Guild Region"}),e.jsx("div",{className:"text-gray-300 font-medium",children:"EU"})]}),e.jsxs("div",{className:"p-2 rounded-sm bg-gray-800/50 border border-gray-700/40 min-w-0",children:[e.jsx("div",{className:"text-gray-500",children:"Auto Sync"}),e.jsx("div",{className:"text-gray-300 font-medium",children:"Every 24h"})]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("div",{className:"px-3 py-1.5 rounded-lg bg-(--theme-primary-color,#6366f1) text-white text-xs font-medium",children:"Save Configuration"}),e.jsx("div",{className:"px-3 py-1.5 rounded-lg bg-gray-600 text-white text-xs font-medium",children:"Test Saved Connection"})]})]})}),e.jsx(a,{type:"warning",children:'Battle.net secrets are encrypted before storage and never shown in the UI after saving. You will see "Configured" instead of the actual secret. Leave the secret blank when editing other settings to keep the stored value, and remember that c
1onnection tests use the saved server-side credentials.'})]})},{title:"Warcraft Logs Integration",shortTitle:"WarcraftLogs",icon:g,description:'WarcraftLogs enables combat log imports, parse history tracking, and fight analysis. It uses OAuth 2.0 V2 with PKCE for secure authentication â make sure you create a V2 client, not the legacy V1 key. Click "Open WCL Client Manager" in the setup card to go directly to warcraftlogs.com/api/clients/. Copy the exact Redirect URL from the right-hand card and paste it into the WCL client form. Enter your guild name, then pick your realm from the searchable dropdown. The dual token system uses client credentials for public data and user authorization for private logs.',tip:'Use the "Open WCL Client Manager" button â it takes you directly to the V2 client page, bypassing the confusing V1/V2 split on the WCL settings page. Copy the Redirect URL from the right card using the copy button and paste it into WCL exactly. After a successful save, a persistent green "Configuration saved at HH:MM" banner appears under the Save button â the Test OAuth Connection button enables immediately so you can verify credentials without reloading the page.',component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Warcraft Logs OAuth 2.0",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-blue-900/20 border border-blue-500/30",children:[e.jsx("div",{className:"w-3 h-3 rounded-full bg-green-400"}),e.jsx("span",{className:"text-sm font-medium text-blue-300",children:"OAuth 2.0 Connected"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Client ID"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"wcl-client-id..."})]}),e.jsxs("div",{children:[e.jsxs("label",{className:"block text-xs font-medium text-gray-400 mb-1.5 flex items-center justify-between",children:[e.jsx("span",{children:"Client Secret"}),e.jsxs("span",{className:"text-green-400 text-[10px] flex items-center gap-1",children:[e.jsx(S,{className:"h-3 w-3"})," Configured"]})]}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-green-600/40 text-sm text-gray-500",children:"â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢â¢"})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Guild Name"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"Loot Goblins"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Realm"}),e.jsxs("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300 flex items-center justify-between gap-2",children:[e.jsx("span",{children:"Stormrage"}),e.jsx("span",{className:"text-gray-500 text-[10px]",children:"â¾ search"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Region"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"EU"})]})]}),e.jsxs("div",{className:"p-3 rounded-lg bg-gray-800/40 border border-gray-700/40",children:[e.jsx("div",{className:"text-xs font-semibold text-gray-400 uppercase mb-2",children:"OAuth 2.0 Features"}),e.jsx("div",{className:"grid grid-cols-2 gap-1.5 text-xs text-gray-400",children:["PKCE security","Dual token system","Auto guild report fetch","Token auto-refresh","GraphQL API v2","Smart token selection"].map(s=>e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("div",{className:"w-1.5 h-1.5 rounded-full bg-blue-400/60"}),s]},s))})]})]})}),e.jsx(a,{type:"tip",children:"To get credentials: click âOpen WCL Client Managerâ in the V2 OAuth setup card â this takes you directly to the V2 client page at warcraftlogs.com/api/clients/. Create a V2 client (not the legacy V1 key under Web API), copy the Redirect URL from the right-hand card using the copy button, and paste it into the WCL client form. Then paste the Client ID and Client Secret here. Enter your guild name, then pick your realm from the searchable dropdown â start typing âmoonâ and âMoon Guardâ jumps to the top. The dropdown ships bundled with the app, so it works even before you've connected Battle.net. The server also normalizes whatever you save: âMoon Guardâ, âmoonguardâ, and âmoon-guardâ all resolve to the same WCL slug. If WCL can't find your guild after saving, the error message shows the exact slug sent so you can spot typos. WCL uses a dual token system: client credentials for public data, and user authorization for accessing private logs."})]})},{title:"Raider.io Integration",shortTitle:"Raider.io",icon:g,de
1scription:'Raider.io enriches character profiles with detailed Mythic+ scores, recent dungeon runs, and raid progression data. Unlike Battle.net and WarcraftLogs, Raider.io uses a simple API key â no OAuth flow, no callback URL required. The API key is optional â many Raider.io features work through their free public API without any key. Click "Open Raider.io Settings" next to the key field to go directly to raider.io/settings. Choose a preferred data source: Battle.net for official data, Raider.io for M+ insights, or Auto to combine both.',tip:'You can test the Raider.io connection even without an API key â the Test Connection button is no longer blocked by an empty key field. The "Auto" data source is recommended: it uses Battle.net as primary and enriches results with Raider.io data automatically. If you need an API key, click "Open Raider.io Settings", scroll to the API section, and click "Generate Key".',component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Raider.io Integration",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-yellow-900/20 border border-yellow-500/30",children:[e.jsx("div",{className:"w-3 h-3 rounded-full bg-yellow-400"}),e.jsx("span",{className:"text-sm font-medium text-yellow-300",children:"Optional \\u2014 Many features work without an API key"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-2",children:"Preferred Data Source"}),e.jsx("div",{className:"space-y-2",children:[{id:"battlenet",label:"Battle.net",desc:"100% coverage, official Blizzard API",active:!1},{id:"raiderio",label:"Raider.io",desc:"Enhanced M+ insights, detailed scores and recent runs",active:!1},{id:"auto",label:"Auto (Recommended)",desc:"Battle.net primary, enhanced with Raider.io when available",active:!0}].map(s=>e.jsxs("div",{className:"flex items-start gap-3 p-2.5 rounded-lg border "+(s.active?"border-blue-500/40 bg-blue-900/10":"border-gray-700/40 bg-gray-800/30"),children:[e.jsx("div",{className:"mt-0.5 w-4 h-4 rounded-full border-2 flex items-center justify-center "+(s.active?"border-blue-400":"border-gray-600"),children:s.active&&e.jsx("div",{className:"w-2 h-2 rounded-full bg-blue-400"})}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-gray-200",children:s.label}),e.jsx("div",{className:"text-xs text-gray-500",children:s.desc})]})]},s.id))})]})]})}),e.jsx(a,{type:"tip",children:"Raider.io uses a simple API key â no OAuth flow, no callback URL needed. Just log in at raider.io/settings, scroll to the API section, click âGenerate Keyâ, and paste it in. The âOpen Raider.io Settingsâ button next to the API key field takes you there directly. The Test Connection button works even without a key since many Raider.io public endpoints don't require authentication. The âAutoâ source uses Battle.net as primary and enriches results with Raider.io data when available â recommended for most guilds."})]})},{title:"wowaudit Integration",shortTitle:"wowaudit",icon:b,description:"wowaudit.com is a third-party raid management platform. Loothing reads from the wowaudit API to sync your team's characters, raids, signup data, attendance, Droptimizer wishlists, loot history, and vault / historical M+ data â all one-way into Loothing. No data is ever written back to wowaudit. Navigate to Settings â External Services â wowaudit, toggle Enabled, paste your API key, set your guild name, realm, and region, save, then click Test Connection. Once connected, each resource type has its own sync status so you can see exactly what was last updated.",tip:"Get your key at wowaudit.com: open your team page, go to Team Settings â API, and copy the bearer token. Each token is tied to one wowaudit team â multi-team guilds need separate tokens per Loothing guild.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"wowaudit Integration",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-teal-900/20 border border-teal-500/30",children:[e.jsx("div",{className:"w-3 h-3 rounded-full bg-green-400"}),e.jsx("span",{className:"text-sm font-medium text-teal-300",children:"Connected â Shadow Company · us-duskwood"})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsxs("div",{className:"sm:col-span-2",children:[e.jsxs("label",{className:"block text-xs font-medium text-gray-400 mb-1.5 flex items-center justify-between",children:[e.jsx("span",{children:"API Key (Bearer Token)"}),e.jsxs("span",{className:"text-green-400 text-[10px] flex items-center gap-1",children:[e.jsx(S,{className:"h-3 w-3"})," Configured"]})]}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-green-600/40 text-sm text-gray-500",children:"â¢".repeat(32)})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Guild Name"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"Shadow Company"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Realm"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"Duskwood"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Region"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"US"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-400 mb-1.5",children:"Auto Sync Interval"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-gray-700/60 border border-gray-600/50 text-sm text-gray-300",children:"Every 4h"})]})]}),e.jsxs("div",{className:"rounded-lg border border-gray-700/50 overflow-hidden",children:[e.jsx("div",{className:"px-3 py-2 bg-gray-800/60 text-[10px] font-semibold text-gray-400 uppercase tracking-wider",children:"Sync Status"}),e.jsx("div",{className:"divide-y divide-gray-700/30",children:W.map((s,t)=>{const a=G[s.status];return e.jsxs(p.div,{initial:{opacity:0,x:-6}
1,animate:{opacity:1,x:0},transition:{delay:.04*t},className:"flex items-center justify-between px-3 py-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:`w-2 h-2 rounded-full shrink-0 ${a.dot}`}),e.jsx("span",{className:"text-sm text-gray-200",children:s.label})]}),e.jsx("span",{className:`text-[10px] ${a.text}`,children:s.ago})]},s.label)})})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("div",{className:"px-3 py-1.5 rounded-lg bg-(--theme-primary-color,#6366f1) text-white text-xs font-medium",children:"Save Configuration"}),e.jsx("div",{className:"px-3 py-1.5 rounded-lg bg-gray-600 text-white text-xs font-medium",children:"Test Connection"}),e.jsx("div",{className:"px-3 py-1.5 rounded-lg bg-gray-600 text-white text-xs font-medium",children:"Sync Now"})]})]})}),e.jsx(a,{type:"tip",children:"To get your API key: log in to wowaudit.com, navigate to your team page, open Team Settings â API, and copy the bearer token shown there. Each token is bound to one team â if you manage multiple wowaudit teams you will need separate tokens for each guild in Loothing."})]})},{title:"AI Settings Card",shortTitle:"AI Settings",icon:f,description:"The AI settings card is where you enter your OpenRouter API key, choose a model, set temperature and token limits, configure image generation, and toggle the memory system. This is the configuration surface â for a deep dive into model selection, capability badges, variants, reasoning config, and how the memory intelligence system works, see the dedicated AI & Bot Intelligence guide.",tip:"Start here to set your OpenRouter API key and pick a model. Then visit the AI guide to understand what each model can do and how to tune it.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"AI Settings Overview",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"p-4 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(f,{className:"h-5 w-5 text-(--theme-primary-color,#6366f1)"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"AI Configuration Card"}),e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded-sm bg-green-900/30 text-green-400 border border-green-500/30",children:"Configured"})]}),e.jsx("p",{className:"text-xs text-gray-400 mb-3",children:"The AI settings card in the masonry grid controls your bot's core intelligence. Expanding it reveals sections for model selection, tuning, image generation, memory, and request-time tool filtering."}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:[{label:"LLM Model",desc:"Which AI model powers your bot (via OpenRouter)"},{label:"Temperature & Tokens",desc:"Creativity level and maximum response length"},{label:"Reasoning Effort",desc:"Low, Medium, High, or Max thinking budget for reasoning models"},{label:"Image Generation",desc:"Model, provider, and rate limits for AI images"},{label:"Memory System",desc:"Whether the bot remembers context between chats"},{label:"Smart Tool Filtering",desc:"Conservatively narrows tool definitions and falls back when requests are ambiguous"},{label:"Bot Personality",desc:"Custom system prompt and behavior instructions"},{label:"OpenRouter API Key",desc:"Your OpenRouter key (securely encrypted)"}].map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,x:-6},animate:{opacity:1,x:0},transition:{delay:.04*t},className:"p-2.5 rounded-lg bg-gray-800/50 border border-gray-700/40",children:[e.jsx("div",{className:"text-xs font-medium text-gray-200",children:s.label}),e.jsx("div",{className:"text-[10px] text-gray-500 mt-0.5",children:s.desc})]},s.label))})]}),e.jsxs("div",{className:"flex items-center gap-3 p-3 rounded-lg bg-purple-900/15 border border-purple-700/30",children:[e.jsx(j,{className:"h-5 w-5 text-purple-400 shrink-0"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-purple-300",children:"Detailed AI Guide Available"}),e.jsxs("div",{className:"text-xs text-gray-400 mt-0.5",children:["For deep dives into model selection, capability badges, model variants (:free, :nitro, :extended), reasoning config, the MCP tool system, and memory intelligence, see the dedicated ",e.jsx("strong",{className:"text-purple-300",children:"AI & Bot Intelligence"})," guide on the hub page."]})]})]})]})}),e.jsx(a,{type:"tip",children:"The AI settings card is where you set your OpenRouter API key and choose a model. For help picking the right model or understanding variants and capabilities, check the dedicated AI guide."})]})},{title:"Bot Channel Configuration",shortTitle:"Channels",icon:v,description:"Control where your bot listens, responds, and stays silent. There are six channel types: Watched (bot reads and may respond), Response (bot sends replies here), Ignored (completely silent), Admin (restr
1icted commands), Mention-Only (responds only to @mentions), and Calendar (event notifications). You can also configure DM restrictions including rate limiting and permission levels.",tip:"Set specific response channels to keep bot replies out of general chat. For example, watch #officer-chat but route responses to #bot-commands.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Channel Types",mobileContent:e.jsx(i,{items:O.map(({type:e,desc:s})=>({label:e,desc:s}))}),children:e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2.5",children:O.map(({type:s,icon:t,color:a,desc:r},i)=>e.jsxs(p.div,{initial:{opacity:0,x:-8},animate:{opacity:1,x:0},transition:{delay:.05*i},className:"flex items-start gap-3 p-3 rounded-lg bg-gray-800/40 border border-gray-700/40",children:[e.jsx(t,{className:`h-4.5 w-4.5 mt-0.5 shrink-0 ${a}`}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-gray-200",children:s}),e.jsx("div",{className:"text-xs text-gray-500 mt-0.5",children:r})]})]},s))})}),e.jsx(a,{type:"tip",children:"Set specific response channels to keep bot replies out of general chat. For example, route all bot responses to a #bot-commands channel while watching #officer-chat for context."})]})},{title:"Memory Settings",shortTitle:"Memory",icon:j,description:"These settings control the bot's temporal memory system: the master switch, retrieval limit, minimum relevance, minimum write importance, and lifecycle retention. Authorized admins can open Manage memories from this section to search and filter records, inspect supersession history, create or edit facts, pin protected records, and invalidate stale information.",tip:"Start with the defaults. Raise minimum relevance if retrieved context is too broad, raise write importance if trivial facts are being stored, and pin only records that should require explicit admin review.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Memory Settings",children:e.jsxs("div",{className:"p-4 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(j,{className:"h-5 w-5 text-purple-400"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"Memory v2 Controls"})]}),e.jsx("p",{className:"text-xs text-gray-400 mb-3",children:"These settings control memory retrieval, write quality, and lifecycle retention. The temporal ranking and reconciliation flow is covered in the AI guide."}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[{label:"Memory Enabled",value:"Yes",desc:"Master toggle for the memory system"},{label:"Retrieval Limit",value:"5",desc:"Maximum memories attached to a reply"}
1,{label:"Minimum Relevance",value:"0.6",desc:"Lowest accepted retrieval score"},{label:"Write Importance",value:"3",desc:"Minimum importance to store (1-10)"},{label:"Lifecycle Retention",value:"Enabled",desc:"Expire stale events and volatile facts"}].map(s=>e.jsxs("div",{className:"p-2.5 rounded-lg bg-gray-800/50 border border-gray-700/40",children:[e.jsx("div",{className:"text-xs text-gray-500",children:s.label}),e.jsx("div",{className:"text-sm font-medium text-gray-200 mt-0.5",children:s.value}),e.jsx("div",{className:"text-[10px] text-gray-600 mt-0.5",children:s.desc})]},s.label))})]})}),e.jsx(a,{type:"info",children:"Open Manage memories from Settings â Discord & AI â Memory System to filter records, inspect supersession chains, and create, edit, pin, or invalidate memories. Pinned memories are attached to every AI reply regardless of relevance, so pin only standing rules and policies â the bot can also pin and unpin on its own when it identifies a standing rule."})]})},{title:"Guild Branding",shortTitle:"Branding",icon:N,description:'Customize your guild\'s visual identity with primary and secondary colors, sidebar themes, and background gradients. The primary color sets the accent for buttons, links, active states, and highlights across the entire application. Choose from preset palettes or enter custom hex values. Sidebar and background presets let you theme the overall feel from "Glass" to "Deep Space".',tip:'Your branding also appears on public-facing forms when "Use Guild Branding" is enabled in form settings.',component:()=>{const[t,i]=s.useState("#6366F1");return e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Guild Branding",interactive:!0,children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-2",children:"Primary Color"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:[{name:"Blue",value:"#3B82F6"},{name:"Purple",value:"#8B5CF6"},{name:"Green",value:"#10B981"},{name:"Red",value:"#EF4444"},{name:"Yellow",value:"#F59E0B"},{name:"Pink",value:"#EC4899"},{name:"Indigo",value:"#6366F1"},{name:"Teal",value:"#14B8A6"}].map(s=>e.jsx("button",{type:"button",onClick:()=>i(s.value),className:"w-8 h-8 sm:w-10 sm:h-10 rounded-lg border-2 transition-all "+(t===s.value?"border-white ring-2 ring-white/20 scale-110":"border-gray-600 hover:border-gray-400"),style:{backgroundColor:s.value},title:s.name},s.name))})]}),e.jsxs("div",{className:"p-3 rounded-lg border border-gray-700/50 bg-gray-900/60",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx("div",{className:"w-8 h-8 rounded-lg",style:{backgroundColor:t}}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-bold text-gray-100",children:"Loot Goblins"}),e.jsx("div",{className:"text-[10px] text-gray-500",children:"Stormrage-US"})]})]}),e.jsxs("div",{className:"flex gap-2 mt-2",children:[e.jsx("div",{className:"px-3 py-1 rounded-sm text-xs font-medium text-white",style:{backgroundColor:t},children:"Primary Button"}),e.jsx("div",{className:"px-3 py-1 rounded-sm text-xs font-medium text-gray-300 bg-gray-700",children:"Secondary Button"})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-1.5",children:"Sidebar Preset"}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:["Default","Glass","Solid","Deep Blue","Purple"].map(s=>e.jsx("div",{className:"w-8 h-8 rounded-sm border border-gray-600 bg-gray-800/80",title:s},s))})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-1.5",children:"Backgroun
1d"}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:["Default","Midnight","Space","Royal","Forest"].map(s=>e.jsx("div",{className:"w-8 h-8 rounded-sm border border-gray-600 bg-linear-to-br from-gray-900 to-slate-900",title:s},s))})]})]})]})}),e.jsx(a,{type:"tip",children:"Your primary color sets the accent for buttons, links, and active states across the entire app. Click a preset above to preview how it looks."})]})}},{title:"Guild Roster Sync",shortTitle:"Roster Sync",icon:h,description:"Automatically synchronize your guild roster from Battle.net on a configurable schedule. Activity scores combine multiple signals â last seen, Raider.io score, guild rank, loot activity, and WCL parse performance â with adjustable weights. These scores help identify inactive members, prioritize active raiders for events, and inform roster decisions.",tip:'Adjust activity score weights to match your guild\'s priorities. If raid attendance matters most, increase "Last Seen". For a performance-focused guild, boost "WCL Parses".',component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Roster Sync & Activity Scores",mobileContent:e.jsxs("div",{className:"space-y-3",children:[e.jsx(n,{stats:[{label:"Auto Sync",value:"Enabled",color:"text-green-400"},{label:"Interval",value:"Every 24h"},{label:"Last Sync",value:"2h ago"},{label:"Members",value:"142"}]}),e.jsx(i,{items:E.map(e=>({label:e.label,desc:e.desc,trailing:`${e.weight}%`}))})]}),children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-2",children:[{label:"Auto Sync",value:"Enabled"},{label:"Interval",value:"Every 24h"},{label:"Last Sync",value:"2h ago"},{label:"Members",value:"142"}].map(s=>e.jsxs("div",{className:"p-2.5 rounded-lg bg-gray-800/50 border border-gray-700/40 text-center",children:[e.jsx("div",{className:"text-sm font-bold text-(--theme-primary-color,#6366f1)",children:s.value}),e.jsx("div",{className:"text-[10px] text-gray-500 uppercase mt-0.5",children:s.label})]},s.label))}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-2",children:"Activity Score Weights"}),e.jsx("div",{className:"space-y-2",children:E.map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,x:-8},animate:{opacity:1,x:0},transition:{delay:.04*t},className:"flex items-center gap-2 sm:gap-3",children:[e.jsx("div",{className:"w-24 sm:w-32 text-xs text-gray-400 truncate shrink-0",children:s.label}),e.jsx("div",{className:"flex-1 h-2 rounded-full bg-gray-700/50 overflow-hidden",children:e.jsx(p.div,{initial:{width:0},animate:{width:`${s.weight}%`},transition:{delay:.04*t+.2,duration:.4},className:"h-full rounded-full bg-(--theme-primary-color,#6366f1)"})}),e.jsxs("div",{className:"w-10 text-right text-xs font-medium text-gray-300",children:[s.weight,"%"]})]},s.key))}),e.jsx("p",{className:"text-[10px] text-gray-500 mt-2",children:"Weights determine how each factor contributes to a member's overall activity score. Adjust to match your guild's priorities."})]})]})}),e.jsx(a,{type:"tip",children:'Activity scores help identify inactive members and prioritize active raiders. Increase the "Last Seen" weight if attendance is your top priority, or boost "WCL Parses" if performance matters more.'})]})},{title:"Role Mapping",shortTitle:"Role Mapping",icon:w,description:"Map Discord roles to WoW guild ranks, classes, specs, and permission levels. When a member has a mapped Discord role, Loothing automatically assigns the corresponding permissions and raid role. This keeps your guild hierarchy synchronized between Discord and Loothing without manual user management. Supported role types include Tank, Healer, DPS, Leadership, Officer, Member, and Trial.",tip:"Start with broad mappings (Officers â Officer, Raiders â DPS) and refine later. Role mappings also affect which settings sections users can see and edit.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Discord Role Mapping",mobileContent:e.jsx(i,{items:[{label:"Guild Master",desc:"â Guild Master · Leadership",badge:"Leadership",badgeColor:"bg-purple-900/40 text-purple-300"},{label:"Officers",desc:"â Officer · Officer",badge:"Officer",badgeColor:"bg-yellow-900/40 text-yellow-300"},{label:"Main Tank",desc:"â Tank · Tank",badge:"Tank",badgeColor:"bg-blue-900/40 text-blue-300"},{label:"Healers",desc:"â Healer · Healer",badge:"Healer",badgeColor:"bg-green-900/40 text-green-300"},{label:"Raider",desc:"â DPS · DPS",badge:"DPS",badgeColor:"bg-red-900/40 text-red-300"},{label:"Trial",desc:"â Trial · Trial",badge:"Trial",badgeColor:"bg-orange-900/40 text-orange-300"}]}),children:e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-gray-400",children:"Map Discord roles to WoW classes, specs, and guild ranks so Loothing can auto-assign roles and enforce permissions."}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-gray-700/50",children:[e.jsx("th",{className:"px-3 py-2 text-left text-xs font-semibold text-gray-400 uppercase",children:"Discord Role"}),e.jsx("th",{className:"px-3 py-2 text-left text-xs font-semibold text-gray-400 uppercase",children:"Maps To"}),e.jsx("th",{className:"px-3 py-2 text-center text-xs font-semibold text-gray-400 uppercase",children:"Type"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-700/30",children:[{role:"Guild Master",color:"#F59E0B",mapsTo:"Guild Master",type:"Leadership",typeBg:"bg-purple-500"},{role:"Officers",color:"#8B5CF6",mapsTo:"Officer",type:"Officer",typeBg:"bg-yellow-500"},{role:"Main Tank",color:"#3B82F6",mapsTo:"Tank",type:"Tank",typeBg:"bg-blue-500"},{role:"Healers",color:"#10B981",mapsTo:"Healer",type:"Healer",typeBg:"bg-green-500"},{role:"Raider",color:"#EF4444",mapsTo:"DPS",type:"DPS",typeBg:"bg-red-500"},{role:"Trial",color:"#F97316",mapsTo:"Trial",type:"Trial",typeBg:"bg-orange-500"}].map((s,t)=>e.jsxs(p.tr,{initial:{opacity:0,x:-6}
1,animate:{opacity:1,x:0},transition:{delay:.04*t},children:[e.jsx("td",{className:"px-3 py-2",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded-full",style:{backgroundColor:s.color}}),e.jsx("span",{className:"text-gray-200 font-medium",children:s.role})]})}),e.jsx("td",{className:"px-3 py-2 text-gray-300",children:s.mapsTo}),e.jsx("td",{className:"px-3 py-2 text-center",children:e.jsx("span",{className:`text-[10px] px-2 py-0.5 rounded-full text-white font-medium ${s.typeBg}`,children:s.type})})]},s.role))})]})})]})}),e.jsx(a,{type:"info",children:'Role mappings sync permissions from Discord. When a user has the "Officers" Discord role, they automatically get officer-level access to Loothing features for your guild.'})]})},{title:"MCP Tool Management",shortTitle:"MCP Tools",icon:k,description:"Control which AI tools the bot can use. The Enable/Disable tab lets you toggle individual tools on or off by category. The Permission Requirements tab lets you restrict entire tool categories to users with specific Loothing permissions â when a user sends a message, the bot only has access to categories they have permission for. Categories with no permissions are available to everyone.",tip:"Use Enable/Disable to turn off tools globally (e.g. image generation to save costs). Use Permission Requirements to restrict tools per-user (e.g. only officers can use roster management tools).",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"MCP Tool Management â Enable/Disable",mobileContent:e.jsx(l,{items:[{label:"send_message",desc:"Send messages to Discord channels",enabled:!0},{label:"create_thread",desc:"Create new discussion threads",enabled:!0},{label:"manage_reactions",desc:"Add/remove reactions on messages",enabled:!1},{label:"query_roster",desc:"Look up guild roster data",enabled:!0},{label:"assign_loot",desc:"Record loot assignments",enabled:!0},{label:"audit_gear",desc:"Check character gear and enchants",enabled:!0},{label:"image",desc:"Generate or edit images (mode: generate | edit)",enabled:!1}]}),children:e.jsx("div",{className:"space-y-3",children:[{category:"Communication",tools:[{name:"send_message",enabled:!0,desc:"Send messages to Discord channels"},{name:"create_thread",enabled:!0,desc:"Create new discussion threads"},{name:"manage_reactions",enabled:!1,desc:"Add/remove reactions on messages"}]},{category:"Roster & Loot",tools:[{name:"query_roster",enabled:!0,desc:"Look up guild roster data"},{name:"assign_loot",enabled:!0,desc:"Record loot assignments"},{name:"audit_gear",enabled:!0,desc:"Check character gear and enchants"}]},{category:"Image Toolkit",tools:[{name:"image",enabled:!1,desc:"Generate or edit images (mode: generate | edit)"},{name:"find_images",enabled:!1,desc:"Discover stored images by query or filters"},{name:"view_image",enabled:!1,desc:"Analyze an image from a URL"}]}].map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:.08*t},className:"rounded-lg border border-gray-700/50 overflow-hidden",children:[e.jsx("div",{className:"px-3 py-2 bg-gray-800/60 text-xs font-semibold text-gray-300 uppercase tracking-wider",children:s.category}),e.jsx("div",{className:"divide-y divide-gray-700/30",children:s.tools.map(s=>e.jsxs("div",{className:"flex items-center justify-between gap-3 px-3 py-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-xs sm:text-sm text-gray-200 font-medium truncate",children:s.name}),e.jsx("div",{className:"text-[10px] text-gray-500 leading-snug",children:s.desc})]}),e.jsx("div",{className:"w-8 h-[18px] rounded-full flex items-center "+(s.enabled?"bg-green-600":"bg-gray-600"),children:e.jsx("div",{className:"w-3.5 h-3.5 rounded-full bg-white shadow-sm transition-transform "+(s.enabled?"translate-x-[14px]":"translate-x-0.5")})})]},s.name))})]},s.category))})}),e.jsx(a,{type:"tip",children:"Disable tools you don't want the bot to use. For example, turn off image generation to save costs, or disable communication tools if you only want the bot to answer questions without posting to channels."}),e.jsx(r,{label:"MCP Tool Management â Permission Requirements",mobileContent:e.jsx(i,{items:[{label:"Loot Database",desc:"Required: loot.view",badge:"Default",badgeColor:"bg-gray-700/60 text-gray-400"},{label:"Image Tools",desc:"Required: none (rate-limited per role)",badge:"Default",badgeColor:"bg-gray-700/60 text-gray-400"},{label:"Roster Management",desc:"Required: players.view, players.manage",badge:"Custom",badgeColor:"bg-indigo-900/40 text-indigo-300"}]}),children:e.jsxs("div",{className:"space-y-2.5",children:[e.jsx("p",{className:"text-[11px] text-gray-400",children:"Restrict entire tool categories to users with specific Loothing permissions."}),[{category:"Loot Database",perms:["loot.view"],status:"Default"},{category:"Image Tools",perms:[],status:"Default"},{category:"Roster Management",perms:["players.view","players.manage"],status:"Custom"}].map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,y:6}
1,animate:{opacity:1,y:0},transition:{delay:.06*t},className:"rounded-lg border border-gray-700/50 p-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("span",{className:"text-xs font-medium text-gray-200",children:s.category}),e.jsx("span",{className:"text-[9px] px-1.5 py-0.5 rounded-sm font-medium "+("Custom"===s.status?"bg-indigo-900/60 text-indigo-300":"bg-gray-700/60 text-gray-400"),children:s.status})]}),e.jsx("div",{className:"flex flex-wrap gap-1",children:s.perms.map(s=>e.jsx("span",{className:"text-[10px] px-2 py-0.5 rounded-full bg-indigo-600/30 text-indigo-300 border border-indigo-500/30",children:s},s))})]},s.category))]})}),e.jsx(a,{type:"tip",children:'When a user sends a message, the bot only has access to tool categories they have permission for. A user without "loot.view" will never trigger loot tools. Categories with no permissions set are unrestricted. Communication tools (send_message, add_reaction, etc.) are always available.'})]})},{title:"Voice Settings",shortTitle:"Voice",icon:C,description:"Configure speech-to-text (STT) and text-to-speech (TTS) for voice channel interactions. Both STT and TTS support two providers: OpenAI (Whisper for STT, TTS-1 voices for speech) and ElevenLabs (Scribe for STT with speaker diarization, premium voices for TTS). Set trigger words that activate the bot in voice channels. Each provider requires its own separate API key.",tip:"OpenAI is faster and cheaper. ElevenLabs supports 99 languages for STT (with speaker diarization) and 5000+ premium voices for TTS. You can mix providers â e.g. OpenAI for STT and ElevenLabs for TTS.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Voice Configuration",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"p-3 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(C,{className:"h-4 w-4 text-blue-400"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"Speech-to-Text"})]}),e.jsxs("div",{className:"space-y-2 text-xs",children:[e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Provider"}),e.jsx("span",{className:"text-gray-300 text-right",children:"OpenAI Whisper"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Alternative"}),e.jsx("span",{className:"text-gray-300 text-right",children:"ElevenLabs Scribe"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Language"}),e.jsx("span",{className:"text-gray-300 text-right",children:"English"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"API Key"}),e.jsxs("span",{className:"text-green-400 flex items-center gap-1",children:[e.jsx(S,{className:"h-3 w-3"})," Configured"]})]})]}),e.jsx("p",{className:"text-[10px] text-gray-500 mt-2",children:"ElevenLabs Scribe adds 99-language support and speaker diarization."})]}),e.jsxs("div",{className:"p-3 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(P,{className:"h-4 w-4 text-green-400"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"Text-to-Speech"})]}),e.jsxs("div",{className:"space-y-2 text-xs",children:[e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Provider"}),e.jsx("span",{className:"text-gray-300 text-right",children:"ElevenLabs"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Alternative"}),e.jsx("span",{className:"text-gray-300 text-right",children:"OpenAI TTS-1"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Voice"}),e.jsx("span",{className:"text-gray-300 text-right",children:"Rachel"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"Model"}),e.jsx("span",{className:"text-gray-300 text-right break-all",children:"eleven_multilingual_v2"})]}),e.jsxs("div",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"text-gray-500 shrink-0",children:"API Key"}),e.jsxs("span",{className:"text-green-400 flex items-center gap-1",children:[e.jsx(S,{className:"h-3 w-3"})," Configured"]})]})]}),e.jsx("p",{className:"text-[10px] text-gray-500 mt-2",children:"OpenAI offers 6 built-in voices (Alloy, Echo, Nova, etc.) with HD quality."})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-1.5",children:"Trigger Words"}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:["hey loothing","bot","assistant"].map(s=>e.jsx("span",{className:"px-2 py-1 rounded-full bg-gray-700/60 border border-gray-600/50 text-xs text-gray-300",children:s},s))}),e.jsx("p",{className:"text-[10px] text-gray-500 mt-1.5",children:"The bot listens for these phrases to activate voice transcription in voice channels."})]})]})}),e.jsx(a,{type:"warning",children:"STT and TTS each support two providers: OpenAI and ElevenLabs. Each provider requires its own API key configured independently. You can mix providers â for example, use OpenAI for STT and ElevenLabs for TTS."})]})},{title:"Image Generation Limits",shortTitle:"Image Limits",icon:T,description:"Set rate limits for AI image generation to control costs. Configure a guild-wide daily cap and per-role overrides. Higher-ranked roles can have higher limits. The default per-role limit applies to any role without a specific override. Usage resets daily and admins can manually reset individual user counters if needed.",tip:"Set higher limits for officers who may need images for announcements and events. The guild-wide cap prevents runaway costs even if individual limits are generous.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Image Generation Rate Limits",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"p-3 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(T,{className:"h-4 w-4 text-pink-400"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"Global Limits"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-xs",children:[e.jsxs("div",{className:"p-2 rounded-sm bg-gray-800/50 border border-gray-700/40",children:[e.jsx("div",{className:"text-gray-500",children:"Max Requests"}),e.jsx("div",{className:"text-gray-200 font-bold text-lg",children:"100"}),e.jsx("div",{className:"text-gray-600",children:"per day (guild-wide)"})]}),e.jsxs("div",{className:"p-2 rounded-sm bg-gray-800/50 border border-gray-700/40",children:[e.jsx("div",{className:"text-gray-500",children:"Default Per-Role"}),e.jsx("div",{className:"text-gray-200 font-bold text-lg",children:"10"}),e.jsx("div",{className:"text-gray-600",children:"per day (per role)"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-gray-300 mb-2",children:"Per-Role Overrides"}),e.jsx("div",{className:"space-y-1.5",children:[{role:"Guild Master",limit:50,color:"#F59E0B"},{role:"Officers",limit:25,color:"#8B5CF6"},{role:"Raiders",limit:10,color:"#EF4444"},{role:"Members",limit:5,color:"#6B7280"}].map(s=>e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2 rounded-lg bg-gray-800/40 border border-gray-700/30",children:[e.jsx("div",{className:"w-3 h-3 rounded-full",style:{backgroundColor:s.color}}),e.jsx("span",{className:"text-sm text-gray-200 flex-1",children:s.role}),e.jsxs("span",{className:"text-sm font-medium text-gray-300",children:[s.limit,"/day"]})]},s.role))})]})]})}),e.jsx(a,{type:"tip",children:"Set higher limits for officers and leaders who may need more images for announcements and events. The guild-wide cap acts as a safety net to prevent runaway costs."})]})},{title:"Member Onboarding",shortTitle:"Onboarding",icon:x,description:"The Onboarding panel (Settings â Guild Management â Onboarding) controls how new members are walked through character linking when they join your Discord server. It has a hard kill-switch plus six axes: trigger mode (auto / manual / disabled), delivery mode (DM / channel / web), whether character linking is required, fallback behavior when the primary path fail
1s, a re-claim approval channel for officers to act on the public /onboarding page's conflicts, and admin-bypass roles. The public /onboarding page is a cinematic, guild-branded six-step flow that runs when delivery is set to web or the web-handoff fallback fires.",tip:"Set the Re-claim approval channel so officers can approve or deny character re-claim requests from the web flow. Without it, members who try to claim a character already linked to someone else just see an error with no path forward.",component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Member Onboarding",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"p-4 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(M,{className:"h-5 w-5 text-emerald-400"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"Master Toggle"})]}),e.jsxs("p",{className:"text-xs text-gray-400 leading-relaxed",children:["The ",e.jsx("strong",{className:"text-gray-200",children:"Enable"})," switch is a hard kill switch. When it's off, new members receive no automated DM, no join-triggered prompt, and no web handoff â no matter what the other fields say. Officers can still invoke manual onboarding tools."]})]}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2 text-xs",children:[{label:"Trigger mode",desc:"auto / manual / disabled",icon:y},{label:"Delivery mode",desc:"DM / channel / web",icon:v},{label:"Linking",desc:"required or optional",icon:L},{label:"Fallback",desc:"officer-assist / web-handoff / none",icon:R},{label:"Re-claim channel",desc:"Approve/Deny approvals",icon:I},{label:"Announcement channel",desc:"Completed-onboarding embeds",icon:v},{label:"Bypass roles",desc:"Officers skip entirely",icon:m}].map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,y:6},animate:{opacity:1,y:0},transition:{delay:.05*t},className:"p-3 rounded-lg bg-gray-800/40 border border-gray-700/40 flex items-start gap-2",children:[e.jsx(s.icon,{className:"h-4 w-4 text-indigo-400 mt-0.5 shrink-0"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-gray-200",children:s.label}),e.jsx("div",{className:"text-[11px] text-gray-500 mt-0.5",children:s.desc})]})]},s.label))}),e.jsxs("div",{className:"p-4 rounded-xl border border-indigo-500/30 bg-indigo-500/5",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(x,{className:"h-5 w-5 text-indigo-400"}),e.jsxs("span",{className:"text-sm font-semibold text-gray-200",children:["Public ",e.jsx("code",{className:"text-xs bg-gray-800 px-1 rounded-sm",children:"/onboarding"})," page"]})]}),e.jsxs("p",{className:"text-xs text-gray-400 leading-relaxed",children:["When ",e.jsx("strong",{className:"text-gray-200",children:"Delivery mode"})," is set to ",e.jsx("strong",{children:"web"}),", or",e.jsx("strong",{children:" Fallback"})," is ",e.jsx("strong",{children:"web-handoff"}),", new members are pointed at a guild-branded public page that walks them through region â realm â character â Discord link in six steps. When a member tries to claim a character already linked to another Discord user, an approval embed with Approve/Deny buttons posts to the channel you set in ",e.jsx("strong",{children:"Re-claim approval channel"}),". Officers with Manage Server permission act on it directly."]})]})]})}),e.jsx(a,{type:"tip",children:"Leaving the re-claim channel blank disables the re-claim path â members will see a plain âcharacter already linkedâ error with no recourse. Set a channel (Settings â Guild Management â Onboarding â Re-claim approval channel) so officers can actually resolve disputes."}),e.jsxs(a,{type:"tip",children:["Set an ",e.jsx("strong",{children:"Officer announcement channel"})," to get a summary embed each time a member completes onboarding â who joined, which character they linked (or that they skipped), and how long it took. Blank means completions happen silently."]}),e.jsxs(a,{type:"warning",children:[e.jsx("strong",{children:"Admin bypass roles"})," skip the flow entirely. Useful for officers, but don't put everyone in a bypass role â you'll lose visibility into who has linked vs who hasn't."]})]})},{title:"How Credentials Are Protected",shortTitle:"Security",icon:S,description:'Every API key and secret you enter is encrypted at rest using industry-standard encryption. Your credentials are never stored in plain text and are never visible in the UI after saving â you will only see "Configured" as a placeholder. Decryption happens only at the exact moment a credential is needed, and the value is immediately discarded afterward. The encryption key is stored separately from the data, so even in the unlikely event of a data breach, your API keys remain protected.',tip:'After saving an API key or secret, you will see "Configured" instead of the actual value. To change a credential, simply enter a new one and save; leave the field blank to keep the existing stored value.',component:()=>e.jsxs("div",{className:"space-y-3",children:[e.jsx(r,{label:"Credential Security",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"p-4 rounded-xl border border-gray-700/50 bg-gray-800/30",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(S,{className:"h-5 w-5 text-green-400"}),e.jsx("span",{className:"text-sm font-semibold text-gray-200",children:"Encryption Pipeline"})]}),e.jsx("div",{className:"hidden sm:flex items-center justify-between gap-2 text-xs",children:[{label:"You enter\nAPI Key",icon:u,color:"text-blue-400"},{label:"Key\nDerivation",icon:y,color:"text-yellow-400"},{label:"Strong\nEncryption",icon:S,color:"text-green-400"},{label:"Stored\nSecurely",icon:b,color:"text-purple-400"}].map((s,a)=>e.jsxs(t.Fragment,{children:[a>0&&e.jsx("span",{className:"text-gray-600 text-lg shrink-0",children:"â"}),e.jsxs(p.div,{initial:{opacity:0,y:8}
1,animate:{opacity:1,y:0},transition:{delay:.12*a},className:"flex flex-col items-center text-center p-2 rounded-lg bg-gray-800/60 border border-gray-700/40 flex-1",children:[e.jsx(s.icon,{className:`h-5 w-5 ${s.color} mb-1`}),e.jsx("span",{className:"text-gray-300 whitespace-pre-line leading-tight",children:s.label})]})]},s.label))}),e.jsx("div",{className:"grid grid-cols-2 gap-2 text-xs sm:hidden",children:[{label:"You enter API Key",icon:u,color:"text-blue-400"},{label:"Key Derivation",icon:y,color:"text-yellow-400"},{label:"Strong Encryption",icon:S,color:"text-green-400"},{label:"Stored Securely",icon:b,color:"text-purple-400"}].map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:.12*t},className:"flex flex-col items-center text-center p-2 rounded-lg bg-gray-800/60 border border-gray-700/40",children:[e.jsx(s.icon,{className:`h-5 w-5 ${s.color} mb-1`}),e.jsx("span",{className:"text-gray-300 leading-tight",children:s.label})]},s.label))})]}),e.jsx("div",{className:"space-y-2",children:[{label:"Never Stored in Plain Text",desc:"Your API keys and secrets are always encrypted. They are never kept unprotected at any point."},{label:"Used Only When Needed",desc:"Credentials are only accessed at the exact moment they are required, then immediately discarded."},{label:"Hidden After Saving",desc:'After saving, the UI shows "Configured" instead of the actual key. The real value never leaves the server.'},{label:"Change Tracking",desc:"All settings changes are logged with who made the change and when, for accountability."}].map((s,t)=>e.jsxs(p.div,{initial:{opacity:0,x:-8},animate:{opacity:1,x:0},transition:{delay:.06*t},className:"flex items-start gap-3 p-3 rounded-lg bg-gray-800/40 border border-gray-700/40",children:[e.jsx(m,{className:"h-4 w-4 text-green-400 mt-0.5 shrink-0"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-gray-200",children:s.label}),e.jsx("div",{className:"text-xs text-gray-500 mt-0.5",children:s.desc})]})]},s.label))})]})}),e.jsx(a,{type:"warning",children:"Your API keys are encrypted at rest and are never visible in the UI after saving. The encryption key is stored separately from your data for maximum protection."})]})}];function z({onDone:s,initialStep:t=0,guideId:a}){return e.jsx(o,{steps:U,onDone:s,initialStep:t,guideId:a})}export{z as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.