{"id":11802,"date":"2026-02-04T16:10:06","date_gmt":"2026-02-04T19:10:06","guid":{"rendered":"https:\/\/rmts.com.br\/wp-01\/codigo-calculadora-impressao-3d-feita-no-gemini\/"},"modified":"2026-02-04T16:10:06","modified_gmt":"2026-02-04T19:10:06","slug":"codigo-calculadora-impressao-3d-feita-no-gemini","status":"publish","type":"post","link":"https:\/\/rmts.com.br\/wp-01\/codigo-calculadora-impressao-3d-feita-no-gemini\/","title":{"rendered":"C\u00f3digo Calculadora Impress\u00e3o 3D feita no Gemini"},"content":{"rendered":"<p><\/p>\n<p>C\u00f3digo da calculadora mostrada no v\u00eddeo:<\/p>\n<\/p>\n<p>&nbsp;<\/p>\n<blockquote>\n<div>\n<div>import React, { useState, useEffect, useMemo } from &#8216;react&#8217;;<\/div>\n<div>import {<\/div>\n<div>Calculator,<\/div>\n<div>Settings,<\/div>\n<div>Save,<\/div>\n<div>Trash2,<\/div>\n<div>AlertCircle,<\/div>\n<div>TrendingUp,<\/div>\n<div>Package,<\/div>\n<div>Zap,<\/div>\n<div>Clock,<\/div>\n<div>Info,<\/div>\n<div>Download,<\/div>\n<div>History,<\/div>\n<div>MessageCircle,<\/div>\n<div>Sliders,<\/div>\n<div>CheckCircle2,<\/div>\n<div>Share2,<\/div>\n<div>FileSpreadsheet,<\/div>\n<div>HelpCircle,<\/div>\n<div>X,<\/div>\n<div>ChevronRight,<\/div>\n<div>Copy,<\/div>\n<div>Coins,<\/div>\n<div>Box<\/div>\n<div>} from &#8216;lucide-react&#8217;;<\/div>\n<div>\/\/ &#8212; Utilit\u00e1rios &#8212;<\/div>\n<div>const parseLocalFloat = (str) =&gt; {<\/div>\n<div>if (typeof str === &#8216;number&#8217;) return str;<\/div>\n<div>if (!str || typeof str !== &#8216;string&#8217; || str.trim() === &#8221;) return0;<\/div>\n<div>return parseFloat(str.replace(&#8216;,&#8217;, &#8216;.&#8217;));<\/div>\n<div>};<\/div>\n<div>const parseSmartTime = (input) =&gt; {<\/div>\n<div>if (!input) return0;<\/div>\n<div>const str = input.toString().toLowerCase().replace(&#8216;,&#8217;, &#8216;.&#8217;);<\/div>\n<div>if (str.includes(&#8216;:&#8217;)) {<\/div>\n<div>const [h, m] = str.split(&#8216;:&#8217;);<\/div>\n<div>return parseFloat(h) + (parseFloat(m) \/ 60);<\/div>\n<div>}<\/div>\n<div>let totalHours = 0;<\/div>\n<div>const matchH = str.match(\/([\\d.]+)h\/);<\/div>\n<div>const matchM = str.match(\/([\\d.]+)m\/);<\/div>\n<div>if (matchH) totalHours += parseFloat(matchH[1]);<\/div>\n<div>if (matchM) totalHours += parseFloat(matchM[1]) \/ 60;<\/div>\n<div>if (!matchH &amp;&amp; !matchM) return parseFloat(str) || 0;<\/div>\n<div>return totalHours;<\/div>\n<div>};<\/div>\n<div>const parseSmartWeight = (input) =&gt; {<\/div>\n<div>if (!input) return0;<\/div>\n<div>const str = input.toString().toLowerCase().replace(&#8216;,&#8217;, &#8216;.&#8217;);<\/div>\n<div>if (str.includes(&#8216;kg&#8217;)) return parseFloat(str.replace(&#8216;kg&#8217;, &#8221;)) * 1000;<\/div>\n<div>if (str.includes(&#8216;g&#8217;)) return parseFloat(str.replace(&#8216;g&#8217;, &#8221;));<\/div>\n<div>return parseFloat(str) || 0;<\/div>\n<div>};<\/div>\n<div>const formatCurrency = (value) =&gt; {<\/div>\n<div>if (isNaN(value) || value === null) return&#8217;R$ 0,00&#8242;;<\/div>\n<div>returnnewIntl.NumberFormat(&#8216;pt-BR&#8217;, { style: &#8216;currency&#8217;, currency: &#8216;BRL&#8217; }).format(value);<\/div>\n<div>};<\/div>\n<div>const formatPercentage = (value) =&gt; {<\/div>\n<div>if (isNaN(value) || value === null) return&#8217;0,00%&#8217;;<\/div>\n<div>return`${value.toFixed(1).replace(&#8216;.&#8217;, &#8216;,&#8217;)}%`;<\/div>\n<div>};<\/div>\n<div>\/\/ &#8212; Presets &#8212;<\/div>\n<div>const MATERIAL_PRESETS = [<\/div>\n<div>{ label: &#8216;PLA&#8217;, cost: &#8216;100.00&#8217; },<\/div>\n<div>{ label: &#8216;PETG&#8217;, cost: &#8216;110.00&#8217; },<\/div>\n<div>{ label: &#8216;ABS&#8217;, cost: &#8216;90.00&#8217; },<\/div>\n<div>{ label: &#8216;Resina&#8217;, cost: &#8216;250.00&#8217; }<\/div>\n<div>];<\/div>\n<div>const PRINTER_PRESETS = [<\/div>\n<div>{ label: &#8216;Ender 3\/V2&#8217;, watts: &#8216;150&#8217;, price: &#8216;1800.00&#8217; },<\/div>\n<div>{ label: &#8216;Bambu A1&#8217;, watts: &#8216;130&#8217;, price: &#8216;3600.00&#8217; },<\/div>\n<div>{ label: &#8216;Bambu X1C&#8217;, watts: &#8216;350&#8217;, price: &#8216;12000.00&#8217; },<\/div>\n<div>{ label: &#8216;Resina&#8217;, watts: &#8217;80&#8217;, price: &#8216;2500.00&#8217; }<\/div>\n<div>];<\/div>\n<div>\/\/ &#8212; Componentes UI &#8212;<\/div>\n<div>const Toast = ({ message, type, onClose }) =&gt; (<\/div>\n<div>&lt;div className={`fixed top-4 right-4 z-50 px-6 py-4 rounded-2xl shadow-xl flex items-center gap-3 animate-fade-in-down border border-opacity-20 backdrop-blur-md ${<\/div>\n<div>type === &#8216;error&#8217; ? &#8216;bg-red-50 border-red-200 text-red-800&#8217; : &#8216;bg-emerald-50 border-emerald-200 text-emerald-800&#8217;<\/div>\n<div>}`}&gt;<\/div>\n<div>{type === &#8216;error&#8217; ? &lt;AlertCircle size={20}\/&gt; : &lt;CheckCircle2 size={20}\/&gt;}<\/div>\n<div>&lt;span className=&#8221;font-medium text-sm&#8221;&gt;{message}&lt;\/span&gt;<\/div>\n<div>&lt;button onClick={onClose} className=&#8221;ml-2 hover:opacity-70 transition-opacity&#8221;&gt;&lt;X size={16}\/&gt;&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>const ConfirmModal = ({ isOpen, title, message, onConfirm, onCancel }) =&gt; {<\/div>\n<div>if (!isOpen) returnnull;<\/div>\n<div>return (<\/div>\n<div>&lt;div className=&#8221;fixed inset-0 z-50 flex items-center justify-center bg-gray-900\/40 backdrop-blur-sm p-4 transition-all&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;bg-white rounded-2xl shadow-2xl max-w-sm w-full p-6 animate-scale-in border border-gray-100&#8243;&gt;<\/div>\n<div>&lt;h3 className=&#8221;text-xl font-bold text-gray-800 mb-2&#8243;&gt;{title}&lt;\/h3&gt;<\/div>\n<div>&lt;p className=&#8221;text-gray-500 text-sm mb-8 leading-relaxed&#8221;&gt;{message}&lt;\/p&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-end gap-3&#8243;&gt;<\/div>\n<div>&lt;button onClick={onCancel} className=&#8221;px-5 py-2.5 text-gray-600 hover:bg-gray-100 rounded-xl text-sm font-semibold transition-colors&#8221;&gt;Cancelar&lt;\/button&gt;<\/div>\n<div>&lt;button onClick={onConfirm} className=&#8221;px-5 py-2.5 bg-red-500 hover:bg-red-600 text-white rounded-xl text-sm font-semibold shadow-lg shadow-red-500\/30 transition-all active:scale-95&#8243;&gt;Confirmar&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>};<\/div>\n<div>const Card = ({ children, className = &#8220;&#8221;, noPadding = false }) =&gt; (<\/div>\n<div>&lt;div className={`bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden transition-all hover:shadow-md ${className}`}&gt;<\/div>\n<div>{children}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>const Tooltip = ({ text, children }) =&gt; (<\/div>\n<div>&lt;div className=&#8221;relative flex items-center group&#8221;&gt;<\/div>\n<div>{children}<\/div>\n<div>&lt;div className=&#8221;absolute bottom-full left-1\/2 transform -translate-x-1\/2 mb-2 w-48 p-3 text-xs font-medium text-white bg-gray-800 rounded-xl shadow-xl opacity-0 group-hover:opacity-100 transition-all duration-200 z-50 pointer-events-none text-center translate-y-2 group-hover:translate-y-0&#8243;&gt;<\/div>\n<div>{text}<\/div>\n<div>&lt;div className=&#8221;absolute top-full left-1\/2 transform -translate-x-1\/2 border-4 border-transparent border-t-gray-800&#8243;&gt;&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>const InputField = ({ id, label, value, onChange, error, placeholder, icon: Icon, helpText, suffix, onBlur }) =&gt; (<\/div>\n<div>&lt;div className=&#8221;flex flex-col mb-5 relative group&#8221;&gt;<\/div>\n<div>&lt;label htmlFor={id} className=&#8221;mb-2 text-xs font-bold text-gray-500 uppercase tracking-wide flex items-center justify-between&#8221;&gt;<\/div>\n<div>&lt;span className=&#8221;flex items-center gap-1.5&#8243;&gt;<\/div>\n<div>{Icon &amp;&amp; &lt;Icon className=&#8221;w-3.5 h-3.5 text-indigo-500&#8243; \/&gt;}<\/div>\n<div>{label}<\/div>\n<div>{helpText &amp;&amp; (<\/div>\n<div>&lt;Tooltip text={helpText}&gt;<\/div>\n<div>&lt;Info className=&#8221;w-3.5 h-3.5 text-gray-400 cursor-help hover:text-indigo-500 transition-colors&#8221; \/&gt;<\/div>\n<div>&lt;\/Tooltip&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/span&gt;<\/div>\n<div>&lt;\/label&gt;<\/div>\n<div>&lt;div className=&#8221;relative&#8221;&gt;<\/div>\n<div>&lt;input<\/div>\n<div>id={id}<\/div>\n<div>type=&#8221;text&#8221;<\/div>\n<div>inputMode=&#8221;decimal&#8221;<\/div>\n<div>value={value}<\/div>\n<div>onChange={(e) =&gt; onChange(id, e.target.value)}<\/div>\n<div>onBlur={onBlur}<\/div>\n<div>placeholder={placeholder}<\/div>\n<div>className={`w-full pl-4 pr-10 py-3 bg-gray-50\/50 border rounded-xl transition-all duration-300 font-semibold text-gray-700 placeholder-gray-400<\/div>\n<div>${error<\/div>\n<div>? &#8216;border-red-300 bg-red-50\/50 focus:ring-4 focus:ring-red-100 focus:border-red-400&#8217;<\/div>\n<div>: &#8216;border-gray-200 focus:bg-white focus:border-indigo-500 focus:ring-4 focus:ring-indigo-500\/10 hover:border-gray-300&#8217;<\/div>\n<div>}<\/div>\n<div>focus:outline-none`}<\/div>\n<div>\/&gt;<\/div>\n<div>{suffix &amp;&amp; (<\/div>\n<div>&lt;span className=&#8221;absolute right-4 top-3.5 text-gray-400 text-xs font-bold pointer-events-none&#8221;&gt;{suffix}&lt;\/span&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{error &amp;&amp; &lt;p className=&#8221;mt-1.5 text-xs text-red-500 flex items-center font-medium animate-pulse&#8221;&gt;&lt;AlertCircle className=&#8221;w-3 h-3 mr-1&#8243;\/&gt;{error}&lt;\/p&gt;}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>const SliderInput = ({ id, label, value, onChange, min = 0, max = 100, step = 1, suffix = &#8220;%&#8221;, presets = [] }) =&gt; {<\/div>\n<div>const numericValue = parseLocalFloat(value);<\/div>\n<div>return (<\/div>\n<div>&lt;div className=&#8221;mb-6 p-4 bg-gray-50\/80 rounded-2xl border border-gray-100&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center mb-3&#8243;&gt;<\/div>\n<div>&lt;label htmlFor={id} className=&#8221;text-sm font-bold text-gray-700&#8243;&gt;{label}&lt;\/label&gt;<\/div>\n<div>&lt;div className=&#8221;flex items-center bg-white px-3 py-1 rounded-lg border border-gray-200 shadow-sm&#8221;&gt;<\/div>\n<div>&lt;input<\/div>\n<div>type=&#8221;number&#8221; value={numericValue}<\/div>\n<div>onChange={(e) =&gt; onChange(id, e.target.value)}<\/div>\n<div>className=&#8221;w-12 text-sm font-bold text-indigo-600 text-right focus:outline-none&#8221;<\/div>\n<div>\/&gt;<\/div>\n<div>&lt;span className=&#8221;text-xs text-gray-400 font-bold ml-1&#8243;&gt;{suffix}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;flex flex-col gap-3&#8243;&gt;<\/div>\n<div>&lt;input<\/div>\n<div>type=&#8221;range&#8221; min={min} max={max} step={step} value={numericValue}<\/div>\n<div>onChange={(e) =&gt; onChange(id, e.target.value)}<\/div>\n<div>className=&#8221;w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-indigo-600 hover:accent-indigo-500 transition-all&#8221;<\/div>\n<div>\/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{presets.length &gt; 0 &amp;&amp; (<\/div>\n<div>&lt;div className=&#8221;flex gap-2 mt-3 overflow-x-auto pb-1 scrollbar-hide&#8221;&gt;<\/div>\n<div>{presets.map(p =&gt; (<\/div>\n<div>&lt;button key={p} onClick={() =&gt; onChange(id, p.toString())} className=&#8221;px-3 py-1.5 text-xs font-semibold bg-white border border-gray-200 text-gray-600 rounded-lg hover:border-indigo-300 hover:text-indigo-600 transition-all shadow-sm active:scale-95 whitespace-nowrap&#8221;&gt;<\/div>\n<div>{p}{suffix}<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>))}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>};<\/div>\n<div>const ProgressBar = ({ label, value, total, colorClass }) =&gt; {<\/div>\n<div>const percent = total &gt; 0 ? (value \/ total) * 100 : 0;<\/div>\n<div>return (<\/div>\n<div>&lt;div className=&#8221;mb-3 last:mb-0&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between text-xs mb-1.5&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-gray-500 font-medium flex items-center gap-1&#8243;&gt;{label}&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;font-bold text-gray-700&#8243;&gt;{formatCurrency(value)} &lt;span className=&#8221;text-gray-400 font-normal ml-1&#8243;&gt;({percent.toFixed(1)}%)&lt;\/span&gt;&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;w-full bg-gray-100 rounded-full h-2 overflow-hidden&#8221;&gt;<\/div>\n<div>&lt;div className={`h-full rounded-full ${colorClass} transition-all duration-700 ease-out`} style={{ width: `${Math.min(percent, 100)}%` }}&gt;&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>};<\/div>\n<div>\/\/ &#8212; Configura\u00e7\u00f5es Iniciais &#8212;<\/div>\n<div>const DEFAULT_SETTINGS = {<\/div>\n<div>consumo_watts: &#8216;150&#8217;,<\/div>\n<div>custo_kwh: &#8216;1.25&#8217;,<\/div>\n<div>valor_impressora: &#8216;6000.00&#8217;,<\/div>\n<div>vida_util_horas: &#8216;4000&#8217;,<\/div>\n<div>custo_filamento_padrao: &#8216;110.00&#8217;,<\/div>\n<div>lucro_minimo_projeto: &#8216;15.00&#8217;<\/div>\n<div>};<\/div>\n<div>const DEFAULT_PROJECT = {<\/div>\n<div>id: null,<\/div>\n<div>nome: &#8221;,<\/div>\n<div>quantidade_pecas: &#8216;1&#8217;,<\/div>\n<div>gramas_filamento: &#8221;,<\/div>\n<div>horas_impressao: &#8221;,<\/div>\n<div>custo_filamento_kg: &#8221;,<\/div>\n<div>custo_outros: &#8216;0&#8217;,<\/div>\n<div>custo_embalagem: &#8216;0&#8217;,<\/div>\n<div>margem_lucro_percentual: &#8216;100&#8217;,<\/div>\n<div>falha_risco_percentual: &#8216;0&#8217;<\/div>\n<div>};<\/div>\n<div>\/\/ &#8212; Componente Principal &#8212;<\/div>\n<div>export default function App() {<\/div>\n<div>const [activeTab, setActiveTab] = useState(&#8216;calc&#8217;);<\/div>\n<div>const [settings, setSettings] = useState(DEFAULT_SETTINGS);<\/div>\n<div>const [project, setProject] = useState(DEFAULT_PROJECT);<\/div>\n<div>const [history, setHistory] = useState([]);<\/div>\n<div><\/div>\n<div>\/\/ UI States<\/div>\n<div>const [showAdvanced, setShowAdvanced] = useState(true);<\/div>\n<div>const [viewUnitMode, setViewUnitMode] = useState(false);<\/div>\n<div><\/div>\n<div>\/\/ New Feedback States<\/div>\n<div>const [notification, setNotification] = useState(null);<\/div>\n<div>const [confirmDialog, setConfirmDialog] = useState(null);<\/div>\n<div>\/\/ Inicializa\u00e7\u00e3o<\/div>\n<div>useEffect(() =&gt; {<\/div>\n<div>const savedSettings = localStorage.getItem(&#8216;calc3d-settings-v6&#8217;);<\/div>\n<div>const savedProject = localStorage.getItem(&#8216;calc3d-project-v6&#8217;);<\/div>\n<div>const savedHistory = localStorage.getItem(&#8216;calc3d-history-v1&#8217;);<\/div>\n<div><\/div>\n<div>if (savedSettings) setSettings(JSON.parse(savedSettings));<\/div>\n<div>if (savedProject) setProject(JSON.parse(savedProject));<\/div>\n<div>if (savedHistory) setHistory(JSON.parse(savedHistory));<\/div>\n<div>else {<\/div>\n<div>setProject(prev =&gt; ({&#8230;prev, custo_filamento_kg: DEFAULT_SETTINGS.custo_filamento_padrao}));<\/div>\n<div>}<\/div>\n<div>}, []);<\/div>\n<div>\/\/ Persist\u00eancia<\/div>\n<div>useEffect(() =&gt; { localStorage.setItem(&#8216;calc3d-settings-v6&#8217;, JSON.stringify(settings)); }, [settings]);<\/div>\n<div>useEffect(() =&gt; { localStorage.setItem(&#8216;calc3d-project-v6&#8217;, JSON.stringify(project)); }, [project]);<\/div>\n<div>useEffect(() =&gt; { localStorage.setItem(&#8216;calc3d-history-v1&#8217;, JSON.stringify(history)); }, [history]);<\/div>\n<div>const showToast = (message, type = &#8216;success&#8217;) =&gt; {<\/div>\n<div>setNotification({ message, type });<\/div>\n<div>setTimeout(() =&gt; setNotification(null), 4000);<\/div>\n<div>};<\/div>\n<div>const handleSettingChange = (id, val) =&gt; setSettings(prev =&gt; ({ &#8230;prev, [id]: val }));<\/div>\n<div>const handleProjectChange = (id, val) =&gt; setProject(prev =&gt; ({ &#8230;prev, [id]: val }));<\/div>\n<div><\/div>\n<div>const handleTimeBlur = () =&gt; {<\/div>\n<div>const hours = parseSmartTime(project.horas_impressao);<\/div>\n<div>if (hours &gt; 0) handleProjectChange(&#8216;horas_impressao&#8217;, hours.toFixed(2));<\/div>\n<div>};<\/div>\n<div>const handleWeightBlur = () =&gt; {<\/div>\n<div>const grams = parseSmartWeight(project.gramas_filamento);<\/div>\n<div>if (grams &gt; 0) handleProjectChange(&#8216;gramas_filamento&#8217;, grams.toFixed(1));<\/div>\n<div>};<\/div>\n<div>\/\/ &#8212; C\u00c1LCULOS &#8212;<\/div>\n<div>const results = useMemo(() =&gt; {<\/div>\n<div>constS = {<\/div>\n<div>watts: parseLocalFloat(settings.consumo_watts),<\/div>\n<div>kwh: parseLocalFloat(settings.custo_kwh),<\/div>\n<div>printerPrice: parseLocalFloat(settings.valor_impressora),<\/div>\n<div>lifeHours: parseLocalFloat(settings.vida_util_horas),<\/div>\n<div>minProfit: parseLocalFloat(settings.lucro_minimo_projeto)<\/div>\n<div>};<\/div>\n<div>constP = {<\/div>\n<div>qty: Math.max(1, parseInt(project.quantidade_pecas) || 1),<\/div>\n<div>grams: parseSmartWeight(project.gramas_filamento),<\/div>\n<div>hours: parseSmartTime(project.horas_impressao),<\/div>\n<div>filPrice: parseLocalFloat(project.custo_filamento_kg) || parseLocalFloat(settings.custo_filamento_padrao),<\/div>\n<div>others: parseLocalFloat(project.custo_outros),<\/div>\n<div>pack: parseLocalFloat(project.custo_embalagem),<\/div>\n<div>margin: parseLocalFloat(project.margem_lucro_percentual),<\/div>\n<div>risk: parseLocalFloat(project.falha_risco_percentual)<\/div>\n<div>};<\/div>\n<div>const kwhPrice = (S.watts \/ 1000) * S.kwh;<\/div>\n<div>const depreciationPrice = S.lifeHours &gt; 0 ? S.printerPrice \/ S.lifeHours : 0;<\/div>\n<div><\/div>\n<div>const costFilament = (P.grams \/ 1000) * P.filPrice;<\/div>\n<div>const costEnergy = kwhPrice * P.hours;<\/div>\n<div>const costDepreciation = depreciationPrice * P.hours;<\/div>\n<div>const costExtras = P.others + P.pack;<\/div>\n<div><\/div>\n<div>const productionSum = costFilament + costEnergy + costDepreciation;<\/div>\n<div>const costFailMargin = productionSum * (P.risk \/ 100);<\/div>\n<div>const baseProductionCost = productionSum + costFailMargin;<\/div>\n<div><\/div>\n<div>\/\/ CUSTO TOTAL (Custo de manufatura + Extras)<\/div>\n<div>const totalCost = baseProductionCost + costExtras;<\/div>\n<div>const unitTotalCost = totalCost \/ P.qty;<\/div>\n<div><\/div>\n<div>const profitValue = baseProductionCost * (P.margin \/ 100);<\/div>\n<div>const finalPrice = baseProductionCost + profitValue + costExtras;<\/div>\n<div>const actualProfit = finalPrice &#8211; totalCost;<\/div>\n<div>const unitPrice = finalPrice \/ P.qty;<\/div>\n<div>const unitProfit = actualProfit \/ P.qty;<\/div>\n<div><\/div>\n<div>\/\/ Sugest\u00e3o de Pre\u00e7o para Lucro M\u00ednimo<\/div>\n<div>const suggestedPriceMinProfit = totalCost + S.minProfit;<\/div>\n<div>return {<\/div>\n<div>S, P,<\/div>\n<div>costs: { filament: costFilament, energy: costEnergy, depreciation: costDepreciation, risk: costFailMargin, packaging: P.pack, others: P.others, totalExtras: costExtras },<\/div>\n<div>baseProductionCost,<\/div>\n<div>totalCost,<\/div>\n<div>unitTotalCost,<\/div>\n<div>actualProfit, finalPrice, unitPrice, unitProfit,<\/div>\n<div>isLowProfit: actualProfit &lt; S.minProfit,<\/div>\n<div>isHighRisk: P.risk &gt; 30,<\/div>\n<div>suggestedPriceMinProfit,<\/div>\n<div>isValid: P.grams &gt; 0 &amp;&amp; P.hours &gt; 0,<\/div>\n<div>missingFields: { grams: P.grams &lt;= 0, hours: P.hours &lt;= 0 }<\/div>\n<div>};<\/div>\n<div>}, [settings, project]);<\/div>\n<div>\/\/ &#8212; A\u00e7\u00f5es &#8212;<\/div>\n<div>const saveToHistory = () =&gt; {<\/div>\n<div>if (!project.nome) {<\/div>\n<div>showToast(&#8220;D\u00ea um nome ao projeto para salvar.&#8221;, &#8220;error&#8221;);<\/div>\n<div>return;<\/div>\n<div>}<\/div>\n<div>const newEntry = { &#8230;project, id: Date.now(), date: newDate().toISOString(), finalPrice: results.finalPrice };<\/div>\n<div>setHistory(prev =&gt; [newEntry, &#8230;prev]);<\/div>\n<div>showToast(&#8220;Projeto salvo no hist\u00f3rico!&#8221;);<\/div>\n<div>};<\/div>\n<div>const confirmReset = () =&gt; {<\/div>\n<div>setConfirmDialog({<\/div>\n<div>title: &#8220;Limpar Projeto&#8221;,<\/div>\n<div>message: &#8220;Tem certeza que deseja apagar todos os dados atuais do formul\u00e1rio?&#8221;,<\/div>\n<div>action: () =&gt; {<\/div>\n<div>setProject({ &#8230;DEFAULT_PROJECT, custo_filamento_kg: settings.custo_filamento_padrao });<\/div>\n<div>setConfirmDialog(null);<\/div>\n<div>showToast(&#8220;Dados limpos com sucesso.&#8221;);<\/div>\n<div>}<\/div>\n<div>});<\/div>\n<div>};<\/div>\n<div>const confirmDeleteHistory = (id) =&gt; {<\/div>\n<div>setConfirmDialog({<\/div>\n<div>title: &#8220;Excluir Registro&#8221;,<\/div>\n<div>message: &#8220;Essa a\u00e7\u00e3o n\u00e3o pode ser desfeita. Deseja continuar?&#8221;,<\/div>\n<div>action: () =&gt; {<\/div>\n<div>setHistory(prev =&gt; prev.filter(i =&gt; i.id !== id));<\/div>\n<div>setConfirmDialog(null);<\/div>\n<div>showToast(&#8220;Item exclu\u00eddo.&#8221;);<\/div>\n<div>}<\/div>\n<div>});<\/div>\n<div>};<\/div>\n<div>const loadFromHistory = (item) =&gt; {<\/div>\n<div>setProject(item);<\/div>\n<div>setActiveTab(&#8216;calc&#8217;);<\/div>\n<div>showToast(&#8220;Projeto carregado!&#8221;);<\/div>\n<div>};<\/div>\n<div>const applyPsychologicalPrice = () =&gt; {<\/div>\n<div>const current = results.finalPrice;<\/div>\n<div>const integerPart = Math.floor(current);<\/div>\n<div>let suggestion = integerPart + 0.90;<\/div>\n<div>if (suggestion &lt; current) suggestion += 1;<\/div>\n<div><\/div>\n<div>const extras = results.costs.totalExtras;<\/div>\n<div>const cost = results.baseProductionCost;<\/div>\n<div>if (cost &gt; 0) {<\/div>\n<div>const newMargin = (((suggestion &#8211; extras) \/ cost) &#8211; 1) * 100;<\/div>\n<div>handleProjectChange(&#8216;margem_lucro_percentual&#8217;, newMargin.toFixed(2));<\/div>\n<div>showToast(&#8220;Pre\u00e7o arredondado!&#8221;);<\/div>\n<div>}<\/div>\n<div>};<\/div>\n<div>const openWhatsApp = () =&gt; {<\/div>\n<div>const text = `*Or\u00e7amento 3D*\\n<img decoding=\"async\" src=\"http:\/\/rmts.com.br\/wp-01\/wp-content\/uploads\/2026\/02\/1f4e6.png\" alt=\"\ud83d\udce6\" class=\"wp-smiley\" style=\"height: 1em;max-height: 1em\" \/> Projeto: ${project.nome || &#8216;Pe\u00e7a&#8217;}\\n<img decoding=\"async\" src=\"http:\/\/rmts.com.br\/wp-01\/wp-content\/uploads\/2026\/02\/1f4b0.png\" alt=\"\ud83d\udcb0\" class=\"wp-smiley\" style=\"height: 1em;max-height: 1em\" \/> Valor: ${formatCurrency(results.finalPrice)}\\n(Gerado por ZoomCalc3D)`;<\/div>\n<div>const url = `https:\/\/wa.me\/?text=${encodeURIComponent(text)}`;<\/div>\n<div>window.open(url, &#8216;_blank&#8217;);<\/div>\n<div>};<\/div>\n<div>\/\/ &#8212; COPY TO CLIPBOARD (Universal) &#8212;<\/div>\n<div>const copyToClipboard = (text) =&gt; {<\/div>\n<div>const textArea = document.createElement(&#8220;textarea&#8221;);<\/div>\n<div>textArea.value = text;<\/div>\n<div><\/div>\n<div>\/\/ Evita scroll quando o elemento \u00e9 inserido<\/div>\n<div>textArea.style.top = &#8220;0&#8221;;<\/div>\n<div>textArea.style.left = &#8220;0&#8221;;<\/div>\n<div>textArea.style.position = &#8220;fixed&#8221;;<\/div>\n<div>textArea.style.opacity = &#8220;0&#8221;; \/\/ Invis\u00edvel<\/div>\n<div>document.body.appendChild(textArea);<\/div>\n<div>textArea.focus();<\/div>\n<div>textArea.select();<\/div>\n<div>try {<\/div>\n<div>const successful = document.execCommand(&#8216;copy&#8217;);<\/div>\n<div>if(successful) showToast(&#8220;Copiado! Cole no Google Sheets (Ctrl+V).&#8221;, &#8220;success&#8221;);<\/div>\n<div>else showToast(&#8220;Erro ao copiar.&#8221;, &#8220;error&#8221;);<\/div>\n<div>} catch (err) {<\/div>\n<div>console.error(&#8216;Fallback: Oops, unable to copy&#8217;, err);<\/div>\n<div>showToast(&#8220;Erro no navegador.&#8221;, &#8220;error&#8221;);<\/div>\n<div>}<\/div>\n<div>document.body.removeChild(textArea);<\/div>\n<div>};<\/div>\n<div>const copyToSheets = () =&gt; {<\/div>\n<div>if (!results.isValid) return;<\/div>\n<div>const fmt = (num) =&gt; typeof num === &#8216;number&#8217; ? num.toFixed(2).replace(&#8216;.&#8217;, &#8216;,&#8217;) : num;<\/div>\n<div><\/div>\n<div>const tsvContent = `<\/div>\n<div>PROJETO\\t${project.nome || &#8220;Sem nome&#8221;}<\/div>\n<div>DATA\\t${new Date().toLocaleDateString()}<\/div>\n<div>&#8212;<\/div>\n<div>Item\\tTotal\\tUnit\u00e1rio<\/div>\n<div>Filamento\\t${fmt(results.costs.filament)}\\t${fmt(results.costs.filament\/results.P.qty)}<\/div>\n<div>Energia\\t${fmt(results.costs.energy)}\\t${fmt(results.costs.energy\/results.P.qty)}<\/div>\n<div>Desgaste\\t${fmt(results.costs.depreciation)}\\t${fmt(results.costs.depreciation\/results.P.qty)}<\/div>\n<div>Risco\\t${fmt(results.costs.risk)}\\t${fmt(results.costs.risk\/results.P.qty)}<\/div>\n<div>Extras\\t${fmt(results.costs.totalExtras)}\\t${fmt(results.costs.totalExtras\/results.P.qty)}<\/div>\n<div>CUSTO TOTAL\\t${fmt(results.totalCost)}\\t${fmt(results.totalCost\/results.P.qty)}<\/div>\n<div>LUCRO\\t${fmt(results.actualProfit)}\\t${fmt(results.actualProfit\/results.P.qty)}<\/div>\n<div>PRE\u00c7O FINAL\\t${fmt(results.finalPrice)}\\t${fmt(results.unitPrice)}<\/div>\n<div>`.trim();<\/div>\n<div>copyToClipboard(tsvContent);<\/div>\n<div>};<\/div>\n<div>\/\/ &#8212; EXPORT ALL HISTORY CSV &#8212;<\/div>\n<div>const exportHistoryCSV = () =&gt; {<\/div>\n<div>if (history.length === 0) {<\/div>\n<div>showToast(&#8220;Hist\u00f3rico vazio.&#8221;, &#8220;error&#8221;);<\/div>\n<div>return;<\/div>\n<div>}<\/div>\n<div>constBOM = &#8220;\\uFEFF&#8221;;<\/div>\n<div>const header = [&#8220;Data&#8221;, &#8220;Projeto&#8221;, &#8220;Qtd&#8221;, &#8220;Preco Final&#8221;];<\/div>\n<div>const rows = history.map(item =&gt; [<\/div>\n<div>newDate(item.date).toLocaleDateString(),<\/div>\n<div>item.nome || &#8220;Sem nome&#8221;,<\/div>\n<div>item.quantidade_pecas,<\/div>\n<div>formatCurrency(item.finalPrice).replace(&#8216;R$&#8217;, &#8221;).trim()<\/div>\n<div>]);<\/div>\n<div><\/div>\n<div>const csvContent = BOM + [header, &#8230;rows].map(e =&gt; e.join(&#8220;;&#8221;)).join(&#8220;\\n&#8221;);<\/div>\n<div>const blob = newBlob([csvContent], { type: &#8216;text\/csv;charset=utf-8;&#8217; });<\/div>\n<div>const link = document.createElement(&#8220;a&#8221;);<\/div>\n<div>link.href = URL.createObjectURL(blob);<\/div>\n<div>link.download = `historico_completo_${new Date().toISOString().slice(0,10)}.csv`;<\/div>\n<div>link.click();<\/div>\n<div>};<\/div>\n<div>const exportToCSV = () =&gt; {<\/div>\n<div>if (!results.isValid) return;<\/div>\n<div>const safeName = project.nome ? project.nome.replace(\/[^a-z0-9]\/gi, &#8216;_&#8217;) : &#8216;orcamento&#8217;;<\/div>\n<div>constBOM = &#8220;\\uFEFF&#8221;;<\/div>\n<div>const fmt = (num) =&gt; typeof num === &#8216;number&#8217; ? num.toFixed(2).replace(&#8216;.&#8217;, &#8216;,&#8217;) : num;<\/div>\n<div>const rows = [<\/div>\n<div>[&#8220;ITEM&#8221;, &#8220;VALOR TOTAL&#8221;, &#8220;VALOR UNITARIO&#8221;],<\/div>\n<div>[&#8220;Nome do Projeto&#8221;, project.nome || &#8220;-&#8220;],<\/div>\n<div>[&#8220;CUSTO: Filamento&#8221;, fmt(results.costs.filament), fmt(results.costs.filament\/results.P.qty)],<\/div>\n<div>[&#8220;CUSTO: Energia&#8221;, fmt(results.costs.energy), fmt(results.costs.energy\/results.P.qty)],<\/div>\n<div>[&#8220;CUSTO: Desgaste&#8221;, fmt(results.costs.depreciation), fmt(results.costs.depreciation\/results.P.qty)],<\/div>\n<div>[&#8220;CUSTO: Risco&#8221;, fmt(results.costs.risk), fmt(results.costs.risk\/results.P.qty)],<\/div>\n<div>[&#8220;CUSTO: Extras&#8221;, fmt(results.costs.totalExtras), fmt(results.costs.totalExtras\/results.P.qty)],<\/div>\n<div>[&#8220;&#8212;&#8220;, &#8220;&#8212;&#8220;, &#8220;&#8212;&#8220;],<\/div>\n<div>[&#8220;CUSTO TOTAL (PRODU\u00c7\u00c3O)&#8221;, fmt(results.totalCost), fmt(results.totalCost\/results.P.qty)],<\/div>\n<div>[&#8220;Lucro&#8221;, fmt(results.actualProfit), fmt(results.actualProfit\/results.P.qty)],<\/div>\n<div>[&#8220;PRE\u00c7O FINAL&#8221;, fmt(results.finalPrice), fmt(results.unitPrice)]<\/div>\n<div>];<\/div>\n<div>const csvContent = BOM + rows.map(e =&gt; e.join(&#8220;;&#8221;)).join(&#8220;\\n&#8221;);<\/div>\n<div>const blob = newBlob([csvContent], { type: &#8216;text\/csv;charset=utf-8;&#8217; });<\/div>\n<div>const link = document.createElement(&#8220;a&#8221;);<\/div>\n<div>link.href = URL.createObjectURL(blob);<\/div>\n<div>link.download = `${safeName}.csv`;<\/div>\n<div>link.click();<\/div>\n<div>};<\/div>\n<div>return (<\/div>\n<div>&lt;div className=&#8221;min-h-screen bg-slate-50 text-gray-800 font-sans pb-24 selection:bg-indigo-100 selection:text-indigo-800&#8243;&gt;<\/div>\n<div>{notification &amp;&amp; &lt;Toast message={notification.message} type={notification.type} onClose={() =&gt; setNotification(null)} \/&gt;}<\/div>\n<div>&lt;ConfirmModal<\/div>\n<div>isOpen={!!confirmDialog}<\/div>\n<div>title={confirmDialog?.title}<\/div>\n<div>message={confirmDialog?.message}<\/div>\n<div>onConfirm={confirmDialog?.action}<\/div>\n<div>onCancel={() =&gt; setConfirmDialog(null)}<\/div>\n<div>\/&gt;<\/div>\n<div>{\/* Modern Gradient Header *\/}<\/div>\n<div>&lt;div className=&#8221;sticky top-0 z-30 bg-white\/80 backdrop-blur-md border-b border-gray-200\/60 shadow-sm transition-all&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;max-w-5xl mx-auto px-4 sm:px-6 h-18 flex items-center justify-between py-3&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex items-center gap-3&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;bg-gradient-to-br from-indigo-500 to-violet-600 text-white p-2 rounded-xl shadow-lg shadow-indigo-200&#8243;&gt;<\/div>\n<div>&lt;Calculator size={22} className=&#8221;stroke-[2.5]&#8221; \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div&gt;<\/div>\n<div>&lt;span className=&#8221;font-bold text-xl tracking-tight text-gray-900 leading-tight block&#8221;&gt;ZoomCalc3D&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;text-[10px] font-semibold text-gray-400 uppercase tracking-widest hidden sm:block&#8221;&gt;Precifica\u00e7\u00e3o Inteligente&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;nav className=&#8221;flex bg-gray-100\/80 p-1.5 rounded-xl overflow-x-auto gap-1&#8243;&gt;<\/div>\n<div>{[{ id: &#8216;calc&#8217;, icon: Calculator, label: &#8216;Calc&#8217; }, { id: &#8216;history&#8217;, icon: History, label: &#8216;Hist\u00f3rico&#8217; }, { id: &#8216;settings&#8217;, icon: Settings, label: &#8216;Ajustes&#8217; }].map(tab =&gt; (<\/div>\n<div>&lt;button key={tab.id} onClick={() =&gt; setActiveTab(tab.id)} className={`px-4 py-2 rounded-lg text-sm font-bold transition-all flex items-center gap-2 whitespace-nowrap outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 ${activeTab === tab.id ? &#8216;bg-white text-indigo-600 shadow-sm&#8217; : &#8216;text-gray-500 hover:text-gray-700 hover:bg-gray-200\/50&#8217;}`}&gt;<\/div>\n<div>&lt;tab.icon size={16} className={activeTab === tab.id ? &#8220;stroke-[2.5]&#8221; : &#8220;stroke-2&#8221;} \/&gt; {tab.label}<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>))}<\/div>\n<div>&lt;\/nav&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;main className=&#8221;max-w-5xl mx-auto px-4 sm:px-6 py-8&#8243;&gt;<\/div>\n<div><\/div>\n<div>{\/* &#8212; SETTINGS TAB &#8212; *\/}<\/div>\n<div>{activeTab === &#8216;settings&#8217; &amp;&amp; (<\/div>\n<div>&lt;div className=&#8221;max-w-2xl mx-auto animate-fade-in&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;mb-6&#8243;&gt;<\/div>\n<div>&lt;h2 className=&#8221;text-2xl font-bold text-gray-900&#8243;&gt;Configura\u00e7\u00f5es&lt;\/h2&gt;<\/div>\n<div>&lt;p className=&#8221;text-gray-500 text-sm&#8221;&gt;Personalize os par\u00e2metros da sua oficina.&lt;\/p&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>&lt;Card className=&#8221;p-8 space-y-8&#8243;&gt;<\/div>\n<div>&lt;div&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center mb-6&#8243;&gt;<\/div>\n<div>&lt;h3 className=&#8221;text-sm font-bold text-gray-400 uppercase tracking-wider flex items-center gap-2&#8243;&gt;&lt;Zap size={14}\/&gt; Perfil da Impressora&lt;\/h3&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-2&#8243;&gt;<\/div>\n<div>{PRINTER_PRESETS.map((p, i) =&gt; (<\/div>\n<div>&lt;button key={i} onClick={() =&gt; setSettings(prev =&gt; ({&#8230;prev, consumo_watts: p.watts, valor_impressora: p.price}))} className=&#8221;text-[10px] font-bold bg-indigo-50 text-indigo-600 px-3 py-1.5 rounded-lg border border-indigo-100 hover:bg-indigo-100 hover:border-indigo-200 transition-colors uppercase tracking-wide&#8221;&gt;<\/div>\n<div>{p.label}<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>))}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-1 sm:grid-cols-2 gap-6&#8243;&gt;<\/div>\n<div>&lt;InputField id=&#8221;consumo_watts&#8221; label=&#8221;Consumo (Watts)&#8221; value={settings.consumo_watts} onChange={handleSettingChange} suffix=&#8221;W&#8221; icon={Zap} \/&gt;<\/div>\n<div>&lt;InputField id=&#8221;custo_kwh&#8221; label=&#8221;Custo Energia (kWh)&#8221; value={settings.custo_kwh} onChange={handleSettingChange} icon={Zap} \/&gt;<\/div>\n<div>&lt;InputField id=&#8221;valor_impressora&#8221; label=&#8221;Pre\u00e7o da M\u00e1quina&#8221; value={settings.valor_impressora} onChange={handleSettingChange} icon={Calculator} \/&gt;<\/div>\n<div>&lt;InputField id=&#8221;vida_util_horas&#8221; label=&#8221;Vida \u00datil&#8221; value={settings.vida_util_horas} onChange={handleSettingChange} suffix=&#8221;h&#8221; icon={Clock} \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;border-t border-gray-100 pt-8&#8243;&gt;<\/div>\n<div>&lt;h3 className=&#8221;text-sm font-bold text-gray-400 uppercase tracking-wider mb-6 flex items-center gap-2&#8243;&gt;&lt;TrendingUp size={14}\/&gt; Par\u00e2metros de Neg\u00f3cio&lt;\/h3&gt;<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-1 sm:grid-cols-2 gap-6&#8243;&gt;<\/div>\n<div>&lt;InputField id=&#8221;custo_filamento_padrao&#8221; label=&#8221;Custo Kg Padr\u00e3o&#8221; value={settings.custo_filamento_padrao} onChange={handleSettingChange} icon={Package} \/&gt;<\/div>\n<div>&lt;InputField id=&#8221;lucro_minimo_projeto&#8221; label=&#8221;Lucro M\u00ednimo (R$)&#8221; value={settings.lucro_minimo_projeto} onChange={handleSettingChange} icon={TrendingUp} \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/Card&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>{\/* &#8212; HISTORY TAB &#8212; *\/}<\/div>\n<div>{activeTab === &#8216;history&#8217; &amp;&amp; (<\/div>\n<div>&lt;div className=&#8221;max-w-3xl mx-auto animate-fade-in&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-end mb-6&#8243;&gt;<\/div>\n<div>&lt;div&gt;<\/div>\n<div>&lt;h2 className=&#8221;text-2xl font-bold text-gray-900 flex items-center gap-2&#8243;&gt;Hist\u00f3rico&lt;\/h2&gt;<\/div>\n<div>&lt;p className=&#8221;text-gray-500 text-sm&#8221;&gt;Seus or\u00e7amentos salvos.&lt;\/p&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-2&#8243;&gt;<\/div>\n<div>&lt;button onClick={exportHistoryCSV} className=&#8221;bg-white border border-gray-200 text-gray-600 px-3 py-1.5 rounded-lg text-xs font-bold hover:bg-gray-50 flex items-center gap-2 transition-colors&#8221;&gt;<\/div>\n<div>&lt;FileSpreadsheet size={14}\/&gt; Exportar Tudo (CSV)<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;div className=&#8221;bg-indigo-50 text-indigo-600 px-3 py-1.5 rounded-lg text-xs font-bold border border-indigo-100&#8243;&gt;<\/div>\n<div>{history.length} Projetos<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>{history.length === 0 ? (<\/div>\n<div>&lt;div className=&#8221;text-center py-20 bg-white rounded-3xl border-2 border-dashed border-gray-200&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;bg-gray-50 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4&#8243;&gt;<\/div>\n<div>&lt;History className=&#8221;text-gray-300&#8243; size={32}\/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;p className=&#8221;text-gray-500 font-medium&#8221;&gt;Nenhum projeto salvo ainda.&lt;\/p&gt;<\/div>\n<div>&lt;button onClick={() =&gt; setActiveTab(&#8216;calc&#8217;)} className=&#8221;mt-4 text-indigo-600 font-bold text-sm hover:underline&#8221;&gt;Criar novo or\u00e7amento&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>) : (<\/div>\n<div>&lt;div className=&#8221;space-y-4&#8243;&gt;<\/div>\n<div>{history.map(item =&gt; (<\/div>\n<div>&lt;div key={item.id} className=&#8221;bg-white p-5 rounded-2xl border border-gray-100 shadow-sm hover:shadow-lg hover:border-indigo-100 transition-all group&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center&#8221;&gt;<\/div>\n<div>&lt;div&gt;<\/div>\n<div>&lt;h3 className=&#8221;font-bold text-gray-800 text-lg group-hover:text-indigo-600 transition-colors&#8221;&gt;{item.nome}&lt;\/h3&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-3 text-xs text-gray-400 mt-1 font-medium uppercase tracking-wide&#8221;&gt;<\/div>\n<div>&lt;span&gt;{new Date(item.date).toLocaleDateString()}&lt;\/span&gt;<\/div>\n<div>&lt;span&gt;\u2022&lt;\/span&gt;<\/div>\n<div>&lt;span&gt;{item.quantidade_pecas} {item.quantidade_pecas &gt; 1 ? &#8216;Pe\u00e7as&#8217; : &#8216;Pe\u00e7a&#8217;}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;flex items-center gap-6&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;font-bold text-gray-900 text-xl&#8221;&gt;{formatCurrency(item.finalPrice)}&lt;\/span&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-2&#8243;&gt;<\/div>\n<div>&lt;button onClick={() =&gt; loadFromHistory(item)} className=&#8221;p-2.5 text-gray-500 hover:text-indigo-600 hover:bg-indigo-50 rounded-xl transition-colors&#8221; title=&#8221;Carregar&#8221;&gt;&lt;Download size={20}\/&gt;&lt;\/button&gt;<\/div>\n<div>&lt;button onClick={() =&gt; confirmDeleteHistory(item.id)} className=&#8221;p-2.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-xl transition-colors&#8221; title=&#8221;Excluir&#8221;&gt;&lt;Trash2 size={20}\/&gt;&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>))}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>{\/* &#8212; CALCULATOR TAB &#8212; *\/}<\/div>\n<div>{activeTab === &#8216;calc&#8217; &amp;&amp; (<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-1 lg:grid-cols-12 gap-8&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;lg:col-span-5 space-y-6&#8243;&gt;<\/div>\n<div><\/div>\n<div>{\/* Form Card *\/}<\/div>\n<div>&lt;Card&gt;<\/div>\n<div>&lt;div className=&#8221;bg-gray-50\/80 backdrop-blur px-6 py-4 border-b border-gray-100 flex justify-between items-center&#8221;&gt;<\/div>\n<div>&lt;h3 className=&#8221;font-bold text-gray-600 flex items-center gap-2 text-xs uppercase tracking-widest&#8221;&gt;<\/div>\n<div>&lt;Sliders size={14}\/&gt; Par\u00e2metros<\/div>\n<div>&lt;\/h3&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-2&#8243;&gt;<\/div>\n<div>&lt;button onClick={() =&gt; setShowAdvanced(!showAdvanced)} className={`text-[10px] font-bold px-3 py-1.5 rounded-lg border transition-all uppercase tracking-wide ${showAdvanced ? &#8216;bg-indigo-50 text-indigo-600 border-indigo-100&#8217; : &#8216;bg-white text-gray-400 border-gray-200 hover:border-gray-300&#8217;}`}&gt;<\/div>\n<div>{showAdvanced ? &#8216;Completo&#8217; : &#8216;B\u00e1sico&#8217;}<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;button onClick={confirmReset} className=&#8221;text-gray-400 hover:text-red-500 hover:bg-red-50 p-1.5 rounded-lg transition-colors&#8221;&gt;&lt;Trash2 size={16} \/&gt;&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>&lt;div className=&#8221;p-6&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-3 gap-4 mb-2&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;col-span-2&#8243;&gt;&lt;InputField id=&#8221;nome&#8221; label=&#8221;Nome do Projeto&#8221; value={project.nome} onChange={handleProjectChange} placeholder=&#8221;Ex: Vaso Geom\u00e9trico&#8221; \/&gt;&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;col-span-1&#8243;&gt;&lt;InputField id=&#8221;quantidade_pecas&#8221; label=&#8221;Qtd. Pe\u00e7as (Finalizadas)&#8221; value={project.quantidade_pecas} onChange={handleProjectChange} placeholder=&#8221;1&#8243; helpText=&#8221;Quantidade total de pe\u00e7as finalizadas no lote.&#8221;\/&gt;&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>&lt;div className=&#8221;bg-gradient-to-br from-indigo-50 to-blue-50 p-5 rounded-2xl border border-indigo-100 mb-6 relative overflow-hidden&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;absolute top-0 right-0 w-20 h-20 bg-white opacity-20 rounded-full blur-2xl -mr-10 -mt-10 pointer-events-none&#8221;&gt;&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-2 gap-4 relative z-10&#8243;&gt;<\/div>\n<div>&lt;InputField id=&#8221;gramas_filamento&#8221; label=&#8221;Peso Total&#8221; value={project.gramas_filamento} onChange={handleProjectChange} onBlur={handleWeightBlur} suffix=&#8221;g&#8221; placeholder=&#8221;0&#8243; error={results.missingFields.grams &amp;&amp; &#8220;Obrigat\u00f3rio&#8221;} \/&gt;<\/div>\n<div>&lt;InputField id=&#8221;horas_impressao&#8221; label=&#8221;Tempo Total&#8221; value={project.horas_impressao} onChange={handleProjectChange} onBlur={handleTimeBlur} suffix=&#8221;h&#8221; placeholder=&#8221;0:00&#8243; error={results.missingFields.hours &amp;&amp; &#8220;Obrigat\u00f3rio&#8221;} \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>&lt;div className=&#8221;mb-6&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center mb-3&#8243;&gt;<\/div>\n<div>&lt;label className=&#8221;text-xs font-bold text-gray-500 uppercase tracking-wide&#8221;&gt;Material (Kg)&lt;\/label&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-2&#8243;&gt;<\/div>\n<div>{MATERIAL_PRESETS.map(m =&gt; (<\/div>\n<div>&lt;button key={m.label} onClick={() =&gt; handleProjectChange(&#8216;custo_filamento_kg&#8217;, m.cost)} className=&#8221;text-[10px] font-bold bg-white text-gray-500 px-2 py-1 rounded border border-gray-200 hover:border-indigo-300 hover:text-indigo-600 transition-all uppercase&#8221;&gt;<\/div>\n<div>{m.label}<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>))}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;InputField id=&#8221;custo_filamento_kg&#8221; label=&#8221;&#8221; value={project.custo_filamento_kg} onChange={handleProjectChange} placeholder={settings.custo_filamento_padrao} icon={Package} \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>&lt;div className={`transition-all duration-500 overflow-hidden ${showAdvanced ? &#8216;max-h-[500px] opacity-100&#8217; : &#8216;max-h-0 opacity-0&#8217;}`}&gt;<\/div>\n<div>&lt;div className=&#8221;border-t border-gray-100 pt-6 mt-2&#8243;&gt;<\/div>\n<div>&lt;h4 className=&#8221;text-xs font-bold text-gray-400 uppercase mb-4 flex items-center gap-1.5&#8243;&gt;&lt;TrendingUp size={12}\/&gt; Custos Extras&lt;\/h4&gt;<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-2 gap-4 mb-4&#8243;&gt;<\/div>\n<div>&lt;InputField id=&#8221;custo_outros&#8221; label=&#8221;Outros (Im\u00e3s, etc)&#8221; value={project.custo_outros} onChange={handleProjectChange} placeholder=&#8221;0.00&#8243; \/&gt;<\/div>\n<div>&lt;InputField id=&#8221;custo_embalagem&#8221; label=&#8221;Embalagem&#8221; value={project.custo_embalagem} onChange={handleProjectChange} placeholder=&#8221;0.00&#8243; \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;SliderInput id=&#8221;falha_risco_percentual&#8221; label=&#8221;Margem de Risco&#8221; value={project.falha_risco_percentual} onChange={handleProjectChange} max={50} step={5} presets={[0, 5, 10, 20]} \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div><\/div>\n<div>&lt;div className=&#8221;border-t border-gray-100 pt-6 mt-2&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex items-center gap-2 mb-2&#8243;&gt;<\/div>\n<div>&lt;TrendingUp size={16} className=&#8221;text-indigo-600&#8243;\/&gt;<\/div>\n<div>&lt;span className=&#8221;text-sm font-bold text-gray-800&#8243;&gt;Lucro Desejado&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;SliderInput id=&#8221;margem_lucro_percentual&#8221; label=&#8221;Markup&#8221; value={project.margem_lucro_percentual} onChange={handleProjectChange} max={300} step={10} presets={[50, 100, 150, 200]} \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/Card&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;lg:col-span-7 space-y-6&#8243;&gt;<\/div>\n<div>{results.isValid ? (<\/div>\n<div>&lt;&gt;<\/div>\n<div>&lt;div className=&#8221;relative group perspective-1000&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;absolute -inset-0.5 bg-gradient-to-r from-indigo-500 to-purple-600 rounded-2xl blur opacity-20 group-hover:opacity-40 transition duration-1000 group-hover:duration-200&#8243;&gt;&lt;\/div&gt;<\/div>\n<div>&lt;Card className=&#8221;relative bg-white border-none ring-1 ring-gray-200 overflow-hidden&#8221;&gt;<\/div>\n<div><\/div>\n<div>{\/* === DUAL HERO SECTION (Total vs Unit) === *\/}<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-gray-100&#8243;&gt;<\/div>\n<div><\/div>\n<div>{\/* 1. LADO ESQUERDO: TOTAL DO PROJETO *\/}<\/div>\n<div>&lt;div className=&#8221;p-6 text-center bg-gradient-to-br from-white to-blue-50\/30 flex flex-col justify-between h-full relative overflow-hidden&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;absolute top-0 right-0 p-2 opacity-10&#8243;&gt;&lt;Box size={40} className=&#8221;text-blue-500&#8243;\/&gt;&lt;\/div&gt;<\/div>\n<div>&lt;div&gt;<\/div>\n<div>&lt;p className=&#8221;text-xs font-bold text-blue-400 uppercase tracking-widest mb-1&#8243;&gt;Projeto Completo&lt;\/p&gt;<\/div>\n<div>&lt;div className=&#8221;text-4xl font-black text-gray-800 tracking-tighter drop-shadow-sm mb-1&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-xl text-gray-400 font-bold mr-1&#8243;&gt;R$&lt;\/span&gt;<\/div>\n<div>{formatCurrency(results.finalPrice).replace(&#8216;R$&#8217;, &#8221;)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;mt-4 space-y-2&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center px-3 py-1.5 bg-emerald-50 rounded-lg border border-emerald-100\/50&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-[10px] font-bold text-emerald-600 uppercase&#8221;&gt;Lucro&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;text-sm font-bold text-emerald-700&#8243;&gt;{formatCurrency(results.actualProfit)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center px-3 py-1.5 bg-gray-50 rounded-lg border border-gray-100&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-[10px] font-bold text-gray-400 uppercase&#8221;&gt;Custo&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;text-sm font-bold text-gray-600&#8243;&gt;{formatCurrency(results.totalCost)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{\/* 2. LADO DIREITO: UNIT\u00c1RIO (Se houver &gt; 1 pe\u00e7a) *\/}<\/div>\n<div>{results.P.qty &gt; 1 ? (<\/div>\n<div>&lt;div className=&#8221;p-6 text-center bg-gradient-to-br from-white to-indigo-50\/30 flex flex-col justify-between h-full relative overflow-hidden&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;absolute top-0 right-0 p-2 opacity-10&#8243;&gt;&lt;Coins size={40} className=&#8221;text-indigo-500&#8243;\/&gt;&lt;\/div&gt;<\/div>\n<div>&lt;div&gt;<\/div>\n<div>&lt;p className=&#8221;text-xs font-bold text-indigo-400 uppercase tracking-widest mb-1&#8243;&gt;Por Unidade&lt;\/p&gt;<\/div>\n<div>&lt;div className=&#8221;text-4xl font-black text-indigo-700 tracking-tighter drop-shadow-sm mb-1&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-xl text-indigo-300 font-bold mr-1&#8243;&gt;R$&lt;\/span&gt;<\/div>\n<div>{formatCurrency(results.unitPrice).replace(&#8216;R$&#8217;, &#8221;)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;mt-4 space-y-2&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center px-3 py-1.5 bg-emerald-50 rounded-lg border border-emerald-100\/50&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-[10px] font-bold text-emerald-600 uppercase&#8221;&gt;Lucro&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;text-sm font-bold text-emerald-700&#8243;&gt;{formatCurrency(results.unitProfit)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center px-3 py-1.5 bg-gray-50 rounded-lg border border-gray-100&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;text-[10px] font-bold text-gray-400 uppercase&#8221;&gt;Custo&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;text-sm font-bold text-gray-600&#8243;&gt;{formatCurrency(results.unitTotalCost)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>) : (<\/div>\n<div>\/* Se for s\u00f3 1 pe\u00e7a, ocupa o espa\u00e7o com info extra ou vazio *\/<\/div>\n<div>&lt;div className=&#8221;hidden md:flex p-6 items-center justify-center bg-gray-50\/30&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;text-center text-gray-400&#8243;&gt;<\/div>\n<div>&lt;p className=&#8221;text-xs font-medium mb-2&#8243;&gt;Pe\u00e7a \u00fanica no lote.&lt;\/p&gt;<\/div>\n<div>&lt;button onClick={applyPsychologicalPrice} className=&#8221;text-[10px] font-bold text-indigo-600 bg-white border border-indigo-100 px-3 py-1.5 rounded-full hover:bg-indigo-50 hover:border-indigo-200 transition-all shadow-sm inline-flex items-center gap-1&#8243;&gt;<\/div>\n<div>&lt;Zap size={10} className=&#8221;fill-indigo-600&#8243;\/&gt; Arredondar<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{\/* Round Price Button (Mobile Only or when needed) *\/}<\/div>\n<div>&lt;div className=&#8221;bg-white border-t border-gray-100 p-2 flex justify-center md:hidden&#8221;&gt;<\/div>\n<div>&lt;button onClick={applyPsychologicalPrice} className=&#8221;text-xs font-bold text-indigo-600 bg-indigo-50 px-4 py-1.5 rounded-full hover:bg-indigo-100 transition-colors flex items-center gap-1&#8243;&gt;<\/div>\n<div>&lt;Zap size={12} className=&#8221;fill-indigo-600&#8243;\/&gt; Arredondar Pre\u00e7o<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{\/* Tabela de Detalhes Estilizada *\/}<\/div>\n<div>&lt;div className=&#8221;border-t border-gray-100 bg-white&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;bg-gray-50\/50 px-8 py-3 text-[10px] font-bold text-gray-400 uppercase flex justify-between tracking-wider&#8221;&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3&#8243;&gt;Composi\u00e7\u00e3o&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right&#8221;&gt;Total&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right&#8221;&gt;Unit\u00e1rio&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;divide-y divide-gray-50 text-sm&#8221;&gt;<\/div>\n<div>{[<\/div>\n<div>{ label: &#8216;Filamento&#8217;, val: results.costs.filament, color: &#8216;text-blue-600&#8242;, bg:&#8217;bg-blue-500&#8217; },<\/div>\n<div>{ label: &#8216;Energia&#8217;, val: results.costs.energy, color: &#8216;text-amber-600&#8242;, bg:&#8217;bg-amber-500&#8217; },<\/div>\n<div>{ label: &#8216;Desgaste&#8217;, val: results.costs.depreciation, color: &#8216;text-purple-600&#8242;, bg:&#8217;bg-purple-500&#8217; },<\/div>\n<div>{ label: &#8216;Risco&#8217;, val: results.costs.risk, color: &#8216;text-rose-500&#8242;, bg:&#8217;bg-rose-500&#8217; },<\/div>\n<div>{ label: &#8216;Extras&#8217;, val: results.costs.totalExtras, color: &#8216;text-gray-600&#8242;, bg:&#8217;bg-gray-400&#8217; },<\/div>\n<div>].map((row, idx) =&gt; (<\/div>\n<div>&lt;div key={idx} className=&#8221;px-8 py-3 flex justify-between hover:bg-gray-50 transition-colors group&#8221;&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 font-semibold text-gray-700 flex items-center gap-2&#8243;&gt;<\/div>\n<div>&lt;span className={`w-2 h-2 rounded-full ${row.bg}`}&gt;&lt;\/span&gt; {row.label}<\/div>\n<div>&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right font-medium text-gray-900&#8243;&gt;{formatCurrency(row.val)}&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right text-gray-400 font-mono text-xs pt-0.5&#8243;&gt;{formatCurrency(row.val \/ results.P.qty)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>))}<\/div>\n<div>&lt;div className=&#8221;px-8 py-3 flex justify-between bg-gray-50\/80 font-bold border-t border-gray-100&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-gray-800 text-xs uppercase pt-0.5&#8243;&gt;Custo Total&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right text-gray-800&#8243;&gt;{formatCurrency(results.totalCost)}&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right text-gray-500 font-mono text-xs pt-0.5&#8243;&gt;{formatCurrency(results.unitTotalCost)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;px-8 py-4 bg-emerald-50\/30 flex justify-between items-center border-t border-emerald-100\/50&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;w-1\/3&#8243;&gt;&lt;span className=&#8221;block font-bold text-emerald-700 text-xs uppercase&#8221;&gt;Lucro L\u00edquido&lt;\/span&gt;&lt;\/div&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right font-bold text-emerald-700 text-lg&#8221;&gt;{formatCurrency(results.actualProfit)}&lt;\/span&gt;<\/div>\n<div>&lt;span className=&#8221;w-1\/3 text-right font-bold text-emerald-600\/70 font-mono text-sm&#8221;&gt;{formatCurrency(results.actualProfit \/ results.P.qty)}&lt;\/span&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{\/* Actions Footer *\/}<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-1 sm:grid-cols-4 border-t border-gray-100 divide-y sm:divide-y-0 sm:divide-x divide-gray-100 bg-gray-50\/30&#8243;&gt;<\/div>\n<div>&lt;button onClick={() =&gt; saveToHistory()} className=&#8221;py-4 text-xs font-bold text-gray-500 hover:bg-white hover:text-indigo-600 flex justify-center items-center gap-2 transition-all uppercase tracking-wide group&#8221;&gt;<\/div>\n<div>&lt;Save size={18} className=&#8221;text-gray-400 group-hover:text-indigo-500 transition-colors&#8221; \/&gt; Salvar<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;button onClick={exportToCSV} className=&#8221;py-4 text-xs font-bold text-gray-500 hover:bg-white hover:text-emerald-600 flex justify-center items-center gap-2 transition-all uppercase tracking-wide group&#8221;&gt;<\/div>\n<div>&lt;FileSpreadsheet size={18} className=&#8221;text-gray-400 group-hover:text-emerald-500 transition-colors&#8221; \/&gt; CSV<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>{\/* Bot\u00e3o Copy to Sheets *\/}<\/div>\n<div>&lt;button onClick={copyToSheets} className=&#8221;py-4 text-xs font-bold text-gray-500 hover:bg-white hover:text-blue-600 flex justify-center items-center gap-2 transition-all uppercase tracking-wide group&#8221;&gt;<\/div>\n<div>&lt;Copy size={18} className=&#8221;text-gray-400 group-hover:text-blue-500 transition-colors&#8221; \/&gt; Sheets<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;button onClick={openWhatsApp} className=&#8221;py-4 text-xs font-bold text-gray-500 hover:bg-white hover:text-green-600 flex justify-center items-center gap-2 transition-all uppercase tracking-wide group&#8221;&gt;<\/div>\n<div>&lt;MessageCircle size={18} className=&#8221;text-gray-400 group-hover:text-green-500 transition-colors&#8221; \/&gt; Enviar<\/div>\n<div>&lt;\/button&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/Card&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{results.isLowProfit &amp;&amp; (<\/div>\n<div>&lt;div className=&#8221;bg-red-50 border border-red-200 p-5 rounded-xl flex items-start gap-4 animate-fade-in shadow-sm&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;bg-red-100 p-2 rounded-full&#8221;&gt;<\/div>\n<div>&lt;TrendingUp className=&#8221;text-red-600 w-5 h-5&#8243; \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;flex-1&#8243;&gt;<\/div>\n<div>&lt;span className=&#8221;font-bold text-red-900 block text-sm mb-1 uppercase tracking-wide&#8221;&gt;Lucro Insuficiente&lt;\/span&gt;<\/div>\n<div>&lt;p className=&#8221;text-xs text-red-700 mb-2&#8243;&gt;<\/div>\n<div>O lucro atual ({formatCurrency(results.actualProfit)}) est\u00e1 abaixo do m\u00ednimo configurado de {formatCurrency(results.S.minProfit)}.<\/div>\n<div>&lt;\/p&gt;<\/div>\n<div>&lt;div className=&#8221;bg-white\/60 p-2 rounded-lg inline-block border border-red-100&#8243;&gt;<\/div>\n<div>&lt;p className=&#8221;text-xs font-bold text-red-800&#8243;&gt;<\/div>\n<div>Pre\u00e7o Sugerido: &lt;span className=&#8221;text-sm&#8221;&gt;{formatCurrency(results.suggestedPriceMinProfit)}&lt;\/span&gt;<\/div>\n<div>&lt;\/p&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;Card className=&#8221;p-8&#8243;&gt;<\/div>\n<div>&lt;div className=&#8221;flex justify-between items-center mb-6&#8243;&gt;<\/div>\n<div>&lt;h3 className=&#8221;font-bold text-gray-700 text-xs uppercase tracking-widest flex items-center gap-2&#8243;&gt;<\/div>\n<div>&lt;Info size={14}\/&gt; Raio-X Visual<\/div>\n<div>&lt;\/h3&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;space-y-4&#8243;&gt;<\/div>\n<div>&lt;ProgressBar label=&#8221;Material&#8221; value={results.costs.filament} total={results.finalPrice} colorClass=&#8221;bg-blue-500&#8243; \/&gt;<\/div>\n<div>&lt;div className=&#8221;grid grid-cols-2 gap-8&#8243;&gt;<\/div>\n<div>&lt;ProgressBar label=&#8221;Energia&#8221; value={results.costs.energy} total={results.finalPrice} colorClass=&#8221;bg-amber-400&#8243; \/&gt;<\/div>\n<div>&lt;ProgressBar label=&#8221;Desgaste&#8221; value={results.costs.depreciation} total={results.finalPrice} colorClass=&#8221;bg-purple-500&#8243; \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>{(results.costs.risk &gt; 0) &amp;&amp; &lt;ProgressBar label=&#8221;Risco&#8221; value={results.costs.risk} total={results.finalPrice} colorClass=&#8221;bg-rose-400&#8243; \/&gt;}<\/div>\n<div>{(results.costs.totalExtras &gt; 0) &amp;&amp; &lt;ProgressBar label=&#8221;Extras&#8221; value={results.costs.totalExtras} total={results.finalPrice} colorClass=&#8221;bg-gray-400&#8243; \/&gt;}<\/div>\n<div>&lt;div className=&#8221;pt-2 border-t border-gray-100 mt-2&#8243;&gt;<\/div>\n<div>&lt;ProgressBar label=&#8221;Lucro L\u00edquido&#8221; value={results.actualProfit} total={results.finalPrice} colorClass=&#8221;bg-emerald-500&#8243; \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/Card&gt;<\/div>\n<div>&lt;\/&gt;<\/div>\n<div>) : (<\/div>\n<div>&lt;div className=&#8221;h-full flex flex-col items-center justify-center text-center p-12 border-2 border-dashed border-gray-200 rounded-3xl bg-gray-50\/50 hover:bg-gray-50 transition-colors&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;bg-white p-6 rounded-3xl shadow-sm mb-6 animate-float&#8221;&gt;<\/div>\n<div>&lt;Calculator size={48} className=&#8221;text-indigo-200 stroke-1&#8243; \/&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;h3 className=&#8221;text-xl font-bold text-gray-800 mb-2&#8243;&gt;Vamos come\u00e7ar?&lt;\/h3&gt;<\/div>\n<div>&lt;p className=&#8221;text-gray-400 font-medium max-w-xs mx-auto mb-8&#8243;&gt;<\/div>\n<div>Preencha o &lt;strong&gt;peso&lt;\/strong&gt; e o &lt;strong&gt;tempo&lt;\/strong&gt; para gerar seu or\u00e7amento detalhado.<\/div>\n<div>&lt;\/p&gt;<\/div>\n<div>&lt;div className=&#8221;flex gap-2 justify-center&#8221;&gt;<\/div>\n<div>&lt;div className=&#8221;w-2 h-2 rounded-full bg-gray-300&#8243;&gt;&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;w-2 h-2 rounded-full bg-gray-300&#8243;&gt;&lt;\/div&gt;<\/div>\n<div>&lt;div className=&#8221;w-2 h-2 rounded-full bg-gray-300&#8243;&gt;&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>)}<\/div>\n<div>&lt;\/main&gt;<\/div>\n<div>&lt;\/div&gt;<\/div>\n<div>);<\/div>\n<div>}<\/div>\n<\/div>\n<\/blockquote>\n<p>O post C\u00f3digo Calculadora Impress\u00e3o 3D feita no Gemini apareceu primeiro em Zoom Digital.<\/p>\n<p><a href=\"https:\/\/zoomdigital.com.br\/codigo-calculadora-impressao-3d-feita-no-gemini\/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=codigo-calculadora-impressao-3d-feita-no-gemini\">Fonte <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>C\u00f3digo da calculadora mostrada no v\u00eddeo: &nbsp; import React, { useState, useEffect, useMemo } from &#8216;react&#8217;; import { Calculator, Settings, Save, Trash2, AlertCircle, TrendingUp, Package, Zap, Clock, Info, Download, History, MessageCircle, Sliders, CheckCircle2, Share2, FileSpreadsheet, HelpCircle, X, ChevronRight, Copy, Coins, Box } from &#8216;lucide-react&#8217;; \/\/ [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-11802","post","type-post","status-publish","format-standard","hentry","category-noticias"],"_links":{"self":[{"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/posts\/11802","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/comments?post=11802"}],"version-history":[{"count":0,"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/posts\/11802\/revisions"}],"wp:attachment":[{"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/media?parent=11802"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/categories?post=11802"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rmts.com.br\/wp-01\/wp-json\/wp\/v2\/tags?post=11802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}