lakshmisravya123 commited on
Commit
efceb0f
·
1 Parent(s): 91dfcf4

Major upgrade: comprehensive debate analysis

Browse files
backend/services/ai.js CHANGED
@@ -8,7 +8,7 @@ async function callAI(prompt) {
8
  const res = await fetch('https://api.groq.com/openai/v1/chat/completions', {
9
  method: 'POST',
10
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${GROQ_API_KEY}` },
11
- body: JSON.stringify({ model: GROQ_MODEL, messages: [{ role: 'user', content: prompt }], temperature: 0.7 }),
12
  });
13
  if (res.ok) { const data = await res.json(); return data.choices[0].message.content; }
14
  console.warn('Groq failed, falling back to Ollama...');
@@ -28,7 +28,7 @@ function parseJSON(text) {
28
  }
29
 
30
  async function settleArgument(topic, side1Name, side1Argument, side2Name, side2Argument) {
31
- const text = await callAI(`You are "The Settler" - a fair, witty, and brutally honest judge of arguments. You analyze both sides objectively.
32
 
33
  TOPIC: ${topic}
34
 
@@ -38,27 +38,54 @@ ${side1Argument}
38
  ${side2Name}'s ARGUMENT:
39
  ${side2Argument}
40
 
41
- Analyze both arguments thoroughly. Return ONLY valid JSON:
 
 
 
 
 
 
 
42
  {
43
  "topic": "<topic summary>",
44
  "side1": {
45
  "name": "${side1Name}",
46
  "score": <1-100>,
47
- "strengths": ["<s1>", "<s2>"],
48
- "weaknesses": ["<w1>", "<w2>"],
49
- "devilsAdvocate": "<2-3 sentences arguing AGAINST this side>"
 
 
 
 
 
 
 
50
  },
51
  "side2": {
52
  "name": "${side2Name}",
53
  "score": <1-100>,
54
- "strengths": ["<s1>", "<s2>"],
55
- "weaknesses": ["<w1>", "<w2>"],
56
- "devilsAdvocate": "<2-3 sentences arguing AGAINST this side>"
 
 
 
 
 
 
 
57
  },
58
  "winner": "<name of winner or 'Draw'>",
59
- "verdict": "<3-4 sentence witty final verdict explaining who won and why>",
60
- "commonGround": "<1-2 sentences on where both sides actually agree>",
61
- "plotTwist": "<a surprising perspective neither side considered>"
 
 
 
 
 
 
62
  }
63
 
64
  Return ONLY JSON, no markdown.`);
 
8
  const res = await fetch('https://api.groq.com/openai/v1/chat/completions', {
9
  method: 'POST',
10
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${GROQ_API_KEY}` },
11
+ body: JSON.stringify({ model: GROQ_MODEL, messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 4096 }),
12
  });
13
  if (res.ok) { const data = await res.json(); return data.choices[0].message.content; }
14
  console.warn('Groq failed, falling back to Ollama...');
 
28
  }
29
 
30
  async function settleArgument(topic, side1Name, side1Argument, side2Name, side2Argument) {
31
+ const text = await callAI(`You are "The Settler" - a world-class debate judge with expertise in logic, rhetoric, and critical thinking. You combine the analytical rigor of a philosophy professor with the wit of a late-night show host.
32
 
33
  TOPIC: ${topic}
34
 
 
38
  ${side2Name}'s ARGUMENT:
39
  ${side2Argument}
40
 
41
+ Perform a DEEP analysis of both arguments. Check for:
42
+ - Logical fallacies (ad hominem, straw man, false dichotomy, appeal to authority, slippery slope, etc.)
43
+ - Evidence quality (anecdotal, statistical, expert opinion, common sense)
44
+ - Emotional vs rational reasoning balance
45
+ - Bias and assumptions
46
+ - Argument structure and coherence
47
+
48
+ Return ONLY valid JSON:
49
  {
50
  "topic": "<topic summary>",
51
  "side1": {
52
  "name": "${side1Name}",
53
  "score": <1-100>,
54
+ "persuasivenessScore": <1-100>,
55
+ "factualScore": <1-100>,
56
+ "emotionalVsRational": { "emotional": <0-100>, "rational": <0-100> },
57
+ "strengths": ["<specific strength 1>", "<specific strength 2>", "<strength 3>"],
58
+ "weaknesses": ["<specific weakness 1>", "<weakness 2>"],
59
+ "fallacies": [{ "name": "<fallacy name>", "quote": "<the part that commits it>", "explanation": "<why it's a fallacy>" }],
60
+ "evidenceQuality": "<anecdotal/statistical/expert/mixed - with explanation>",
61
+ "devilsAdvocate": "<3 sentences arguing AGAINST this side>",
62
+ "steelMan": "<The strongest possible version of this argument rewritten in 2-3 sentences>",
63
+ "whatWouldChangeTheirMind": "<What evidence or argument would make this person reconsider?>"
64
  },
65
  "side2": {
66
  "name": "${side2Name}",
67
  "score": <1-100>,
68
+ "persuasivenessScore": <1-100>,
69
+ "factualScore": <1-100>,
70
+ "emotionalVsRational": { "emotional": <0-100>, "rational": <0-100> },
71
+ "strengths": ["<specific strength 1>", "<specific strength 2>", "<strength 3>"],
72
+ "weaknesses": ["<specific weakness 1>", "<weakness 2>"],
73
+ "fallacies": [{ "name": "<fallacy name>", "quote": "<the part that commits it>", "explanation": "<why it's a fallacy>" }],
74
+ "evidenceQuality": "<anecdotal/statistical/expert/mixed - with explanation>",
75
+ "devilsAdvocate": "<3 sentences arguing AGAINST this side>",
76
+ "steelMan": "<The strongest possible version of this argument rewritten in 2-3 sentences>",
77
+ "whatWouldChangeTheirMind": "<What evidence or argument would make this person reconsider?>"
78
  },
79
  "winner": "<name of winner or 'Draw'>",
80
+ "verdict": "<4-5 sentence witty final verdict with specific reasoning>",
81
+ "commonGround": "<2-3 sentences on where both sides actually agree>",
82
+ "plotTwist": "<A surprising perspective neither side considered>",
83
+ "biasCheck": "<Any shared biases or blind spots both arguers have>",
84
+ "compromise": "<A detailed middle-ground solution that could satisfy both sides>",
85
+ "debateTips": {
86
+ "side1Tip": "<Specific advice for ${side1Name} on how to argue better>",
87
+ "side2Tip": "<Specific advice for ${side2Name} on how to argue better>"
88
+ }
89
  }
90
 
91
  Return ONLY JSON, no markdown.`);
backend/services/ai.js.backup ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const GROQ_API_KEY = process.env.GROQ_API_KEY;
2
+ const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
3
+ const GROQ_MODEL = process.env.GROQ_MODEL || 'llama-3.3-70b-versatile';
4
+ const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'llama3.2:3b';
5
+
6
+ async function callAI(prompt) {
7
+ if (GROQ_API_KEY) {
8
+ const res = await fetch('https://api.groq.com/openai/v1/chat/completions', {
9
+ method: 'POST',
10
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${GROQ_API_KEY}` },
11
+ body: JSON.stringify({ model: GROQ_MODEL, messages: [{ role: 'user', content: prompt }], temperature: 0.7 }),
12
+ });
13
+ if (res.ok) { const data = await res.json(); return data.choices[0].message.content; }
14
+ console.warn('Groq failed, falling back to Ollama...');
15
+ }
16
+ const res = await fetch(`${OLLAMA_URL}/api/generate`, {
17
+ method: 'POST',
18
+ headers: { 'Content-Type': 'application/json' },
19
+ body: JSON.stringify({ model: OLLAMA_MODEL, prompt, stream: false }),
20
+ });
21
+ if (!res.ok) throw new Error('Both Groq and Ollama failed.');
22
+ return (await res.json()).response;
23
+ }
24
+
25
+ function parseJSON(text) {
26
+ try { return JSON.parse(text.trim()); }
27
+ catch { const m = text.match(/\{[\s\S]*\}/); if (m) return JSON.parse(m[0]); throw new Error('Failed to parse AI response'); }
28
+ }
29
+
30
+ async function settleArgument(topic, side1Name, side1Argument, side2Name, side2Argument) {
31
+ const text = await callAI(`You are "The Settler" - a fair, witty, and brutally honest judge of arguments. You analyze both sides objectively.
32
+
33
+ TOPIC: ${topic}
34
+
35
+ ${side1Name}'s ARGUMENT:
36
+ ${side1Argument}
37
+
38
+ ${side2Name}'s ARGUMENT:
39
+ ${side2Argument}
40
+
41
+ Analyze both arguments thoroughly. Return ONLY valid JSON:
42
+ {
43
+ "topic": "<topic summary>",
44
+ "side1": {
45
+ "name": "${side1Name}",
46
+ "score": <1-100>,
47
+ "strengths": ["<s1>", "<s2>"],
48
+ "weaknesses": ["<w1>", "<w2>"],
49
+ "devilsAdvocate": "<2-3 sentences arguing AGAINST this side>"
50
+ },
51
+ "side2": {
52
+ "name": "${side2Name}",
53
+ "score": <1-100>,
54
+ "strengths": ["<s1>", "<s2>"],
55
+ "weaknesses": ["<w1>", "<w2>"],
56
+ "devilsAdvocate": "<2-3 sentences arguing AGAINST this side>"
57
+ },
58
+ "winner": "<name of winner or 'Draw'>",
59
+ "verdict": "<3-4 sentence witty final verdict explaining who won and why>",
60
+ "commonGround": "<1-2 sentences on where both sides actually agree>",
61
+ "plotTwist": "<a surprising perspective neither side considered>"
62
+ }
63
+
64
+ Return ONLY JSON, no markdown.`);
65
+ return parseJSON(text);
66
+ }
67
+
68
+ module.exports = { settleArgument };
frontend/src/App.jsx CHANGED
@@ -1,6 +1,73 @@
1
  import { useState } from 'react';
2
  import { settleArgument } from './utils/api';
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  export default function App() {
5
  const [topic, setTopic] = useState('');
6
  const [side1Name, setSide1Name] = useState('');
@@ -44,7 +111,7 @@ export default function App() {
44
  <div className="loading">
45
  <div className="spinner"></div>
46
  <p>The Settler is analyzing both sides...</p>
47
- <p style={{ color: '#888', marginTop: '0.5rem', fontSize: '0.9rem' }}>Playing devil's advocate for each argument</p>
48
  </div>
49
  </div>
50
  );
@@ -55,53 +122,75 @@ export default function App() {
55
  <div className="app">
56
  <h1><span>Argument Settler</span></h1>
57
  <div className="results">
 
58
  <div className="verdict-card">
59
  <div style={{ fontSize: '0.9rem', color: '#888', marginBottom: '0.5rem' }}>THE WINNER IS</div>
60
  <div className="winner-name">{result.winner === 'Draw' ? "It's a Draw!" : result.winner}</div>
61
  <div className="verdict-text">{result.verdict}</div>
62
  </div>
63
 
 
64
  <div className="scores">
65
  <div className="score-card left">
66
  <h3>{result.side1?.name}</h3>
67
- <div className="score-number">{result.side1?.score}/100</div>
68
  </div>
 
69
  <div className="score-card right">
70
  <h3>{result.side2?.name}</h3>
71
- <div className="score-number">{result.side2?.score}/100</div>
72
  </div>
73
  </div>
74
 
 
75
  <div className="scores">
76
- <div className="detail-section">
77
- <h4>{result.side1?.name}'s Strengths</h4>
78
- <ul>{result.side1?.strengths?.map((s, i) => <li key={i}>{s}</li>)}</ul>
79
- <h4 style={{ marginTop: '1rem' }}>Weaknesses</h4>
80
- <ul>{result.side1?.weaknesses?.map((w, i) => <li key={i}>{w}</li>)}</ul>
81
- <h4 style={{ marginTop: '1rem', color: '#ff6b6b' }}>Devil's Advocate</h4>
82
- <p style={{ color: '#bbb' }}>{result.side1?.devilsAdvocate}</p>
83
- </div>
84
- <div className="detail-section">
85
- <h4>{result.side2?.name}'s Strengths</h4>
86
- <ul>{result.side2?.strengths?.map((s, i) => <li key={i}>{s}</li>)}</ul>
87
- <h4 style={{ marginTop: '1rem' }}>Weaknesses</h4>
88
- <ul>{result.side2?.weaknesses?.map((w, i) => <li key={i}>{w}</li>)}</ul>
89
- <h4 style={{ marginTop: '1rem', color: '#4ecdc4' }}>Devil's Advocate</h4>
90
- <p style={{ color: '#bbb' }}>{result.side2?.devilsAdvocate}</p>
91
- </div>
92
  </div>
93
 
 
 
 
 
 
 
 
 
 
94
  {result.commonGround && (
95
- <div className="detail-section">
96
  <h4>Common Ground</h4>
97
- <p style={{ color: '#bbb' }}>{result.commonGround}</p>
 
 
 
 
 
 
 
 
98
  </div>
99
  )}
100
 
 
101
  {result.plotTwist && (
102
  <div className="plot-twist">
103
  <h4>Plot Twist</h4>
104
- <p style={{ color: '#bbb' }}>{result.plotTwist}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  </div>
106
  )}
107
 
@@ -114,7 +203,7 @@ export default function App() {
114
  return (
115
  <div className="app">
116
  <h1><span>Argument Settler</span></h1>
117
- <p className="subtitle">AI judges both sides fairly. No more endless debates.</p>
118
 
119
  {error && <p style={{ color: '#ff6b6b', textAlign: 'center', marginBottom: '1rem' }}>{error}</p>}
120
 
 
1
  import { useState } from 'react';
2
  import { settleArgument } from './utils/api';
3
 
4
+ function ScoreBar({ label, value, color }) {
5
+ return (
6
+ <div className="score-bar-wrap">
7
+ <div className="score-bar-label">{label}</div>
8
+ <div className="score-bar-track">
9
+ <div className="score-bar-fill" style={{ width: `${value}%`, background: color }}></div>
10
+ </div>
11
+ <span className="score-bar-val">{value}</span>
12
+ </div>
13
+ );
14
+ }
15
+
16
+ function SidePanel({ side, color, accentClass }) {
17
+ return (
18
+ <div className={`detail-section ${accentClass}`}>
19
+ <h3 style={{ color }}>{side.name}</h3>
20
+
21
+ <div className="mini-scores">
22
+ <ScoreBar label="Overall" value={side.score} color={color} />
23
+ <ScoreBar label="Persuasiveness" value={side.persuasivenessScore} color={color} />
24
+ <ScoreBar label="Factual Accuracy" value={side.factualScore} color={color} />
25
+ </div>
26
+
27
+ {side.emotionalVsRational && (
28
+ <div className="emo-rational">
29
+ <span>Emotional {side.emotionalVsRational.emotional}%</span>
30
+ <div className="emo-bar">
31
+ <div className="emo-fill" style={{ width: `${side.emotionalVsRational.emotional}%` }}></div>
32
+ </div>
33
+ <span>Rational {side.emotionalVsRational.rational}%</span>
34
+ </div>
35
+ )}
36
+
37
+ <h4>Strengths</h4>
38
+ <ul className="list-good">{side.strengths?.map((s, i) => <li key={i}>{s}</li>)}</ul>
39
+
40
+ <h4>Weaknesses</h4>
41
+ <ul className="list-bad">{side.weaknesses?.map((w, i) => <li key={i}>{w}</li>)}</ul>
42
+
43
+ {side.fallacies?.length > 0 && (
44
+ <>
45
+ <h4>Logical Fallacies Detected</h4>
46
+ {side.fallacies.map((f, i) => (
47
+ <div className="fallacy-card" key={i}>
48
+ <span className="fallacy-name">{f.name}</span>
49
+ {f.quote && <p className="fallacy-quote">"{f.quote}"</p>}
50
+ <p className="fallacy-explain">{f.explanation}</p>
51
+ </div>
52
+ ))}
53
+ </>
54
+ )}
55
+
56
+ <h4>Evidence Quality</h4>
57
+ <p className="info-text">{side.evidenceQuality}</p>
58
+
59
+ <h4 style={{ color: '#ff6b6b' }}>Devil's Advocate</h4>
60
+ <p className="info-text">{side.devilsAdvocate}</p>
61
+
62
+ <h4 style={{ color: '#4ade80' }}>Steel Man (Strongest Version)</h4>
63
+ <p className="info-text">{side.steelMan}</p>
64
+
65
+ <h4>What Would Change Their Mind?</h4>
66
+ <p className="info-text">{side.whatWouldChangeTheirMind}</p>
67
+ </div>
68
+ );
69
+ }
70
+
71
  export default function App() {
72
  const [topic, setTopic] = useState('');
73
  const [side1Name, setSide1Name] = useState('');
 
111
  <div className="loading">
112
  <div className="spinner"></div>
113
  <p>The Settler is analyzing both sides...</p>
114
+ <p style={{ color: '#888', marginTop: '0.5rem', fontSize: '0.9rem' }}>Checking for logical fallacies, biases, and evidence quality</p>
115
  </div>
116
  </div>
117
  );
 
122
  <div className="app">
123
  <h1><span>Argument Settler</span></h1>
124
  <div className="results">
125
+ {/* Verdict */}
126
  <div className="verdict-card">
127
  <div style={{ fontSize: '0.9rem', color: '#888', marginBottom: '0.5rem' }}>THE WINNER IS</div>
128
  <div className="winner-name">{result.winner === 'Draw' ? "It's a Draw!" : result.winner}</div>
129
  <div className="verdict-text">{result.verdict}</div>
130
  </div>
131
 
132
+ {/* Score comparison */}
133
  <div className="scores">
134
  <div className="score-card left">
135
  <h3>{result.side1?.name}</h3>
136
+ <div className="score-number">{result.side1?.score}<span>/100</span></div>
137
  </div>
138
+ <div className="vs-badge">VS</div>
139
  <div className="score-card right">
140
  <h3>{result.side2?.name}</h3>
141
+ <div className="score-number">{result.side2?.score}<span>/100</span></div>
142
  </div>
143
  </div>
144
 
145
+ {/* Detailed panels */}
146
  <div className="scores">
147
+ {result.side1 && <SidePanel side={result.side1} color="#ff6b6b" accentClass="accent-left" />}
148
+ {result.side2 && <SidePanel side={result.side2} color="#4ecdc4" accentClass="accent-right" />}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  </div>
150
 
151
+ {/* Bias Check */}
152
+ {result.biasCheck && (
153
+ <div className="insight-card bias">
154
+ <h4>Shared Bias Check</h4>
155
+ <p>{result.biasCheck}</p>
156
+ </div>
157
+ )}
158
+
159
+ {/* Common Ground */}
160
  {result.commonGround && (
161
+ <div className="insight-card common">
162
  <h4>Common Ground</h4>
163
+ <p>{result.commonGround}</p>
164
+ </div>
165
+ )}
166
+
167
+ {/* Compromise */}
168
+ {result.compromise && (
169
+ <div className="insight-card compromise">
170
+ <h4>Suggested Compromise</h4>
171
+ <p>{result.compromise}</p>
172
  </div>
173
  )}
174
 
175
+ {/* Plot Twist */}
176
  {result.plotTwist && (
177
  <div className="plot-twist">
178
  <h4>Plot Twist</h4>
179
+ <p>{result.plotTwist}</p>
180
+ </div>
181
+ )}
182
+
183
+ {/* Debate Tips */}
184
+ {result.debateTips && (
185
+ <div className="scores">
186
+ <div className="insight-card tip-left">
187
+ <h4>Tip for {result.side1?.name}</h4>
188
+ <p>{result.debateTips.side1Tip}</p>
189
+ </div>
190
+ <div className="insight-card tip-right">
191
+ <h4>Tip for {result.side2?.name}</h4>
192
+ <p>{result.debateTips.side2Tip}</p>
193
+ </div>
194
  </div>
195
  )}
196
 
 
203
  return (
204
  <div className="app">
205
  <h1><span>Argument Settler</span></h1>
206
+ <p className="subtitle">AI debate judge with logical fallacy detection, evidence scoring, and bias analysis.</p>
207
 
208
  {error && <p style={{ color: '#ff6b6b', textAlign: 'center', marginBottom: '1rem' }}>{error}</p>}
209
 
frontend/src/styles/global.css CHANGED
@@ -1,11 +1,10 @@
1
  * { margin: 0; padding: 0; box-sizing: border-box; }
2
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0a0a0f; color: #e0e0e0; min-height: 100vh; }
3
- .app { max-width: 900px; margin: 0 auto; padding: 2rem 1rem; }
4
  h1 { text-align: center; font-size: 2.5rem; margin-bottom: 0.5rem; }
5
  h1 span { background: linear-gradient(135deg, #ff6b6b, #ffd93d); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
6
  .subtitle { text-align: center; color: #888; margin-bottom: 2rem; }
7
  .form-section { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; margin-bottom: 1.5rem; }
8
- .form-section h3 { margin-bottom: 1rem; color: #ffd93d; }
9
  .input-group { margin-bottom: 1rem; }
10
  .input-group label { display: block; margin-bottom: 0.3rem; color: #aaa; font-size: 0.9rem; }
11
  .input-group input, .input-group textarea { width: 100%; padding: 0.8rem; border: 1px solid #333; border-radius: 8px; background: #12121a; color: #e0e0e0; font-size: 1rem; }
@@ -16,25 +15,76 @@ h1 span { background: linear-gradient(135deg, #ff6b6b, #ffd93d); -webkit-backgro
16
  .side.right { border-top: 3px solid #4ecdc4; }
17
  .btn { width: 100%; padding: 1rem; border: none; border-radius: 8px; font-size: 1.1rem; font-weight: 600; cursor: pointer; background: linear-gradient(135deg, #ff6b6b, #ffd93d); color: #000; transition: transform 0.2s; }
18
  .btn:hover { transform: scale(1.02); }
19
- .btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
20
  .loading { text-align: center; padding: 3rem; }
21
  .loading .spinner { width: 50px; height: 50px; border: 4px solid #333; border-top-color: #ffd93d; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1rem; }
22
  @keyframes spin { to { transform: rotate(360deg); } }
23
- .results { margin-top: 2rem; }
 
24
  .verdict-card { background: linear-gradient(135deg, #1a1a2e, #16213e); border-radius: 12px; padding: 2rem; text-align: center; margin-bottom: 2rem; border: 1px solid #333; }
25
  .winner-name { font-size: 2rem; font-weight: 700; color: #ffd93d; margin-bottom: 0.5rem; }
26
- .verdict-text { color: #ccc; font-size: 1.1rem; line-height: 1.6; }
27
- .scores { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 2rem; }
28
- .score-card { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; }
 
29
  .score-card h3 { margin-bottom: 0.5rem; }
30
  .score-number { font-size: 2.5rem; font-weight: 700; }
 
31
  .score-card.left .score-number { color: #ff6b6b; }
32
  .score-card.right .score-number { color: #4ecdc4; }
33
- .detail-section { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; margin-bottom: 1rem; }
34
- .detail-section h4 { color: #ffd93d; margin-bottom: 0.8rem; }
 
 
 
35
  .detail-section ul { padding-left: 1.2rem; }
36
- .detail-section li { margin-bottom: 0.4rem; color: #bbb; }
37
- .plot-twist { background: linear-gradient(135deg, #2d1b69, #1a1a2e); border-radius: 12px; padding: 1.5rem; margin-top: 1.5rem; border: 1px solid #6c5ce7; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  .plot-twist h4 { color: #a29bfe; margin-bottom: 0.5rem; }
 
 
39
  .back-btn { background: #333; color: #fff; margin-top: 1.5rem; }
40
- @media (max-width: 768px) { .sides-container, .scores { grid-template-columns: 1fr; } h1 { font-size: 1.8rem; } }
 
1
  * { margin: 0; padding: 0; box-sizing: border-box; }
2
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0a0a0f; color: #e0e0e0; min-height: 100vh; }
3
+ .app { max-width: 950px; margin: 0 auto; padding: 2rem 1rem; }
4
  h1 { text-align: center; font-size: 2.5rem; margin-bottom: 0.5rem; }
5
  h1 span { background: linear-gradient(135deg, #ff6b6b, #ffd93d); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
6
  .subtitle { text-align: center; color: #888; margin-bottom: 2rem; }
7
  .form-section { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; margin-bottom: 1.5rem; }
 
8
  .input-group { margin-bottom: 1rem; }
9
  .input-group label { display: block; margin-bottom: 0.3rem; color: #aaa; font-size: 0.9rem; }
10
  .input-group input, .input-group textarea { width: 100%; padding: 0.8rem; border: 1px solid #333; border-radius: 8px; background: #12121a; color: #e0e0e0; font-size: 1rem; }
 
15
  .side.right { border-top: 3px solid #4ecdc4; }
16
  .btn { width: 100%; padding: 1rem; border: none; border-radius: 8px; font-size: 1.1rem; font-weight: 600; cursor: pointer; background: linear-gradient(135deg, #ff6b6b, #ffd93d); color: #000; transition: transform 0.2s; }
17
  .btn:hover { transform: scale(1.02); }
 
18
  .loading { text-align: center; padding: 3rem; }
19
  .loading .spinner { width: 50px; height: 50px; border: 4px solid #333; border-top-color: #ffd93d; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1rem; }
20
  @keyframes spin { to { transform: rotate(360deg); } }
21
+ .results { margin-top: 1rem; animation: fadeIn 0.4s ease; }
22
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
23
  .verdict-card { background: linear-gradient(135deg, #1a1a2e, #16213e); border-radius: 12px; padding: 2rem; text-align: center; margin-bottom: 2rem; border: 1px solid #333; }
24
  .winner-name { font-size: 2rem; font-weight: 700; color: #ffd93d; margin-bottom: 0.5rem; }
25
+ .verdict-text { color: #ccc; font-size: 1.05rem; line-height: 1.6; }
26
+ .scores { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 1.5rem; position: relative; }
27
+ .vs-badge { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); background: #ffd93d; color: #000; font-weight: 800; font-size: 0.8rem; padding: 0.4rem 0.7rem; border-radius: 20px; z-index: 1; }
28
+ .score-card { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; text-align: center; }
29
  .score-card h3 { margin-bottom: 0.5rem; }
30
  .score-number { font-size: 2.5rem; font-weight: 700; }
31
+ .score-number span { font-size: 1rem; color: #888; }
32
  .score-card.left .score-number { color: #ff6b6b; }
33
  .score-card.right .score-number { color: #4ecdc4; }
34
+
35
+ /* Detail panels */
36
+ .detail-section { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; }
37
+ .detail-section h3 { margin-bottom: 1rem; font-size: 1.2rem; }
38
+ .detail-section h4 { color: #ffd93d; margin: 1rem 0 0.5rem; font-size: 0.95rem; }
39
  .detail-section ul { padding-left: 1.2rem; }
40
+ .detail-section li { margin-bottom: 0.4rem; color: #bbb; line-height: 1.4; }
41
+ .accent-left { border-left: 3px solid #ff6b6b; }
42
+ .accent-right { border-left: 3px solid #4ecdc4; }
43
+
44
+ /* Score bars */
45
+ .mini-scores { margin-bottom: 0.5rem; }
46
+ .score-bar-wrap { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
47
+ .score-bar-label { width: 110px; font-size: 0.8rem; color: #aaa; }
48
+ .score-bar-track { flex: 1; height: 8px; background: #12121a; border-radius: 4px; overflow: hidden; }
49
+ .score-bar-fill { height: 100%; border-radius: 4px; transition: width 0.6s ease; }
50
+ .score-bar-val { width: 30px; text-align: right; font-size: 0.85rem; font-weight: 600; }
51
+
52
+ /* Emotional vs Rational bar */
53
+ .emo-rational { display: flex; align-items: center; gap: 0.5rem; margin: 0.8rem 0; font-size: 0.8rem; color: #aaa; }
54
+ .emo-bar { flex: 1; height: 8px; background: #4ecdc4; border-radius: 4px; overflow: hidden; }
55
+ .emo-fill { height: 100%; background: #ff6b6b; border-radius: 4px; }
56
+
57
+ /* Lists */
58
+ .list-good li::marker { color: #4ade80; }
59
+ .list-bad li::marker { color: #ef4444; }
60
+
61
+ /* Fallacy cards */
62
+ .fallacy-card { background: rgba(239, 68, 68, 0.08); border: 1px solid rgba(239, 68, 68, 0.2); border-radius: 8px; padding: 0.8rem; margin-bottom: 0.5rem; }
63
+ .fallacy-name { display: inline-block; background: rgba(239, 68, 68, 0.2); color: #ef4444; padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.3px; }
64
+ .fallacy-quote { color: #ff9999; font-style: italic; margin: 0.4rem 0; font-size: 0.85rem; }
65
+ .fallacy-explain { color: #aaa; font-size: 0.85rem; line-height: 1.4; }
66
+
67
+ .info-text { color: #bbb; line-height: 1.5; font-size: 0.95rem; }
68
+
69
+ /* Insight cards */
70
+ .insight-card { background: #1a1a2e; border-radius: 12px; padding: 1.5rem; margin-bottom: 1rem; }
71
+ .insight-card h4 { margin-bottom: 0.5rem; }
72
+ .insight-card p { color: #bbb; line-height: 1.5; }
73
+ .insight-card.bias { border-left: 3px solid #fbbf24; }
74
+ .insight-card.bias h4 { color: #fbbf24; }
75
+ .insight-card.common { border-left: 3px solid #4ade80; }
76
+ .insight-card.common h4 { color: #4ade80; }
77
+ .insight-card.compromise { border-left: 3px solid #60a5fa; }
78
+ .insight-card.compromise h4 { color: #60a5fa; }
79
+ .insight-card.tip-left { border-left: 3px solid #ff6b6b; }
80
+ .insight-card.tip-left h4 { color: #ff6b6b; }
81
+ .insight-card.tip-right { border-left: 3px solid #4ecdc4; }
82
+ .insight-card.tip-right h4 { color: #4ecdc4; }
83
+
84
+ /* Plot twist */
85
+ .plot-twist { background: linear-gradient(135deg, #2d1b69, #1a1a2e); border-radius: 12px; padding: 1.5rem; margin-bottom: 1.5rem; border: 1px solid #6c5ce7; }
86
  .plot-twist h4 { color: #a29bfe; margin-bottom: 0.5rem; }
87
+ .plot-twist p { color: #bbb; line-height: 1.5; }
88
+
89
  .back-btn { background: #333; color: #fff; margin-top: 1.5rem; }
90
+ @media (max-width: 768px) { .sides-container, .scores { grid-template-columns: 1fr; } h1 { font-size: 1.8rem; } .vs-badge { display: none; } }