import tkinter as tk
from tkinter import ttk, messagebox
import math
import random

COLORS = {
    "bg_primary": "#F0F4F8",
    "bg_secondary": "#E2E8F0",
    "card_bg": "#FFFFFF",
    "text_primary": "#2D3748",
    "text_secondary": "#718096",
    "text_light": "#A0AEC0",
    "accent_blue": "#667EEA",
    "accent_purple": "#764BA2",
    "accent_pink": "#F093FB",
    "accent_cyan": "#4FD1C5",
    "accent_green": "#48BB78",
    "accent_orange": "#ED8936",
    "accent_red": "#FC8181",
    "gradient_start": "#667EEA",
    "gradient_end": "#764BA2",
    "shadow": "#CBD5E0",
    "correct": "#48BB78",
    "wrong": "#FC8181",
    "hint_bg": "#EBF8FF",
    "hint_border": "#BEE3F8",
}

CATEGORY_COLORS = {
    "初中代数": "#667EEA",
    "初中几何": "#4FD1C5",
    "初中统计": "#48BB78",
    "高中集合与逻辑": "#667EEA",
    "高中函数": "#764BA2",
    "高中三角函数": "#F093FB",
    "高中数列": "#ED8936",
    "高中不等式": "#FC8181",
    "高中向量": "#4FD1C5",
    "高中解析几何": "#667EEA",
    "高中立体几何": "#48BB78",
    "高中概率统计": "#764BA2",
    "高中导数": "#F093FB",
    "大学微积分": "#667EEA",
    "大学线性代数": "#4FD1C5",
    "大学概率论": "#48BB78",
}

FORMULAS = {
    "初中代数": [
        {"name": "乘法公式——平方差", "formula": "(a+b)(a-b) = a² - b²", "desc": "两数和与两数差的积等于两数的平方差"},
        {"name": "乘法公式——完全平方和", "formula": "(a+b)² = a² + 2ab + b²", "desc": "两数和的平方等于两数平方和加两数积的2倍"},
        {"name": "乘法公式——完全平方差", "formula": "(a-b)² = a² - 2ab + b²", "desc": "两数差的平方等于两数平方和减两数积的2倍"},
        {"name": "一元二次方程求根公式", "formula": "x = (-b ± √(b²-4ac)) / 2a", "desc": "ax²+bx+c=0 (a≠0)，Δ=b²-4ac为判别式"},
        {"name": "韦达定理", "formula": "x₁+x₂ = -b/a，x₁·x₂ = c/a", "desc": "一元二次方程两根之间的关系"},
        {"name": "一元二次方程判别式", "formula": "Δ = b² - 4ac\nΔ>0：两个不相等的实根\nΔ=0：两个相等的实根\nΔ<0：无实根", "desc": "判断一元二次方程根的情况"},
        {"name": "幂的运算法则——同底数幂相乘", "formula": "aᵐ · aⁿ = aᵐ⁺ⁿ", "desc": "底数不变，指数相加"},
        {"name": "幂的运算法则——同底数幂相除", "formula": "aᵐ ÷ aⁿ = aᵐ⁻ⁿ (a≠0, m>n)", "desc": "底数不变，指数相减"},
        {"name": "幂的运算法则——幂的乘方", "formula": "(aᵐ)ⁿ = aᵐⁿ", "desc": "底数不变，指数相乘"},
        {"name": "幂的运算法则——积的乘方", "formula": "(ab)ⁿ = aⁿbⁿ", "desc": "每个因式分别乘方"},
        {"name": "负整数指数幂", "formula": "a⁻ⁿ = 1/aⁿ (a≠0)", "desc": "负指数等于正指数的倒数"},
        {"name": "零指数幂", "formula": "a⁰ = 1 (a≠0)", "desc": "任何非零数的零次幂等于1"},
        {"name": "二次根式乘法", "formula": "√a · √b = √(ab) (a≥0, b≥0)", "desc": "二次根式相乘，把被开方数相乘"},
        {"name": "二次根式除法", "formula": "√a ÷ √b = √(a/b) (a≥0, b>0)", "desc": "二次根式相除，把被开方数相除"},
        {"name": "分式的基本性质", "formula": "a/b = (a·c)/(b·c) = (a÷c)/(b÷c) (c≠0)", "desc": "分子分母同乘(除以)一个不为零的数，分式值不变"},
        {"name": "等式的基本性质", "formula": "若a=b，则 a±c = b±c\n若a=b，则 a·c = b·c (c≠0)", "desc": "等式两边同加(减、乘、除)相同的数，等式仍成立"},
        {"name": "绝对值", "formula": "|a| = a (a>0)\n|a| = 0 (a=0)\n|a| = -a (a<0)", "desc": "一个数的绝对值是其到原点的距离"},
        {"name": "科学记数法", "formula": "a × 10ⁿ (1 ≤ |a| < 10, n为整数)", "desc": "将数表示为一个绝对值在1与10之间的数与10的幂的积"},
    ],
    "初中几何": [
        {"name": "三角形面积", "formula": "S = ½ × 底 × 高", "desc": "三角形面积等于底与高乘积的一半"},
        {"name": "勾股定理", "formula": "a² + b² = c²", "desc": "直角三角形两直角边的平方和等于斜边的平方"},
        {"name": "圆的周长", "formula": "C = 2πr = πd", "desc": "周长等于直径乘π"},
        {"name": "圆的面积", "formula": "S = πr²", "desc": "面积等于π乘半径的平方"},
        {"name": "弧长公式", "formula": "l = nπr/180", "desc": "n为圆心角度数，r为半径"},
        {"name": "扇形面积公式", "formula": "S = nπr²/360 = ½lr", "desc": "n为圆心角度数，l为弧长"},
        {"name": "三角形内角和", "formula": "∠A + ∠B + ∠C = 180°", "desc": "三角形三个内角之和等于180度"},
        {"name": "多边形内角和", "formula": "(n-2) × 180°", "desc": "n边形的内角和等于(n-2)乘180度"},
        {"name": "多边形外角和", "formula": "360°", "desc": "任意凸多边形外角和恒为360度"},
        {"name": "平行四边形面积", "formula": "S = 底 × 高", "desc": "平行四边形面积等于底乘高"},
        {"name": "梯形面积", "formula": "S = ½ × (上底+下底) × 高", "desc": "梯形面积等于上底与下底之和乘高的一半"},
        {"name": "菱形面积", "formula": "S = ½ × d₁ × d₂", "desc": "d₁、d₂为两条对角线长度"},
        {"name": "正n边形中心角", "formula": "360°/n", "desc": "正n边形的每个中心角等于360度除以n"},
        {"name": "相似三角形面积比", "formula": "S₁/S₂ = (a₁/a₂)² = k²", "desc": "相似比k，面积比为k²"},
        {"name": "相似三角形周长比", "formula": "C₁/C₂ = a₁/a₂ = k", "desc": "相似比k，周长比等于相似比"},
        {"name": "圆周角定理", "formula": "圆周角 = ½ × 同弧所对圆心角", "desc": "圆周角等于同弧上圆心角的一半"},
        {"name": "切线长定理", "formula": "从圆外一点所作两条切线等长", "desc": "PA = PB，其中P为圆外一点，A、B为切点"},
    ],
    "初中统计": [
        {"name": "平均数", "formula": "x̄ = (x₁+x₂+...+xₙ)/n", "desc": "所有数据之和除以数据个数"},
        {"name": "加权平均数", "formula": "x̄ = (f₁x₁+f₂x₂+...+fₙxₙ)/(f₁+f₂+...+fₙ)", "desc": "各数据乘以相应权重后求和，再除以权重之和"},
        {"name": "方差", "formula": "s² = [(x₁-x̄)²+(x₂-x̄)²+...+(xₙ-x̄)²]/n", "desc": "各数据与平均数之差的平方的平均值"},
        {"name": "标准差", "formula": "s = √s²", "desc": "方差的算术平方根"},
        {"name": "中位数", "formula": "将数据从小到大排列，取中间值", "desc": "奇数个取中间，偶数个取中间两个的平均"},
        {"name": "众数", "formula": "出现次数最多的数据", "desc": "一组数据中出现频次最高的值"},
    ],
    "高中集合与逻辑": [
        {"name": "交集", "formula": "A∩B = {x|x∈A 且 x∈B}", "desc": "同时属于A和B的所有元素"},
        {"name": "并集", "formula": "A∪B = {x|x∈A 或 x∈B}", "desc": "属于A或属于B的所有元素"},
        {"name": "补集", "formula": "∁ᵤA = {x|x∈U 且 x∉A}", "desc": "全集中不属于A的所有元素"},
        {"name": "子集个数", "formula": "含n个元素的集合有 2ⁿ 个子集\n2ⁿ-1 个真子集\n2ⁿ-1 个非空子集\n2ⁿ-2 个非空真子集", "desc": "集合子集数量的计算"},
        {"name": "充分条件与必要条件", "formula": "若p⇒q：p是q的充分条件，q是p的必要条件\n若p⇔q：p是q的充要条件", "desc": "命题间的逻辑关系"},
        {"name": "含绝对值的不等式", "formula": "|x| < a (a>0) ⇔ -a < x < a\n|x| > a (a>0) ⇔ x<-a 或 x>a", "desc": "绝对值不等式的等价形式"},
    ],
    "高中函数": [
        {"name": "函数的定义域", "formula": "分式：分母≠0\n根式：偶次根号下≥0\n对数：真数>0，底数>0且≠1", "desc": "自变量可取值的集合"},
        {"name": "函数的奇偶性", "formula": "偶函数：f(-x) = f(x)，图像关于y轴对称\n奇函数：f(-x) = -f(x)，图像关于原点对称", "desc": "函数的重要性质"},
        {"name": "函数的单调性", "formula": "增函数：x₁<x₂ ⇒ f(x₁)<f(x₂)\n减函数：x₁<x₂ ⇒ f(x₁)>f(x₂)", "desc": "函数值随自变量变化的趋势"},
        {"name": "指数函数", "formula": "y = aˣ (a>0, a≠1)\na>1时递增\n0<a<1时递减\n恒过点(0,1)", "desc": "底数为常数，指数为自变量"},
        {"name": "对数函数", "formula": "y = logₐx (a>0, a≠1)\na>1时递增\n0<a<1时递减\n恒过点(1,0)", "desc": "指数函数的反函数"},
        {"name": "对数运算法则", "formula": "logₐ(MN) = logₐM + logₐN\nlogₐ(M/N) = logₐM - logₐN\nlogₐMⁿ = n·logₐM\n换底公式：logₐb = lgb/lga", "desc": "对数的基本运算规则"},
        {"name": "二次函数", "formula": "y = ax²+bx+c (a≠0)\n顶点：(-b/2a, (4ac-b²)/4a)\n对称轴：x = -b/2a", "desc": "最基本的一类多项式函数"},
        {"name": "反函数", "formula": "若 y=f(x)，则反函数为 x=f⁻¹(y)\nf与f⁻¹图像关于y=x对称", "desc": "原函数与反函数图像关于y=x对称"},
        {"name": "幂函数", "formula": "y = xᵅ (α为常数)\n恒过点(1,1)", "desc": "底数为自变量，指数为常数"},
    ],
    "高中三角函数": [
        {"name": "弧度制", "formula": "1 rad = 180°/π\n1° = π/180 rad", "desc": "弧度与角度的换算"},
        {"name": "弧长公式(弧度制)", "formula": "l = |α|·r", "desc": "α为弧度，r为半径"},
        {"name": "扇形面积(弧度制)", "formula": "S = ½|α|r²", "desc": "α为弧度，r为半径"},
        {"name": "同角三角函数关系", "formula": "sin²α + cos²α = 1\ntanα = sinα/cosα\n1 + tan²α = sec²α\n1 + cot²α = csc²α", "desc": "平方关系与商数关系"},
        {"name": "诱导公式(一)", "formula": "sin(2kπ+α) = sinα\ncos(2kπ+α) = cosα\ntan(2kπ+α) = tanα", "desc": "终边相同的角三角函数值相等"},
        {"name": "诱导公式(二)", "formula": "sin(π+α) = -sinα\ncos(π+α) = -cosα\ntan(π+α) = tanα", "desc": "π+α的三角函数"},
        {"name": "诱导公式(三)", "formula": "sin(-α) = -sinα\ncos(-α) = cosα\ntan(-α) = -tanα", "desc": "-α的三角函数"},
        {"name": "诱导公式(四)", "formula": "sin(π-α) = sinα\ncos(π-α) = -cosα\ntan(π-α) = -tanα", "desc": "π-α的三角函数"},
        {"name": "诱导公式(五)", "formula": "sin(π/2-α) = cosα\ncos(π/2-α) = sinα", "desc": "π/2-α的三角函数"},
        {"name": "诱导公式(六)", "formula": "sin(π/2+α) = cosα\ncos(π/2+α) = -sinα", "desc": "π/2+α的三角函数"},
        {"name": "两角和差公式", "formula": "sin(α±β) = sinαcosβ ± cosαsinβ\ncos(α±β) = cosαcosβ ∓ sinαsinβ\ntan(α±β) = (tanα±tanβ)/(1∓tanαtanβ)", "desc": "两角和与差的三角函数"},
        {"name": "二倍角公式", "formula": "sin2α = 2sinαcosα\ncos2α = cos²α-sin²α = 2cos²α-1 = 1-2sin²α\ntan2α = 2tanα/(1-tan²α)", "desc": "二倍角的三角函数"},
        {"name": "半角公式", "formula": "sin(α/2) = ±√((1-cosα)/2)\ncos(α/2) = ±√((1+cosα)/2)\ntan(α/2) = sinα/(1+cosα) = (1-cosα)/sinα", "desc": "半角的三角函数，符号由象限决定"},
        {"name": "和差化积", "formula": "sinA+sinB = 2sin((A+B)/2)cos((A-B)/2)\nsinA-sinB = 2cos((A+B)/2)sin((A-B)/2)\ncosA+cosB = 2cos((A+B)/2)cos((A-B)/2)\ncosA-cosB = -2sin((A+B)/2)sin((A-B)/2)", "desc": "三角函数和差转化为积"},
        {"name": "积化和差", "formula": "sinαcosβ = ½[sin(α+β)+sin(α-β)]\ncosαsinβ = ½[sin(α+β)-sin(α-β)]\ncosαcosβ = ½[cos(α+β)+cos(α-β)]\nsinαsinβ = -½[cos(α+β)-cos(α-β)]", "desc": "三角函数积转化为和差"},
        {"name": "正弦定理", "formula": "a/sinA = b/sinB = c/sinC = 2R", "desc": "R为外接圆半径"},
        {"name": "余弦定理", "formula": "a² = b²+c²-2bc·cosA\nb² = a²+c²-2ac·cosB\nc² = a²+b²-2ab·cosC", "desc": "推广的勾股定理"},
        {"name": "三角形面积公式", "formula": "S = ½ab·sinC = ½bc·sinA = ½ac·sinB", "desc": "用两边及其夹角求面积"},
    ],
    "高中数列": [
        {"name": "等差数列通项公式", "formula": "aₙ = a₁ + (n-1)d", "desc": "a₁为首项，d为公差"},
        {"name": "等差数列前n项和", "formula": "Sₙ = n(a₁+aₙ)/2 = na₁ + n(n-1)d/2", "desc": "首末项之和乘项数的一半"},
        {"name": "等差中项", "formula": "若a、b、c成等差数列，则2b = a+c", "desc": "等差数列中相邻三项的关系"},
        {"name": "等比数列通项公式", "formula": "aₙ = a₁ · qⁿ⁻¹", "desc": "a₁为首项，q为公比"},
        {"name": "等比数列前n项和", "formula": "Sₙ = a₁(1-qⁿ)/(1-q) (q≠1)\nSₙ = na₁ (q=1)", "desc": "注意公比是否为1"},
        {"name": "等比中项", "formula": "若a、b、c成等比数列，则b² = ac", "desc": "等比数列中相邻三项的关系"},
        {"name": "通项与前n项和的关系", "formula": "aₙ = Sₙ - Sₙ₋₁ (n≥2)\na₁ = S₁", "desc": "由Sₙ求aₙ的方法"},
        {"name": "裂项求和(常用)", "formula": "1/(n(n+1)) = 1/n - 1/(n+1)\n1/((2n-1)(2n+1)) = ½(1/(2n-1) - 1/(2n+1))", "desc": "将通项拆成两项之差来求和"},
    ],
    "高中不等式": [
        {"name": "基本不等式(均值不等式)", "formula": "a²+b² ≥ 2ab (a,b∈R)\na+b ≥ 2√(ab) (a>0, b>0)\n当且仅当a=b时取等号", "desc": "算术平均数不小于几何平均数"},
        {"name": "重要不等式", "formula": "(a+b)/2 ≥ √(ab) (a>0, b>0)\n(a+b+c)/3 ≥ ∛(abc) (a,b,c>0)", "desc": "均值不等式的常见形式"},
        {"name": "绝对值三角不等式", "formula": "||a|-|b|| ≤ |a±b| ≤ |a|+|b|", "desc": "绝对值的重要性质"},
        {"name": "一元二次不等式", "formula": "ax²+bx+c>0 (a>0, Δ>0)：x<x₁ 或 x>x₂\nax²+bx+c<0 (a>0, Δ>0)：x₁<x<x₂", "desc": "结合二次函数图像求解"},
        {"name": "柯西不等式", "formula": "(a₁²+a₂²)(b₁²+b₂²) ≥ (a₁b₁+a₂b₂)²\n当且仅当a₁/b₁=a₂/b₂时取等号", "desc": "二维形式的柯西不等式"},
    ],
    "高中向量": [
        {"name": "向量加法", "formula": "a⃗ + b⃗ = (x₁+x₂, y₁+y₂)", "desc": "对应分量相加"},
        {"name": "向量数乘", "formula": "λa⃗ = (λx, λy)", "desc": "每个分量乘以标量"},
        {"name": "向量数量积(点积)", "formula": "a⃗·b⃗ = x₁x₂ + y₁y₂ = |a⃗||b⃗|cosθ", "desc": "θ为两向量夹角"},
        {"name": "向量模", "formula": "|a⃗| = √(x²+y²)", "desc": "向量的长度"},
        {"name": "两向量垂直条件", "formula": "a⃗ ⊥ b⃗ ⇔ a⃗·b⃗ = 0", "desc": "数量积为零"},
        {"name": "两向量平行条件", "formula": "a⃗ ∥ b⃗ ⇔ x₁y₂ = x₂y₁\n即 a⃗ = λb⃗ (b⃗≠0⃗)", "desc": "对应分量成比例"},
        {"name": "向量夹角公式", "formula": "cosθ = (a⃗·b⃗)/(|a⃗||b⃗|)", "desc": "用数量积求夹角"},
        {"name": "向量坐标运算", "formula": "A(x₁,y₁), B(x₂,y₂)\nAB⃗ = (x₂-x₁, y₂-y₁)\n|AB⃗| = √((x₂-x₁)²+(y₂-y₁)²)", "desc": "两点间的向量表示"},
    ],
    "高中解析几何": [
        {"name": "两点间距离公式", "formula": "|AB| = √((x₂-x₁)²+(y₂-y₁)²)", "desc": "平面上两点间的距离"},
        {"name": "中点坐标公式", "formula": "M = ((x₁+x₂)/2, (y₁+y₂)/2)", "desc": "两点连线的中点坐标"},
        {"name": "直线的斜率", "formula": "k = (y₂-y₁)/(x₂-x₁) (x₁≠x₂)", "desc": "纵坐标差与横坐标差之比"},
        {"name": "直线方程——点斜式", "formula": "y-y₀ = k(x-x₀)", "desc": "过点(x₀,y₀)，斜率为k"},
        {"name": "直线方程——斜截式", "formula": "y = kx + b", "desc": "k为斜率，b为纵截距"},
        {"name": "直线方程——两点式", "formula": "(y-y₁)/(y₂-y₁) = (x-x₁)/(x₂-x₁)", "desc": "过两点(x₁,y₁)和(x₂,y₂)"},
        {"name": "直线方程——截距式", "formula": "x/a + y/b = 1", "desc": "a为横截距，b为纵截距"},
        {"name": "直线方程——一般式", "formula": "Ax + By + C = 0", "desc": "所有直线方程都可以化为一般式"},
        {"name": "点到直线距离", "formula": "d = |Ax₀+By₀+C|/√(A²+B²)", "desc": "点(x₀,y₀)到直线Ax+By+C=0的距离"},
        {"name": "两平行线间距离", "formula": "d = |C₁-C₂|/√(A²+B²)", "desc": "Ax+By+C₁=0 与 Ax+By+C₂=0 之间的距离"},
        {"name": "两条直线平行", "formula": "k₁ = k₂ 且 b₁ ≠ b₂\n(或 A₁B₂ = A₂B₁ 且 B₁C₂ ≠ B₂C₁)", "desc": "斜率相等且截距不等"},
        {"name": "两条直线垂直", "formula": "k₁·k₂ = -1\n(或 A₁A₂ + B₁B₂ = 0)", "desc": "斜率之积为-1"},
        {"name": "圆的标准方程", "formula": "(x-a)²+(y-b)² = r²", "desc": "圆心(a,b)，半径r"},
        {"name": "圆的一般方程", "formula": "x²+y²+Dx+Ey+F=0\n圆心(-D/2,-E/2)\nr = ½√(D²+E²-4F)\n需 D²+E²-4F>0", "desc": "圆的另一种表示形式"},
        {"name": "椭圆标准方程", "formula": "x²/a² + y²/b² = 1 (a>b>0)\nc² = a² - b²\ne = c/a\n焦点在x轴上", "desc": "a为半长轴，b为半短轴，c为半焦距"},
        {"name": "椭圆焦点在y轴", "formula": "x²/b² + y²/a² = 1 (a>b>0)\nc² = a² - b²", "desc": "长轴在y轴上的椭圆"},
        {"name": "双曲线标准方程", "formula": "x²/a² - y²/b² = 1 (a>0, b>0)\nc² = a² + b²\ne = c/a\n渐近线：y = ±(b/a)x", "desc": "焦点在x轴上的双曲线"},
        {"name": "抛物线标准方程", "formula": "y² = 2px (p>0)：焦点(p/2,0)\ny² = -2px (p>0)：焦点(-p/2,0)\nx² = 2py (p>0)：焦点(0,p/2)\nx² = -2py (p>0)：焦点(0,-p/2)", "desc": "四种标准形式的抛物线"},
        {"name": "抛物线焦半径公式", "formula": "y²=2px 中 |PF| = x₀+p/2\n其中P(x₀,y₀)在抛物线上", "desc": "焦点到抛物线上点的距离"},
    ],
    "高中立体几何": [
        {"name": "球的体积", "formula": "V = 4πr³/3", "desc": "r为球的半径"},
        {"name": "球的表面积", "formula": "S = 4πr²", "desc": "r为球的半径"},
        {"name": "圆柱体积", "formula": "V = πr²h", "desc": "r为底面半径，h为高"},
        {"name": "圆柱侧面积", "formula": "S侧 = 2πrh", "desc": "r为底面半径，h为高"},
        {"name": "圆锥体积", "formula": "V = πr²h/3", "desc": "r为底面半径，h为高"},
        {"name": "圆锥侧面积", "formula": "S侧 = πrl", "desc": "r为底面半径，l为母线长"},
        {"name": "圆台体积", "formula": "V = πh(R²+Rr+r²)/3", "desc": "R、r为上下底面半径，h为高"},
        {"name": "棱锥体积", "formula": "V = Sh/3", "desc": "S为底面积，h为高"},
        {"name": "棱柱体积", "formula": "V = Sh", "desc": "S为底面积，h为高"},
        {"name": "线面平行判定", "formula": "平面外一条直线与平面内一条直线平行\n⇒ 该直线与此平面平行", "desc": "线面平行的判定定理"},
        {"name": "面面平行判定", "formula": "一个平面内两条相交直线均平行于另一平面\n⇒ 两平面平行", "desc": "面面平行的判定定理"},
        {"name": "线面垂直判定", "formula": "一条直线与平面内两条相交直线都垂直\n⇒ 该直线与此平面垂直", "desc": "线面垂直的判定定理"},
        {"name": "三垂线定理", "formula": "在平面内的一条直线，如果和这个平面的\n一条斜线的射影垂直，则它也和这条斜线垂直", "desc": "立体几何中的重要定理"},
    ],
    "高中概率统计": [
        {"name": "古典概型", "formula": "P(A) = A包含的基本事件数/基本事件总数", "desc": "等可能事件的概率"},
        {"name": "互斥事件", "formula": "P(A∪B) = P(A) + P(B)\n(A与B互斥，即AB=∅)", "desc": "不可能同时发生的事件"},
        {"name": "对立事件", "formula": "P(Ā) = 1 - P(A)", "desc": "必有一个发生的互斥事件"},
        {"name": "条件概率", "formula": "P(B|A) = P(AB)/P(A)", "desc": "在A发生的条件下B发生的概率"},
        {"name": "乘法公式", "formula": "P(AB) = P(A)·P(B|A) = P(B)·P(A|B)", "desc": "两事件同时发生的概率"},
        {"name": "独立事件", "formula": "P(AB) = P(A)·P(B)", "desc": "一个事件的发生不影响另一事件"},
        {"name": "二项分布", "formula": "P(X=k) = C(n,k)·pᵏ·(1-p)ⁿ⁻ᵏ\nX ~ B(n, p)\nE(X) = np, D(X) = np(1-p)", "desc": "n次独立重复试验中成功k次的概率"},
        {"name": "正态分布", "formula": "X ~ N(μ, σ²)\nP(μ-σ<X<μ+σ) ≈ 0.6826\nP(μ-2σ<X<μ+2σ) ≈ 0.9544\nP(μ-3σ<X<μ+3σ) ≈ 0.9974", "desc": "3σ原则"},
        {"name": "排列数", "formula": "A(n,m) = n!/(n-m)!\n= n(n-1)(n-2)…(n-m+1)", "desc": "从n个元素中取m个排列"},
        {"name": "组合数", "formula": "C(n,m) = n!/[m!(n-m)!]\nC(n,m) = C(n,n-m)", "desc": "从n个元素中取m个组合"},
        {"name": "期望与方差", "formula": "E(X) = Σxᵢpᵢ\nD(X) = E(X²)-[E(X)]²\nD(aX+b) = a²D(X)", "desc": "随机变量的数字特征"},
        {"name": "回归分析", "formula": "ŷ = b̂x + â\nb̂ = Σ(xᵢ-x̄)(yᵢ-ȳ)/Σ(xᵢ-x̄)²\nâ = ȳ - b̂x̄", "desc": "最小二乘法求回归方程"},
    ],
    "高中导数": [
        {"name": "导数的定义", "formula": "f'(x₀) = lim[Δx→0] [f(x₀+Δx)-f(x₀)]/Δx", "desc": "函数在某点的瞬时变化率"},
        {"name": "基本求导公式", "formula": "(C)' = 0\n(xⁿ)' = nxⁿ⁻¹\n(sin x)' = cos x\n(cos x)' = -sin x\n(eˣ)' = eˣ\n(aˣ)' = aˣln a\n(ln x)' = 1/x\n(logₐx)' = 1/(xln a)", "desc": "常用函数的导数"},
        {"name": "导数四则运算", "formula": "(u±v)' = u'±v'\n(uv)' = u'v+uv'\n(u/v)' = (u'v-uv')/v²", "desc": "导数的加减乘除法则"},
        {"name": "链式法则(复合函数求导)", "formula": "[f(g(x))]' = f'(g(x))·g'(x)", "desc": "外层函数对内层函数求导，再乘内层函数导数"},
        {"name": "函数的单调性", "formula": "在区间(a,b)上：\nf'(x)>0 ⇒ f(x)单调递增\nf'(x)<0 ⇒ f(x)单调递减", "desc": "导数判断函数单调性"},
        {"name": "函数的极值", "formula": "f'(x₀)=0，且f'(x)在x₀两侧变号\n左正右负 ⇒ 极大值\n左负右正 ⇒ 极小值", "desc": "极值的判定方法"},
        {"name": "函数的最值", "formula": "在闭区间[a,b]上：\n比较f(x)的极值与端点值\n最大者为最大值，最小者为最小值", "desc": "闭区间上函数最值的求法"},
        {"name": "定积分", "formula": "∫[a,b] f(x)dx = F(b)-F(a)\n其中F'(x) = f(x)", "desc": "牛顿-莱布尼茨公式"},
        {"name": "定积分的性质", "formula": "∫[a,b] f(x)dx = -∫[b,a] f(x)dx\n∫[a,b] [f(x)±g(x)]dx = ∫[a,b]f(x)dx ± ∫[a,b]g(x)dx\n∫[a,b] kf(x)dx = k∫[a,b]f(x)dx", "desc": "定积分的基本性质"},
        {"name": "微积分基本定理", "formula": "若F'(x)=f(x)，则\n∫[a,b]f(x)dx = F(b)-F(a)", "desc": "联系微分与积分的核心定理"},
    ],
    "大学微积分": [
        {"name": "洛必达法则", "formula": "若lim f(x)/g(x) 为 0/0 或 ∞/∞ 型\n则 lim f(x)/g(x) = lim f'(x)/g'(x)", "desc": "求未定式极限的方法"},
        {"name": "泰勒公式", "formula": "f(x) = f(x₀)+f'(x₀)(x-x₀)+f''(x₀)(x-x₀)²/2!\n+...+f⁽ⁿ⁾(x₀)(x-x₀)ⁿ/n!+Rₙ(x)", "desc": "用多项式近似表示函数"},
        {"name": "常用泰勒展开", "formula": "eˣ = 1+x+x²/2!+x³/3!+...\nsin x = x-x³/3!+x⁵/5!-...\ncos x = 1-x²/2!+x⁴/4!-...\nln(1+x) = x-x²/2+x³/3-... (|x|<1)\n1/(1-x) = 1+x+x²+x³+... (|x|<1)", "desc": "常见函数的麦克劳林展开"},
        {"name": "多元函数偏导数", "formula": "∂f/∂x：将其他变量视为常数对x求导\n∂f/∂y：将其他变量视为常数对y求导", "desc": "多元函数对其中一个变量的导数"},
        {"name": "全微分", "formula": "df = (∂f/∂x)dx + (∂f/∂y)dy", "desc": "函数增量的线性主部"},
        {"name": "二重积分", "formula": "∬D f(x,y)dσ\n= ∫[a,b]dx ∫[φ₁(x),φ₂(x)] f(x,y)dy", "desc": "在区域D上的二重积分化为累次积分"},
        {"name": "分部积分法", "formula": "∫u dv = uv - ∫v du", "desc": "不定积分与定积分的常用方法"},
        {"name": "换元积分法", "formula": "∫f(g(x))g'(x)dx = ∫f(u)du (u=g(x))", "desc": "第一类换元法（凑微分法）"},
        {"name": "格林公式", "formula": "∮L Pdx+Qdy = ∬D (∂Q/∂x-∂P/∂y)dxdy", "desc": "曲线积分与二重积分的关系"},
    ],
    "大学线性代数": [
        {"name": "行列式性质", "formula": "|Aᵀ| = |A|\n|kA| = kⁿ|A| (n阶)\n|AB| = |A||B|\n互换两行(列)，行列式变号", "desc": "n阶行列式的基本性质"},
        {"name": "2阶行列式", "formula": "|a b|\n|c d| = ad - bc", "desc": "最简单的行列式"},
        {"name": "3阶行列式(沙路法则)", "formula": "|a₁ a₂ a₃|\n|b₁ b₂ b₃| = a₁b₂c₃+a₂b₃c₁+a₃b₁c₂\n|c₁ c₂ c₃|  -a₃b₂c₁-a₁b₃c₂-a₂b₁c₃", "desc": "3阶行列式的计算方法"},
        {"name": "克莱默法则", "formula": "若|A|≠0，则xᵢ = |Aᵢ|/|A|\nAᵢ为将A的第i列换为b所得", "desc": "用行列式解线性方程组"},
        {"name": "矩阵乘法", "formula": "(AB)ᵢⱼ = Σ(k=1→n) aᵢₖbₖⱼ\nA(m×n)·B(n×p) = C(m×p)", "desc": "行乘列，对应元素相乘再相加"},
        {"name": "矩阵的秩", "formula": "r(A) = 阶梯形中非零行的行数\nr(AB) ≤ min(r(A), r(B))\nr(A+B) ≤ r(A)+r(B)", "desc": "矩阵中最高阶非零子式的阶数"},
        {"name": "逆矩阵", "formula": "AA⁻¹ = A⁻¹A = I\nA⁻¹ = A*/|A| (二阶三阶常用)\n(AB)⁻¹ = B⁻¹A⁻¹", "desc": "矩阵的倒数"},
        {"name": "特征值与特征向量", "formula": "Ax = λx (x≠0)\n|A-λI| = 0 求特征值λ\n(A-λI)x = 0 求特征向量x", "desc": "矩阵只改变向量长度不改变方向"},
        {"name": "特征值的性质", "formula": "Σλᵢ = tr(A) = Σaᵢᵢ (迹)\nΠλᵢ = |A|\n不同特征值对应的特征向量线性无关", "desc": "特征值的重要性质"},
        {"name": "向量空间维数公式", "formula": "dim(V₁+V₂) = dimV₁ + dimV₂ - dim(V₁∩V₂)", "desc": "两个子空间之和的维数"},
    ],
    "大学概率论": [
        {"name": "全概率公式", "formula": "P(A) = Σ P(Bᵢ)P(A|Bᵢ)\n其中B₁,B₂,...,Bₙ为样本空间的一个划分", "desc": "将复杂事件分解为简单事件"},
        {"name": "贝叶斯公式", "formula": "P(Bⱼ|A) = P(Bⱼ)P(A|Bⱼ)/Σ P(Bᵢ)P(A|Bᵢ)", "desc": "由结果推断原因的概率"},
        {"name": "泊松分布", "formula": "P(X=k) = λᵏe⁻ᵏ/k!\nX ~ P(λ)\nE(X) = λ, D(X) = λ", "desc": "稀有事件的概率模型"},
        {"name": "均匀分布", "formula": "X ~ U(a,b)\nf(x) = 1/(b-a), a≤x≤b\nE(X) = (a+b)/2, D(X) = (b-a)²/12", "desc": "等可能分布"},
        {"name": "指数分布", "formula": "X ~ Exp(λ)\nf(x) = λe⁻λˣ, x>0\nE(X) = 1/λ, D(X) = 1/λ²", "desc": "等待时间的分布"},
        {"name": "协方差与相关系数", "formula": "Cov(X,Y) = E(XY)-E(X)E(Y)\nρ = Cov(X,Y)/[√D(X)·√D(Y)]\n-1 ≤ ρ ≤ 1", "desc": "衡量两个变量的线性关系"},
        {"name": "大数定律", "formula": "X₁,X₂,...独立同分布，E(Xᵢ)=μ\n则 (X₁+...+Xₙ)/n → μ (n→∞)", "desc": "频率稳定于概率的理论基础"},
        {"name": "中心极限定理", "formula": "X₁,X₂,...独立同分布\n(X₁+...+Xₙ-nμ)/(σ√n) → N(0,1)", "desc": "大量独立随机变量之和近似正态分布"},
        {"name": "最大似然估计", "formula": "L(θ) = Π f(xᵢ;θ)\n求使L(θ)最大的θ", "desc": "使样本出现概率最大的参数估计"},
    ],
}

EXERCISES = {
    "初中代数": [
        {"q": "计算：(3+2)(3-2) = ?", "options": ["5", "1", "9", "13"], "answer": 0,
         "explain": "(a+b)(a-b)=a²-b²，所以(3+2)(3-2)=3²-2²=9-4=5"},
        {"q": "计算：(x+3)² = ?", "options": ["x²+9", "x²+6x+9", "x²+3x+9", "x²+6x+3"], "answer": 1,
         "explain": "(a+b)²=a²+2ab+b²，所以(x+3)²=x²+6x+9"},
        {"q": "方程 x²-5x+6=0 的两个根分别是？", "options": ["1和6", "2和3", "-2和-3", "-1和6"], "answer": 1,
         "explain": "x²-5x+6=(x-2)(x-3)=0，所以x=2或x=3"},
        {"q": "若 x₁=2, x₂=3 是方程 x²+px+q=0 的两根，则 p = ?", "options": ["5", "-5", "6", "-6"], "answer": 1,
         "explain": "由韦达定理：x₁+x₂=-p，即2+3=-p，p=-5"},
        {"q": "计算：2³ × 2⁴ = ?", "options": ["2⁷", "2¹²", "4⁷", "4¹²"], "answer": 0,
         "explain": "同底数幂相乘，底数不变指数相加：2³×2⁴=2⁷"},
        {"q": "计算：√12 = ?", "options": ["2√3", "3√2", "4√3", "6"], "answer": 0,
         "explain": "√12=√(4×3)=2√3"},
        {"q": "若 |x| = 5，则 x 的值为？", "options": ["5", "-5", "5或-5", "25"], "answer": 2,
         "explain": "绝对值等于5的数有5和-5两个"},
        {"q": "计算：(a²)³ = ?", "options": ["a⁵", "a⁶", "a⁸", "a⁹"], "answer": 1,
         "explain": "幂的乘方，底数不变指数相乘：(a²)³=a⁶"},
    ],
    "初中几何": [
        {"q": "直角三角形两直角边为3和4，斜边长为？", "options": ["5", "6", "7", "√7"], "answer": 0,
         "explain": "由勾股定理：c=√(3²+4²)=√25=5"},
        {"q": "半径为3的圆，面积为？", "options": ["6π", "9π", "3π", "12π"], "answer": 1,
         "explain": "S=πr²=π×3²=9π"},
        {"q": "半径为2的圆，周长为？", "options": ["2π", "4π", "6π", "8π"], "answer": 1,
         "explain": "C=2πr=2π×2=4π"},
        {"q": "六边形的内角和为？", "options": ["540°", "720°", "900°", "360°"], "answer": 1,
         "explain": "(n-2)×180°=(6-2)×180°=720°"},
        {"q": "扇形圆心角为90°，半径为4，弧长为？", "options": ["2π", "4π", "π", "8π"], "answer": 0,
         "explain": "l=nπr/180=90π×4/180=2π"},
        {"q": "底为6，高为4的三角形面积为？", "options": ["24", "12", "10", "20"], "answer": 1,
         "explain": "S=½×底×高=½×6×4=12"},
    ],
    "高中三角函数": [
        {"q": "sin30° = ?", "options": ["1/2", "√2/2", "√3/2", "1"], "answer": 0,
         "explain": "sin30°=1/2，这是特殊角的三角函数值"},
        {"q": "cos60° = ?", "options": ["1/2", "√2/2", "√3/2", "0"], "answer": 0,
         "explain": "cos60°=1/2，这是特殊角的三角函数值"},
        {"q": "tan45° = ?", "options": ["0", "1", "√3", "不存在"], "answer": 1,
         "explain": "tan45°=sin45°/cos45°=1"},
        {"q": "sin²α+cos²α = ?", "options": ["0", "1", "2", "取决于α"], "answer": 1,
         "explain": "同角三角函数基本关系：sin²α+cos²α=1"},
        {"q": "sin(π-α) = ?", "options": ["sinα", "-sinα", "cosα", "-cosα"], "answer": 0,
         "explain": "诱导公式：sin(π-α)=sinα"},
        {"q": "若sinα=3/5，α为锐角，则cosα = ?", "options": ["4/5", "3/5", "-4/5", "5/4"], "answer": 0,
         "explain": "由sin²α+cos²α=1，cosα=√(1-9/25)=4/5"},
        {"q": "sin2α = ?", "options": ["2sinα", "2sinαcosα", "sin²α", "cos²α-sin²α"], "answer": 1,
         "explain": "二倍角公式：sin2α=2sinαcosα"},
    ],
    "高中数列": [
        {"q": "等差数列{aₙ}中，a₁=3，d=2，则a₁₀ = ?", "options": ["21", "23", "20", "19"], "answer": 0,
         "explain": "aₙ=a₁+(n-1)d=3+9×2=21"},
        {"q": "等差数列前10项和S₁₀，a₁=1，a₁₀=19，则S₁₀ = ?", "options": ["100", "95", "105", "90"], "answer": 0,
         "explain": "S₁₀=10(a₁+a₁₀)/2=10×20/2=100"},
        {"q": "等比数列{aₙ}中，a₁=2，q=3，则a₄ = ?", "options": ["54", "18", "162", "27"], "answer": 0,
         "explain": "a₄=a₁×q³=2×27=54"},
        {"q": "等比数列a₁=1，q=2，则S₅ = ?", "options": ["31", "32", "16", "15"], "answer": 0,
         "explain": "S₅=a₁(1-q⁵)/(1-q)=1×(1-32)/(1-2)=31"},
    ],
    "高中导数": [
        {"q": "f(x)=x³，则f'(x) = ?", "options": ["3x²", "x²", "3x", "x³/3"], "answer": 0,
         "explain": "(xⁿ)'=nxⁿ⁻¹，所以(x³)'=3x²"},
        {"q": "f(x)=sinx，则f'(x) = ?", "options": ["-cosx", "cosx", "sinx", "-sinx"], "answer": 1,
         "explain": "(sinx)'=cosx"},
        {"q": "f(x)=eˣ，则f'(x) = ?", "options": ["xeˣ⁻¹", "eˣ", "eˣ⁻¹", "1"], "answer": 1,
         "explain": "(eˣ)'=eˣ，这是eˣ的重要性质"},
        {"q": "f(x)=lnx，则f'(x) = ?", "options": ["1/x", "x", "lnx", "-1/x"], "answer": 0,
         "explain": "(lnx)'=1/x"},
        {"q": "f(x)=x²+2x，则在x=1处的切线斜率为？", "options": ["4", "3", "5", "2"], "answer": 0,
         "explain": "f'(x)=2x+2，f'(1)=4"},
    ],
    "高中解析几何": [
        {"q": "点(1,2)到直线3x+4y-5=0的距离为？", "options": ["6/5", "4/5", "2/5", "6"], "answer": 0,
         "explain": "d=|3×1+4×2-5|/√(9+16)=|6|/5=6/5"},
        {"q": "圆心(2,3)，半径为5的圆的方程为？", "options": ["(x-2)²+(y-3)²=25", "(x+2)²+(y+3)²=25",
         "(x-2)²+(y-3)²=5", "x²+y²=25"], "answer": 0,
         "explain": "圆的标准方程(x-a)²+(y-b)²=r²"},
        {"q": "过点(1,2)，斜率为3的直线方程为？", "options": ["y-2=3(x-1)", "y=3x-1", "y-1=3(x-2)", "y=3x+1"], "answer": 0,
         "explain": "点斜式：y-y₀=k(x-x₀)，即y-2=3(x-1)"},
        {"q": "椭圆 x²/9+y²/4=1 的离心率为？", "options": ["√5/3", "5/9", "√5/2", "2/3"], "answer": 0,
         "explain": "a²=9,b²=4,c²=5,e=c/a=√5/3"},
    ],
    "高中概率统计": [
        {"q": "从1到10中随机取一个数，取到偶数的概率为？", "options": ["1/2", "2/5", "3/5", "4/5"], "answer": 0,
         "explain": "1到10中偶数有5个，P=5/10=1/2"},
        {"q": "C(5,2) = ?", "options": ["10", "20", "25", "5"], "answer": 0,
         "explain": "C(5,2)=5!/(2!×3!)=10"},
        {"q": "A(4,2) = ?", "options": ["12", "6", "8", "16"], "answer": 0,
         "explain": "A(4,2)=4×3=12"},
        {"q": "X~B(10,0.3)，则E(X) = ?", "options": ["3", "7", "2.1", "0.3"], "answer": 0,
         "explain": "二项分布E(X)=np=10×0.3=3"},
    ],
}


class AnimatedButton(tk.Canvas):

    def __init__(self, parent, text="", command=None, width=200, height=44,
                 bg_color=None, text_color="white", font_size=12, radius=10, **kwargs):
        super().__init__(parent, width=width, height=height,
                         bg=parent.cget("bg") if isinstance(parent, (tk.Frame, tk.Tk)) else COLORS["bg_primary"],
                         highlightthickness=0, bd=0, **kwargs)
        self._text = text
        self._command = command
        self._width = width
        self._height = height
        self._bg_color = bg_color or COLORS["accent_blue"]
        self._text_color = text_color
        self._font_size = font_size
        self._radius = radius
        self._pressed = False
        self._hover = False

        self._draw()

        self.bind("<Enter>", self._on_enter)
        self.bind("<Leave>", self._on_leave)
        self.bind("<ButtonPress-1>", self._on_press)
        self.bind("<ButtonRelease-1>", self._on_release)

    def _rounded_rect(self, x1, y1, x2, y2, r, **kwargs):
        points = [
            x1 + r, y1,
            x2 - r, y1,
            x2, y1,
            x2, y1 + r,
            x2, y2 - r,
            x2, y2,
            x2 - r, y2,
            x1 + r, y2,
            x1, y2,
            x1, y2 - r,
            x1, y1 + r,
            x1, y1,
        ]
        return self.create_polygon(points, smooth=True, **kwargs)

    def _draw(self):
        self.delete("all")
        pad = 2 if self._pressed else 0
        shadow_off = 3 if not self._pressed else 1

        self._rounded_rect(pad + shadow_off, pad + shadow_off,
                           self._width - pad + shadow_off, self._height - pad + shadow_off,
                           self._radius, fill=COLORS["shadow"], outline="")

        if self._pressed:
            color = self._darken(self._bg_color, 0.15)
        elif self._hover:
            color = self._lighten(self._bg_color, 0.1)
        else:
            color = self._bg_color

        self._rounded_rect(pad, pad, self._width - pad, self._height - pad,
                           self._radius, fill=color, outline="")

        self.create_text(self._width / 2, self._height / 2,
                         text=self._text, fill=self._text_color,
                         font=("Microsoft YaHei UI", self._font_size, "bold"))

    @staticmethod
    def _darken(hex_color, factor):
        r, g, b = int(hex_color[1:3], 16), int(hex_color[3:5], 16), int(hex_color[5:7], 16)
        r = int(r * (1 - factor))
        g = int(g * (1 - factor))
        b = int(b * (1 - factor))
        return f"#{r:02x}{g:02x}{b:02x}"

    @staticmethod
    def _lighten(hex_color, factor):
        r, g, b = int(hex_color[1:3], 16), int(hex_color[3:5], 16), int(hex_color[5:7], 16)
        r = min(255, int(r + (255 - r) * factor))
        g = min(255, int(g + (255 - g) * factor))
        b = min(255, int(b + (255 - b) * factor))
        return f"#{r:02x}{g:02x}{b:02x}"

    def _on_enter(self, e):
        self._hover = True
        self._draw()

    def _on_leave(self, e):
        self._hover = False
        self._pressed = False
        self._draw()

    def _on_press(self, e):
        self._pressed = True
        self._draw()

    def _on_release(self, e):
        self._pressed = False
        self._draw()
        if self._command:
            self._command()


class FormulaCard(tk.Frame):

    def __init__(self, parent, formula_data, category_color, on_click=None, **kwargs):
        super().__init__(parent, bg=COLORS["card_bg"], **kwargs)
        self.formula_data = formula_data
        self._on_click = on_click

        bar = tk.Frame(self, bg=category_color, width=5)
        bar.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 0))

        content = tk.Frame(self, bg=COLORS["card_bg"])
        content.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=12, pady=10)

        name_label = tk.Label(content, text=formula_data["name"],
                              font=("Microsoft YaHei UI", 11, "bold"),
                              fg=COLORS["text_primary"], bg=COLORS["card_bg"],
                              anchor="w", justify="left")
        name_label.pack(fill=tk.X)

        formula_label = tk.Label(content, text=formula_data["formula"],
                                 font=("Consolas", 11),
                                 fg=category_color, bg=COLORS["card_bg"],
                                 anchor="w", justify="left", wraplength=500)
        formula_label.pack(fill=tk.X, pady=(4, 2))

        desc_label = tk.Label(content, text=formula_data["desc"],
                              font=("Microsoft YaHei UI", 9),
                              fg=COLORS["text_secondary"], bg=COLORS["card_bg"],
                              anchor="w", justify="left", wraplength=500)
        desc_label.pack(fill=tk.X)

        for widget in [self, content, name_label, formula_label, desc_label, bar]:
            widget.bind("<Button-1>", self._handle_click)
            widget.bind("<Enter>", self._on_enter)
            widget.bind("<Leave>", self._on_leave)

        self._configure_highlight(self, False)

    def _configure_highlight(self, widget, highlight):
        try:
            if highlight:
                widget.configure(bg="#F7FAFC")
            else:
                widget.configure(bg=COLORS["card_bg"])
        except tk.TclError:
            pass

    def _on_enter(self, e):
        self._configure_highlight(self, True)

    def _on_leave(self, e):
        self._configure_highlight(self, False)

    def _handle_click(self, e):
        if self._on_click:
            self._on_click(self.formula_data)


class MathApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("📐 数学公式查询")
        self.geometry("960x720")
        self.minsize(800, 600)
        self.configure(bg=COLORS["bg_primary"])

        self.current_page = "home"
        self.current_category = None
        self.exercise_index = 0
        self.exercise_score = 0
        self.exercise_total = 0
        self.exercise_category = None
        self.exercise_questions = []

        self._build_ui()
        self._show_home()

    def _build_ui(self):
        self.top_bar = tk.Canvas(self, height=64, bg=COLORS["bg_primary"],
                                  highlightthickness=0)
        self.top_bar.pack(fill=tk.X, side=tk.TOP)
        self.top_bar.bind("<Configure>", self._draw_top_bar)

        self.back_btn_frame = tk.Frame(self.top_bar, bg=COLORS["bg_primary"])
        self.back_btn_canvas = None

        self.search_frame = tk.Frame(self, bg=COLORS["bg_primary"])
        self.search_frame.pack(fill=tk.X, padx=24, pady=(0, 8))

        search_inner = tk.Frame(self.search_frame, bg=COLORS["card_bg"])
        search_inner.pack(fill=tk.X)

        self.search_entry = tk.Entry(search_inner, font=("Microsoft YaHei UI", 12),
                                      bg=COLORS["card_bg"], fg=COLORS["text_primary"],
                                      relief="flat", bd=0, insertbackground=COLORS["accent_blue"])
        self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=16, pady=10)
        self.search_entry.insert(0, "🔍 搜索公式...")
        self.search_entry.bind("<FocusIn>", self._search_focus_in)
        self.search_entry.bind("<FocusOut>", self._search_focus_out)
        self.search_entry.bind("<KeyRelease>", self._on_search)

        self.content_frame = tk.Frame(self, bg=COLORS["bg_primary"])
        self.content_frame.pack(fill=tk.BOTH, expand=True, padx=24, pady=(0, 16))

        self.canvas = tk.Canvas(self.content_frame, bg=COLORS["bg_primary"],
                                 highlightthickness=0)
        self.scrollbar = ttk.Scrollbar(self.content_frame, orient="vertical",
                                        command=self.canvas.yview)
        self.scrollable_frame = tk.Frame(self.canvas, bg=COLORS["bg_primary"])

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )

        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
        self.canvas.bind_all("<Button-4>", self._on_mousewheel_linux)
        self.canvas.bind_all("<Button-5>", self._on_mousewheel_linux)

    def _draw_top_bar(self, event=None):
        self.top_bar.delete("gradient")
        w = self.top_bar.winfo_width()
        h = 64
        steps = 40
        for i in range(steps):
            ratio = i / steps
            r1, g1, b1 = int(COLORS["gradient_start"][1:3], 16), int(COLORS["gradient_start"][3:5], 16), int(COLORS["gradient_start"][5:7], 16)
            r2, g2, b2 = int(COLORS["gradient_end"][1:3], 16), int(COLORS["gradient_end"][3:5], 16), int(COLORS["gradient_end"][5:7], 16)
            r = int(r1 + (r2 - r1) * ratio)
            g = int(g1 + (g2 - g1) * ratio)
            b = int(b1 + (b2 - b1) * ratio)
            color = f"#{r:02x}{g:02x}{b:02x}"
            y0 = int(h * i / steps)
            y1 = int(h * (i + 1) / steps) + 1
            self.top_bar.create_rectangle(0, y0, w, y1, fill=color, outline="", tags="gradient")

        self.top_bar.create_text(w // 2, h // 2, text="📐 数学公式查询",
                                  fill="white", font=("Microsoft YaHei UI", 18, "bold"),
                                  tags="gradient")

    def _on_mousewheel(self, event):
        self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def _on_mousewheel_linux(self, event):
        if event.num == 4:
            self.canvas.yview_scroll(-1, "units")
        elif event.num == 5:
            self.canvas.yview_scroll(1, "units")

    def _clear_content(self):
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()

    def _search_focus_in(self, e):
        if self.search_entry.get() == "🔍 搜索公式...":
            self.search_entry.delete(0, tk.END)

    def _search_focus_out(self, e):
        if not self.search_entry.get():
            self.search_entry.insert(0, "🔍 搜索公式...")

    def _on_search(self, e):
        query = self.search_entry.get().strip()
        if query in ("🔍 搜索公式...", ""):
            if self.current_page == "home":
                self._show_home()
            return

        self._clear_content()
        self.current_page = "search"
        results = []
        for cat, formulas in FORMULAS.items():
            for f in formulas:
                if query.lower() in f["name"].lower() or query.lower() in f["formula"].lower() or query.lower() in f["desc"].lower():
                    results.append((cat, f))

        if not results:
            tk.Label(self.scrollable_frame, text=f"未找到与「{query}」相关的公式",
                     font=("Microsoft YaHei UI", 13), fg=COLORS["text_secondary"],
                     bg=COLORS["bg_primary"]).pack(pady=40)
            return

        tk.Label(self.scrollable_frame, text=f"搜索结果（{len(results)}条）",
                 font=("Microsoft YaHei UI", 13, "bold"), fg=COLORS["text_primary"],
                 bg=COLORS["bg_primary"]).pack(anchor="w", pady=(8, 12))

        for cat, f in results:
            color = CATEGORY_COLORS.get(cat, COLORS["accent_blue"])
            card = FormulaCard(self.scrollable_frame, f, color, on_click=self._show_formula_detail)
            card.pack(fill=tk.X, pady=4)

    def _show_home(self):
        self.current_page = "home"
        self.search_entry.delete(0, tk.END)
        self.search_entry.insert(0, "🔍 搜索公式...")
        self._clear_content()

        self._build_category_section("📘 初中数学", [
            ("初中代数", "方程、不等式、幂运算、乘法公式"),
            ("初中几何", "三角形、圆、多边形、弧长扇形"),
            ("初中统计", "平均数、方差、中位数、众数"),
        ])

        self._build_category_section("📗 高中数学", [
            ("高中集合与逻辑", "集合运算、充要条件"),
            ("高中函数", "指数函数、对数函数、二次函数"),
            ("高中三角函数", "诱导公式、和差化积、正余弦定理"),
            ("高中数列", "等差数列、等比数列、求和方法"),
            ("高中不等式", "均值不等式、柯西不等式"),
            ("高中向量", "数量积、平行垂直、坐标运算"),
            ("高中解析几何", "直线方程、圆、椭圆、双曲线、抛物线"),
            ("高中立体几何", "体积表面积、线面关系"),
            ("高中概率统计", "排列组合、二项分布、正态分布"),
            ("高中导数", "求导法则、极值最值、定积分"),
        ])

        self._build_category_section("📕 大学数学", [
            ("大学微积分", "洛必达、泰勒展开、重积分、格林公式"),
            ("大学线性代数", "行列式、矩阵、逆矩阵、特征值"),
            ("大学概率论", "全概率公式、贝叶斯、泊松分布"),
        ])

        tk.Label(self.scrollable_frame, text="", bg=COLORS["bg_primary"]).pack(pady=8)

        practice_frame = tk.Frame(self.scrollable_frame, bg=COLORS["bg_primary"])
        practice_frame.pack(pady=16)

        AnimatedButton(practice_frame, text="✏️  进入练习模式",
                       command=self._show_exercise_menu, width=240, height=50,
                       bg_color=COLORS["accent_purple"], font_size=14).pack()

    def _build_category_section(self, title, categories):
        tk.Label(self.scrollable_frame, text=title,
                 font=("Microsoft YaHei UI", 16, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["bg_primary"],
                 anchor="w").pack(fill=tk.X, pady=(16, 8))

        grid_frame = tk.Frame(self.scrollable_frame, bg=COLORS["bg_primary"])
        grid_frame.pack(fill=tk.X)

        for i, (cat_name, cat_desc) in enumerate(categories):
            row, col = divmod(i, 2)
            self._build_category_card(grid_frame, cat_name, cat_desc, row, col)

        grid_frame.columnconfigure(0, weight=1)
        grid_frame.columnconfigure(1, weight=1)

    def _build_category_card(self, parent, cat_name, cat_desc, row, col):
        color = CATEGORY_COLORS.get(cat_name, COLORS["accent_blue"])

        card = tk.Frame(parent, bg=COLORS["card_bg"], cursor="hand2")
        card.grid(row=row, column=col, padx=(0, 8) if col == 0 else (8, 0),
                  pady=4, sticky="ew")

        indicator = tk.Frame(card, bg=color, height=4)
        indicator.pack(fill=tk.X)

        inner = tk.Frame(card, bg=COLORS["card_bg"])
        inner.pack(fill=tk.BOTH, padx=14, pady=10)

        count = len(FORMULAS.get(cat_name, []))
        tk.Label(inner, text=cat_name, font=("Microsoft YaHei UI", 11, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["card_bg"],
                 anchor="w").pack(fill=tk.X)
        tk.Label(inner, text=f"{cat_desc}  |  {count}个公式",
                 font=("Microsoft YaHei UI", 9),
                 fg=COLORS["text_secondary"], bg=COLORS["card_bg"],
                 anchor="w", wraplength=380, justify="left").pack(fill=tk.X, pady=(2, 0))

        def on_enter(e, c=card, i=inner, ind=indicator):
            c.configure(bg="#F7FAFC")
            i.configure(bg="#F7FAFC")

        def on_leave(e, c=card, i=inner, ind=indicator):
            c.configure(bg=COLORS["card_bg"])
            i.configure(bg=COLORS["card_bg"])

        def on_click(e, cn=cat_name):
            self._show_category(cn)

        for widget in [card, inner, indicator]:
            widget.bind("<Enter>", on_enter)
            widget.bind("<Leave>", on_leave)
            widget.bind("<Button-1>", on_click)

        for child in inner.winfo_children():
            child.bind("<Enter>", on_enter)
            child.bind("<Leave>", on_leave)
            child.bind("<Button-1>", on_click)

    def _show_category(self, cat_name):
        self.current_page = "category"
        self.current_category = cat_name
        self._clear_content()

        color = CATEGORY_COLORS.get(cat_name, COLORS["accent_blue"])
        formulas = FORMULAS.get(cat_name, [])

        nav_frame = tk.Frame(self.scrollable_frame, bg=COLORS["bg_primary"])
        nav_frame.pack(fill=tk.X, pady=(4, 8))

        AnimatedButton(nav_frame, text="← 返回", command=self._show_home,
                       width=100, height=36, bg_color=COLORS["text_secondary"],
                       font_size=10, radius=8).pack(side=tk.LEFT)

        if cat_name in EXERCISES and len(EXERCISES[cat_name]) > 0:
            AnimatedButton(nav_frame, text="✏️ 练习", width=100, height=36,
                           command=lambda: self._start_exercise(cat_name),
                           bg_color=color, font_size=10, radius=8).pack(side=tk.RIGHT)

        tk.Label(self.scrollable_frame, text=cat_name,
                 font=("Microsoft YaHei UI", 20, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["bg_primary"],
                 anchor="w").pack(fill=tk.X, pady=(4, 12))

        for f in formulas:
            card = FormulaCard(self.scrollable_frame, f, color,
                               on_click=self._show_formula_detail)
            card.pack(fill=tk.X, pady=4)

    def _show_formula_detail(self, formula_data):
        detail = tk.Toplevel(self)
        detail.title(formula_data["name"])
        detail.geometry("520x360")
        detail.configure(bg=COLORS["card_bg"])
        detail.resizable(False, False)

        detail.update_idletasks()
        x = self.winfo_x() + (self.winfo_width() - 520) // 2
        y = self.winfo_y() + (self.winfo_height() - 360) // 2
        detail.geometry(f"+{x}+{y}")

        detail.grab_set()

        content = tk.Frame(detail, bg=COLORS["card_bg"])
        content.pack(fill=tk.BOTH, expand=True, padx=30, pady=24)

        tk.Label(content, text=formula_data["name"],
                 font=("Microsoft YaHei UI", 16, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["card_bg"],
                 wraplength=460, justify="left").pack(anchor="w", pady=(0, 16))

        formula_box = tk.Frame(content, bg=COLORS["hint_bg"],
                                highlightbackground=COLORS["hint_border"],
                                highlightthickness=1)
        formula_box.pack(fill=tk.X, pady=(0, 16))

        tk.Label(formula_box, text=formula_data["formula"],
                 font=("Consolas", 14), fg=COLORS["accent_blue"],
                 bg=COLORS["hint_bg"], justify="left",
                 wraplength=440).pack(padx=16, pady=14)

        tk.Label(content, text=formula_data["desc"],
                 font=("Microsoft YaHei UI", 11),
                 fg=COLORS["text_secondary"], bg=COLORS["card_bg"],
                 wraplength=460, justify="left").pack(anchor="w")

        AnimatedButton(content, text="关闭", command=detail.destroy,
                       width=120, height=38, bg_color=COLORS["accent_blue"],
                       font_size=11, radius=8).pack(pady=(20, 0))

    def _show_exercise_menu(self):
        self.current_page = "exercise_menu"
        self._clear_content()

        tk.Label(self.scrollable_frame, text="✏️  选择练习类别",
                 font=("Microsoft YaHei UI", 20, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["bg_primary"]).pack(pady=(16, 4))

        tk.Label(self.scrollable_frame, text="选择一个分类开始练习吧！",
                 font=("Microsoft YaHei UI", 11),
                 fg=COLORS["text_secondary"], bg=COLORS["bg_primary"]).pack(pady=(0, 16))

        nav_frame = tk.Frame(self.scrollable_frame, bg=COLORS["bg_primary"])
        nav_frame.pack(fill=tk.X, pady=(0, 8))

        AnimatedButton(nav_frame, text="← 返回", command=self._show_home,
                       width=100, height=36, bg_color=COLORS["text_secondary"],
                       font_size=10, radius=8).pack(side=tk.LEFT)

        for cat_name, questions in EXERCISES.items():
            if not questions:
                continue
            color = CATEGORY_COLORS.get(cat_name, COLORS["accent_blue"])

            card = tk.Frame(self.scrollable_frame, bg=COLORS["card_bg"], cursor="hand2")
            card.pack(fill=tk.X, pady=4)

            indicator = tk.Frame(card, bg=color, height=4)
            indicator.pack(fill=tk.X)

            inner = tk.Frame(card, bg=COLORS["card_bg"])
            inner.pack(fill=tk.BOTH, padx=14, pady=10)

            tk.Label(inner, text=cat_name, font=("Microsoft YaHei UI", 12, "bold"),
                     fg=COLORS["text_primary"], bg=COLORS["card_bg"],
                     anchor="w").pack(side=tk.LEFT)
            tk.Label(inner, text=f"{len(questions)} 道题",
                     font=("Microsoft YaHei UI", 10),
                     fg=COLORS["text_secondary"], bg=COLORS["card_bg"]).pack(side=tk.RIGHT)

            def on_enter(e, c=card, i=inner):
                c.configure(bg="#F7FAFC")
                i.configure(bg="#F7FAFC")

            def on_leave(e, c=card, i=inner):
                c.configure(bg=COLORS["card_bg"])
                i.configure(bg=COLORS["card_bg"])

            def on_click(e, cn=cat_name):
                self._start_exercise(cn)

            for widget in [card, inner, indicator]:
                widget.bind("<Enter>", on_enter)
                widget.bind("<Leave>", on_leave)
                widget.bind("<Button-1>", on_click)

            for child in inner.winfo_children():
                child.bind("<Enter>", on_enter)
                child.bind("<Leave>", on_leave)
                child.bind("<Button-1>", on_click)

    def _start_exercise(self, cat_name):
        self.current_page = "exercise"
        self.exercise_category = cat_name
        self.exercise_questions = list(EXERCISES.get(cat_name, []))
        random.shuffle(self.exercise_questions)
        self.exercise_index = 0
        self.exercise_score = 0
        self.exercise_total = len(self.exercise_questions)
        self._show_exercise_question()

    def _show_exercise_question(self):
        self._clear_content()

        if self.exercise_index >= self.exercise_total:
            self._show_exercise_result()
            return

        q = self.exercise_questions[self.exercise_index]
        color = CATEGORY_COLORS.get(self.exercise_category, COLORS["accent_blue"])

        nav_frame = tk.Frame(self.scrollable_frame, bg=COLORS["bg_primary"])
        nav_frame.pack(fill=tk.X, pady=(4, 8))

        AnimatedButton(nav_frame, text="← 退出", command=self._show_exercise_menu,
                       width=100, height=36, bg_color=COLORS["text_secondary"],
                       font_size=10, radius=8).pack(side=tk.LEFT)

        tk.Label(self.scrollable_frame,
                 text=f"第 {self.exercise_index + 1} / {self.exercise_total} 题    得分：{self.exercise_score}",
                 font=("Microsoft YaHei UI", 12),
                 fg=COLORS["text_secondary"], bg=COLORS["bg_primary"]).pack(anchor="w", pady=(8, 16))

        progress_frame = tk.Frame(self.scrollable_frame, bg=COLORS["bg_secondary"],
                                   height=6)
        progress_frame.pack(fill=tk.X, pady=(0, 16))
        progress_frame.pack_propagate(False)

        progress = (self.exercise_index) / self.exercise_total if self.exercise_total > 0 else 0
        fill_width = int(progress * progress_frame.winfo_reqwidth())
        progress_fill = tk.Frame(progress_frame, bg=color, height=6)
        progress_fill.place(relwidth=progress, relheight=1)

        card = tk.Frame(self.scrollable_frame, bg=COLORS["card_bg"])
        card.pack(fill=tk.X, pady=4)

        inner = tk.Frame(card, bg=COLORS["card_bg"])
        inner.pack(fill=tk.BOTH, padx=20, pady=16)

        tk.Label(inner, text=q["q"], font=("Microsoft YaHei UI", 14, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["card_bg"],
                 wraplength=600, justify="left").pack(anchor="w", pady=(0, 16))

        self._selected_option = tk.IntVar(value=-1)
        self._option_frames = []
        self._option_labels = []

        for i, opt in enumerate(q["options"]):
            opt_frame = tk.Frame(inner, bg=COLORS["bg_primary"], cursor="hand2",
                                  highlightbackground=COLORS["bg_secondary"],
                                  highlightthickness=1)
            opt_frame.pack(fill=tk.X, pady=3)

            opt_inner = tk.Frame(opt_frame, bg=COLORS["bg_primary"])
            opt_inner.pack(fill=tk.BOTH, padx=12, pady=8)

            letter = chr(65 + i)
            tk.Label(opt_inner, text=f"{letter}.", font=("Microsoft YaHei UI", 12, "bold"),
                     fg=COLORS["accent_blue"], bg=COLORS["bg_primary"]).pack(side=tk.LEFT, padx=(0, 8))
            tk.Label(opt_inner, text=opt, font=("Microsoft YaHei UI", 12),
                     fg=COLORS["text_primary"], bg=COLORS["bg_primary"]).pack(side=tk.LEFT)

            self._option_frames.append(opt_frame)
            self._option_labels.append(opt_inner)

            for widget in [opt_frame, opt_inner] + list(opt_inner.winfo_children()):
                widget.bind("<Button-1>", lambda e, idx=i: self._select_option(idx))

        self._submit_btn_frame = tk.Frame(inner, bg=COLORS["card_bg"])
        self._submit_btn_frame.pack(pady=(16, 0))

        self._submit_btn = AnimatedButton(self._submit_btn_frame, text="提交答案",
                                           command=lambda: self._submit_answer(q),
                                           width=160, height=42,
                                           bg_color=color, font_size=12, radius=8)
        self._submit_btn.pack()

        self._explain_frame = tk.Frame(inner, bg=COLORS["card_bg"])

    def _select_option(self, idx):
        self._selected_option.set(idx)
        for i, (frame, inner) in enumerate(zip(self._option_frames, self._option_labels)):
            if i == idx:
                frame.configure(highlightbackground=COLORS["accent_blue"],
                                highlightthickness=2)
                for child in inner.winfo_children():
                    try:
                        if isinstance(child, tk.Label) and child.cget("text").endswith(".") or True:
                            pass
                    except:
                        pass
            else:
                frame.configure(highlightbackground=COLORS["bg_secondary"],
                                highlightthickness=1)

    def _submit_answer(self, q):
        selected = self._selected_option.get()
        if selected == -1:
            return

        correct = q["answer"]
        is_correct = (selected == correct)

        if is_correct:
            self.exercise_score += 1

        for i, frame in enumerate(self._option_frames):
            if i == correct:
                frame.configure(highlightbackground=COLORS["correct"], highlightthickness=2)
            elif i == selected and not is_correct:
                frame.configure(highlightbackground=COLORS["wrong"], highlightthickness=2)
            else:
                frame.configure(highlightbackground=COLORS["bg_secondary"], highlightthickness=1)

        self._explain_frame.pack(fill=tk.X, pady=(16, 0))

        result_text = "✅ 回答正确！" if is_correct else "❌ 回答错误"
        result_color = COLORS["correct"] if is_correct else COLORS["wrong"]

        tk.Label(self._explain_frame, text=result_text,
                 font=("Microsoft YaHei UI", 13, "bold"),
                 fg=result_color, bg=COLORS["card_bg"]).pack(anchor="w")

        explain_box = tk.Frame(self._explain_frame, bg=COLORS["hint_bg"],
                                highlightbackground=COLORS["hint_border"],
                                highlightthickness=1)
        explain_box.pack(fill=tk.X, pady=(8, 0))

        correct_text = f"正确答案：{chr(65 + correct)}. {q['options'][correct]}"
        if not is_correct:
            tk.Label(explain_box, text=correct_text,
                     font=("Microsoft YaHei UI", 11, "bold"),
                     fg=COLORS["correct"], bg=COLORS["hint_bg"]).pack(anchor="w", padx=12, pady=(10, 4))

        tk.Label(explain_box, text=f"解析：{q['explain']}",
                 font=("Microsoft YaHei UI", 11),
                 fg=COLORS["text_primary"], bg=COLORS["hint_bg"],
                 wraplength=560, justify="left").pack(anchor="w", padx=12, pady=(4, 10))

        self._submit_btn_frame.destroy()
        next_frame = tk.Frame(self._explain_frame, bg=COLORS["card_bg"])
        next_frame.pack(pady=(12, 0))

        btn_text = "下一题 →" if self.exercise_index < self.exercise_total - 1 else "查看结果 →"
        AnimatedButton(next_frame, text=btn_text,
                       command=self._next_exercise_question,
                       width=160, height=42,
                       bg_color=COLORS["accent_blue"], font_size=12, radius=8).pack()

    def _next_exercise_question(self):
        self.exercise_index += 1
        self._show_exercise_question()

    def _show_exercise_result(self):
        self._clear_content()

        score_pct = (self.exercise_score / self.exercise_total * 100) if self.exercise_total > 0 else 0

        card = tk.Frame(self.scrollable_frame, bg=COLORS["card_bg"])
        card.pack(fill=tk.X, pady=40)

        inner = tk.Frame(card, bg=COLORS["card_bg"])
        inner.pack(fill=tk.BOTH, padx=30, pady=30)

        emoji = "🎉" if score_pct >= 80 else "👍" if score_pct >= 60 else "💪"
        tk.Label(inner, text=f"{emoji}  练习完成！",
                 font=("Microsoft YaHei UI", 22, "bold"),
                 fg=COLORS["text_primary"], bg=COLORS["card_bg"]).pack(pady=(0, 16))

        score_color = COLORS["correct"] if score_pct >= 60 else COLORS["wrong"]
        tk.Label(inner, text=f"{self.exercise_score} / {self.exercise_total}",
                 font=("Microsoft YaHei UI", 36, "bold"),
                 fg=score_color, bg=COLORS["card_bg"]).pack()

        tk.Label(inner, text=f"正确率 {score_pct:.0f}%",
                 font=("Microsoft YaHei UI", 14),
                 fg=COLORS["text_secondary"], bg=COLORS["card_bg"]).pack(pady=(4, 24))

        if score_pct >= 90:
            msg = "太棒了！你对这些公式掌握得非常好！"
        elif score_pct >= 70:
            msg = "不错！再多练习一下就能更熟练了！"
        elif score_pct >= 50:
            msg = "继续加油！建议回顾一下相关公式！"
        else:
            msg = "别灰心！回到公式页面再复习一下吧！"

        tk.Label(inner, text=msg, font=("Microsoft YaHei UI", 12),
                 fg=COLORS["text_secondary"], bg=COLORS["card_bg"]).pack(pady=(0, 24))

        btn_frame = tk.Frame(inner, bg=COLORS["card_bg"])
        btn_frame.pack()

        AnimatedButton(btn_frame, text="再做一次",
                       command=lambda: self._start_exercise(self.exercise_category),
                       width=140, height=42, bg_color=COLORS["accent_blue"],
                       font_size=12, radius=8).pack(side=tk.LEFT, padx=8)

        AnimatedButton(btn_frame, text="返回首页",
                       command=self._show_home,
                       width=140, height=42, bg_color=COLORS["accent_purple"],
                       font_size=12, radius=8).pack(side=tk.LEFT, padx=8)


if __name__ == "__main__":
    app = MathApp()
    app.mainloop()
