<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MyEngNote</title>
	<atom:link href="https://myengnote.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://myengnote.com</link>
	<description></description>
	<lastBuildDate>Mon, 20 Jul 2026 23:07:51 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>
	<item>
		<title>📚 공학 계산기 &#038; 시뮬레이터 전체 모음</title>
		<link>https://myengnote.com/engineering-calculators-simulators-index/</link>
					<comments>https://myengnote.com/engineering-calculators-simulators-index/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Mon, 20 Jul 2026 23:07:51 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<guid isPermaLink="false">https://myengnote.com/engineering-calculators-simulators-index/</guid>

					<description><![CDATA[기계공학설계, 기계요소 표준 규격, 유체역학, 열역학, 응력 및 진동 등 46종의 공학 시뮬레이터 및 간편 계산기를 한곳에 모았습니다. 실시간 2D 그래픽 시각화 뷰를 지원합니다.]]></description>
										<content:encoded><![CDATA[

<style>
.eng-index-container {
    max-width: 1200px;
    margin: 0 auto;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    color: #1e293b;
    padding: 20px 0;
}
.eng-search-box {
    width: 100%;
    max-width: 600px;
    margin: 0 auto 40px auto;
    display: block;
    padding: 14px 24px;
    font-size: 16px;
    border: 2px solid #e2e8f0;
    border-radius: 30px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
    outline: none;
    transition: all 0.3s ease;
}
.eng-search-box:focus {
    border-color: #3b82f6;
    box-shadow: 0 10px 15px -3px rgba(59, 130, 246, 0.1), 0 4px 6px -2px rgba(59, 130, 246, 0.05);
}
.eng-section-title {
    font-size: 22px;
    font-weight: 700;
    color: #0f172a;
    margin-top: 40px;
    margin-bottom: 20px;
    padding-bottom: 8px;
    border-bottom: 2px solid #f1f5f9;
    display: flex;
    align-items: center;
}
.eng-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
    margin-bottom: 40px;
}
.eng-card {
    background: #ffffff;
    border: 1px solid #e2e8f0;
    border-radius: 14px;
    padding: 20px;
    text-decoration: none !important;
    color: inherit !important;
    display: flex;
    flex-direction: column;
    transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 1px 3px rgba(0,0,0,0.02);
}
.eng-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 12px 20px -8px rgba(0, 0, 0, 0.08);
    border-color: #3b82f6;
}
.eng-card-header {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}
.eng-card-icon {
    font-size: 24px;
}
.eng-card-title {
    font-size: 16px;
    font-weight: 600;
    color: #0f172a;
    line-height: 1.4;
}
.eng-card-desc {
    font-size: 13px;
    color: #64748b;
    line-height: 1.5;
    flex-grow: 1;
}
.eng-card-badge {
    font-size: 11px;
    font-weight: 500;
    padding: 3px 10px;
    border-radius: 20px;
    background: #f1f5f9;
    color: #475569;
    align-self: flex-start;
    margin-top: 15px;
    transition: all 0.2s ease;
}
.eng-card:hover .eng-card-badge {
    background: #eff6ff;
    color: #2563eb;
}
.no-results-msg {
    display: none;
    text-align: center;
    color: #64748b;
    font-size: 16px;
    margin: 40px 0;
}
</style>

<div class="eng-index-container">
    <input type="text" id="engSearchInput" class="eng-search-box" placeholder="&#x1f50d; 필요한 계산기나 시뮬레이터를 검색하세요... (예: 기어, 토크, 보)">
    
    <div id="noResults" class="no-results-msg">
        검색 결과가 없습니다.
    </div>

    <div class="eng-section-block" id="sec-power-transmission">
        <h2 class="eng-section-title"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2699.png" alt="⚙" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 동력 전달 &#038; 기계 설계 (Power Transmission &#038; Machine Design)</h2>
        <div class="eng-grid">

            <a href="https://myengnote.com/gear-ratio-calculator-simulator-3/" class="eng-card" data-title="기어비 계산기 &#038; 시뮬레이터" data-desc="기어 잇수와 입력 rpm을 조절하여 기어비, 출력 속도, 토크 변화 및 기하학적 치수를 실시간으로 계산하고 완벽히 맞물려 회전하는 기어열을 시각화하는 초정밀 2d 물리 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2699.png" alt="⚙" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">기어비 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">기어 잇수와 입력 RPM을 조절하여 기어비, 출력 속도, 토크 변화 및 기하학적 치수를 실시간으로 계산하고 완벽히 맞물려 회전하는 기어열을 시각화하는 초정밀 2D 물리 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/belt-pulley-speed-calculator-simulator-2/" class="eng-card" data-title="벨트-풀리 계산기 &#038; 시뮬레이터" data-desc="두 풀리의 지름, 축간거리, 입력 rpm을 조절하여 벨트 길이, 접촉각, 벨트 속도 및 출력 속도를 실시간 계산하고 부드럽게 구동되는 벨트 전동 시스템을 시각화하는 초정밀 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3a1.png" alt="🎡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">벨트-풀리 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">두 풀리의 지름, 축간거리, 입력 RPM을 조절하여 벨트 길이, 접촉각, 벨트 속도 및 출력 속도를 실시간 계산하고 부드럽게 구동되는 벨트 전동 시스템을 시각화하는 초정밀 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/torque-power-converter-simulator/" class="eng-card" data-title="토크 &#038; 동력 계산기 &#038; 시뮬레이터" data-desc="동력(kw, hp), 토크(n·m, kgf·m), 회전 속도(rpm) 간의 상호 변환을 계산하고, 부하에 따른 모터의 회전 및 발열 상호작용을 시각화하는 초정밀 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3cb.png" alt="🏋" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">토크 &#038; 동력 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">동력(kW, HP), 토크(N·m, kgf·m), 회전 속도(RPM) 간의 상호 변환을 계산하고, 부하에 따른 모터의 회전 및 발열 상호작용을 시각화하는 초정밀 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/chain-sprocket-speed-calculator-simulator/" class="eng-card" data-title="체인-스프로킷 계산기 &#038; 시뮬레이터" data-desc="체인 피치, 스프로킷 잇수(z), 회전 속도(rpm) 및 전달 동력을 입력하여 체인의 주속도, 피치원 지름(pcd), 작용 인장력을 실시간으로 계산하고 시각화하는 초정밀 2d 물리 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26d3.png" alt="⛓" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">체인-스프로킷 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">체인 피치, 스프로킷 잇수(Z), 회전 속도(RPM) 및 전달 동력을 입력하여 체인의 주속도, 피치원 지름(PCD), 작용 인장력을 실시간으로 계산하고 시각화하는 초정밀 2D 물리 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/bearing-life-calculator-simulator/" class="eng-card" data-title="베어링 수명 계산기 &#038; 시뮬레이터" data-desc="iso 281 규격에 의거하여 볼/롤러 베어링의 동당량 하중과 정격 수명(l10h)을 계산하고, 부하 벡터에 따른 궤도면 접촉 응력 분포와 윤활 유동을 시각화하는 초정밀 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f300.png" alt="🌀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">베어링 수명 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">ISO 281 규격에 의거하여 볼/롤러 베어링의 동당량 하중과 정격 수명(L10h)을 계산하고, 부하 벡터에 따른 궤도면 접촉 응력 분포와 윤활 유동을 시각화하는 초정밀 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/bolt-torque-tension-calculator-simulator/" class="eng-card" data-title="볼트 체결 토크 계산기 &#038; 시뮬레이터" data-desc="볼트 호칭 지름, 강도 등급, 마찰 계수에 따른 체결 토크(torque)와 볼트 축력(tension) 간의 물리적 상호작용을 정밀 계산하고, 축부 인장 응력과 피체 체결압 분포를 시각화하는 2d 기계요소 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f527.png" alt="🔧" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">볼트 체결 토크 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">볼트 호칭 지름, 강도 등급, 마찰 계수에 따른 체결 토크(Torque)와 볼트 축력(Tension) 간의 물리적 상호작용을 정밀 계산하고, 축부 인장 응력과 피체 체결압 분포를 시각화하는 2D 기계요소 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/spring-deflection-stiffness-calculator-simulator/" class="eng-card" data-title="스프링 처짐 계산기 &#038; 시뮬레이터" data-desc="소선 지름, 코일 평균 지름, 유효 권수 및 가해진 하중에 따른 코일 스프링의 강성(stiffness), 처짐량(deflection), wahl 보정 응력을 정밀 계산하고 스프링의 실시간 기하학적 압축 상태를 시각화하는 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1fa97.png" alt="🪗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">스프링 처짐 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">소선 지름, 코일 평균 지름, 유효 권수 및 가해진 하중에 따른 코일 스프링의 강성(Stiffness), 처짐량(Deflection), Wahl 보정 응력을 정밀 계산하고 스프링의 실시간 기하학적 압축 상태를 시각화하는 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/fit-tolerance-iso286-calculator-simulator-2/" class="eng-card" data-title="끼워맞춤 공차 계산기 &#038; 시뮬레이터" data-desc="iso 286 규격에 의거한 축과 구멍의 공차 등급(h7, g6 등)과 기준 치수에 따라 정밀 치수 허용 한계, 최대/최소 틈새 및 죔새를 실시간 계산하고 마이크로 공차 밴드의 맞물림 영역을 1000배율 확대 시각화하는 2d 공학 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d0.png" alt="📐" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">끼워맞춤 공차 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">ISO 286 규격에 의거한 축과 구멍의 공차 등급(H7, g6 등)과 기준 치수에 따라 정밀 치수 허용 한계, 최대/최소 틈새 및 죔새를 실시간 계산하고 마이크로 공차 밴드의 맞물림 영역을 1000배율 확대 시각화하는 2D 공학 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/welded-joint-strength-calculator/" class="eng-card" data-title="용접 강도 계산기 &#038; 시뮬레이터" data-desc="용접부의 길이, 다리 크기(목두께), 가해지는 하중 및 전극 강도(exx)를 실시간 조절하여 맞대기(butt) 및 필렛(fillet) 용접의 유효 목단면적, 전단/인장 응력, aisc 기준 허용 안전율을 산출하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">용접 강도 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">용접부의 길이, 다리 크기(목두께), 가해지는 하중 및 전극 강도(Exx)를 실시간 조절하여 맞대기(Butt) 및 필렛(Fillet) 용접의 유효 목단면적, 전단/인장 응력, AISC 기준 허용 안전율을 산출하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/motor-selection-calculator-simulator/" class="eng-card" data-title="모터 선정 계산기 &#038; 시뮬레이터" data-desc="부하의 질량, 직경, 가속 시간 및 목표 회전수를 설정하여 소요 토크, 관성모멘트, 가속 동력 및 효율을 고려한 최적의 모터 규격(kw)을 실시간으로 계산하고 시각화하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50c.png" alt="🔌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">모터 선정 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">부하의 질량, 직경, 가속 시간 및 목표 회전수를 설정하여 소요 토크, 관성모멘트, 가속 동력 및 효율을 고려한 최적의 모터 규격(kW)을 실시간으로 계산하고 시각화하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/inverter-motor-vfd-calculator-simulator/" class="eng-card" data-title="인버터 슬립 계산기 &#038; 시뮬레이터" data-desc="주파수와 모터 극수를 제어하여 유도전동기의 동기 속도, 실제 회전 속도 및 슬립(slip)을 계산하고, v/f 패턴 곡선 및 고정자 회전자계의 속도 편차를 실시간으로 시각화하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f39b.png" alt="🎛" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">인버터 슬립 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">주파수와 모터 극수를 제어하여 유도전동기의 동기 속도, 실제 회전 속도 및 슬립(Slip)을 계산하고, V/F 패턴 곡선 및 고정자 회전자계의 속도 편차를 실시간으로 시각화하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/flywheel-energy-storage-calculator-simulator/" class="eng-card" data-title="플라이휠 관성 계산기 &#038; 시뮬레이터" data-desc="플라이휠의 질량, 반경 치수, 평균 회전 속도 및 엔진 맥동 에너지에 따른 회전 관성 모멘트(i), 운동 에너지 저장량, 회전 속도 변동 계수(cf)를 실시간 연산하고 속도 주기 맥동을 그래픽 시각화하는 초정밀 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6de.png" alt="🛞" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">플라이휠 관성 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">플라이휠의 질량, 반경 치수, 평균 회전 속도 및 엔진 맥동 에너지에 따른 회전 관성 모멘트(I), 운동 에너지 저장량, 회전 속도 변동 계수(Cf)를 실시간 연산하고 속도 주기 맥동을 그래픽 시각화하는 초정밀 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/cam-mechanism-profile-motion-simulator/" class="eng-card" data-title="캠 기구 계산기 &#038; 시뮬레이터" data-desc="기초원 반경, 리프트 양, 회전 속도 및 캠 형상(심편심, 하트형, 등속도)에 따라 결정되는 종동절의 실시간 변위(displacement), 속도(velocity), 가속도(acceleration)를 2d 역학 물리엔진으로 가시화하는 명품 기계요소 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f529.png" alt="🔩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">캠 기구 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">기초원 반경, 리프트 양, 회전 속도 및 캠 형상(심편심, 하트형, 등속도)에 따라 결정되는 종동절의 실시간 변위(Displacement), 속도(Velocity), 가속도(Acceleration)를 2D 역학 물리엔진으로 가시화하는 명품 기계요소 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/clutch-brake-torque-power-simulator/" class="eng-card" data-title="클러치 &#038; 브레이크 계산기 &#038; 시뮬레이터" data-desc="마찰 계수, 작용 하중, 접촉 반경 및 랩 각도에 따른 단판 클러치의 동력 전달(uniform wear/pressure)과 밴드 브레이크의 제동 토크 및 인장비(euler-eytelwein)를 정밀 해석하고 마찰 맞물림/제동 거동을 2d 그래픽으로 검증하는 복합 기계요소 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6d1.png" alt="🛑" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">클러치 &#038; 브레이크 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">마찰 계수, 작용 하중, 접촉 반경 및 랩 각도에 따른 단판 클러치의 동력 전달(Uniform Wear/Pressure)과 밴드 브레이크의 제동 토크 및 인장비(Euler-Eytelwein)를 정밀 해석하고 마찰 맞물림/제동 거동을 2D 그래픽으로 검증하는 복합 기계요소 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

        </div>
    </div>

    <div class="eng-section-block" id="sec-fluid-thermal">
        <h2 class="eng-section-title"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a7.png" alt="💧" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 유체 &#038; 열역학 &#038; 에너지 (Fluid, Thermal &#038; Energy Systems)</h2>
        <div class="eng-grid">

            <a href="https://myengnote.com/reynolds-number-calculator-simulator/" class="eng-card" data-title="레이놀즈 수 계산기 &#038; 시뮬레이터" data-desc="유체의 밀도, 점도, 배관 직경 및 유속을 입력하여 레이놀즈 수를 실시간 계산하고, 층류(laminar), 천이(transition), 난류(turbulent) 구역의 유동 흐름을 2d 물리 엔진으로 시각화하는 전문 웹 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ea.png" alt="🧪" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">레이놀즈 수 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">유체의 밀도, 점도, 배관 직경 및 유속을 입력하여 레이놀즈 수를 실시간 계산하고, 층류(Laminar), 천이(Transition), 난류(Turbulent) 구역의 유동 흐름을 2D 물리 엔진으로 시각화하는 전문 웹 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/pipe-flow-velocity-calculator-simulator/" class="eng-card" data-title="배관 유량 계산기 &#038; 시뮬레이터" data-desc="배관의 내경(d)과 설계 유량(q)을 입력하여 단면 유속(v)을 실시간 산출하고, 배관 내 유속에 따른 권장 유속 조건 만족 여부 판정과 유체 흐름을 물리 엔진으로 시각화하는 고정밀 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a7.png" alt="💧" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">배관 유량 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">배관의 내경(D)과 설계 유량(Q)을 입력하여 단면 유속(v)을 실시간 산출하고, 배관 내 유속에 따른 권장 유속 조건 만족 여부 판정과 유체 흐름을 물리 엔진으로 시각화하는 고정밀 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/bernoulli-venturi-effect-calculator-simulator/" class="eng-card" data-title="베르누이 계산기 &#038; 시뮬레이터" data-desc="벤투리 관(venturi tube)의 입구와 목(throat) 직경, 유속, 정압을 입력하여 베르누이 정리(bernoulli's theorem)에 의한 속도 상승 및 정압 강하(venturi effect)를 실시간 해석하고 압력계를 시각화하는 2d 물리 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1fa82.png" alt="🪂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">베르누이 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">벤투리 관(Venturi Tube)의 입구와 목(Throat) 직경, 유속, 정압을 입력하여 베르누이 정리(Bernoulli&#8217;s Theorem)에 의한 속도 상승 및 정압 강하(Venturi Effect)를 실시간 해석하고 압력계를 시각화하는 2D 물리 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/thermal-expansion-calculator-simulator/" class="eng-card" data-title="열팽창 계산기 &#038; 시뮬레이터" data-desc="온도 변화에 따른 다양한 금속 봉의 길이 팽창을 실시간 시각화하고, 선팽창 공식과 마이크로 미터 단위의 변위를 물리 모델링과 아토믹 진동으로 보여주는 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1fab5.png" alt="🪵" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">열팽창 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">온도 변화에 따른 다양한 금속 봉의 길이 팽창을 실시간 시각화하고, 선팽창 공식과 마이크로 미터 단위의 변위를 물리 모델링과 아토믹 진동으로 보여주는 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/heat-transfer-conduction-calculator/" class="eng-card" data-title="열전달 계산기 &#038; 시뮬레이터" data-desc="전도, 대류 및 단열재 3중 복합 벽체 구조를 통과하는 열유동을 실시간 유한차분 모델링으로 해석하여 온도 구배 선도와 총 열손실을 정밀하게 계산하는 공학 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f321.png" alt="🌡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">열전달 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">전도, 대류 및 단열재 3중 복합 벽체 구조를 통과하는 열유동을 실시간 유한차분 모델링으로 해석하여 온도 구배 선도와 총 열손실을 정밀하게 계산하는 공학 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/thin-walled-pressure-vessel-calculator-2/" class="eng-card" data-title="압력용기 계산기 &#038; 시뮬레이터" data-desc="실린더형 및 구형 압력용기의 내경, 벽면 두께, 작동 내압 및 재료 항복강도를 조절하여 박막 압력용기 공식에 입각한 원주 응력(hoop), 축 방향 응력(longitudinal), 최대 전단 응력 및 안전율과 파열 시뮬레이션을 제공하는 계산기입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e2.png" alt="🛢" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">압력용기 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">실린더형 및 구형 압력용기의 내경, 벽면 두께, 작동 내압 및 재료 항복강도를 조절하여 박막 압력용기 공식에 입각한 원주 응력(Hoop), 축 방향 응력(Longitudinal), 최대 전단 응력 및 안전율과 파열 시뮬레이션을 제공하는 계산기입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/orifice-flow-torricelli-calculator-simulator/" class="eng-card" data-title="오리피스 유량 계산기 &#038; 시뮬레이터" data-desc="오리피스 구경(d), 수두 높이(h), 유출 계수(cd)를 입력하여 토리첼리 정리(torricelli's law)에 의한 유출 속도 및 토출 유량을 계산하고, 아름다운 물 분출 궤적을 2d 포물선 물리 엔진으로 시각화하는 계산기입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26f2.png" alt="⛲" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">오리피스 유량 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">오리피스 구경(d), 수두 높이(H), 유출 계수(Cd)를 입력하여 토리첼리 정리(Torricelli&#8217;s Law)에 의한 유출 속도 및 토출 유량을 계산하고, 아름다운 물 분출 궤적을 2D 포물선 물리 엔진으로 시각화하는 계산기입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/pipe-friction-pressure-drop-darcy-weisbach/" class="eng-card" data-title="배관 마찰손실 계산기 &#038; 시뮬레이터" data-desc="배관 구경, 배관 길이, 설계 유량 및 재질별 표면 조도(ε)를 대입하여 레이놀즈수(re) 판정, haaland 공식에 의한 darcy 마찰계수(f), 배관 마찰 압력 손실을 실시간 해석하는 엔지니어링 계산기입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c9.png" alt="📉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">배관 마찰손실 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">배관 구경, 배관 길이, 설계 유량 및 재질별 표면 조도(ε)를 대입하여 레이놀즈수(Re) 판정, Haaland 공식에 의한 Darcy 마찰계수(f), 배관 마찰 압력 손실을 실시간 해석하는 엔지니어링 계산기입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/hydraulic-cylinder-force-velocity-calculator-simulator/" class="eng-card" data-title="유압 실린더 계산기 &#038; 시뮬레이터" data-desc="실린더 내경(bore), 로드경(rod), 작동 압력, 공급 유량을 조절하여 전진/후진 추력(force)과 피스톤 이동 유동 속도를 실시간 산출하고, 밸브 절환에 따른 양방향 거동을 모사하는 고성밀 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f69c.png" alt="🚜" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">유압 실린더 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">실린더 내경(Bore), 로드경(Rod), 작동 압력, 공급 유량을 조절하여 전진/후진 추력(Force)과 피스톤 이동 유동 속도를 실시간 산출하고, 밸브 절환에 따른 양방향 거동을 모사하는 고성밀 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/pneumatic-cylinder-air-consumption-force-calculator/" class="eng-card" data-title="공압 실린더 계산기 &#038; 시뮬레이터" data-desc="실린더 보어 내경, 로드경, 작동 스트로크, 제어 압력 및 분당 작동 주기를 입력하여 실린더 추력(n)과 에어 소모량(nl/min)을 실시간 해석하는 공장 자동화 설계용 물리 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a8.png" alt="💨" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">공압 실린더 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">실린더 보어 내경, 로드경, 작동 스트로크, 제어 압력 및 분당 작동 주기를 입력하여 실린더 추력(N)과 에어 소모량(NL/min)을 실시간 해석하는 공장 자동화 설계용 물리 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/pump-power-shaft-motor-calculator-simulator/" class="eng-card" data-title="펌프 양정 계산기 &#038; 시뮬레이터" data-desc="설계 유량(q), 전양정(h), 유체 밀도, 펌프 효율을 조절하여 수동력(water power), 축동력(shaft power), 모터 설계 동력을 실시간 연산하고 유체를 위로 이송하는 펌프 운전을 가시화하는 2d 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a1.png" alt="⚡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">펌프 양정 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">설계 유량(Q), 전양정(H), 유체 밀도, 펌프 효율을 조절하여 수동력(Water Power), 축동력(Shaft Power), 모터 설계 동력을 실시간 연산하고 유체를 위로 이송하는 펌프 운전을 가시화하는 2D 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/heat-exchanger-lmtd-ntu-calculator/" class="eng-card" data-title="열교환기 계산기 &#038; 시뮬레이터" data-desc="대향류와 평행류 배열에 따른 이중관 열교환기의 출구 온도, 전열량, 대수평균온도차(lmtd) 및 유용도(ntu)를 실시간 수치 해석하고 동적 온도 구배를 시각화하는 계산기입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f504.png" alt="🔄" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">열교환기 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">대향류와 평행류 배열에 따른 이중관 열교환기의 출구 온도, 전열량, 대수평균온도차(LMTD) 및 유용도(NTU)를 실시간 수치 해석하고 동적 온도 구배를 시각화하는 계산기입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/refrigeration-cooling-cycle-cop-calculator/" class="eng-card" data-title="냉각사이클 계산기 &#038; 시뮬레이터" data-desc="압축기 효율, 증발 온도 및 응축 온도를 실시간 입력받아 냉동 사이클의 4대 작동 상태를 시뮬레이션하고, 압축기 일량, 냉동 능력 및 성적계수(cop)를 압력-엔탈피 선도와 함께 렌더링하는 명품 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2744.png" alt="❄" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">냉각사이클 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">압축기 효율, 증발 온도 및 응축 온도를 실시간 입력받아 냉동 사이클의 4대 작동 상태를 시뮬레이션하고, 압축기 일량, 냉동 능력 및 성적계수(COP)를 압력-엔탈피 선도와 함께 렌더링하는 명품 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/industrial-boiler-efficiency-calculator-losses/" class="eng-card" data-title="보일러 효율 계산기 &#038; 시뮬레이터" data-desc="연소 가스 온도, 과잉 공기(산소 농도), 보일러 부하율 및 연료 종류를 조절하여 asme ptc 4.1 간접법 표준에 의거한 주요 열손실 인자들을 실시간 계산하고 효율을 높이는 운전 지점을 제어하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3ed.png" alt="🏭" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">보일러 효율 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">연소 가스 온도, 과잉 공기(산소 농도), 보일러 부하율 및 연료 종류를 조절하여 ASME PTC 4.1 간접법 표준에 의거한 주요 열손실 인자들을 실시간 계산하고 효율을 높이는 운전 지점을 제어하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

        </div>
    </div>

    <div class="eng-section-block" id="sec-solid-mechanics">
        <h2 class="eng-section-title"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f309.png" alt="🌉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 고체역학 &#038; 물리학 &#038; 진동 (Solid Mechanics, Physics &#038; Vibrations)</h2>
        <div class="eng-grid">

            <a href="https://myengnote.com/hydroelectric-energy-conversion-calculator-simulator/" class="eng-card" data-title="수력 발전 계산기 &#038; 시뮬레이터" data-desc="취수원 수두 낙차 높이와 체적 유량을 기반으로 위치에너지가 회전 운동에너지를 거쳐 전기에너지(mw)로 변환되는 전 과정을 실시간 2d 발전기 물리 흐름으로 시각화하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3a2.png" alt="🎢" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">수력 발전 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">취수원 수두 낙차 높이와 체적 유량을 기반으로 위치에너지가 회전 운동에너지를 거쳐 전기에너지(MW)로 변환되는 전 과정을 실시간 2D 발전기 물리 흐름으로 시각화하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/friction-force-inclined-plane-calculator-simulator/" class="eng-card" data-title="마찰력 계산기 &#038; 시뮬레이터" data-desc="경사면 위에 가해진 물체의 질량, 경사각, 정지/운동 마찰계수를 조절하여 수직항력 및 슬라이딩 임계점 속도를 계산하고 물체의 미끄러짐 가속 운행을 실시간 시뮬레이션하는 기계공학 계산기입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6f9.png" alt="🛹" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">마찰력 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">경사면 위에 가해진 물체의 질량, 경사각, 정지/운동 마찰계수를 조절하여 수직항력 및 슬라이딩 임계점 속도를 계산하고 물체의 미끄러짐 가속 운행을 실시간 시뮬레이션하는 기계공학 계산기입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/impulse-momentum-calculator-simulator/" class="eng-card" data-title="충격량 운동량 계산기 &#038; 시뮬레이터" data-desc="질량, 충돌 전후의 속도 변화, 접촉 시간(크럼플존)을 다각도로 설정하여 충격력(n)과 운동량의 변화를 정밀 연산하고 실시간 변형 거동을 물리 애니메이션으로 확인하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a5.png" alt="💥" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">충격량 운동량 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">질량, 충돌 전후의 속도 변화, 접촉 시간(크럼플존)을 다각도로 설정하여 충격력(N)과 운동량의 변화를 정밀 연산하고 실시간 변형 거동을 물리 애니메이션으로 확인하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/pendulum-dynamics-calculator-simulator/" class="eng-card" data-title="단진자 주기 계산기 &#038; 시뮬레이터" data-desc="진자의 길이, 추의 질량, 초기 요동 각도 및 공기 감쇠계수를 설정하여 실시간 비선형 운동궤적을 추적하고, 동적 장력과 위치/운동 에너지 보존 거동을 분석하는 물리 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f570.png" alt="🕰" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">단진자 주기 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">진자의 길이, 추의 질량, 초기 요동 각도 및 공기 감쇠계수를 설정하여 실시간 비선형 운동궤적을 추적하고, 동적 장력과 위치/운동 에너지 보존 거동을 분석하는 물리 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/projectile-motion-calculator-simulator/" class="eng-card" data-title="포물선 운동 계산기 &#038; 시뮬레이터" data-desc="포사체의 발사 속도, 각도, 초기 높이 및 공기 저항 계수를 변수로 정밀 설정하여 2d 궤적을 실시간으로 추적하고 발사 역학 물리 엔진을 구동하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">포물선 운동 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">포사체의 발사 속도, 각도, 초기 높이 및 공기 저항 계수를 변수로 정밀 설정하여 2D 궤적을 실시간으로 추적하고 발사 역학 물리 엔진을 구동하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/stress-strain-relation-calculator-simulator/" class="eng-card" data-title="응력-변형률 계산기 &#038; 시뮬레이터" data-desc="재료의 단면적, 게이지 길이, 인장 하중과 재료 특성(탄성계수, 항복/인장강도)을 실시간 변동하여 응력-변형률 곡선 상의 거동 영역(탄성, 항복, 소성 변형, 네킹) 및 파단 시점과 안전율을 분석하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c8.png" alt="📈" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">응력-변형률 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">재료의 단면적, 게이지 길이, 인장 하중과 재료 특성(탄성계수, 항복/인장강도)을 실시간 변동하여 응력-변형률 곡선 상의 거동 영역(탄성, 항복, 소성 변형, 네킹) 및 파단 시점과 안전율을 분석하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/safety-factor-failure-theories-calculator/" class="eng-card" data-title="안전계수 계산기 &#038; 시뮬레이터" data-desc="항복강도, 인장/압축강도 및 2차원 응력 상태(σx, σy, τxy)를 실시간 조절하여 주응력 및 본 미세스 등가응력을 산출하고, 연성(von mises 타원) 및 취성(coulomb-mohr) 파괴 모형 엔벨로프와 안전율을 시각화 분석하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e1.png" alt="🛡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">안전계수 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">항복강도, 인장/압축강도 및 2차원 응력 상태(σx, σy, τxy)를 실시간 조절하여 주응력 및 본 미세스 등가응력을 산출하고, 연성(Von Mises 타원) 및 취성(Coulomb-Mohr) 파괴 모형 엔벨로프와 안전율을 시각화 분석하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/moment-of-inertia-cross-sections-calculator/" class="eng-card" data-title="단면 2차 모멘트 계산기 &#038; 시뮬레이터" data-desc="사각형, 중공 사각형, i형강, 원형 단면의 폭, 높이, 두께를 실시간 설정하여 단면적, 도심축, 단면 2차 모멘트(ix, iy) 및 단면회전반경을 실시간 유도 분석하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d0.png" alt="📐" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">단면 2차 모멘트 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">사각형, 중공 사각형, I형강, 원형 단면의 폭, 높이, 두께를 실시간 설정하여 단면적, 도심축, 단면 2차 모멘트(Ix, Iy) 및 단면회전반경을 실시간 유도 분석하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/euler-buckling-column-calculator/" class="eng-card" data-title="오일러 좌굴 계산기 &#038; 시뮬레이터" data-desc="기둥의 길이, 지지 조건(양단 핀, 일단 고정 일단 자유, 양단 고정, 일단 고정 일단 핀) 및 하중과 강성을 실시간 연동하여 기둥이 컴프레션 하중을 이기지 못하고 횡방향으로 휘어지는 임계 좌굴 하중(pcr)을 시각화 분석하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3db.png" alt="🏛" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">오일러 좌굴 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">기둥의 길이, 지지 조건(양단 핀, 일단 고정 일단 자유, 양단 고정, 일단 고정 일단 핀) 및 하중과 강성을 실시간 연동하여 기둥이 컴프레션 하중을 이기지 못하고 횡방향으로 휘어지는 임계 좌굴 하중(Pcr)을 시각화 분석하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/beam-deflection-calculator-simulator/" class="eng-card" data-title="보의 처짐 계산기 &#038; 시뮬레이터" data-desc="보의 길이, 집중 하중 및 하중 위치, 단면 계수, 탄성 계수를 실시간으로 조절하여 외형 처짐 곡선과 지점 반력, 모멘트 분포를 시각화하는 초정밀 2d 구조 해석 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f309.png" alt="🌉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">보의 처짐 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">보의 길이, 집중 하중 및 하중 위치, 단면 계수, 탄성 계수를 실시간으로 조절하여 외형 처짐 곡선과 지점 반력, 모멘트 분포를 시각화하는 초정밀 2D 구조 해석 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/vibration-natural-frequency-resonance-calculator-simulator/" class="eng-card" data-title="고유진동수 계산기 &#038; 시뮬레이터" data-desc="질량, 스프링 강성, 감쇠 계수 및 외력 주파수를 설정하여 감쇠계의 자유진동 감쇠 거동과 공진(resonance) 조건에서의 진폭 극대화 현상을 실시간 2d 물리 궤적과 스펙트럼 차트로 시뮬레이션합니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50a.png" alt="🔊" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">고유진동수 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">질량, 스프링 강성, 감쇠 계수 및 외력 주파수를 설정하여 감쇠계의 자유진동 감쇠 거동과 공진(Resonance) 조건에서의 진폭 극대화 현상을 실시간 2D 물리 궤적과 스펙트럼 차트로 시뮬레이션합니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/fatigue-life-sn-curve-calculator/" class="eng-card" data-title="피로수명 계산기 &#038; 시뮬레이터" data-desc="재료의 인장강도(sut) 및 평균 응력(σm)과 교번 응력 amplitude(σa), 신뢰도/표면 계수를 연동하여 수정 피로한도(se)를 도출하고, s-n 곡선 상의 수명 주기(cycles) 및 굿맨 안전율을 진단하는 시각화 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/23f3.png" alt="⏳" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">피로수명 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">재료의 인장강도(Sut) 및 평균 응력(σm)과 교번 응력 amplitude(σa), 신뢰도/표면 계수를 연동하여 수정 피로한도(Se)를 도출하고, S-N 곡선 상의 수명 주기(Cycles) 및 굿맨 안전율을 진단하는 시각화 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

        </div>
    </div>

    <div class="eng-section-block" id="sec-electrical-machining">
        <h2 class="eng-section-title"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 전기공학 &#038; 생산 가공 (Electrical &#038; Manufacturing Machining)</h2>
        <div class="eng-grid">

            <a href="https://myengnote.com/ohms-law-calculator-simulator/" class="eng-card" data-title="옴의 법칙 계산기 &#038; 시뮬레이터" data-desc="전압, 저항, 전류의 상관관계를 실시간으로 계산하고 회로 내 전자(electron)들의 흐름과 에너지 소모를 시각적으로 관찰할 수 있는 물리 회로 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">옴의 법칙 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">전압, 저항, 전류의 상관관계를 실시간으로 계산하고 회로 내 전자(Electron)들의 흐름과 에너지 소모를 시각적으로 관찰할 수 있는 물리 회로 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/power-factor-correction-calculator-simulator/" class="eng-card" data-title="역률 개선 계산기 &#038; 시뮬레이터" data-desc="부하의 유효전력과 기존 역률, 목표 역률을 입력하여 요구되는 역률 개선용 콘덴서(capacitor bank)의 용량(kvar)과 전기 에너지 절감 효과를 2d 벡터 위상 시뮬레이션으로 정밀 분석하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c9.png" alt="📉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">역률 개선 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">부하의 유효전력과 기존 역률, 목표 역률을 입력하여 요구되는 역률 개선용 콘덴서(Capacitor Bank)의 용량(kVAR)과 전기 에너지 절감 효과를 2D 벡터 위상 시뮬레이션으로 정밀 분석하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/cable-sizing-calculator-simulator/" class="eng-card" data-title="케이블 허용전류 계산기 &#038; 시뮬레이터" data-desc="부하 전류, 전송 거리, 허용 전압 강하율 및 포설 환경을 입력하여 규격에 적합한 케이블 단면적(sq/mm²)을 설계하고 전하 밀도와 케이블 발열 상태를 2d 시각화하는 시뮬레이터입니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50c.png" alt="🔌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">케이블 허용전류 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">부하 전류, 전송 거리, 허용 전압 강하율 및 포설 환경을 입력하여 규격에 적합한 케이블 단면적(sq/mm²)을 설계하고 전하 밀도와 케이블 발열 상태를 2D 시각화하는 시뮬레이터입니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/" class="eng-card" data-title="선삭 절삭 속도 계산기 &#038; 시뮬레이터" data-desc="공작물 직경과 주축 회전수(rpm)를 기반으로 선반 가공의 원주 방향 절삭 속도(m/min)와 이송량에 따른 이론적 표면 조도(ra, ry) 및 소재 제거율(mrr)을 실시간 2d 절삭 칩 시뮬레이션으로 분석합니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1fa9a.png" alt="🪚" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">선삭 절삭 속도 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">공작물 직경과 주축 회전수(RPM)를 기반으로 선반 가공의 원주 방향 절삭 속도(m/min)와 이송량에 따른 이론적 표면 조도(Ra, Ry) 및 소재 제거율(MRR)을 실시간 2D 절삭 칩 시뮬레이션으로 분석합니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

            <a href="https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/" class="eng-card" data-title="드릴 회전수 계산기 &#038; 시뮬레이터" data-desc="드릴 직경과 공작물 재질별 추천 절삭 속도를 기반으로 주축 스핀들 회전수(rpm) 및 선형 분당 이송속도(mm/min), 가공 소요 시간을 실시간 2d 드릴 드릴링 물리 시뮬레이션으로 가시화합니다.">
                <div class="eng-card-header">
                    <span class="eng-card-icon"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
                    <h3 class="eng-card-title">드릴 회전수 계산기 &#038; 시뮬레이터</h3>
                </div>
                <p class="eng-card-desc">드릴 직경과 공작물 재질별 추천 절삭 속도를 기반으로 주축 스핀들 회전수(RPM) 및 선형 분당 이송속도(mm/min), 가공 소요 시간을 실시간 2D 드릴 드릴링 물리 시뮬레이션으로 가시화합니다.</p>
                <span class="eng-card-badge">시뮬레이터 바로가기 →</span>
            </a>

        </div>
    </div>

</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const searchInput = document.getElementById('engSearchInput');
    const cards = document.querySelectorAll('.eng-card');
    const sections = document.querySelectorAll('.eng-section-block');
    const noResults = document.getElementById('noResults');

    searchInput.addEventListener('input', function(e) {
        const query = e.target.value.toLowerCase().trim();
        let anyVisible = false;

        sections.forEach(sec => {
            let secHasVisibleCard = false;
            const secCards = sec.querySelectorAll('.eng-card');
            
            secCards.forEach(card => {
                const title = card.getAttribute('data-title');
                const desc = card.getAttribute('data-desc');
                
                if (title.includes(query) || desc.includes(query)) {
                    card.style.display = 'flex';
                    secHasVisibleCard = true;
                    anyVisible = true;
                } else {
                    card.style.display = 'none';
                }
            });

            if (secHasVisibleCard) {
                sec.style.display = 'block';
            } else {
                sec.style.display = 'none';
            }
        });

        if (anyVisible) {
            noResults.style.display = 'none';
        } else {
            noResults.style.display = 'block';
        }
    });
});
</script>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/engineering-calculators-simulators-index/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>클러치 &#038; 브레이크 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/clutch-brake-torque-power-simulator/</link>
					<comments>https://myengnote.com/clutch-brake-torque-power-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 02 Jul 2026 23:51:17 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[마찰클러치]]></category>
		<category><![CDATA[밴드브레이크]]></category>
		<category><![CDATA[일정마모설]]></category>
		<category><![CDATA[일정압력설]]></category>
		<category><![CDATA[제동토크]]></category>
		<guid isPermaLink="false">https://myengnote.com/clutch-brake-torque-power-simulator/</guid>

					<description><![CDATA[마찰 계수, 작용 하중, 접촉 반경 및 랩 각도에 따른 단판 클러치의 동력 전달(Uniform Wear/Pressure)과 밴드 브레이크의 제동 토크 및 인장비(Euler-Eytelwein)를 정밀 해석하고 마찰 맞물림/제동 거동을 2D 그래픽으로 검증하는 복합 기계요소 시뮬레이터입니다. <a href="https://myengnote.com/clutch-brake-torque-power-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클러치 &#038; 브레이크 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for clutchbrake-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .clutchbrake-calculator-wrapper *, .clutchbrake-calculator-wrapper *::before, .clutchbrake-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .clutchbrake-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .clutchbrake-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            z-index: -1; overflow: hidden; pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: ''; position: absolute; width: 600px; height: 600px; border-radius: 50%; filter: blur(140px); opacity: 0.12;
        }
        .app-background-glow::before { background: var(--color-cyan); top: -10%; right: -5%; animation: pulse-slow 15s infinite alternate; }
        .app-background-glow::after { background: var(--color-purple); bottom: -10%; left: -5%; animation: pulse-slow 20s infinite alternate-reverse; }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.08; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.15; }
        }
        .app-container {
            width: 100%; max-width: 1440px; padding: 24px; display: flex; flex-direction: column; gap: 24px;
        }
        .app-header {
            display: flex; justify-content: space-between; align-items: center; padding: 20px 24px;
            background: var(--color-panel-bg); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 16px; box-shadow: var(--shadow-card);
        }
        .logo-area { display: flex; align-items: center; gap: 16px; }
        .logo-icon {
            font-size: 32px; background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
            display: flex; align-items: center; justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-dark)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle { font-size: 12px; color: var(--color-text-muted); font-weight: 500; letter-spacing: 0.5px; }
        .header-badge {
            display: flex; align-items: center; gap: 10px; background: rgba(219, 39, 119, 0.1); border: 1px solid rgba(219, 39, 119, 0.2); padding: 6px 14px; border-radius: 20px;
        }
        .pulse-dot {
            width: 8px; height: 8px; background-color: var(--color-magenta); border-radius: 50%; box-shadow: 0 0 10px var(--color-magenta); animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text { font-size: 11px; font-weight: 600; color: var(--color-magenta); letter-spacing: 0.5px; }
        /* Premium 2-Column Responsive Layout Setup */
        .app-main-grid { display: grid; grid-template-columns: 340px 1fr 340px; gap: 24px; align-items: start; }
        .panel {
            background: var(--gradient-panel); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 20px; padding: 24px; box-shadow: var(--shadow-card);
            display: flex; flex-direction: column; gap: 18px; transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover { border-color: var(--color-border-hover); }
        .panel-header { display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--color-border); padding-bottom: 14px; }
        .panel-header i { font-size: 18px; }
        .panel-header h2 { font-family: var(--font-heading); font-size: 18px; font-weight: 600; letter-spacing: 0.5px; }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel { grid-column: 1; }
        .simulation-panel { grid-column: 2; }
        .results-container-panel { grid-column: 3; display: flex; flex-direction: column; gap: 24px; }
        .input-group { display: flex; flex-direction: column; gap: 8px; }
        .input-label-row { display: flex; justify-content: space-between; align-items: center; }
        .input-label-row label { font-size: 13px; font-weight: 600; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .helper-text { font-size: 10px; color: var(--color-text-muted); font-weight: 500; }
        .segmented-control {
            display: grid; grid-template-columns: repeat(2, 1fr); background: rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); padding: 4px; border-radius: 12px; gap: 4px;
        }
        .segmented-btn {
            background: transparent; border: none; color: var(--color-text-muted); padding: 8px 2px; border-radius: 8px; font-size: 10.5px; font-weight: 700; cursor: pointer; transition: all 0.2s ease; text-align: center;
        }
        .segmented-btn:hover { color: var(--color-text-main); background: rgba(0, 0, 0, 0.015); }
        .segmented-btn.active { background: #ffffff; color: var(--color-cyan); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within { border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow); }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button, .custom-number-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none; width: 100%; height: 6px; border-radius: 3px; background: rgba(0, 0, 0, 0.05); outline: none; margin: 4px 0; transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; cursor: pointer; transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        .slider-cyan::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 8px var(--color-cyan); }
        .slider-cyan::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-magenta::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 8px var(--color-magenta); }
        .slider-magenta::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-purple::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 8px var(--color-purple); }
        .slider-purple::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-cyan::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-cyan); }
        .slider-magenta::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-magenta); }
        .slider-purple::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-purple); }
        .presets-section { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--color-border); padding-top: 16px; }
        .presets-section h3 { font-size: 13px; font-weight: 700; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .presets-grid { display: flex; flex-direction: column; gap: 8px; }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px; padding: 8px 12px; cursor: pointer; color: var(--color-text-main);
            display: flex; align-items: center; gap: 12px; text-align: left; transition: all 0.2s ease;
        }
        .preset-btn:hover { background: rgba(0, 0, 0, 0.04); transform: translateX(4px); }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow)); border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px; height: 28px; background: rgba(0, 0, 0, 0.02); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon { background: var(--gradient-primary); color: #fff; }
        .preset-name { font-size: 11.5px; font-weight: 600; }
        .simulation-panel { width: 100%; justify-content: space-between; }
        /* Restored: Max-width constraint completely REMOVED for majestic wide screen experience! */
        .canvas-wrapper {
            position: relative; 
            width: 100%; 
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%); 
            border: 1px solid rgba(0, 0, 0, 0.06); 
            border-radius: 16px;
            overflow: hidden; 
            display: flex; 
            align-items: center; 
            justify-content: center; 
            box-shadow: 0 4px 20px rgba(15, 23, 42, 0.04);
        }
        #physics-canvas { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; }
        /* Fixed Overlay UI CSS styles to prevent overlapping */
        .canvas-overlay-data {
            position: absolute;
            top: 20px;
            left: 20px;
            z-index: 10;
            pointer-events: none;
        }
        .overlay-item {
            background: rgba(255, 255, 255, 0.85);
            backdrop-filter: blur(8px);
            -webkit-backdrop-filter: blur(8px);
            border: 1px solid rgba(255, 255, 255, 0.6);
            padding: 8px 16px;
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(15, 23, 42, 0.08);
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .overlay-item .label {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .overlay-item .value {
            font-size: 13px;
            font-weight: 800;
            color: var(--color-magenta);
            transition: color 0.3s ease;
        }
        .action-overlay-area {
            position: absolute; bottom: 20px; right: 20px; z-index: 10;
        }
        .action-btn {
            background: var(--gradient-accent); border: none; color: #fff; padding: 11px 20px; border-radius: 12px; font-size: 12.5px; font-weight: 700;
            cursor: pointer; display: flex; align-items: center; gap: 8px; box-shadow: 0 4px 15px var(--color-magenta-glow); transition: all 0.25s ease;
        }
        .action-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px var(--color-magenta); }
        .action-btn:active { transform: translateY(1px); }
        /* Restored: metrics strip width is 100% wide matching restored canvas wrapper */
        .simulation-metrics-strip {
            display: flex; 
            background: rgba(0, 0, 0, 0.015); 
            border: 1px solid var(--color-border); 
            border-radius: 12px; 
            padding: 14px 20px;
            justify-content: space-around; 
            align-items: center; 
            gap: 10px; 
            margin: 12px auto 0 auto;
            width: 100%;
        }
        .mini-metric { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
        .mini-metric .label { font-size: 10px; font-weight: 600; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
        .mini-metric .value { font-size: 14px; font-weight: 700; color: var(--color-text-main); font-family: var(--font-heading); }
        .mini-divider { width: 1px; height: 24px; background: var(--color-border); }
        .results-panel { display: flex; flex-direction: column; gap: 18px; }
        .ratio-readout-box {
            background: linear-gradient(135deg, var(--color-cyan-glow) 0%, var(--color-purple-glow) 100%); border: 1px solid rgba(2, 132, 199, 0.15); border-radius: 16px;
            padding: 24px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
        }
        .ratio-title { font-size: 11px; font-weight: 700; color: var(--color-cyan); letter-spacing: 1px; text-transform: uppercase; }
        .ratio-value {
            font-family: var(--font-heading); font-weight: 800; font-size: 28px; background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .ratio-type { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .results-grid { display: flex; flex-direction: column; gap: 12px; }
        .result-card {
            background: rgba(255, 255, 255, 0.85); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); border-radius: 12px;
            padding: 14px 18px; display: flex; align-items: center; gap: 16px; transition: all 0.2s ease;
        }
        .result-card:hover { transform: translateY(-2px); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-icon {
            width: 38px; height: 38px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px;
            display: flex; align-items: center; justify-content: center; font-size: 14px; color: var(--color-text-muted);
        }
        .result-card:hover .card-icon { color: var(--color-cyan); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-content { display: flex; flex-direction: column; gap: 2px; }
        .card-unit { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .card-value { font-family: var(--font-heading); font-weight: 700; font-size: 17px; color: var(--color-text-main); }
        .formula-card {
            background: #ffffff; border: 1px solid var(--color-border); border-radius: 16px; padding: 20px; display: flex; flex-direction: column; gap: 10px; font-size: 12px;
            justify-content: center;
        }
        .formula-card h4 { font-weight: 700; color: var(--color-text-main); font-size: 13.5px; display: flex; align-items: center; gap: 8px; }
        .formula-equation {
            font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace; color: #0284c7; font-size: 14px; background: #f8fafc; border: 1px solid var(--color-border);
            padding: 10px 14px; border-radius: 8px; font-weight: 600; letter-spacing: 0.5px;
        }
        @container clutch-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-container-panel {
                grid-column: 1 / span 2;
                display: grid;
                grid-template-columns: 1fr 1.2fr;
                gap: 20px;
            }
        }
        @container clutch-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-container-panel {
                grid-column: 1;
            }
            .results-container-panel {
                grid-template-columns: 1fr;
                gap: 20px;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container clutch-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
            .simulation-metrics-strip {
                flex-direction: column;
                gap: 12px;
            }
            .mini-divider {
                width: 80%;
                height: 1px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.clutchbrake-calculator-wrapper .app-main-grid,
.clutchbrake-calculator-wrapper .main-grid,
.clutchbrake-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.clutchbrake-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.clutchbrake-calculator-wrapper .simulation-panel,
.clutchbrake-calculator-wrapper .canvas-panel,
.clutchbrake-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.clutchbrake-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.clutchbrake-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.clutchbrake-calculator-wrapper .simulation-results-section .ratio-readout-box,
.clutchbrake-calculator-wrapper .simulation-results-section .re-readout-box,
.clutchbrake-calculator-wrapper .simulation-results-section .status-readout-box,
.clutchbrake-calculator-wrapper .simulation-results-section .flow-readout-box,
.clutchbrake-calculator-wrapper .simulation-results-section [class*="readout-box"],
.clutchbrake-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.clutchbrake-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.clutchbrake-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.clutchbrake-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .clutchbrake-calculator-wrapper .app-main-grid,
    .clutchbrake-calculator-wrapper .main-grid,
    .clutchbrake-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .clutchbrake-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .clutchbrake-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .clutchbrake-calculator-wrapper .simulation-panel,
    .clutchbrake-calculator-wrapper .canvas-panel,
    .clutchbrake-calculator-wrapper .sim-panel,
    .clutchbrake-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .clutchbrake-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .clutchbrake-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .clutchbrake-calculator-wrapper .simulation-results-section .re-readout-box,
    .clutchbrake-calculator-wrapper .simulation-results-section .status-readout-box,
    .clutchbrake-calculator-wrapper .simulation-results-section .flow-readout-box,
    .clutchbrake-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .clutchbrake-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .clutchbrake-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .clutchbrake-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.clutchbrake-calculator-wrapper .app-container,
.clutchbrake-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.clutchbrake-calculator-wrapper .simulation-results-section .formula-card,
.clutchbrake-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.clutchbrake-calculator-wrapper .simulation-results-section .formula-card h4,
.clutchbrake-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.clutchbrake-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.clutchbrake-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="clutchbrake-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-compact-disc"></i></div>
                <div>
                    <h1>CLUTCH &#038; BRAKE</h1>
                    <div class="subtitle">클러치/브레이크 동력 전달 및 제동 토크 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">FRICTION ANALYSIS ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>구동 및 설계 변수</h2>
                </div>
                <!-- Core Mode selection -->
                <div class="input-group">
                    <span class="helper-text" style="font-weight:700; color:var(--color-text-muted);">해석 대상 기계요소</span>
                    <div class="segmented-control" id="control-analysis-mode">
                        <button class="segmented-btn active" id="btn-mode-clutch">마찰 클러치</button>
                        <button class="segmented-btn" id="btn-mode-brake">밴드 브레이크</button>
                    </div>
                </div>
                <!-- Friction Coefficient mu -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-mu"><i class="fa-solid fa-oil-can text-cyan"></i> 마찰 계수 (&mu;)</label>
                        <span class="helper-text">(0.10 ~ 0.60)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-mu" class="custom-number-input" min="0.1" max="0.6" value="0.35" step="any">
                        <div class="unit-badge">&mu;</div>
                    </div>
                    <input type="range" id="slider-mu" class="custom-slider slider-cyan" min="10" max="60" value="35">
                </div>
                <!-- Operating Force F -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-force"><i class="fa-solid fa-weight-hanging text-magenta"></i> 인가 조작력 (F)</label>
                        <span class="helper-text">(100 ~ 5000 N)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-force" class="custom-number-input" min="100" max="5000" value="1200" step="any">
                        <div class="unit-badge">N</div>
                    </div>
                    <input type="range" id="slider-force" class="custom-slider slider-magenta" min="100" max="5000" value="1200">
                </div>
                <!-- Speed RPM N -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-rpm"><i class="fa-solid fa-arrows-spin text-purple"></i> 구동축 회전 속도 (N)</label>
                        <span class="helper-text">(500 ~ 4000 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="500" max="4000" value="1800" step="any">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider slider-purple" min="500" max="4000" value="1800">
                </div>
                <!-- CLUTCH SPECIFIC INPUTS -->
                <div id="clutch-inputs-container" style="display:flex; flex-direction:column; gap:16px;">
                    <div class="input-group">
                        <div class="input-label-row">
                            <label for="input-ro"><i class="fa-solid fa-circle text-cyan"></i> 마찰면 외경 (Ro)</label>
                            <span class="helper-text">(50 ~ 300 mm)</span>
                        </div>
                        <div class="number-input-wrapper">
                            <input type="number" id="input-ro" class="custom-number-input" min="50" max="300" value="180" step="any">
                            <div class="unit-badge">mm</div>
                        </div>
                        <input type="range" id="slider-ro" class="custom-slider slider-cyan" min="50" max="300" value="180">
                    </div>
                    <div class="input-group">
                        <div class="input-label-row">
                            <label for="input-ri"><i class="fa-solid fa-circle-notch text-cyan"></i> 마찰면 내경 (Ri)</label>
                            <span class="helper-text">(20 ~ 250 mm)</span>
                        </div>
                        <div class="number-input-wrapper">
                            <input type="number" id="input-ri" class="custom-number-input" min="20" max="250" value="100" step="any">
                            <div class="unit-badge">mm</div>
                        </div>
                        <input type="range" id="slider-ri" class="custom-slider slider-cyan" min="20" max="250" value="100">
                    </div>
                    <div class="input-group">
                        <span class="helper-text" style="font-weight:700; color:var(--color-text-muted);">면압 분포 설계식</span>
                        <div class="segmented-control" id="control-clutch-theory">
                            <button class="segmented-btn active" id="btn-theory-wear">일등 마모설</button>
                            <button class="segmented-btn" id="btn-theory-pressure">일등 압력설</button>
                        </div>
                    </div>
                </div>
                <!-- BRAKE SPECIFIC INPUTS (hidden initially) -->
                <div id="brake-inputs-container" style="display:none; flex-direction:column; gap:16px;">
                    <div class="input-group">
                        <div class="input-label-row">
                            <label for="input-drum-r"><i class="fa-solid fa-circle text-magenta"></i> 브레이크 드럼 반경 (R)</label>
                            <span class="helper-text">(50 ~ 300 mm)</span>
                        </div>
                        <div class="number-input-wrapper">
                            <input type="number" id="input-drum-r" class="custom-number-input" min="50" max="300" value="150" step="any">
                            <div class="unit-badge">mm</div>
                        </div>
                        <input type="range" id="slider-drum-r" class="custom-slider slider-magenta" min="50" max="300" value="150">
                    </div>
                    <div class="input-group">
                        <div class="input-label-row">
                            <label for="input-wrap"><i class="fa-solid fa-ring text-purple"></i> 밴드 감김 랩각 (&theta;)</label>
                            <span class="helper-text">(90° ~ 300°)</span>
                        </div>
                        <div class="number-input-wrapper">
                            <input type="number" id="input-wrap" class="custom-number-input" min="90" max="300" value="210" step="any">
                            <div class="unit-badge">deg</div>
                        </div>
                        <input type="range" id="slider-wrap" class="custom-slider slider-purple" min="90" max="300" value="210">
                    </div>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 파워팩 사양 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" id="preset-car-clutch">
                            <div class="preset-icon"><i class="fa-solid fa-car"></i></div>
                            <div class="preset-details"><span class="preset-name">일반 승용차 건식 클러치</span><span class="preset-spec">M/T 디스크</span></div>
                        </button>
                        <button class="preset-btn" id="preset-crane-brake">
                            <div class="preset-icon"><i class="fa-solid fa-truck-pickup"></i></div>
                            <div class="preset-details"><span class="preset-name">기중기 비상 밴드 브레이크</span><span class="preset-spec">고랩각 제동</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <i class="fa-solid fa-dharmachakra text-magenta"></i>
                                    <h2>체결 및 제동 물리 회전 거동 가시화 (3D Isometric)</h2>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas" width="800" height="500"></canvas>
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">작동 상태:</span>
                                            <span class="value" id="overlay-run-status">동력 전달 대기중 (클러치 분리)</span>
                                        </div>
                                    </div>
                                    <div class="action-overlay-area">
                                        <button class="action-btn" id="btn-engage-action">
                                            <i class="fa-solid fa-circle-play" id="icon-action-btn"></i>
                                            <span id="txt-action-btn">클러치 체결하기 (Engage)</span>
                                        </button>
                                    </div>
                                </div>
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <span class="label" id="lbl-metric-1">구동축 입력 속도</span>
                                        <span class="value" id="val-speed-in">1800 RPM</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label" id="lbl-metric-2">종동축 출력 속도</span>
                                        <span class="value" id="val-speed-out">0 RPM</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label" id="lbl-metric-3">클러치 슬립 비율</span>
                                        <span class="value" id="val-slip">100.0%</span>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                        <div class="ratio-title" id="txt-readout-title">전달 가능한 마찰 토크 (T)</div>
                                        <div class="ratio-value" id="txt-readout-val">58.8 N·m</div>
                                        <div class="ratio-type" id="txt-readout-sub">동력 전달 용량: 14.8 HP (11.1 kW)</div>
                                    </div>
                                <div class="results-grid">
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-circle-nodes"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit" id="lbl-card-1">평균 마찰 접촉 반경</span>
                                                <span class="card-value" id="res-metric-1">140 mm</span>
                                            </div>
                                        </div>
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-bolt"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit" id="lbl-card-2">구동 전력 전달 용량</span>
                                                <span class="card-value" id="res-metric-2">11.08 kW</span>
                                            </div>
                                        </div>
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-circle-exclamation"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit" id="lbl-card-3">미끄럼 열손실 평가</span>
                                                <span class="card-value" id="res-metric-3">안전 (적정 점착 성질)</span>
                                            </div>
                                        </div>
                                    </div>
                                <section class="panel formula-card">
                                    <div class="panel-header">
                                        <i class="fa-solid fa-circle-info text-cyan"></i>
                                        <h2>설계 역학 주요 방정식</h2>
                                    </div>
                                    <div class="input-group">
                                        <span class="helper-text">토크 유도 설계식</span>
                                        <div class="formula-equation" id="lbl-formula-1">
                                            T = &mu; &times; F &times; R_mean
                                        </div>
                                    </div>
                                    <div class="input-group">
                                        <span class="helper-text">전동/제동 출력식</span>
                                        <div class="formula-equation" id="lbl-formula-2">
                                            P = T &times; &omega; &nbsp;[W]
                                        </div>
                                    </div>
                                </section>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- CORE INTERACTIVE ENGINE -->
    </div>
</div>
<script>
        (function() {
            if (window.__clutchbrake_initialized) return;
            window.__clutchbrake_initialized = true;
            const btnModeClutch = document.getElementById('btn-mode-clutch');
            const btnModeBrake = document.getElementById('btn-mode-brake');
            const clutchInputs = document.getElementById('clutch-inputs-container');
            const brakeInputs = document.getElementById('brake-inputs-container');
            const inputMu = document.getElementById('input-mu');
            const sliderMu = document.getElementById('slider-mu');
            const inputForce = document.getElementById('input-force');
            const sliderForce = document.getElementById('slider-force');
            const inputRpm = document.getElementById('input-rpm');
            const sliderRpm = document.getElementById('slider-rpm');
            // Clutch inputs
            const inputRo = document.getElementById('input-ro');
            const sliderRo = document.getElementById('slider-ro');
            const inputRi = document.getElementById('input-ri');
            const sliderRi = document.getElementById('slider-ri');
            const btnTheoryWear = document.getElementById('btn-theory-wear');
            const btnTheoryPressure = document.getElementById('btn-theory-pressure');
            // Brake inputs
            const inputDrumR = document.getElementById('input-drum-r');
            const sliderDrumR = document.getElementById('slider-drum-r');
            const inputWrap = document.getElementById('input-wrap');
            const sliderWrap = document.getElementById('slider-wrap');
            const txtReadoutTitle = document.getElementById('txt-readout-title');
            const txtReadoutVal = document.getElementById('txt-readout-val');
            const txtReadoutSub = document.getElementById('txt-readout-sub');
            const lblMetric1 = document.getElementById('lbl-metric-1');
            const lblMetric2 = document.getElementById('lbl-metric-2');
            const lblMetric3 = document.getElementById('lbl-metric-3');
            const valSpeedIn = document.getElementById('val-speed-in');
            const valSpeedOut = document.getElementById('val-speed-out');
            const valSlip = document.getElementById('val-slip');
            const lblCard1 = document.getElementById('lbl-card-1');
            const lblCard2 = document.getElementById('lbl-card-2');
            const lblCard3 = document.getElementById('lbl-card-3');
            const resMetric1 = document.getElementById('res-metric-1');
            const resMetric2 = document.getElementById('res-metric-2');
            const resMetric3 = document.getElementById('res-metric-3');
            const lblFormula1 = document.getElementById('lbl-formula-1');
            const lblFormula2 = document.getElementById('lbl-formula-2');
            const btnEngageAction = document.getElementById('btn-engage-action');
            const iconActionBtn = document.getElementById('icon-action-btn');
            const txtActionBtn = document.getElementById('txt-action-btn');
            const overlayRunStatus = document.getElementById('overlay-run-status');
            // Internal Interactive State Model
            const state = {
                mode: 'clutch', // 'clutch' or 'brake'
                mu: 0.35,
                force: 1200.0, // N
                rpm: 1800.0,
                // Clutch
                ro: 180.0, // mm
                ri: 100.0, // mm
                theory: 'wear', // 'wear' or 'pressure'
                // Brake
                drumR: 150.0, // mm
                wrapAngle: 210.0, // deg
                // Dynamic simulation running flags
                engaged: false, // Unified Toggle Control (Clutch: clamped vs split, Brake: braking vs free)
                speedIn: 1800.0,
                speedOut: 0.0, // Output shaft for clutch, drum for brake
                slipRatio: 1.0,
                // Animation physics
                rotationAngleIn: 0.0,
                rotationAngleOut: 0.0,
                clampGap: 55.0, // horizontal distance visualizer for clutch plates (55px when split, 0px when clamped)
                leverAngle: 0.0, // angular offset visualizer for brake band lever (0 deg when free, 12 deg when pulling)
                sparks: []
            };
            const ranges = {
                mu: { min: 0.10, max: 0.60 },
                force: { min: 100.0, max: 5000.0 },
                rpm: { min: 500.0, max: 4000.0 },
                ro: { min: 50.0, max: 300.0 },
                ri: { min: 20.0, max: 250.0 },
                drumR: { min: 50.0, max: 300.0 },
                wrapAngle: { min: 90.0, max: 300.0 }
            };
            function calculateClutchBrake() {
                if (state.mode === 'clutch') {
                    // Keep ri always less than ro
                    if (state.ri >= state.ro - 10.0) {
                        state.ri = state.ro - 15.0;
                        if (state.ri < 20.0) { state.ri = 20.0; }
                        inputRi.value = state.ri.toFixed(0);
                        sliderRi.value = Math.round(state.ri);
                    }
                    const r2 = state.ro / 1000.0; // m
                    const r1 = state.ri / 1000.0; // m
                    let rMean = 0;
                    if (state.theory === 'wear') {
                        rMean = (r1 + r2) / 2.0;
                    } else {
                        rMean = (2.0 / 3.0) * (Math.pow(r2, 3) - Math.pow(r1, 3)) / (Math.pow(r2, 2) - Math.pow(r1, 2));
                    }
                    // Torque T = mu * F * R_mean
                    const torque = state.mu * state.force * rMean;
                    state.calculatedTorque = torque;
                    // Power P = T * omega / 1000 (kW)
                    const omega = (2.0 * Math.PI * state.rpm) / 60.0;
                    const power = (torque * omega) / 1000.0;
                    state.calculatedPower = power;
                    const hp = power * 1.341;
                    state.calculatedHP = hp;
                    state.rMean = rMean;
                } else {
                    // Band Brake calculation
                    const r = state.drumR / 1000.0; // m
                    const alpha = (state.wrapAngle * Math.PI) / 180.0; // rad
                    // Euler belt formula: F1 = F2 * e^(mu * alpha)
                    // F2 (slack side) = F applied
                    const F2 = state.force;
                    const F1 = F2 * Math.exp(state.mu * alpha);
                    state.tightTension = F1;
                    state.slackTension = F2;
                    // Net force
                    const Fnet = F1 - F2;
                    // Brake torque
                    const torque = Fnet * r;
                    state.calculatedTorque = torque;
                    // Instantaneous power at initial slip
                    const omega = (2.0 * Math.PI * state.rpm) / 60.0;
                    const power = (torque * omega) / 1000.0;
                    state.calculatedPower = power;
                    state.calculatedHP = power * 1.341;
                }
                updateUIValues();
            }
            function syncMuFromInput() {
                let val = parseFloat(inputMu.value);
                if (isNaN(val)) { val = ranges.mu.min; }
                if (val < ranges.mu.min) { val = ranges.mu.min; }
                if (val > ranges.mu.max) { val = ranges.mu.max; }
                state.mu = val;
                inputMu.value = val.toFixed(2);
                sliderMu.value = Math.round(val * 100);
                calculateClutchBrake();
            }
            function syncMuFromSlider() {
                state.mu = parseFloat(sliderMu.value) / 100;
                inputMu.value = state.mu.toFixed(2);
                calculateClutchBrake();
            }
            function syncForceFromInput() {
                let val = parseFloat(inputForce.value);
                if (isNaN(val)) { val = ranges.force.min; }
                if (val < ranges.force.min) { val = ranges.force.min; }
                if (val > ranges.force.max) { val = ranges.force.max; }
                state.force = val;
                inputForce.value = val.toFixed(0);
                sliderForce.value = Math.round(val);
                calculateClutchBrake();
            }
            function syncForceFromSlider() {
                state.force = parseFloat(sliderForce.value);
                inputForce.value = state.force.toFixed(0);
                calculateClutchBrake();
            }
            function syncRpmFromInput() {
                let val = parseFloat(inputRpm.value);
                if (isNaN(val)) { val = ranges.rpm.min; }
                if (val < ranges.rpm.min) { val = ranges.rpm.min; }
                if (val > ranges.rpm.max) { val = ranges.rpm.max; }
                state.rpm = val;
                inputRpm.value = val.toFixed(0);
                sliderRpm.value = Math.round(val);
                if (!state.engaged) {
                    state.speedIn = val;
                    if (state.mode === 'brake') { state.speedOut = val; }
                }
                calculateClutchBrake();
            }
            function syncRpmFromSlider() {
                state.rpm = parseFloat(sliderRpm.value);
                inputRpm.value = state.rpm.toFixed(0);
                if (!state.engaged) {
                    state.speedIn = state.rpm;
                    if (state.mode === 'brake') { state.speedOut = state.rpm; }
                }
                calculateClutchBrake();
            }
            // Clutch size sync
            function syncRoFromInput() {
                let val = parseFloat(inputRo.value);
                if (isNaN(val)) { val = ranges.ro.min; }
                if (val < ranges.ro.min) { val = ranges.ro.min; }
                if (val > ranges.ro.max) { val = ranges.ro.max; }
                state.ro = val;
                inputRo.value = val.toFixed(0);
                sliderRo.value = Math.round(val);
                calculateClutchBrake();
            }
            function syncRoFromSlider() {
                state.ro = parseFloat(sliderRo.value);
                inputRo.value = state.ro.toFixed(0);
                calculateClutchBrake();
            }
            function syncRiFromInput() {
                let val = parseFloat(inputRi.value);
                if (isNaN(val)) { val = ranges.ri.min; }
                if (val < ranges.ri.min) { val = ranges.ri.min; }
                if (val > ranges.ri.max) { val = ranges.ri.max; }
                state.ri = val;
                inputRi.value = val.toFixed(0);
                sliderRi.value = Math.round(val);
                calculateClutchBrake();
            }
            function syncRiFromSlider() {
                state.ri = parseFloat(sliderRi.value);
                inputRi.value = state.ri.toFixed(0);
                calculateClutchBrake();
            }
            // Brake size sync
            function syncDrumRFromInput() {
                let val = parseFloat(inputDrumR.value);
                if (isNaN(val)) { val = ranges.drumR.min; }
                if (val < ranges.drumR.min) { val = ranges.drumR.min; }
                if (val > ranges.drumR.max) { val = ranges.drumR.max; }
                state.drumR = val;
                inputDrumR.value = val.toFixed(0);
                sliderDrumR.value = Math.round(val);
                calculateClutchBrake();
            }
            function syncDrumRFromSlider() {
                state.drumR = parseFloat(sliderDrumR.value);
                inputDrumR.value = state.drumR.toFixed(0);
                calculateClutchBrake();
            }
            function syncWrapFromInput() {
                let val = parseFloat(inputWrap.value);
                if (isNaN(val)) { val = ranges.wrapAngle.min; }
                if (val < ranges.wrapAngle.min) { val = ranges.wrapAngle.min; }
                if (val > ranges.wrapAngle.max) { val = ranges.wrapAngle.max; }
                state.wrapAngle = val;
                inputWrap.value = val.toFixed(0);
                sliderWrap.value = Math.round(val);
                calculateClutchBrake();
            }
            function syncWrapFromSlider() {
                state.wrapAngle = parseFloat(sliderWrap.value);
                inputWrap.value = state.wrapAngle.toFixed(0);
                calculateClutchBrake();
            }
            function updateUIValues() {
                if (state.mode === 'clutch') {
                    // Update texts to clutch vocabulary
                    txtReadoutTitle.innerText = '전달 마찰 토크 (T)';
                    txtReadoutVal.innerText = state.calculatedTorque.toFixed(1) + ' N·m';
                    txtReadoutSub.innerText = '동력 전달 용량: ' + state.calculatedHP.toFixed(1) + ' HP (' + state.calculatedPower.toFixed(1) + ' kW)';
                    lblMetric1.innerText = '구동축 입력 속도';
                    lblMetric2.innerText = '종동축 출력 속도';
                    lblMetric3.innerText = '클러치 슬립 비율';
                    lblCard1.innerText = '평균 마찰 접촉 반경';
                    resMetric1.innerText = (state.rMean * 1000.0).toFixed(0) + ' mm';
                    lblCard2.innerText = '구동 전력 전달 용량';
                    resMetric2.innerText = state.calculatedPower.toFixed(2) + ' kW';
                    lblCard3.innerText = '미끄럼 열손실 평가';
                    if (state.mu < 0.25) {
                        resMetric3.innerText = '경고 (미끄럼 과열 위험)';
                        resMetric3.style.color = '#db2777';
                    } else {
                        resMetric3.innerText = '안전 (적정 점착 성질)';
                        resMetric3.style.color = '#10b981';
                    }
                    lblFormula1.innerText = 'T = \u03bc \u00d7 F \u00d7 R_mean';
                    lblFormula2.innerText = 'P = T \u00d7 \u03c9  [W]';
                } else {
                    // Update texts to brake vocabulary
                    txtReadoutTitle.innerText = '제동 토크 용량 (T)';
                    txtReadoutVal.innerText = state.calculatedTorque.toFixed(1) + ' N·m';
                    txtReadoutSub.innerText = '긴장측 장력 (F1): ' + state.tightTension.toFixed(0) + ' N';
                    lblMetric1.innerText = '드럼 설계 속도';
                    lblMetric2.innerText = '드럼 제동 속도';
                    lblMetric3.innerText = '제동 정지 완료 수준';
                    lblCard1.innerText = '제동 장력비 (F1/F2)';
                    const rat = state.tightTension / state.slackTension;
                    resMetric1.innerText = rat.toFixed(2);
                    lblCard2.innerText = '최대 마찰 제동 동력';
                    resMetric2.innerText = state.calculatedPower.toFixed(2) + ' kW';
                    lblCard3.innerText = '셀프 락(Self-Lock) 유무';
                    if (state.mu * state.wrapAngle * Math.PI / 180 > 2.0) {
                        resMetric3.innerText = '발생 (쐐기 고착 주의)';
                        resMetric3.style.color = '#f59e0b';
                    } else {
                        resMetric3.innerText = '미발생 (부드러운 조작)';
                        resMetric3.style.color = '#10b981';
                    }
                    lblFormula1.innerText = 'F1 / F2 = e^(\u03b1 \u00d7 \u03bc)';
                    lblFormula2.innerText = 'T_brake = (F1 - F2) \u00d7 r';
                }
            }
            function setAnalysisMode(newMode) {
                state.mode = newMode;
                state.engaged = false; // Reset to disconnected/unbraked on mode change
                state.sparks = [];
                if (newMode === 'clutch') {
                    btnModeClutch.classList.add('active');
                    btnModeBrake.classList.remove('active');
                    clutchInputs.style.display = 'flex';
                    brakeInputs.style.display = 'none';
                    txtActionBtn.innerText = '클러치 체결하기 (Engage)';
                    iconActionBtn.className = 'fa-solid fa-circle-play';
                    overlayRunStatus.innerText = '동력 전달 대기중 (클러치 분리)';
                    overlayRunStatus.style.color = '#475569';
                    state.speedIn = state.rpm;
                    state.speedOut = 0.0;
                    state.slipRatio = 1.0;
                    state.clampGap = 55.0;
                } else {
                    btnModeBrake.classList.add('active');
                    btnModeClutch.classList.remove('active');
                    clutchInputs.style.display = 'none';
                    brakeInputs.style.display = 'flex';
                    txtActionBtn.innerText = '제동 브레이크 가동 (Brake)';
                    iconActionBtn.className = 'fa-solid fa-circle-play';
                    overlayRunStatus.innerText = '제동 대기중 (드럼 무부하 회전)';
                    overlayRunStatus.style.color = '#475569';
                    state.speedIn = state.rpm;
                    state.speedOut = state.rpm;
                    state.slipRatio = 0.0;
                    state.leverAngle = 0.0;
                }
                calculateClutchBrake();
            }
            // Bindings
            btnModeClutch.addEventListener('click', function() { setAnalysisMode('clutch'); });
            btnModeBrake.addEventListener('click', function() { setAnalysisMode('brake'); });
            inputMu.addEventListener('change', syncMuFromInput);
            sliderMu.addEventListener('input', syncMuFromSlider);
            inputForce.addEventListener('change', syncForceFromInput);
            sliderForce.addEventListener('input', syncForceFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            // Clutch bindings
            inputRo.addEventListener('change', syncRoFromInput);
            sliderRo.addEventListener('input', syncRoFromSlider);
            inputRi.addEventListener('change', syncRiFromInput);
            sliderRi.addEventListener('input', syncRiFromSlider);
            btnTheoryWear.addEventListener('click', function() {
                btnTheoryWear.classList.add('active');
                btnTheoryPressure.classList.remove('active');
                state.theory = 'wear';
                calculateClutchBrake();
            });
            btnTheoryPressure.addEventListener('click', function() {
                btnTheoryPressure.classList.add('active');
                btnTheoryWear.classList.remove('active');
                state.theory = 'pressure';
                calculateClutchBrake();
            });
            // Brake bindings
            inputDrumR.addEventListener('change', syncDrumRFromInput);
            sliderDrumR.addEventListener('input', syncDrumRFromSlider);
            inputWrap.addEventListener('change', syncWrapFromInput);
            sliderWrap.addEventListener('input', syncWrapFromSlider);
            // Presets
            document.getElementById('preset-car-clutch').addEventListener('click', function() {
                setActivePreset('preset-car-clutch');
                setAnalysisMode('clutch');
                state.mu = 0.38;
                state.force = 2200;
                state.rpm = 2200;
                state.ro = 220;
                state.ri = 150;
                state.theory = 'wear';
                syncControlsToState();
                calculateClutchBrake();
            });
            document.getElementById('preset-crane-brake').addEventListener('click', function() {
                setActivePreset('preset-crane-brake');
                setAnalysisMode('brake');
                state.mu = 0.45;
                state.force = 600;
                state.rpm = 800;
                state.drumR = 200;
                state.wrapAngle = 240;
                syncControlsToState();
                calculateClutchBrake();
            });
            function setActivePreset(id) {
                document.getElementById('preset-car-clutch').classList.remove('active');
                document.getElementById('preset-crane-brake').classList.remove('active');
                document.getElementById(id).classList.add('active');
            }
            function syncControlsToState() {
                inputMu.value = state.mu.toFixed(2);
                sliderMu.value = Math.round(state.mu * 100);
                inputForce.value = state.force.toFixed(0);
                sliderForce.value = Math.round(state.force);
                inputRpm.value = state.rpm.toFixed(0);
                sliderRpm.value = Math.round(state.rpm);
                if (state.mode === 'clutch') {
                    inputRo.value = state.ro.toFixed(0);
                    sliderRo.value = Math.round(state.ro);
                    inputRi.value = state.ri.toFixed(0);
                    sliderRi.value = Math.round(state.ri);
                    if (state.theory === 'wear') {
                        btnTheoryWear.classList.add('active');
                        btnTheoryPressure.classList.remove('active');
                    } else {
                        btnTheoryPressure.classList.add('active');
                        btnTheoryWear.classList.remove('active');
                    }
                } else {
                    inputDrumR.value = state.drumR.toFixed(0);
                    sliderDrumR.value = Math.round(state.drumR);
                    inputWrap.value = state.wrapAngle.toFixed(0);
                    sliderWrap.value = Math.round(state.wrapAngle);
                }
            }
            // Interactive Toggle Engine: Clutch & Brake Toggle Control Handler
            btnEngageAction.addEventListener('click', function() {
                state.engaged = !state.engaged;
                if (state.mode === 'clutch') {
                    if (state.engaged) {
                        txtActionBtn.innerText = '클러치 분리하기 (Disengage)';
                        iconActionBtn.className = 'fa-solid fa-circle-pause';
                        overlayRunStatus.innerText = '동력 전달 중 (슬립 가속 중)';
                        overlayRunStatus.style.color = '#f59e0b';
                    } else {
                        txtActionBtn.innerText = '클러치 체결하기 (Engage)';
                        iconActionBtn.className = 'fa-solid fa-circle-play';
                        overlayRunStatus.innerText = '동력 전달 대기중 (클러치 분리)';
                        overlayRunStatus.style.color = '#475569';
                    }
                } else {
                    if (state.engaged) {
                        txtActionBtn.innerText = '제동 브레이크 해제 (Release)';
                        iconActionBtn.className = 'fa-solid fa-circle-pause';
                        overlayRunStatus.innerText = '마찰 제동 가동 (감속 제동 중)';
                        overlayRunStatus.style.color = '#f59e0b';
                    } else {
                        txtActionBtn.innerText = '제동 브레이크 가동 (Brake)';
                        iconActionBtn.className = 'fa-solid fa-circle-play';
                        overlayRunStatus.innerText = '제동 대기중 (드럼 무부하 회전)';
                        overlayRunStatus.style.color = '#475569';
                    }
                }
            });
            // Canvas drawing & animation
            const canvas = document.getElementById('physics-canvas');
            const ctx = canvas.getContext('2d');
            function getDPR() { return window.devicePixelRatio || 1; }
            function initCanvas() {
                const dpr = getDPR();
                const rect = canvas.getBoundingClientRect();
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            window.addEventListener('resize', initCanvas);
            initCanvas();
            setTimeout(initCanvas, 300);
            let lastTime = 0;
            function animate(currentTime) {
                if (lastTime === 0) { lastTime = currentTime; }
                const dt = Math.min((currentTime - lastTime) / 1000, 0.1); // Clamp dt to prevent massive jumps
                lastTime = currentTime;
                const dpr = getDPR();
                const width = canvas.width / dpr;
                const height = canvas.height / dpr;
                // Dynamic Scale Factor Calculation (Widescreen Optimized)
                const baseWidth = 800;
                const baseHeight = 500;
                const scale = Math.min(width / baseWidth, height / baseHeight);
                ctx.clearRect(0, 0, width, height);
                // Premium Blueprint grid lines
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                ctx.lineWidth = 1;
                const gridSize = 25 * scale;
                for (let x = 0; x < width; x += gridSize) {
                    ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, height); ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSize) {
                    ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke();
                }
                // Render elements in absolute vertical center
                const cx = width / 2;
                const cy = height / 2;
                // Dynamic simulation math step
                if (state.mode === 'clutch') {
                    // 1. CLUTCH SIMULATION LOGIC
                    const targetGap = state.engaged ? 0.0 : 55.0;
                    state.clampGap += (targetGap - state.clampGap) * 8 * dt; // Smooth clamp transition
                    state.speedIn = state.rpm;
                    if (state.engaged) {
                        // Clutch is clamping
                        if (state.clampGap < 2.0) {
                            // Plates are in contact, calculate slip acceleration
                            // Accel scale based on Torque and damped inertia for premium 3s transition
                            const dw = (state.calculatedTorque / 12) * dt; 
                            const targetW = (2.0 * Math.PI * state.rpm) / 60.0;
                            let wOut = (2.0 * Math.PI * state.speedOut) / 60.0;
                            wOut += dw;
                            if (wOut >= targetW) {
                                wOut = targetW;
                                state.speedOut = state.rpm;
                                state.slipRatio = 0.0;
                                overlayRunStatus.innerText = '동력 체결 완료 (100% 동기화)';
                                overlayRunStatus.style.color = '#10b981';
                            } else {
                                state.speedOut = (wOut * 60.0) / (2.0 * Math.PI);
                                state.slipRatio = (state.rpm - state.speedOut) / state.rpm;
                                overlayRunStatus.innerText = '동력 전달 중 (슬립 가속 중)';
                                overlayRunStatus.style.color = '#f59e0b';
                            }
                            // Generate glowing sparks while slipping
                            if (state.slipRatio > 0.02) {
                                if (Math.random() < 0.35) {
                                    state.sparks.push({
                                        x: cx - 30 * scale + (Math.random() - 0.5) * 12 * scale,
                                        // Align with scaled-up Ro disc height
                                        y: cy + (Math.random() - 0.5) * (40 + (state.ro / 300) * 160) * scale,
                                        vx: ((Math.random() - 0.5) * 140 + 50) * scale,
                                        vy: ((Math.random() - 0.5) * 160) * scale,
                                        life: 0.7 + Math.random() * 0.3,
                                        color: Math.random() > 0.5 ? 'rgba(219,39,119,' : 'rgba(245,158,11,'
                                    });
                                }
                            }
                        } else {
                            // Moving to contact, no contact yet
                            state.slipRatio = 1.0;
                        }
                    } else {
                        // Clutch is disengaged, speed out decelerates smoothly under friction
                        const decel = 300 * dt; 
                        state.speedOut = Math.max(0.0, state.speedOut - decel);
                        state.slipRatio = 1.0;
                    }
                } else {
                    // 2. BAND BRAKE SIMULATION LOGIC
                    state.speedIn = state.rpm;
                    const targetLeverAngle = state.engaged ? 11.0 * Math.PI / 180 : 0.0;
                    state.leverAngle += (targetLeverAngle - state.leverAngle) * 8 * dt; // Smooth lever pull
                    if (state.engaged) {
                        // Braking is active, drum decelerates based on torque
                        const dw = (state.calculatedTorque / 8.0) * dt; 
                        let wDrum = (2.0 * Math.PI * state.speedOut) / 60.0;
                        wDrum -= dw;
                        if (wDrum <= 0.0) {
                            wDrum = 0.0;
                            state.speedOut = 0.0;
                            state.slipRatio = 1.0; // 100% stopped
                            overlayRunStatus.innerText = '제동 완전 정지 완료';
                            overlayRunStatus.style.color = '#10b981';
                        } else {
                            state.speedOut = (wDrum * 60.0) / (2.0 * Math.PI);
                            state.slipRatio = (state.rpm - state.speedOut) / state.rpm;
                            overlayRunStatus.innerText = '마찰 제동 가동 (감속 제동 중)';
                            overlayRunStatus.style.color = '#f59e0b';
                        }
                        // Generate circular friction sparks during deceleration
                        if (state.speedOut > 5.0) {
                            const drumCx = cx - 110 * scale;
                            const drumCy = cy;
                            // Align with scaled-up drum radius
                            const drawRad = (50.0 + (state.drumR / 300.0) * 65.0) * scale;
                            const sparkAngle = Math.random() * Math.PI * 2;
                            if (Math.random() < 0.4) {
                                state.sparks.push({
                                    x: drumCx + Math.cos(sparkAngle) * drawRad,
                                    y: drumCy + Math.sin(sparkAngle) * drawRad,
                                    vx: (-Math.sin(sparkAngle) * (state.speedOut / 8.0) + (Math.random() - 0.5) * 60) * scale,
                                    vy: (Math.cos(sparkAngle) * (state.speedOut / 8.0) + (Math.random() - 0.5) * 60) * scale,
                                    life: 0.6 + Math.random() * 0.4,
                                    color: Math.random() > 0.4 ? 'rgba(219,39,119,' : 'rgba(251,146,60,'
                                });
                            }
                        }
                    } else {
                        // Released, drum revs back up smoothly
                        state.speedOut += (state.rpm - state.speedOut) * 6 * dt;
                        state.slipRatio = (state.rpm - state.speedOut) / state.rpm;
                        if (state.rpm - state.speedOut < 1.0) {
                            state.speedOut = state.rpm;
                        }
                    }
                }
                // Update rotational angles for animation
                const wIn = (2.0 * Math.PI * state.speedIn) / 60.0;
                const wOut = (2.0 * Math.PI * state.speedOut) / 60.0;
                // Applied visual speed scale to prevent wagon-wheel strobing
                state.rotationAngleIn += wIn * 0.12 * dt;
                state.rotationAngleOut += wOut * 0.12 * dt;
                // Update indicators
                valSpeedIn.innerText = state.speedIn.toFixed(0) + ' RPM';
                valSpeedOut.innerText = state.speedOut.toFixed(0) + ' RPM';
                if (state.mode === 'clutch') {
                    valSlip.innerText = (state.slipRatio * 100.0).toFixed(1) + '%';
                } else {
                    const stopPercentage = (1.0 - state.speedOut / state.rpm) * 100.0;
                    valSlip.innerText = stopPercentage.toFixed(1) + '%';
                }
                // Render dynamic sparks particle system
                for (let i = state.sparks.length - 1; i >= 0; i--) {
                    const sp = state.sparks[i];
                    sp.x += sp.vx * dt;
                    sp.y += sp.vy * dt;
                    sp.life -= dt;
                    if (sp.life <= 0) {
                        state.sparks.splice(i, 1);
                    } else {
                        ctx.fillStyle = sp.color + sp.life + ')';
                        ctx.beginPath();
                        ctx.arc(sp.x, sp.y, (1.5 + sp.life * 2.5) * scale, 0, Math.PI * 2);
                        ctx.fill();
                    }
                }
                // Render 3D Perspective Graphic / Premium 2D Mechanism
                if (state.mode === 'clutch') {
                    // DRAWING CLUTCH: 3D Isometric View (Scale dynamic zoom)
                    const drawRo = (45 + (state.ro / 300) * 80) * scale;
                    const drawRi = drawRo * (state.ri / state.ro);
                    // Widen the layout to make full use of the wide canvas space
                    const leftDiskX = cx - 90 * scale;
                    const leftShaftX = cx - 280 * scale;
                    const currentGap = state.clampGap * scale;
                    const rightDiskX = cx + 30 * scale + currentGap;
                    const rightShaftX = rightDiskX + 18 * scale;
                    // 1. LEFT SHAFTS (3D Cylinder - Dynamic length)
                    ctx.save();
                    const shaftGrad = ctx.createLinearGradient(leftShaftX, cy - 19 * scale, leftShaftX, cy + 19 * scale);
                    shaftGrad.addColorStop(0, '#0f172a');
                    shaftGrad.addColorStop(0.3, '#334155');
                    shaftGrad.addColorStop(0.7, '#64748b');
                    shaftGrad.addColorStop(1, '#0f172a');
                    ctx.fillStyle = shaftGrad;
                    ctx.beginPath();
                    ctx.rect(leftShaftX, cy - 19 * scale, leftDiskX - leftShaftX, 38 * scale);
                    ctx.fill();
                    // Left Input shaft 3D end face
                    ctx.fillStyle = '#1e293b';
                    ctx.beginPath();
                    ctx.ellipse(leftShaftX, cy, 8 * scale, 19 * scale, 0, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                    // 2. LEFT DRIVING DISC
                    ctx.save();
                    ctx.shadowBlur = 20 * scale;
                    ctx.shadowColor = 'rgba(2, 132, 199, 0.22)';
                    const discLeftGrad = ctx.createLinearGradient(leftDiskX, cy - drawRo, leftDiskX + 30 * scale, cy + drawRo);
                    discLeftGrad.addColorStop(0, '#0369a1');
                    discLeftGrad.addColorStop(0.5, '#0284c7');
                    discLeftGrad.addColorStop(1, '#0f766e');
                    ctx.fillStyle = discLeftGrad;
                    ctx.strokeStyle = '#0284c7';
                    ctx.lineWidth = 2 * scale;
                    ctx.beginPath();
                    ctx.ellipse(leftDiskX, cy, 18 * scale, drawRo, 0, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.stroke();
                    ctx.restore();
                    // Radial Slots on Left Plate
                    ctx.save();
                    ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
                    ctx.lineWidth = 3 * scale;
                    const slots = 8;
                    for (let i = 0; i < slots; i++) {
                        const phi = state.rotationAngleIn + (i * Math.PI * 2) / slots;
                        const outerX = leftDiskX + Math.cos(phi) * 16 * scale;
                        const outerY = cy + Math.sin(phi) * drawRo;
                        const innerX = leftDiskX + Math.cos(phi) * 6 * scale;
                        const innerY = cy + Math.sin(phi) * drawRi;
                        ctx.beginPath();
                        ctx.moveTo(innerX, innerY);
                        ctx.lineTo(outerX, outerY);
                        ctx.stroke();
                    }
                    ctx.restore();
                    // 3. FRICTION LINING PAD LAYER
                    ctx.save();
                    ctx.fillStyle = '#1e293b';
                    ctx.strokeStyle = '#475569';
                    ctx.lineWidth = 1 * scale;
                    ctx.beginPath();
                    ctx.ellipse(leftDiskX + 11 * scale, cy, 8 * scale, drawRo - 1 * scale, 0, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.stroke();
                    ctx.fillStyle = '#cbd5e1';
                    ctx.beginPath();
                    ctx.ellipse(leftDiskX + 11 * scale, cy, 5 * scale, drawRi, 0, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                    // 4. RIGHT DRIVEN DISC
                    ctx.save();
                    const discRightGrad = ctx.createLinearGradient(rightDiskX, cy - drawRo, rightDiskX + 30 * scale, cy + drawRo);
                    discRightGrad.addColorStop(0, '#db2777');
                    discRightGrad.addColorStop(0.5, '#ec4899');
                    discRightGrad.addColorStop(1, '#db2777');
                    ctx.fillStyle = discRightGrad;
                    ctx.strokeStyle = '#f472b6';
                    ctx.lineWidth = 2 * scale;
                    ctx.beginPath();
                    ctx.ellipse(rightDiskX, cy, 18 * scale, drawRo, 0, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.stroke();
                    ctx.restore();
                    // Radial slots on Right Plate
                    ctx.save();
                    ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
                    ctx.lineWidth = 3 * scale;
                    for (let i = 0; i < slots; i++) {
                        const phi = state.rotationAngleOut + (i * Math.PI * 2) / slots;
                        const outerX = rightDiskX + Math.cos(phi) * 16 * scale;
                        const outerY = cy + Math.sin(phi) * drawRo;
                        const innerX = rightDiskX + Math.cos(phi) * 6 * scale;
                        const innerY = cy + Math.sin(phi) * drawRi;
                        ctx.beginPath();
                        ctx.moveTo(innerX, innerY);
                        ctx.lineTo(outerX, outerY);
                        ctx.stroke();
                    }
                    ctx.restore();
                    // 5. RIGHT OUTPUT SHAFT
                    ctx.save();
                    const rightShaftGrad = ctx.createLinearGradient(rightShaftX, cy - 19 * scale, rightShaftX, cy + 19 * scale);
                    rightShaftGrad.addColorStop(0, '#334155');
                    rightShaftGrad.addColorStop(0.3, '#475569');
                    rightShaftGrad.addColorStop(0.7, '#94a3b8');
                    rightShaftGrad.addColorStop(1, '#334155');
                    ctx.fillStyle = rightShaftGrad;
                    ctx.beginPath();
                    ctx.rect(rightShaftX, cy - 19 * scale, (cx + 280 * scale) - rightShaftX, 38 * scale);
                    ctx.fill();
                    ctx.strokeStyle = 'rgba(255, 255, 255, 0.25)';
                    ctx.lineWidth = 4 * scale;
                    const shaftLineX = rightDiskX + 70 * scale;
                    const lineOffset = (state.rotationAngleOut * 120 * scale) % (50 * scale);
                    ctx.beginPath();
                    ctx.moveTo(shaftLineX + lineOffset, cy - 19 * scale);
                    ctx.lineTo(shaftLineX + lineOffset, cy + 19 * scale);
                    ctx.stroke();
                    ctx.restore();
                    // 6. ACTION EFFECTS: GLOW &#038; PRESSURE ARROWS
                    if (state.engaged) {
                        ctx.save();
                        if ((state.clampGap < 3.0) ? (state.slipRatio > 0.0) : false) {
                            const heatIntensity = state.slipRatio;
                            ctx.strokeStyle = 'rgba(239, 68, 68, ' + (0.3 + heatIntensity * 0.5) + ')';
                            ctx.shadowBlur = 30 * scale;
                            ctx.shadowColor = '#ef4444';
                            ctx.lineWidth = 14 * scale;
                            ctx.beginPath();
                            ctx.ellipse(cx - 30 * scale, cy, 24 * scale, drawRo + 8 * scale, 0, 0, Math.PI * 2);
                            ctx.stroke();
                        }
                        ctx.strokeStyle = '#db2777';
                        ctx.fillStyle = '#db2777';
                        ctx.lineWidth = 5 * scale;
                        ctx.shadowBlur = 12 * scale;
                        ctx.shadowColor = '#db2777';
                        const arrowHeadX = rightDiskX + 32 * scale;
                        ctx.beginPath(); ctx.moveTo(arrowHeadX + 80 * scale, cy - 45 * scale); ctx.lineTo(arrowHeadX, cy - 45 * scale); ctx.stroke();
                        ctx.beginPath(); ctx.moveTo(arrowHeadX, cy - 45 * scale); ctx.lineTo(arrowHeadX + 10 * scale, cy - 51 * scale); ctx.lineTo(arrowHeadX + 10 * scale, cy - 39 * scale); ctx.closePath(); ctx.fill();
                        ctx.beginPath(); ctx.moveTo(arrowHeadX + 80 * scale, cy + 45 * scale); ctx.lineTo(arrowHeadX, cy + 45 * scale); ctx.stroke();
                        ctx.beginPath(); ctx.moveTo(arrowHeadX, cy + 45 * scale); ctx.lineTo(arrowHeadX + 10 * scale, cy + 51 * scale); ctx.lineTo(arrowHeadX + 10 * scale, cy + 39 * scale); ctx.closePath(); ctx.fill();
                        ctx.restore();
                    }
                } else {
                    // DRAWING BAND BRAKE: High-Fidelity Drum (Scale dynamic zoom)
                    const drawRad = (50.0 + (state.drumR / 300.0) * 65.0) * scale;
                    const drumCx = cx - 110 * scale;
                    const drumCy = cy;
                    // 1. BRAKE DRUM
                    ctx.save();
                    ctx.translate(drumCx, drumCy);
                    ctx.rotate(state.rotationAngleOut);
                    ctx.shadowBlur = 25 * scale;
                    ctx.shadowColor = 'rgba(71, 85, 105, 0.15)';
                    const drumGrad = ctx.createRadialGradient(0, 0, 10 * scale, 0, 0, drawRad);
                    drumGrad.addColorStop(0, '#ffffff');
                    drumGrad.addColorStop(0.5, '#cbd5e1');
                    drumGrad.addColorStop(0.95, '#94a3b8');
                    drumGrad.addColorStop(1, '#475569');
                    ctx.fillStyle = drumGrad;
                    ctx.strokeStyle = '#1e293b';
                    ctx.lineWidth = 5.5 * scale;
                    ctx.beginPath();
                    ctx.arc(0, 0, drawRad, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.stroke();
                    // Drastically reduced holes
                    ctx.fillStyle = '#334155';
                    const holes = 3;
                    for (let i = 0; i < holes; i++) {
                        const holeAngle = (i * Math.PI * 2) / holes;
                        const hx = Math.cos(holeAngle) * (drawRad - 18 * scale);
                        const hy = Math.sin(holeAngle) * (drawRad - 18 * scale);
                        ctx.beginPath();
                        ctx.arc(hx, hy, 7 * scale, 0, Math.PI * 2);
                        ctx.fill();
                    }
                    // Prominent high-contrast line/marker
                    ctx.strokeStyle = '#0284c7';
                    ctx.lineWidth = 5 * scale;
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.lineTo(drawRad - 6 * scale, 0);
                    ctx.stroke();
                    // Elegant Internal spokes
                    ctx.strokeStyle = '#64748b';
                    ctx.lineWidth = 5 * scale;
                    for (let i = 0; i < 4; i++) {
                        const spokeA = (i * Math.PI) / 2;
                        ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(Math.cos(spokeA) * (drawRad - 22 * scale), Math.sin(spokeA) * (drawRad - 22 * scale)); ctx.stroke();
                    }
                    // Heavy center axle pin
                    ctx.fillStyle = '#0f172a';
                    ctx.strokeStyle = '#cbd5e1';
                    ctx.lineWidth = 3 * scale;
                    ctx.beginPath(); ctx.arc(0, 0, 16 * scale, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
                    ctx.restore();
                    // 2. TIGHT &#038; SLACK LEVER SYSTEM (Lever Joint Anchor Mechanics)
                    ctx.save();
                    const wAngRad = (state.wrapAngle * Math.PI) / 180.0;
                    const startA = Math.PI - wAngRad / 2.0;
                    const anchorHingeX = drumCx + drawRad + 35 * scale;
                    const anchorHingeY = drumCy + drawRad * 0.4;
                    // Draw static support frame
                    ctx.strokeStyle = '#94a3b8';
                    ctx.lineWidth = 6 * scale;
                    ctx.lineCap = 'round';
                    ctx.beginPath();
                    ctx.moveTo(anchorHingeX, anchorHingeY);
                    ctx.lineTo(anchorHingeX - 12 * scale, anchorHingeY + 25 * scale);
                    ctx.stroke();
                    // Ground hash lines
                    ctx.lineWidth = 2 * scale;
                    ctx.beginPath();
                    ctx.moveTo(anchorHingeX - 20 * scale, anchorHingeY + 25 * scale);
                    ctx.lineTo(anchorHingeX - 4 * scale, anchorHingeY + 25 * scale);
                    ctx.stroke();
                    // Joint Pin anchor pivot
                    ctx.fillStyle = '#475569';
                    ctx.beginPath(); ctx.arc(anchorHingeX, anchorHingeY, 7 * scale, 0, Math.PI * 2); ctx.fill();
                    // Solid operating lever bar
                    const leverLength = 180 * scale;
                    const endLeverX = anchorHingeX + Math.cos(state.leverAngle) * leverLength;
                    const endLeverY = anchorHingeY + Math.sin(state.leverAngle) * leverLength;
                    ctx.strokeStyle = '#475569';
                    ctx.lineWidth = 9 * scale;
                    ctx.beginPath();
                    ctx.moveTo(anchorHingeX, anchorHingeY);
                    ctx.lineTo(endLeverX, endLeverY);
                    ctx.stroke();
                    // F1 &#038; F2 attachment pins
                    const tightPinDist = 32 * scale;
                    const slackPinDist = 78 * scale;
                    const pinTightX = anchorHingeX + Math.cos(state.leverAngle) * tightPinDist;
                    const pinTightY = anchorHingeY + Math.sin(state.leverAngle) * tightPinDist;
                    const pinSlackX = anchorHingeX + Math.cos(state.leverAngle) * slackPinDist;
                    const pinSlackY = anchorHingeY + Math.sin(state.leverAngle) * slackPinDist;
                    ctx.fillStyle = '#0284c7';
                    ctx.beginPath(); ctx.arc(pinTightX, pinTightY, 4.5 * scale, 0, Math.PI * 2); ctx.fill();
                    ctx.fillStyle = '#db2777';
                    ctx.beginPath(); ctx.arc(pinSlackX, pinSlackY, 4.5 * scale, 0, Math.PI * 2); ctx.fill();
                    // 3. BRAKE STRAP BAND (Glows red-hot under friction deceleration)
                    ctx.save();
                    if (state.engaged ? (state.speedOut > 0.0) : false) {
                        ctx.strokeStyle = 'rgba(239, 68, 68, 0.45)';
                        ctx.shadowBlur = 18 * scale;
                        ctx.shadowColor = '#ef4444';
                        ctx.lineWidth = 11 * scale;
                        ctx.beginPath();
                        ctx.arc(drumCx, drumCy, drawRad + 3 * scale, startA, startA + wAngRad);
                        ctx.stroke();
                    }
                    // Strap structure
                    ctx.strokeStyle = '#db2777';
                    ctx.lineWidth = state.engaged ? 7.5 * scale : 4.0 * scale;
                    ctx.lineCap = 'round';
                    ctx.beginPath();
                    const bandPoints = 90;
                    for (let i = 0; i <= bandPoints; i++) {
                        const phi = startA + (i / bandPoints) * wAngRad;
                        const strapDistance = state.engaged ? drawRad + 2.0 * scale : drawRad + 7.5 * scale;
                        const bx = drumCx + Math.cos(phi) * strapDistance;
                        const by = drumCy + Math.sin(phi) * strapDistance;
                        if (i === 0) { ctx.moveTo(bx, by); }
                        else { ctx.lineTo(bx, by); }
                    }
                    ctx.stroke();
                    // Links from strap to pins
                    ctx.strokeStyle = '#cbd5e1';
                    ctx.lineWidth = 3.5 * scale;
                    const bandStartStrapX = drumCx + Math.cos(startA) * (state.engaged ? drawRad + 2.0 * scale : drawRad + 7.5 * scale);
                    const bandStartStrapY = drumCy + Math.sin(startA) * (state.engaged ? drawRad + 2.0 * scale : drawRad + 7.5 * scale);
                    const bandEndStrapX = drumCx + Math.cos(startA + wAngRad) * (state.engaged ? drawRad + 2.0 * scale : drawRad + 7.5 * scale);
                    const bandEndStrapY = drumCy + Math.sin(startA + wAngRad) * (state.engaged ? drawRad + 2.0 * scale : drawRad + 7.5 * scale);
                    ctx.beginPath();
                    ctx.moveTo(bandStartStrapX, bandStartStrapY);
                    ctx.lineTo(pinSlackX, pinSlackY);
                    ctx.moveTo(bandEndStrapX, bandEndStrapY);
                    ctx.lineTo(pinTightX, pinTightY);
                    ctx.stroke();
                    ctx.restore();
                    // 4. DESIGN DIRECTION FORCE VECTOR (Pink vector on the lever)
                    if (state.engaged) {
                        ctx.save();
                        ctx.strokeStyle = '#db2777';
                        ctx.fillStyle = '#db2777';
                        ctx.lineWidth = 4 * scale;
                        ctx.shadowBlur = 8 * scale;
                        ctx.shadowColor = '#db2777';
                        ctx.beginPath(); ctx.moveTo(endLeverX, endLeverY - 45 * scale); ctx.lineTo(endLeverX, endLeverY - 4 * scale); ctx.stroke();
                        ctx.beginPath(); ctx.moveTo(endLeverX, endLeverY - 4 * scale); ctx.lineTo(endLeverX - 6 * scale, endLeverY - 14 * scale); ctx.lineTo(endLeverX + 6 * scale, endLeverY - 14 * scale); ctx.closePath(); ctx.fill();
                        ctx.font = '700 ' + (11 * scale) + 'px Inter';
                        ctx.fillText('인가력 F', endLeverX - 8 * scale, endLeverY - 50 * scale);
                        ctx.restore();
                    }
                }
                requestAnimationFrame(animate);
            }
            requestAnimationFrame(animate);
            // Initial calculations
            calculateClutchBrake();
            // Right click / Copy Protection
            (function() {
                function blockEvents() {
                    document.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }, { capture: true });
                    document.addEventListener('selectstart', function(e) {
                        e.preventDefault();
                        return false;
                    }, { capture: true });
                }
                if (document.readyState === 'complete' || document.readyState === 'interactive') {
                    blockEvents();
                } else {
                    document.addEventListener('DOMContentLoaded', blockEvents);
                }
            })();
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>구동 해석 장치 선택: '단판 마찰 클러치' 분석 모드 또는 '밴드 제동 브레이크' 분석 모드를 선택합니다.</strong></li>
<li style="margin-bottom: 6px;">기본 마찰 조건 설정: 접촉면의 마찰 계수(mu)와 작동 수직 클램핑 힘(F)을 지정합니다.</li>
<li style="margin-bottom: 6px;">기하 형상 입력: 클러치 외경/내경(Ro, Ri) 및 마모 이론(마모설 vs 압력설)을 지정하거나, 브레이크 드럼 직경(D) 및 밴드 감김 랩 각도(theta)를 지정합니다.</li>
<li style="margin-bottom: 6px;">구동 속도 RPM 인가: 입력축의 구동 속도(N)를 설정합니다.</li>
<li style="margin-bottom: 6px;">실시간 체결 및 제동 동역학 감상: '체결/제동 구동(Engage / Brake)' 버튼을 클릭해 2D 물리 시뮬레이션 속에서 클러치가 미끄러지며(Slip) 가속되거나, 밴드가 드럼을 감싸 쥐어 회전 속도가 서서히 정지하는 역학 관계를 실시간으로 확인합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 마찰 체결 기구 설계 식 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 마찰 클러치의 두 가지 설계 가설: 일등 마모설 vs 일등 압력설</h3>
<p>마찰 클러치(Friction Clutch)는 주동축의 동력을 종동축으로 부드럽게 연결하거나 차단하는 장치로, 면마찰 접촉 조건에 대해 다음과 같은 두 가지 극단적인 설계 가설이 쓰입니다:</p><ul><li><strong>일등 마모설 (Uniform Wear Theory):</strong> 마찰면 전체의 물리적 마모율(압력 p &times; 미끄럼속도 v)이 일정하다고 가정합니다. 클러치가 길들어 오랜 기간 사용된 상태(Worn-in)에 적합하며, 안전 마진 확보를 위해 <u>실무 설계 시 표준</u>으로 채택됩니다. 평균 마찰 반경은 다음과 같습니다:<br><code style="background:#f3f4f6; padding:2px 6px; border-radius:4px;">R<sub>mean</sub> = (R<sub>i</sub> + R<sub>o</sub>) / 2</code></li><li><strong>일등 압력설 (Uniform Pressure Theory):</strong> 접촉면 전체에 작용하는 단위 면적당 면압(p)이 완전히 균일하다고 가정합니다. 마찰재가 단단하고 평평하게 맞닿은 신품 클러치(New Clutch) 상태에 적합합니다. 평균 마찰 반경은 다음과 같습니다:<br><code style="background:#f3f4f6; padding:2px 6px; border-radius:4px;">R<sub>mean</sub> = 2/3 &middot; (R<sub>o</sub><sup>3</sup> - R<sub>i</sub><sup>3</sup>) / (R<sub>o</sub><sup>2</sup> - R<sub>i</sub><sup>2</sup>)</code></li></ul><p>클러치 전달 토크는 <code>T = &mu; &middot; F &middot; R<sub>mean</sub></code>으로 계산되며, 전달 동력은 <code>P = T &middot; &omega;</code>이 성립합니다.</p>
<h3>2. 밴드 브레이크와 벨트 마찰 방정식 (오일러-아이텔바인 공식)</h3>
<p><strong>밴드 브레이크 (Band Brake)</strong>는 회전하는 드럼 외주면에 유연한 강철 마찰 밴드를 둘러싸고, 레버를 통해 밴드를 강하게 당겨 마찰 저항력으로 제동을 거는 고토크 제동 장치입니다.</p><p>드럼에 밀착된 벨트의 긴장측(Tight Side) 장력 <code>F<sub>1</sub></code>과 이완측(Slack Side) 장력 <code>F<sub>2</sub></code> 사이의 수학적 관계는 오일러의 <strong>벨트 마찰 공식(Euler-Eytelwein Equation)</strong>을 충실히 따릅니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.1em; color: #0369a1;">F<sub>1</sub> / F<sub>2</sub> = e<sup>&mu; &middot; &alpha;</sup> &nbsp;&nbsp;(여기서 &alpha;는 라디안 단위의 감김각 랩앵글)</p><p>제동 레버 조작력에 의한 이완측 장력이 <code>F<sub>2</sub> = F</code>일 때, 전달(제동)되는 유효 힘은 <code>F<sub>net</sub> = F<sub>1</sub> - F<sub>2</sub> = F &middot; (e<sup>&mu;&alpha;</sup> - 1)</code>이 되며, 드럼 반경 <code>r</code>에 작용하는 제동 토크는 다음과 같이 유도되어 랩 각도가 커질수록 제동력이 기하급수적으로 폭증합니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">T<sub>brake</sub> = F &middot; (e<sup>&mu;&alpha;</sup> - 1) &middot; r &nbsp;[N&middot;m]</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/clutch-brake-torque-power-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>캠 기구 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/cam-mechanism-profile-motion-simulator/</link>
					<comments>https://myengnote.com/cam-mechanism-profile-motion-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 02 Jul 2026 23:48:20 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[SVA선도]]></category>
		<category><![CDATA[변위선도]]></category>
		<category><![CDATA[종동절]]></category>
		<category><![CDATA[캠기구]]></category>
		<category><![CDATA[캠프로파일]]></category>
		<guid isPermaLink="false">https://myengnote.com/cam-mechanism-profile-motion-simulator/</guid>

					<description><![CDATA[기초원 반경, 리프트 양, 회전 속도 및 캠 형상(심편심, 하트형, 등속도)에 따라 결정되는 종동절의 실시간 변위(Displacement), 속도(Velocity), 가속도(Acceleration)를 2D 역학 물리엔진으로 가시화하는 명품 기계요소 시뮬레이터입니다. <a href="https://myengnote.com/cam-mechanism-profile-motion-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 캠 기구 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for cammechanism-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .cammechanism-calculator-wrapper *, .cammechanism-calculator-wrapper *::before, .cammechanism-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .cammechanism-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .cammechanism-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            z-index: -1; overflow: hidden; pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: ''; position: absolute; width: 600px; height: 600px; border-radius: 50%; filter: blur(140px); opacity: 0.12;
        }
        .app-background-glow::before { background: var(--color-cyan); top: -10%; right: -5%; animation: pulse-slow 15s infinite alternate; }
        .app-background-glow::after { background: var(--color-purple); bottom: -10%; left: -5%; animation: pulse-slow 20s infinite alternate-reverse; }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.08; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.15; }
        }
        .app-container {
            width: 100%; max-width: 1440px; padding: 24px; display: flex; flex-direction: column; gap: 24px;
        }
        .app-header {
            display: flex; justify-content: space-between; align-items: center; padding: 20px 24px;
            background: var(--color-panel-bg); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 16px; box-shadow: var(--shadow-card);
        }
        .logo-area { display: flex; align-items: center; gap: 16px; }
        .logo-icon {
            font-size: 32px; background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
            display: flex; align-items: center; justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-dark)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle { font-size: 12px; color: var(--color-text-muted); font-weight: 500; letter-spacing: 0.5px; }
        .header-badge {
            display: flex; align-items: center; gap: 10px; background: rgba(124, 58, 237, 0.1); border: 1px solid rgba(124, 58, 237, 0.2); padding: 6px 14px; border-radius: 20px;
        }
        .pulse-dot {
            width: 8px; height: 8px; background-color: var(--color-purple); border-radius: 50%; box-shadow: 0 0 10px var(--color-purple); animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text { font-size: 11px; font-weight: 600; color: var(--color-purple); letter-spacing: 0.5px; }
        .app-main-grid { display: grid; grid-template-columns: 340px 1fr 340px; gap: 24px; align-items: start; }
        .panel {
            background: var(--gradient-panel); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 20px; padding: 24px; box-shadow: var(--shadow-card);
            display: flex; flex-direction: column; gap: 18px; transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover { border-color: var(--color-border-hover); }
        .panel-header { display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--color-border); padding-bottom: 14px; }
        .panel-header i { font-size: 18px; }
        .panel-header h2 { font-family: var(--font-heading); font-size: 18px; font-weight: 600; letter-spacing: 0.5px; }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel { grid-column: 1; }
        .input-group { display: flex; flex-direction: column; gap: 8px; }
        .input-label-row { display: flex; justify-content: space-between; align-items: center; }
        .input-label-row label { font-size: 13px; font-weight: 600; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .helper-text { font-size: 10px; color: var(--color-text-muted); font-weight: 500; }
        .segmented-control {
            display: grid; grid-template-columns: repeat(3, 1fr); background: rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); padding: 4px; border-radius: 12px; gap: 4px;
        }
        .segmented-btn {
            background: transparent; border: none; color: var(--color-text-muted); padding: 8px 2px; border-radius: 8px; font-size: 10px; font-weight: 700; cursor: pointer; transition: all 0.2s ease; text-align: center;
        }
        .segmented-btn:hover { color: var(--color-text-main); background: rgba(0, 0, 0, 0.015); }
        .segmented-btn.active { background: #ffffff; color: var(--color-cyan); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within { border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow); }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button, .custom-number-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none; width: 100%; height: 6px; border-radius: 3px; background: rgba(0, 0, 0, 0.05); outline: none; margin: 4px 0; transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; cursor: pointer; transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        .slider-cyan::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 8px var(--color-cyan); }
        .slider-cyan::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-magenta::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 8px var(--color-magenta); }
        .slider-magenta::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-purple::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 8px var(--color-purple); }
        .slider-purple::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-cyan::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-cyan); }
        .slider-magenta::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-magenta); }
        .slider-purple::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-purple); }
        .presets-section { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--color-border); padding-top: 16px; }
        .presets-section h3 { font-size: 13px; font-weight: 700; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .presets-grid { display: flex; flex-direction: column; gap: 8px; }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px; padding: 8px 12px; cursor: pointer; color: var(--color-text-main);
            display: flex; align-items: center; gap: 12px; text-align: left; transition: all 0.2s ease;
        }
        .preset-btn:hover { background: rgba(0, 0, 0, 0.04); transform: translateX(4px); }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow)); border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px; height: 28px; background: rgba(0, 0, 0, 0.02); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon { background: var(--gradient-primary); color: #fff; }
        .preset-name { font-size: 12px; font-weight: 600; }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-wrapper {
            position: relative; width: 100%; background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%); border: 1px solid rgba(0, 0, 0, 0.06); border-radius: 16px;
            overflow: hidden; display: flex; align-items: center; justify-content: center; 
        }
        #physics-canvas { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; }
        .canvas-overlay-data { position: absolute; top: 16px; left: 16px; pointer-events: none; display: flex; flex-direction: column; gap: 6px; }
        .overlay-item {
            background: rgba(255, 255, 255, 0.9); color: var(--color-text-main); backdrop-filter: blur(4px); border: 1px solid var(--color-border); padding: 6px 12px; border-radius: 8px;
            display: flex; align-items: center; gap: 8px; font-size: 11px;
        }
        .overlay-item .label { color: var(--color-text-muted); font-weight: 500; }
        .overlay-item .value { font-weight: 700; }
        .simulation-metrics-strip {
            display: flex; background: rgba(0, 0, 0, 0.01); border: 1px solid var(--color-border); border-radius: 12px; padding: 12px 20px;
            justify-content: space-around; align-items: center; gap: 10px; margin-top: 10px;
        }
        .mini-metric { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
        .mini-metric .label { font-size: 10px; font-weight: 600; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
        .mini-metric .value { font-size: 14px; font-weight: 700; color: var(--color-text-main); font-family: var(--font-heading); }
        .mini-divider { width: 1px; height: 24px; background: var(--color-border); }
        .results-panel { grid-column: 3; }
        .ratio-readout-box {
            background: linear-gradient(135deg, var(--color-cyan-glow) 0%, var(--color-purple-glow) 100%); border: 1px solid rgba(2, 132, 199, 0.15); border-radius: 16px;
            padding: 20px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
        }
        .ratio-title { font-size: 11px; font-weight: 700; color: var(--color-cyan); letter-spacing: 1px; text-transform: uppercase; }
        .ratio-value {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .ratio-type { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .results-grid { display: flex; flex-direction: column; gap: 12px; }
        .result-card {
            background: rgba(255, 255, 255, 0.85); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); border-radius: 12px;
            padding: 12px 16px; display: flex; align-items: center; gap: 16px; transition: all 0.2s ease;
        }
        .result-card:hover { transform: translateY(-2px); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-icon {
            width: 38px; height: 38px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px;
            display: flex; align-items: center; justify-content: center; font-size: 14px; color: var(--color-text-muted);
        }
        .result-card:hover .card-icon { color: var(--color-cyan); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-content { display: flex; flex-direction: column; gap: 2px; word-break: keep-all; }
        .card-unit { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .card-value { font-family: var(--font-heading); font-weight: 700; font-size: 17px; color: var(--color-text-main); }
        .formula-card {
            background: #ffffff; border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 8px; font-size: 12px;
        }
        .formula-card h4 { font-weight: 700; color: var(--color-text-main); }
        .formula-equation {
            font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace; color: #0284c7; font-size: 13px; background: #f8fafc; border-color: var(--color-border);
            padding: 8px 10px; border-radius: 6px;
        }
        @container cam-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container cam-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container cam-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
            .simulation-metrics-strip {
                flex-direction: column;
                gap: 12px;
            }
            .mini-divider {
                width: 80%;
                height: 1px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
        /* Action Buttons (Play/Pause) styling */
        .action-btn {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            background: rgba(2, 132, 199, 0.08);
            color: var(--color-cyan) !important;
            border: 1px solid rgba(2, 132, 199, 0.2);
            padding: 10px;
            border-radius: 10px;
            font-size: 12px;
            font-weight: 700;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        .action-btn:hover {
            background: var(--color-cyan);
            color: #ffffff !important;
            box-shadow: var(--shadow-neon-cyan);
        }
        .action-btn.active {
            background: var(--color-cyan);
            color: #ffffff !important;
            border-color: var(--color-cyan);
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.cammechanism-calculator-wrapper .app-main-grid,
.cammechanism-calculator-wrapper .main-grid,
.cammechanism-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.cammechanism-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.cammechanism-calculator-wrapper .simulation-panel,
.cammechanism-calculator-wrapper .canvas-panel,
.cammechanism-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.cammechanism-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.cammechanism-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.cammechanism-calculator-wrapper .simulation-results-section .ratio-readout-box,
.cammechanism-calculator-wrapper .simulation-results-section .re-readout-box,
.cammechanism-calculator-wrapper .simulation-results-section .status-readout-box,
.cammechanism-calculator-wrapper .simulation-results-section .flow-readout-box,
.cammechanism-calculator-wrapper .simulation-results-section [class*="readout-box"],
.cammechanism-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.cammechanism-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.cammechanism-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.cammechanism-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .cammechanism-calculator-wrapper .app-main-grid,
    .cammechanism-calculator-wrapper .main-grid,
    .cammechanism-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .cammechanism-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .cammechanism-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .cammechanism-calculator-wrapper .simulation-panel,
    .cammechanism-calculator-wrapper .canvas-panel,
    .cammechanism-calculator-wrapper .sim-panel,
    .cammechanism-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .cammechanism-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .cammechanism-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .cammechanism-calculator-wrapper .simulation-results-section .re-readout-box,
    .cammechanism-calculator-wrapper .simulation-results-section .status-readout-box,
    .cammechanism-calculator-wrapper .simulation-results-section .flow-readout-box,
    .cammechanism-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .cammechanism-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .cammechanism-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .cammechanism-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.cammechanism-calculator-wrapper .app-container,
.cammechanism-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.cammechanism-calculator-wrapper .simulation-results-section .formula-card,
.cammechanism-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.cammechanism-calculator-wrapper .simulation-results-section .formula-card h4,
.cammechanism-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.cammechanism-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.cammechanism-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="cammechanism-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-shapes"></i></div>
                <div>
                    <h1>CAM MECHANISM</h1>
                    <div class="subtitle">캠 기구 운동 기하학적 실시간 2D 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">KINEMATICS ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>캠 기하 형상 설계</h2>
                </div>
                <!-- Cam Profile Type -->
                <div class="input-group">
                    <span class="helper-text" style="font-weight:700; color:var(--color-text-muted);">캠 윤곽 프로파일</span>
                    <div class="segmented-control" id="control-cam-type">
                        <button class="segmented-btn active" id="btn-cam-eccentric" data-type="eccentric">편심 원형</button>
                        <button class="segmented-btn" id="btn-cam-heart" data-type="heart">하트 등속</button>
                        <button class="segmented-btn" id="btn-cam-pear" data-type="pear">배형 낙하</button>
                    </div>
                </div>
                <!-- Follower Type -->
                <div class="input-group">
                    <span class="helper-text" style="font-weight:700; color:var(--color-text-muted);">종동절 헤드 형태</span>
                    <div class="segmented-control" id="control-follower-type">
                        <button class="segmented-btn active" id="btn-fol-roller" data-type="roller">롤러</button>
                        <button class="segmented-btn" id="btn-fol-flat" data-type="flat">평판</button>
                        <button class="segmented-btn" id="btn-fol-knife" data-type="knife">나이프</button>
                    </div>
                </div>
                <!-- Base Circle Rb -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-rb"><i class="fa-solid fa-circle text-cyan"></i> 기초원 반경 (Rb)</label>
                        <span class="helper-text">(20.0 ~ 80.0 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rb" class="custom-number-input" min="20" max="80" value="45" step="any">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-rb" class="custom-slider slider-cyan" min="200" max="800" value="450">
                </div>
                <!-- Max Lift h -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-lift"><i class="fa-solid fa-up-down text-magenta"></i> 최대 리프트 변위 (h)</label>
                        <span class="helper-text">(5.0 ~ 40.0 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-lift" class="custom-number-input" min="5" max="40" value="20" step="any">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-lift" class="custom-slider slider-magenta" min="50" max="400" value="200">
                </div>
                <!-- Cam Speed N -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-rpm"><i class="fa-solid fa-arrows-spin text-purple"></i> 캠 회전 속도 (N)</label>
                        <span class="helper-text">(10 ~ 400 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="10" max="400" value="60" step="any">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider slider-purple" min="10" max="400" value="60">
                </div>
                <!-- Control Action Buttons -->
                <div class="control-actions" style="margin-top: 6px;">
                    <button id="btn-play-pause" class="action-btn">
                        <i class="fa-solid fa-pause"></i> <span>일시정지</span>
                    </button>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 기구 구동 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" id="preset-harmonic">
                            <div class="preset-icon"><i class="fa-solid fa-wave-square"></i></div>
                            <div class="preset-details"><span class="preset-name">조화 왕복 기구</span><span class="preset-spec">고조파 저진동 편심 캠</span></div>
                        </button>
                        <button class="preset-btn" id="preset-uniform">
                            <div class="preset-icon"><i class="fa-solid fa-heart"></i></div>
                            <div class="preset-details"><span class="preset-name">하트형 등속 코일 권선기</span><span class="preset-spec">좌우 정밀 분배</span></div>
                        </button>
                        <button class="preset-btn" id="preset-valve">
                            <div class="preset-icon"><i class="fa-solid fa-cog"></i></div>
                            <div class="preset-details"><span class="preset-name">엔진 밸브 급개폐 기구</span><span class="preset-spec">고속 리프트형 배형 캠</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <i class="fa-solid fa-dharmachakra text-magenta"></i>
                                    <h2>캠 기구 2D 회전 애니메이션 &#038; S-V-A 선도</h2>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas" width="640" height="400"></canvas>
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">접촉 충격:</span>
                                            <span class="value" id="overlay-run-status">정상 슬라이딩</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <span class="label">현재 회전각 (&theta;)</span>
                                        <span class="value" id="val-angle">120.4°</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">실시간 종동절 리프트 (s)</span>
                                        <span class="value" id="val-lift">12.5 mm</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">최대 가속도 (a_max)</span>
                                        <span class="value" id="val-accel">2.4 m/s²</span>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">현재 종동절 리프트 변위 (s)</div>
                                    <div class="ratio-value" id="txt-current-lift">12.50 mm</div>
                                    <div class="ratio-type" id="txt-lift-range">설계 구동 범위: 0.0 ~ 20.0 mm</div>
                                    <div class="ratio-type" id="txt-cam-type-label">윤곽: 편심 원형 캠 (Rb = 45.0mm)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- 구동 속도 범위 (v_max / v_min) -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-gauge-high text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">구동 속도 범위 (v_max / v_min)</span>
                                            <div>
                                                <div>
                                                    <span>최대 (v_max)</span>
                                                    <span class="card-value" id="res-velocity-max">0.00 m/s</span>
                                                </div>
                                                <div>
                                                    <span>최소 (v_min)</span>
                                                    <span class="card-value" id="res-velocity-min">0.00 m/s</span>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- 실시간 구동 속도 (v) -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-gauge-simple text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">실시간 구동 속도 (v)</span>
                                            <span class="card-value" id="res-velocity">0.00 m/s</span>
                                        </div>
                                    </div>
                                    <!-- 구동 가속도 범위 (a_max / a_min) -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-bolt text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">구동 가속도 범위 (a_max / a_min)</span>
                                            <div>
                                                <div>
                                                    <span>최대 (a_max)</span>
                                                    <span class="card-value" id="res-accel-max">0.0 m/s²</span>
                                                </div>
                                                <div>
                                                    <span>최소 (a_min)</span>
                                                    <span class="card-value" id="res-accel-min">0.0 m/s²</span>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- 실시간 구동 가속도 (a) -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-bolt-lightning text-warning"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">실시간 구동 가속도 (a)</span>
                                            <span class="card-value" id="res-accel">0.0 m/s²</span>
                                        </div>
                                    </div>
                                    <!-- 가속도 급변 충격 (Jerk) 지표 -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-triangle-exclamation text-success"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">가속도 급변 충격 (Jerk) 지표</span>
                                            <span class="card-value" id="res-jerk">우수 (저진동)</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 캠 역학 해석 관계식</h4>
                                    <div class="formula-equation">
                                        v = (ds/d&theta;) × &omega; &nbsp;[m/s]
                                    </div>
                                    <div class="formula-equation">
                                        a = (d²s/d&theta;²) × &omega;² &nbsp;[m/s²]
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- CORE INTERACTIVE ENGINE -->
    </div>
</div>
<script>
    // Polyfill for CanvasRenderingContext2D.roundRect for backward compatibility
    if (typeof CanvasRenderingContext2D !== 'undefined') {
        if (!CanvasRenderingContext2D.prototype.roundRect) {
        CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
            if (typeof r === 'number') r = [r];
            if (!Array.isArray(r)) r = [0];
            const rad = r[0] || 0;
            this.beginPath();
            this.moveTo(x + rad, y);
            this.lineTo(x + w - rad, y);
            this.quadraticCurveTo(x + w, y, x + w, y + rad);
            this.lineTo(x + w, y + h - rad);
            this.quadraticCurveTo(x + w, y + h, x + w - rad, y + h);
            this.lineTo(x + rad, y + h);
            this.quadraticCurveTo(x, y + h, x, y + h - rad);
            this.lineTo(x, y + rad);
            this.quadraticCurveTo(x, y, x + rad, y);
            this.closePath();
            return this;
        };
      }
    }
        (function() {
            if (window.__cammechanism_initialized) return;
            window.__cammechanism_initialized = true;
            const inputRb = document.getElementById('input-rb');
            const sliderRb = document.getElementById('slider-rb');
            const inputLift = document.getElementById('input-lift');
            const sliderLift = document.getElementById('slider-lift');
            const inputRpm = document.getElementById('input-rpm');
            const sliderRpm = document.getElementById('slider-rpm');
            const txtCurrentLift = document.getElementById('txt-current-lift');
            const txtCamTypeLabel = document.getElementById('txt-cam-type-label');
            const valAngle = document.getElementById('val-angle');
            const valLift = document.getElementById('val-lift');
            const valAccel = document.getElementById('val-accel');
            const resVelocity = document.getElementById('res-velocity');
            const resVelocityMax = document.getElementById('res-velocity-max');
            const resVelocityMin = document.getElementById('res-velocity-min');
            const resAccel = document.getElementById('res-accel');
            const resAccelMax = document.getElementById('res-accel-max');
            const resAccelMin = document.getElementById('res-accel-min');
            const resJerk = document.getElementById('res-jerk');
            const overlayRunStatus = document.getElementById('overlay-run-status');
            const state = {
                camType: 'eccentric', // 'eccentric', 'heart', 'pear'
                followerType: 'roller', // 'roller', 'flat', 'knife'
                rb: 45.0,  // mm
                lift: 20.0, // mm (h)
                rpm: 60,
                angle: 0.0, // rad
                isPlaying: true
            };
            const ranges = {
                rb: { min: 20.0, max: 80.0 },
                lift: { min: 5.0, max: 40.0 },
                rpm: { min: 10.0, max: 400.0 }
            };
            // Calculate lift function s(theta)
            // theta is from 0 to 2*PI. Returns lift s in mm (0 to h)
            function getCamLift(theta) {
                const h = state.lift;
                let th = theta % (2.0 * Math.PI);
                if (th < 0) {
                    th += 2.0 * Math.PI;
                }
                if (state.camType === 'eccentric') {
                    // s = (h/2) * (1 - cos(th))
                    return (h / 2.0) * (1.0 - Math.cos(th));
                }
                if (state.camType === 'heart') {
                    // Symmetric constant velocity Heart cam
                    if (th <= Math.PI) {
                        return h * (th / Math.PI);
                    } else {
                        return h * (2.0 - th / Math.PI);
                    }
                }
                if (state.camType === 'pear') {
                    // Slow rise (240 deg), rapid drop (120 deg)
                    const limit = (4.0 * Math.PI) / 3.0; // 240 deg
                    if (th <= limit) {
                        // Rise
                        const phi = th / limit;
                        return h * Math.sin(phi * Math.PI / 2.0);
                    } else {
                        // Drop
                        const phi = (th - limit) / ((2.0 * Math.PI) / 3.0);
                        return h * Math.pow(Math.cos(phi * Math.PI / 2.0), 2);
                    }
                }
                return 0.0;
            }
            function syncRbFromInput() {
                let val = parseFloat(inputRb.value);
                if (isNaN(val)) { val = ranges.rb.min; }
                if (val < ranges.rb.min) { val = ranges.rb.min; }
                if (val > ranges.rb.max) { val = ranges.rb.max; }
                state.rb = val;
                inputRb.value = val.toFixed(1);
                sliderRb.value = Math.round(val * 10);
                updateStaticUI();
            }
            function syncRbFromSlider() {
                state.rb = parseFloat(sliderRb.value) / 10;
                inputRb.value = state.rb.toFixed(1);
                updateStaticUI();
            }
            function syncLiftFromInput() {
                let val = parseFloat(inputLift.value);
                if (isNaN(val)) { val = ranges.lift.min; }
                if (val < ranges.lift.min) { val = ranges.lift.min; }
                if (val > ranges.lift.max) { val = ranges.lift.max; }
                state.lift = val;
                inputLift.value = val.toFixed(1);
                sliderLift.value = Math.round(val * 10);
                updateStaticUI();
            }
            function syncLiftFromSlider() {
                state.lift = parseFloat(sliderLift.value) / 10;
                inputLift.value = state.lift.toFixed(1);
                updateStaticUI();
            }
            function syncRpmFromInput() {
                let val = parseFloat(inputRpm.value);
                if (isNaN(val)) { val = ranges.rpm.min; }
                if (val < ranges.rpm.min) { val = ranges.rpm.min; }
                if (val > ranges.rpm.max) { val = ranges.rpm.max; }
                state.rpm = val;
                inputRpm.value = val.toFixed(0);
                sliderRpm.value = Math.round(val);
                updateStaticUI();
            }
            function syncRpmFromSlider() {
                state.rpm = parseFloat(sliderRpm.value);
                inputRpm.value = state.rpm.toFixed(0);
                updateStaticUI();
            }
            function updateStaticUI() {
                let camName = '편심 원형 캠';
                if (state.camType === 'heart') { camName = '하트형 등속 캠'; }
                if (state.camType === 'pear') { camName = '배형 급격 낙하 캠'; }
                txtCamTypeLabel.innerText = '윤곽: ' + camName + ' (Rb = ' + state.rb.toFixed(1) + 'mm)';
            }
            // Segment control bindings
            const camTypeButtons = document.querySelectorAll('#control-cam-type .segmented-btn');
            camTypeButtons.forEach(function(btn) {
                btn.addEventListener('click', function() {
                    camTypeButtons.forEach(function(b) { b.classList.remove('active'); });
                    btn.classList.add('active');
                    state.camType = btn.getAttribute('data-type');
                    updateStaticUI();
                });
            });
            const followerButtons = document.querySelectorAll('#control-follower-type .segmented-btn');
            followerButtons.forEach(function(btn) {
                btn.addEventListener('click', function() {
                    followerButtons.forEach(function(b) { b.classList.remove('active'); });
                    btn.classList.add('active');
                    state.followerType = btn.getAttribute('data-type');
                });
            });
            // Input event listeners
            inputRb.addEventListener('change', syncRbFromInput);
            sliderRb.addEventListener('input', syncRbFromSlider);
            inputLift.addEventListener('change', syncLiftFromInput);
            sliderLift.addEventListener('input', syncLiftFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            // Play/Pause interaction
            const btnPlayPause = document.getElementById('btn-play-pause');
            if (btnPlayPause) {
                btnPlayPause.addEventListener('click', function() {
                    state.isPlaying = !state.isPlaying;
                    if (state.isPlaying) {
                        btnPlayPause.innerHTML = '<i class="fa-solid fa-pause"></i> <span>일시정지</span>';
                        btnPlayPause.classList.remove('active');
                    } else {
                        btnPlayPause.innerHTML = '<i class="fa-solid fa-play"></i> <span>재생</span>';
                        btnPlayPause.classList.add('active');
                    }
                });
            }
            // Presets
            document.getElementById('preset-harmonic').addEventListener('click', function() {
                setActivePreset('preset-harmonic');
                state.camType = 'eccentric';
                state.followerType = 'roller';
                state.rb = 40.0;
                state.lift = 15.0;
                state.rpm = 120;
                syncControlsToState();
            });
            document.getElementById('preset-uniform').addEventListener('click', function() {
                setActivePreset('preset-uniform');
                state.camType = 'heart';
                state.followerType = 'flat';
                state.rb = 45.0;
                state.lift = 25.0;
                state.rpm = 40;
                syncControlsToState();
            });
            document.getElementById('preset-valve').addEventListener('click', function() {
                setActivePreset('preset-valve');
                state.camType = 'pear';
                state.followerType = 'roller';
                state.rb = 35.0;
                state.lift = 20.0;
                state.rpm = 180;
                syncControlsToState();
            });
            function setActivePreset(id) {
                document.getElementById('preset-harmonic').classList.remove('active');
                document.getElementById('preset-uniform').classList.remove('active');
                document.getElementById('preset-valve').classList.remove('active');
                document.getElementById(id).classList.add('active');
            }
            function syncControlsToState() {
                // Segment active states
                camTypeButtons.forEach(function(btn) {
                    if (btn.getAttribute('data-type') === state.camType) { btn.classList.add('active'); }
                    else { btn.classList.remove('active'); }
                });
                followerButtons.forEach(function(btn) {
                    if (btn.getAttribute('data-type') === state.followerType) { btn.classList.add('active'); }
                    else { btn.classList.remove('active'); }
                });
                inputRb.value = state.rb.toFixed(1);
                sliderRb.value = Math.round(state.rb * 10);
                inputLift.value = state.lift.toFixed(1);
                sliderLift.value = Math.round(state.lift * 10);
                inputRpm.value = state.rpm;
                sliderRpm.value = state.rpm;
                updateStaticUI();
            }
            // Canvas Drawing
            const canvas = document.getElementById('physics-canvas');
            const ctx = canvas.getContext('2d');
            function getDPR() { return window.devicePixelRatio || 1; }
            function initCanvas() {
                const dpr = getDPR();
                const rect = canvas.getBoundingClientRect();
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            window.addEventListener('resize', initCanvas);
            initCanvas();
            let lastTime = 0;
            function animate(currentTime) {
                if (lastTime === 0) { lastTime = currentTime; }
                const dt = (currentTime - lastTime) / 1000;
                lastTime = currentTime;
                const dpr = getDPR();
                const width = canvas.width / dpr;
                const height = canvas.height / dpr;
                ctx.clearRect(0, 0, width, height);
                // Grid
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                ctx.lineWidth = 1;
                const gridSize = 25;
                for (let x = 0; x < width; x += gridSize) {
                    ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, height); ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSize) {
                    ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke();
                }
                // Update Cam rotation angle (Control based on Play/Pause)
                const omega = (2.0 * Math.PI * state.rpm) / 60.0;
                if (state.isPlaying) {
                    state.angle += omega * dt;
                }
                const currentTh = state.angle % (2.0 * Math.PI);
                // Left portion: Cam animation
                const cx = width / 3;
                const cy = height / 2 + 20;
                // Visual scaling: dynamic auto-zooming scale to fill the canvas beautifully
                const scale = (height * 0.38) / (state.rb + state.lift);
                const curLift = getCamLift(currentTh);
                // Numerical differentiation for velocity and acceleration
                // delta theta
                const dTh = 0.005;
                const liftPlus = getCamLift(currentTh + dTh);
                const liftMinus = getCamLift(currentTh - dTh);
                // d(lift)/d(theta) in mm/rad
                const ds_dth = (liftPlus - liftMinus) / (2.0 * dTh);
                // Velocity in m/s (s in mm => ds in m/1000)
                const vel = (ds_dth * omega) / 1000.0;
                // d2(lift)/d(theta)2 in mm/rad²
                const d2s_dth2 = (liftPlus - 2.0 * curLift + liftMinus) / (dTh * dTh);
                // Acceleration in m/s²
                const acc = (d2s_dth2 * omega * omega) / 1000.0;
                // S-V-A peak limit calculations for right panel gauges
                // Base harmonic acceleration peak: a = (h/2)*omega^2
                const basePeakAcc = (state.lift / 2000.0) * omega * omega;
                // Real-time panel display values
                valAngle.innerText = ((currentTh * 180.0) / Math.PI).toFixed(0) + '°';
                valLift.innerText = curLift.toFixed(1) + ' mm';
                valAccel.innerText = Math.abs(acc).toFixed(1) + ' m/s²';
                txtCurrentLift.innerText = curLift.toFixed(2) + ' mm';
                resVelocity.innerText = vel.toFixed(2) + ' m/s';
                resAccel.innerText = acc.toFixed(2) + ' m/s²';
                // Jerk analysis
                if (state.camType === 'eccentric') {
                    resJerk.innerHTML = '우수<span style="font-size: 13px; font-weight: 500; display: block; margin-top: 4px; opacity: 0.95;">(조화 가속도 곡선)</span>';
                    resJerk.style.color = '#10b981';
                    overlayRunStatus.innerText = '안정적 운동 특성 (조화 편심)';
                    overlayRunStatus.style.color = '#10b981';
                } else {
                    if (state.camType === 'heart') {
                        resJerk.innerHTML = '경고<span style="font-size: 13px; font-weight: 500; display: block; margin-top: 4px; opacity: 0.95;">(변곡점 무한 가속도 충격)</span>';
                        resJerk.style.color = '#f59e0b';
                        overlayRunStatus.innerText = '가속도 급변! 변곡점 충격 주의';
                        overlayRunStatus.style.color = '#f59e0b';
                    } else {
                        resJerk.innerHTML = '위험<span style="font-size: 13px; font-weight: 500; display: block; margin-top: 4px; opacity: 0.95;">(고낙하 충격 및 종동 점프 위험)</span>';
                        resJerk.style.color = '#db2777';
                        overlayRunStatus.innerText = '종동절 낙하 가속 충격 급증!';
                        overlayRunStatus.style.color = '#db2777';
                    }
                }
                // 1. Draw Cam shaft anchor ring
                ctx.save();
                ctx.fillStyle = '#94a3b8';
                ctx.strokeStyle = '#475569';
                ctx.lineWidth = 2;
                ctx.beginPath();
                ctx.arc(cx, cy, 14, 0, Math.PI * 2);
                ctx.fill();
                ctx.stroke();
                ctx.restore();
                // 2. Draw rotating Cam profile
                ctx.save();
                ctx.translate(cx, cy);
                // Rotate against follower angle coordinate to simulate physical rotation
                ctx.rotate(-state.angle - Math.PI / 2);
                ctx.strokeStyle = '#334155';
                ctx.lineWidth = 3;
                ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
                ctx.shadowBlur = 10;
                ctx.shadowColor = 'rgba(0,0,0,0.06)';
                // Draw Cam boundary path
                ctx.beginPath();
                const pathPoints = 180;
                for (let i = 0; i <= pathPoints; i++) {
                    const phi = (i * Math.PI * 2) / pathPoints;
                    const r = state.rb + getCamLift(phi);
                    const drawR = r * scale;
                    const px = Math.cos(phi) * drawR;
                    const py = Math.sin(phi) * drawR;
                    if (i === 0) {
                        ctx.moveTo(px, py);
                    } else {
                        ctx.lineTo(px, py);
                    }
                }
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
                // Drawing Cam inner lines (Base circle boundary reference)
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.2)';
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.arc(0, 0, state.rb * scale, 0, Math.PI * 2);
                ctx.stroke();
                // (Keyway hub slot decoration removed to prevent unnatural square rendering)
                ctx.restore();
                // 3. Draw Follower (sitting on top, vertically constrained)
                // Follower contact point is at cx, cy - (rb + curLift) * scale
                const contactY = cy - (state.rb + curLift) * scale;
                const folX = cx;
                ctx.save();
                ctx.strokeStyle = '#334155';
                ctx.lineWidth = 3;
                ctx.fillStyle = '#64748b';
                // Follower body shaft (slides dynamically through fixed guide bracket)
                ctx.beginPath();
                ctx.moveTo(folX, Math.min(contactY - 40, 35));
                ctx.lineTo(folX, contactY);
                ctx.stroke();
                // Draw Follower head based on type
                if (state.followerType === 'roller') {
                    // Roller contact circle
                    const rollerRadius = 8 * scale;
                    // Roller center is shifted up by rollerRadius
                    const rollerY = contactY - rollerRadius;
                    ctx.save();
                    ctx.fillStyle = 'rgba(219,39,119,0.15)';
                    ctx.strokeStyle = '#db2777';
                    ctx.beginPath();
                    ctx.arc(folX, rollerY, rollerRadius, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.stroke();
                    // Center pin
                    ctx.fillStyle = '#db2777';
                    ctx.beginPath();
                    ctx.arc(folX, rollerY, 3, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                } else {
                    if (state.followerType === 'flat') {
                        // Flat plate bar resting on top of cam
                        ctx.fillStyle = '#475569';
                        ctx.beginPath();
                        ctx.roundRect(folX - 25, contactY - 6, 50, 6, 1);
                        ctx.fill();
                        ctx.stroke();
                    } else {
                        // Knife edge triangular tip pointing down
                        ctx.fillStyle = '#0284c7';
                        ctx.beginPath();
                        ctx.moveTo(folX, contactY);
                        ctx.lineTo(folX - 6, contactY - 12);
                        ctx.lineTo(folX + 6, contactY - 12);
                        ctx.closePath();
                        ctx.fill();
                        ctx.stroke();
                    }
                }
                ctx.restore();
                // 4. Draw Right Side S-V-A graphs! (X: width*0.58 to width*0.92)
                const gx = width * 0.58;
                const gw = width * 0.35;
                const gh = 75; // height of each graph
                const displacementY = 40;
                const velocityY = 155;
                const accelY = 270;
                // Helper to draw a single graph background and grids
                function drawSubGraph(subY, label, maxVal, minVal, curVal, color) {
                    ctx.save();
                    ctx.fillStyle = 'rgba(255,255,255,0.95)';
                    ctx.roundRect(gx, subY, gw, gh, 6);
                    ctx.fill();
                    ctx.strokeStyle = '#e2e8f0';
                    ctx.lineWidth = 1;
                    ctx.stroke();
                    // Grid line
                    ctx.strokeStyle = 'rgba(0,0,0,0.03)';
                    ctx.beginPath();
                    ctx.moveTo(gx, subY + gh / 2);
                    ctx.lineTo(gx + gw, subY + gh / 2);
                    ctx.stroke();
                    // Title label text (positioned cleanly outside/above the graph box)
                    ctx.fillStyle = '#334155';
                    ctx.font = 'bold 10px Inter';
                    ctx.fillText(label, gx, subY - 6);
                    // Min/Max indicator values (positioned safely inside)
                    ctx.font = '500 9px Inter';
                    ctx.fillStyle = '#94a3b8';
                    ctx.fillText(maxVal, gx + gw - 45, subY + 12);
                    ctx.fillText(minVal, gx + gw - 45, subY + gh - 6);
                    ctx.restore();
                }
                // Numerical differentiation and S-V-A peak profile calculations
                const velPoints = [];
                const accPoints = [];
                for (let i = 0; i <= 100; i++) {
                    const phi = (i / 100.0) * Math.PI * 2;
                    // Velocity calculation
                    const lPlus = getCamLift(phi + dTh);
                    const lMinus = getCamLift(phi - dTh);
                    const ds = (lPlus - lMinus) / (2.0 * dTh);
                    const vVal = (ds * omega) / 1000.0;
                    velPoints.push(vVal);
                    // Acceleration calculation
                    const lMid = getCamLift(phi);
                    const d2s = (lPlus - 2.0 * lMid + lMinus) / (dTh * dTh);
                    const aVal = (d2s * omega * omega) / 1000.0;
                    accPoints.push(aVal);
                }
                const maxVelVal = Math.max.apply(null, velPoints.map(Math.abs));
                const maxAccVal = Math.max.apply(null, accPoints.map(Math.abs));
                const minAccVal_real = Math.min.apply(null, accPoints);
                const maxAccVal_real = Math.max.apply(null, accPoints);
                const maxVelVal_real = Math.max.apply(null, velPoints);
                const minVelVal_real = Math.min.apply(null, velPoints);
                // Update results-grid peak values in real-time
                if (resVelocityMax) {
                    resVelocityMax.innerText = (maxVelVal_real > 0 ? '+' : '') + maxVelVal_real.toFixed(2) + ' m/s';
                }
                if (resVelocityMin) {
                    resVelocityMin.innerText = minVelVal_real.toFixed(2) + ' m/s';
                }
                if (resAccelMax) {
                    resAccelMax.innerText = (maxAccVal_real > 0 ? '+' : '') + maxAccVal_real.toFixed(1) + ' m/s²';
                }
                if (resAccelMin) {
                    resAccelMin.innerText = (minAccVal_real > 0 ? '+' : '') + minAccVal_real.toFixed(1) + ' m/s²';
                }
                const txtLiftRange = document.getElementById('txt-lift-range');
                if (txtLiftRange) {
                    txtLiftRange.innerText = '설계 구동 범위: 0.0 ~ ' + state.lift.toFixed(1) + ' mm';
                }
                // Draw Subgraph boxes with real-time numeric scale values
                drawSubGraph(displacementY, 'Displacement s (mm)', state.lift.toFixed(0), '0', curLift.toFixed(1), '#0284c7');
                drawSubGraph(velocityY, 'Velocity v (m/s)', '+' + maxVelVal.toFixed(2), '-' + maxVelVal.toFixed(2), vel.toFixed(2), '#7c3aed');
                drawSubGraph(accelY, 'Acceleration a (m/s²)', '+' + maxAccVal.toFixed(1), '-' + maxAccVal.toFixed(1), acc.toFixed(1), '#db2777');
                // Draw curves inside S-V-A graphs
                ctx.save();
                ctx.lineWidth = 2.0;
                // Displacement curve
                ctx.strokeStyle = '#0284c7';
                ctx.beginPath();
                for (let i = 0; i <= 100; i++) {
                    const phi = (i / 100.0) * Math.PI * 2;
                    const val_s = getCamLift(phi);
                    const hx = gx + (i / 100.0) * gw;
                    const hy = displacementY + gh - (val_s / state.lift) * (gh - 24) - 10;
                    if (i === 0) { ctx.moveTo(hx, hy); }
                    else { ctx.lineTo(hx, hy); }
                }
                ctx.stroke();
                // Velocity curve (rendered using precalculated points)
                ctx.strokeStyle = '#7c3aed';
                ctx.beginPath();
                for (let i = 0; i <= 100; i++) {
                    const hx = gx + (i / 100.0) * gw;
                    let normV = 0.5;
                    if (maxVelVal > 0) { normV = 0.5 + (velPoints[i] / maxVelVal) * 0.35; }
                    const hy = velocityY + gh - (normV * gh);
                    if (i === 0) { ctx.moveTo(hx, hy); }
                    else { ctx.lineTo(hx, hy); }
                }
                ctx.stroke();
                // Acceleration curve (rendered using precalculated points)
                ctx.strokeStyle = '#db2777';
                ctx.beginPath();
                for (let i = 0; i <= 100; i++) {
                    const hx = gx + (i / 100.0) * gw;
                    let normA = 0.5;
                    if (maxAccVal > 0) { normA = 0.5 + (accPoints[i] / maxAccVal) * 0.35; }
                    const hy = accelY + gh - (normA * gh);
                    if (i === 0) { ctx.moveTo(hx, hy); }
                    else { ctx.lineTo(hx, hy); }
                }
                ctx.stroke();
                ctx.restore();
                // Draw Red vertical tracking dot in SVA curves
                ctx.save();
                const trackX = gx + (currentTh / (Math.PI * 2)) * gw;
                ctx.strokeStyle = 'rgba(219,39,119,0.3)';
                ctx.lineWidth = 1;
                // Vertical grid alignment line
                ctx.beginPath();
                ctx.moveTo(trackX, displacementY);
                ctx.lineTo(trackX, accelY + gh);
                ctx.stroke();
                // Glow dots
                ctx.fillStyle = '#db2777';
                ctx.shadowBlur = 6;
                ctx.shadowColor = '#db2777';
                // s tracking dot
                const trY_s = displacementY + gh - (curLift / state.lift) * (gh - 24) - 10;
                ctx.beginPath(); ctx.arc(trackX, trY_s, 4, 0, Math.PI * 2); ctx.fill();
                // v tracking dot
                let normV = 0.5;
                if (maxVelVal > 0) { normV = 0.5 + (vel / maxVelVal) * 0.35; }
                const trY_v = velocityY + gh - (normV * gh);
                ctx.beginPath(); ctx.arc(trackX, trY_v, 4, 0, Math.PI * 2); ctx.fill();
                // a tracking dot
                let normA = 0.5;
                if (maxAccVal > 0) { normA = 0.5 + (acc / maxAccVal) * 0.35; }
                const trY_a = accelY + gh - (normA * gh);
                ctx.beginPath(); ctx.arc(trackX, trY_a, 4, 0, Math.PI * 2); ctx.fill();
                ctx.restore();
                requestAnimationFrame(animate);
            }
            requestAnimationFrame(animate);
            // Initial static update
            updateStaticUI();
            // Right click / Copy Protection
            (function() {
                function blockEvents() {
                    document.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }, { capture: true });
                    document.addEventListener('selectstart', function(e) {
                        e.preventDefault();
                        return false;
                    }, { capture: true });
                }
                if (document.readyState === 'complete' || document.readyState === 'interactive') {
                    blockEvents();
                } else {
                    document.addEventListener('DOMContentLoaded', blockEvents);
                }
            })();
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>캠 프로파일(Profile) 선정: 편심 원형 캠(Eccentric), 대칭 등속도 캠(Heart), 급격낙하 캠(Pear) 중 프로파일 설계를 선택합니다.</strong></li>
<li style="margin-bottom: 6px;">기초 치수 조절: 캠의 기준이 되는 기초원 반경(Rb)과 최대 리프트 행정(h)을 설정합니다.</li>
<li style="margin-bottom: 6px;">종동절(Follower) 유형 지정: 롤러(Roller), 평판(Flat-face), 나이프(Knife-edge) 중 기구학적 접촉 단면을 선택합니다.</li>
<li style="margin-bottom: 6px;">작동 RPM 기동: 캠의 회전 속도(N)를 설정합니다.</li>
<li style="margin-bottom: 6px;">S-V-A 선도 및 점핑 검증: 실시간 2D 회전 구동 속에서 종동절의 상승·하강 거동을 관찰하고, 실시간 변위(s)-속도(v)-가속도(a) 선도를 통해 캠 가속도 급변에 따른 충격(Jerk) 구간을 진단합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 캠 기구 설계 선도 (VDI 2143) 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 캠 기구(Cam Mechanism)의 정의와 동력 전달 메커니즘</h3>
<p>캠 기구(Cam Mechanism)는 구동축의 단순 연속 회전 운동을 종동절(Follower)의 복잡한 왕복, 요동 또는 간헐 운동으로 즉각 변환할 수 있어 자동 기계, 엔진 밸브 개폐 기구, 인덱싱 장치 등에 널리 쓰이는 대표적인 고차 고페어(Higher Pair) 기구 요소입니다. 캠의 윤곽곡선인 **프로파일(Cam Profile)**에 의해 종동절의 가속도 특성이 결정되므로, 진동과 소음을 억제하기 위한 정밀 프로파일 설계가 매우 중요합니다.</p>
<h3>2. 캠 종류별 수학적 운동 방정식 및 변위 선도</h3>
<p>대표적인 캠 윤곽의 각도 <code>&theta;</code>에 따른 변위(Lift) <code>s(&theta;)</code> 방정식은 다음과 같습니다:</p><ul><li><strong>편심 원형 캠 (Circular Eccentric Cam):</strong> 편심량 <code>e = h / 2</code>에 대해 고조파 운동(Harmonic Motion)을 따릅니다.<br><code style="background:#f3f4f6; padding:2px 6px; border-radius:4px;">s(&theta;) = e &middot; (1 - cos&theta;)</code></li><li><strong>하트 캠 (Heart Cam &#8211; 대칭 등속 캠):</strong> 회전각에 비례하여 변위가 선형적으로 상승 및 하강합니다. <code>&theta; &le; &pi;</code> 구간에서:<br><code style="background:#f3f4f6; padding:2px 6px; border-radius:4px;">s(&theta;) = h &middot; (&theta; / &pi;)</code></li><li><strong>배형 캠 (Pear Cam &#8211; 고성능 밸브 캠):</strong> 완만한 상승(240&deg;) 후 급격한 낙하와 정지(Dwell) 구간을 형성하여 흡배기 밸브 오버랩에 적합합니다.</li></ul><p>종동절의 운동은 캠의 각속도 <code>&omega; = (2&pi; &middot; N) / 60</code>에 대해 <strong>시간 미분</strong>하여 계산됩니다. 즉, 속도 <code>v = (ds/d&theta;) &middot; &omega;</code>, 가속도 <code>a = (d<sup>2</sup>s/d&theta;<sup>2</sup>) &middot; &omega;<sup>2</sup></code>이 성립합니다.</p>
<h3>3. 종동절 접촉 형태와 압력각(Pressure Angle) 제어</h3>
<p>종동절 끝단의 기하학적 형태는 마찰 손실 및 접촉 응력 분산에 결정적인 영향을 줍니다:</p><ul><li><strong>롤러 종동절 (Roller Follower):</strong> 회전 접촉으로 마찰 저항이 가장 작고 내마모성이 우수하여 초고속 크랭크 캠에 널리 활용됩니다.</li><li><strong>평판 종동절 (Flat-Face Follower):</strong> 마찰은 미끄럼 마찰이나 접촉면적이 커 정렬 오차에 강하며 큰 힘 전달이 유리합니다.</li><li><strong>나이프 에지 종동절 (Knife-Edge Follower):</strong> 정밀한 프로파일 추종이 가능하지만 집중 접촉 응력으로 마멸이 심해 계측장비 외 실무에서는 기피됩니다.</li></ul><p>캠 설계 시 압력각(종동절 운동 방향과 캠 접촉부 법선 사이의 각도)이 <strong>30&deg; 이상</strong>으로 커지면 전단 측방향 분력이 급증하여 종동절 가이드의 바인딩(쐐기 고착) 파손이 발생하므로 이를 회피하기 위한 기초원 확장이 권장됩니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/cam-mechanism-profile-motion-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>플라이휠 관성 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/flywheel-energy-storage-calculator-simulator/</link>
					<comments>https://myengnote.com/flywheel-energy-storage-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Wed, 01 Jul 2026 21:25:11 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[맥동저감]]></category>
		<category><![CDATA[속도변동계수]]></category>
		<category><![CDATA[에너지저장]]></category>
		<category><![CDATA[플라이휠]]></category>
		<category><![CDATA[회전관성모멘트]]></category>
		<guid isPermaLink="false">https://myengnote.com/flywheel-energy-storage-calculator-simulator/</guid>

					<description><![CDATA[플라이휠의 질량, 반경 치수, 평균 회전 속도 및 엔진 맥동 에너지에 따른 회전 관성 모멘트(I), 운동 에너지 저장량, 회전 속도 변동 계수(Cf)를 실시간 연산하고 속도 주기 맥동을 그래픽 시각화하는 초정밀 2D 시뮬레이터입니다. <a href="https://myengnote.com/flywheel-energy-storage-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 플라이휠 관성 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for flywheel-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .flywheel-calculator-wrapper *, .flywheel-calculator-wrapper *::before, .flywheel-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .flywheel-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .flywheel-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            z-index: -1; overflow: hidden; pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: ''; position: absolute; width: 600px; height: 600px; border-radius: 50%; filter: blur(140px); opacity: 0.12;
        }
        .app-background-glow::before { background: var(--color-cyan); top: -10%; right: -5%; animation: pulse-slow 15s infinite alternate; }
        .app-background-glow::after { background: var(--color-purple); bottom: -10%; left: -5%; animation: pulse-slow 20s infinite alternate-reverse; }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.08; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.15; }
        }
        .app-container {
            width: 100%; max-width: 1440px; padding: 24px; display: flex; flex-direction: column; gap: 24px;
        }
        .app-header {
            display: flex; justify-content: space-between; align-items: center; padding: 20px 24px;
            background: var(--color-panel-bg); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 16px; box-shadow: var(--shadow-card);
        }
        .logo-area { display: flex; align-items: center; gap: 16px; }
        .logo-icon {
            font-size: 32px; background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
            display: flex; align-items: center; justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-dark)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle { font-size: 12px; color: var(--color-text-muted); font-weight: 500; letter-spacing: 0.5px; }
        .header-badge {
            display: flex; align-items: center; gap: 10px; background: rgba(2, 132, 199, 0.1); border: 1px solid rgba(2, 132, 199, 0.2); padding: 6px 14px; border-radius: 20px;
        }
        .pulse-dot {
            width: 8px; height: 8px; background-color: var(--color-cyan); border-radius: 50%; box-shadow: 0 0 10px var(--color-cyan); animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text { font-size: 11px; font-weight: 600; color: var(--color-cyan); letter-spacing: 0.5px; }
        .app-main-grid { display: grid; grid-template-columns: 340px 1fr 340px; gap: 24px; align-items: start; }
        .panel {
            background: var(--gradient-panel); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 20px; padding: 24px; box-shadow: var(--shadow-card);
            display: flex; flex-direction: column; gap: 18px; transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover { border-color: var(--color-border-hover); }
        .panel-header { display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--color-border); padding-bottom: 14px; }
        .panel-header i { font-size: 18px; }
        .panel-header h2 { font-family: var(--font-heading); font-size: 18px; font-weight: 600; letter-spacing: 0.5px; }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel { grid-column: 1; }
        .input-group { display: flex; flex-direction: column; gap: 8px; }
        .input-label-row { display: flex; justify-content: space-between; align-items: center; }
        .input-label-row label { font-size: 13px; font-weight: 600; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .helper-text { font-size: 10px; color: var(--color-text-muted); font-weight: 500; }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within { border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow); }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button, .custom-number-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none; width: 100%; height: 6px; border-radius: 3px; background: rgba(0, 0, 0, 0.05); outline: none; margin: 4px 0; transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; cursor: pointer; transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        .slider-cyan::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 8px var(--color-cyan); }
        .slider-cyan::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-magenta::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 8px var(--color-magenta); }
        .slider-magenta::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-purple::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 8px var(--color-purple); }
        .slider-purple::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-cyan::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-cyan); }
        .slider-magenta::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-magenta); }
        .slider-purple::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-purple); }
        .presets-section { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--color-border); padding-top: 16px; }
        .presets-section h3 { font-size: 13px; font-weight: 700; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .presets-grid { display: flex; flex-direction: column; gap: 8px; }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px; padding: 8px 12px; cursor: pointer; color: var(--color-text-main);
            display: flex; align-items: center; gap: 12px; text-align: left; transition: all 0.2s ease;
        }
        .preset-btn:hover { background: rgba(0, 0, 0, 0.04); transform: translateX(4px); }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow)); border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px; height: 28px; background: rgba(0, 0, 0, 0.02); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon { background: var(--gradient-primary); color: #fff; }
        .preset-name { font-size: 12px; font-weight: 600; }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-wrapper {
            position: relative; width: 100%; background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%); border: 1px solid rgba(0, 0, 0, 0.06); border-radius: 16px;
            overflow: hidden; display: flex; align-items: center; justify-content: center; 
        }
        #physics-canvas { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; }
        .canvas-overlay-data { position: absolute; top: 16px; left: 16px; pointer-events: none; display: flex; flex-direction: column; gap: 6px; }
        .overlay-item {
            background: rgba(255, 255, 255, 0.9); color: var(--color-text-main); backdrop-filter: blur(4px); border: 1px solid var(--color-border); padding: 6px 12px; border-radius: 8px;
            display: flex; align-items: center; gap: 8px; font-size: 11px;
        }
        .overlay-item .label { color: var(--color-text-muted); font-weight: 500; }
        .overlay-item .value { font-weight: 700; }
        .simulation-metrics-strip {
            display: flex; background: rgba(0, 0, 0, 0.01); border: 1px solid var(--color-border); border-radius: 12px; padding: 12px 20px;
            justify-content: space-around; align-items: center; gap: 10px; margin-top: 10px;
        }
        .mini-metric { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
        .mini-metric .label { font-size: 10px; font-weight: 600; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
        .mini-metric .value { font-size: 14px; font-weight: 700; color: var(--color-text-main); font-family: var(--font-heading); }
        .mini-divider { width: 1px; height: 24px; background: var(--color-border); }
        .results-panel { grid-column: 3; }
        .ratio-readout-box {
            background: linear-gradient(135deg, var(--color-cyan-glow) 0%, var(--color-purple-glow) 100%); border: 1px solid rgba(2, 132, 199, 0.15); border-radius: 16px;
            padding: 20px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
        }
        .ratio-title { font-size: 11px; font-weight: 700; color: var(--color-cyan); letter-spacing: 1px; text-transform: uppercase; }
        .ratio-value {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .ratio-type { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .results-grid { display: flex; flex-direction: column; gap: 12px; }
        .result-card {
            background: rgba(255, 255, 255, 0.85); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); border-radius: 12px;
            padding: 12px 16px; display: flex; align-items: center; gap: 16px; transition: all 0.2s ease;
        }
        .result-card:hover { transform: translateY(-2px); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-icon {
            width: 38px; height: 38px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px;
            display: flex; align-items: center; justify-content: center; font-size: 14px; color: var(--color-text-muted);
        }
        .result-card:hover .card-icon { color: var(--color-cyan); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-content { display: flex; flex-direction: column; gap: 2px; }
        .card-unit { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .card-value { font-family: var(--font-heading); font-weight: 700; font-size: 17px; color: var(--color-text-main); }
        .formula-card {
            background: #ffffff; border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 8px; font-size: 12px;
        }
        .formula-card h4 { font-weight: 700; color: var(--color-text-main); }
        .formula-equation {
            font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace; color: #0284c7; font-size: 13px; background: #f8fafc; border-color: var(--color-border);
            padding: 8px 10px; border-radius: 6px;
        }
        @container flywheel-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container flywheel-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container flywheel-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
            .simulation-metrics-strip {
                flex-direction: column;
                gap: 12px;
            }
            .mini-divider {
                width: 80%;
                height: 1px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.flywheel-calculator-wrapper .app-main-grid,
.flywheel-calculator-wrapper .main-grid,
.flywheel-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.flywheel-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.flywheel-calculator-wrapper .simulation-panel,
.flywheel-calculator-wrapper .canvas-panel,
.flywheel-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.flywheel-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.flywheel-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.flywheel-calculator-wrapper .simulation-results-section .ratio-readout-box,
.flywheel-calculator-wrapper .simulation-results-section .re-readout-box,
.flywheel-calculator-wrapper .simulation-results-section .status-readout-box,
.flywheel-calculator-wrapper .simulation-results-section .flow-readout-box,
.flywheel-calculator-wrapper .simulation-results-section [class*="readout-box"],
.flywheel-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.flywheel-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.flywheel-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.flywheel-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .flywheel-calculator-wrapper .app-main-grid,
    .flywheel-calculator-wrapper .main-grid,
    .flywheel-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .flywheel-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .flywheel-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .flywheel-calculator-wrapper .simulation-panel,
    .flywheel-calculator-wrapper .canvas-panel,
    .flywheel-calculator-wrapper .sim-panel,
    .flywheel-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .flywheel-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .flywheel-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .flywheel-calculator-wrapper .simulation-results-section .re-readout-box,
    .flywheel-calculator-wrapper .simulation-results-section .status-readout-box,
    .flywheel-calculator-wrapper .simulation-results-section .flow-readout-box,
    .flywheel-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .flywheel-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .flywheel-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .flywheel-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.flywheel-calculator-wrapper .app-container,
.flywheel-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.flywheel-calculator-wrapper .simulation-results-section .formula-card,
.flywheel-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.flywheel-calculator-wrapper .simulation-results-section .formula-card h4,
.flywheel-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.flywheel-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.flywheel-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="flywheel-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-circle-notch"></i></div>
                <div>
                    <h1>FLYWHEEL ENERGY</h1>
                    <div class="subtitle">플라이휠 에너지 저장 및 맥동 감쇠 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">DYNAMICS MODEL ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>물리 설계 변수</h2>
                </div>
                <!-- Flywheel Mass M -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-mass"><i class="fa-solid fa-weight-hanging text-cyan"></i> 플라이휠 질량 (M)</label>
                        <span class="helper-text">(1.0 ~ 500.0 kg)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-mass" class="custom-number-input" min="1" max="500" value="80" step="any">
                        <div class="unit-badge">kg</div>
                    </div>
                    <input type="range" id="slider-mass" class="custom-slider slider-cyan" min="1" max="500" value="80">
                </div>
                <!-- Outer Radius Ro -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-outer-r"><i class="fa-solid fa-circle text-magenta"></i> 플라이휠 외경 (Ro)</label>
                        <span class="helper-text">(0.10 ~ 2.00 m)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-outer-r" class="custom-number-input" min="0.1" max="2" value="0.60" step="any">
                        <div class="unit-badge">m</div>
                    </div>
                    <input type="range" id="slider-outer-r" class="custom-slider slider-magenta" min="10" max="200" value="60">
                </div>
                <!-- Inner Radius Ri -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-inner-r"><i class="fa-solid fa-circle-notch text-cyan"></i> 플라이휠 내경 (Ri)</label>
                        <span class="helper-text">(0.00 ~ 1.80 m)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-inner-r" class="custom-number-input" min="0" max="1.8" value="0.40" step="any">
                        <div class="unit-badge">m</div>
                    </div>
                    <input type="range" id="slider-inner-r" class="custom-slider slider-cyan" min="0" max="180" value="40">
                </div>
                <!-- Mean Speed N -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-rpm"><i class="fa-solid fa-gauge text-purple"></i> 평균 운전 속도 (N)</label>
                        <span class="helper-text">(100 ~ 5000 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="100" max="5000" value="1200" step="any">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider slider-purple" min="100" max="5000" value="1200">
                </div>
                <!-- Fluctuation Energy dE -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-de"><i class="fa-solid fa-bolt text-magenta"></i> 변동 부하 에너지 (&Delta;E)</label>
                        <span class="helper-text">(10 ~ 5000 J)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-de" class="custom-number-input" min="10" max="5000" value="450" step="any">
                        <div class="unit-badge">J</div>
                    </div>
                    <input type="range" id="slider-de" class="custom-slider slider-magenta" min="10" max="5000" value="450">
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 장비 관성 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" id="preset-generator">
                            <div class="preset-icon"><i class="fa-solid fa-plug"></i></div>
                            <div class="preset-details"><span class="preset-name">교류 동기 발전기</span><span class="preset-spec">정밀 속도 유지용</span></div>
                        </button>
                        <button class="preset-btn" id="preset-punch">
                            <div class="preset-icon"><i class="fa-solid fa-industry"></i></div>
                            <div class="preset-details"><span class="preset-name">산업용 펀치 가공기</span><span class="preset-spec">순간 에너지 방출형</span></div>
                        </button>
                        <button class="preset-btn" id="preset-diesel">
                            <div class="preset-icon"><i class="fa-solid fa-truck"></i></div>
                            <div class="preset-details"><span class="preset-name">대형 단기통 디젤 엔진</span><span class="preset-spec">격렬한 폭발 맥동</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <i class="fa-solid fa-dharmachakra text-magenta"></i>
                                    <h2>실시간 회전 맥동 관찰 및 가감속 그래프</h2>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas" width="640" height="400"></canvas>
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">맥동 제어 상태:</span>
                                            <span class="value" id="overlay-run-status">정상 평활 운전</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <span class="label">관성 모멘트 (I)</span>
                                        <span class="value" id="val-inertia">20.80 kg·m²</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">회전 속도 변동 (Min ~ Max)</span>
                                        <span class="value" id="val-speed-limits">1180 ~ 1220 RPM</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">실시간 속도 변동 계수 (Cf)</span>
                                        <span class="value" id="val-cf">0.034</span>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">저장된 평균 운동에너지 (Ek)</div>
                                    <div class="ratio-value" id="txt-kinetic-energy">164.2 kJ</div>
                                    <div class="ratio-type" id="txt-cf-percent">회전속도 리플: 3.4% (Cf = 0.034)</div>
                                </div>
                                <div class="results-grid">
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-arrows-spin"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">관성 모멘트 (I)</span>
                                            <span class="card-value" id="res-inertia">20.80 kg·m²</span>
                                        </div>
                                    </div>
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-gauge-simple-high"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">최대 / 최소 운전 속도</span>
                                            <span class="card-value" id="res-rpm-range">1220 / 1180 RPM</span>
                                        </div>
                                    </div>
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-heart-circle-check"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">시스템 운전 적합성 판정</span>
                                            <span class="card-value" id="res-status">적합 (매우 안정적)</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 플라이휠 역학 공식</h4>
                                    <div class="formula-equation">
                                        I = 0.5 × M × (Ro^2 + Ri^2)
                                    </div>
                                    <div class="formula-equation">
                                        Cf = &Delta;E / (I × &omega;^2)
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- CORE INTERACTIVE ENGINE -->
    </div>
</div>
<script>
    // Polyfill for CanvasRenderingContext2D.roundRect for backward compatibility
    if (typeof CanvasRenderingContext2D !== 'undefined') {
        if (!CanvasRenderingContext2D.prototype.roundRect) {
        CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
            if (typeof r === 'number') r = [r];
            if (!Array.isArray(r)) r = [0];
            const rad = r[0] || 0;
            this.beginPath();
            this.moveTo(x + rad, y);
            this.lineTo(x + w - rad, y);
            this.quadraticCurveTo(x + w, y, x + w, y + rad);
            this.lineTo(x + w, y + h - rad);
            this.quadraticCurveTo(x + w, y + h, x + w - rad, y + h);
            this.lineTo(x + rad, y + h);
            this.quadraticCurveTo(x, y + h, x, y + h - rad);
            this.lineTo(x, y + rad);
            this.quadraticCurveTo(x, y, x + rad, y);
            this.closePath();
            return this;
        };
      }
    }
        (function() {
            if (window.__flywheel_initialized) return;
            window.__flywheel_initialized = true;
            const inputMass = document.getElementById('input-mass');
            const sliderMass = document.getElementById('slider-mass');
            const inputOuterR = document.getElementById('input-outer-r');
            const sliderOuterR = document.getElementById('slider-outer-r');
            const inputInnerR = document.getElementById('input-inner-r');
            const sliderInnerR = document.getElementById('slider-inner-r');
            const inputRpm = document.getElementById('input-rpm');
            const sliderRpm = document.getElementById('slider-rpm');
            const inputDe = document.getElementById('input-de');
            const sliderDe = document.getElementById('slider-de');
            const txtKineticEnergy = document.getElementById('txt-kinetic-energy');
            const txtCfPercent = document.getElementById('txt-cf-percent');
            const valInertia = document.getElementById('val-inertia');
            const valSpeedLimits = document.getElementById('val-speed-limits');
            const valCf = document.getElementById('val-cf');
            const resInertia = document.getElementById('res-inertia');
            const resRpmRange = document.getElementById('res-rpm-range');
            const resStatus = document.getElementById('res-status');
            const overlayRunStatus = document.getElementById('overlay-run-status');
            const state = {
                mass: 80.0,
                outerR: 0.60,
                innerR: 0.40,
                rpm: 1200,
                de: 450.0,
                inertia: 0.0,
                ek: 0.0,
                cf: 0.0,
                angle: 0.0,
                speedHistory: []
            };
            const ranges = {
                mass: { min: 1.0, max: 500.0 },
                outerR: { min: 0.10, max: 2.00 },
                innerR: { min: 0.00, max: 1.80 },
                rpm: { min: 100.0, max: 5000.0 },
                de: { min: 10.0, max: 5000.0 }
            };
            // Setup speed history for graph
            for (let i = 0; i < 110; i++) {
                state.speedHistory.push(1200);
            }
            function calculateFlywheel() {
                // Keep inner diameter always less than outer diameter
                if (state.innerR >= state.outerR - 0.02) {
                    state.innerR = state.outerR - 0.05;
                    if (state.innerR < 0.0) { state.innerR = 0.0; }
                    inputInnerR.value = state.innerR.toFixed(2);
                    sliderInnerR.value = Math.round(state.innerR * 100);
                }
                // Moment of Inertia: I = 0.5 * M * (Ro^2 + Ri^2)
                const I = 0.5 * state.mass * (Math.pow(state.outerR, 2) + Math.pow(state.innerR, 2));
                state.inertia = I;
                // Mean angular velocity omega
                const omega = (2.0 * Math.PI * state.rpm) / 60.0;
                // Kinetic Energy: Ek = 0.5 * I * omega^2
                const Ek = 0.5 * I * Math.pow(omega, 2);
                state.ek = Ek;
                // Speed fluctuation coefficient: Cf = de / (I * omega^2)
                let cf = 0.0;
                const denominator = I * Math.pow(omega, 2);
                if (denominator > 0) {
                    cf = state.de / denominator;
                }
                // Safety bound to avoid extreme overflow in visualization
                if (cf > 1.2) { cf = 1.2; }
                state.cf = cf;
                // Speeds limits
                let rpmMax = state.rpm * (1.0 + cf / 2.0);
                let rpmMin = state.rpm * (1.0 - cf / 2.0);
                if (rpmMin < 0) { rpmMin = 0; }
                state.rpmMax = rpmMax;
                state.rpmMin = rpmMin;
                updateUIValues();
            }
            function syncMassFromInput() {
                let val = parseFloat(inputMass.value);
                if (isNaN(val)) { val = ranges.mass.min; }
                if (val < ranges.mass.min) { val = ranges.mass.min; }
                if (val > ranges.mass.max) { val = ranges.mass.max; }
                state.mass = val;
                inputMass.value = val.toFixed(1);
                sliderMass.value = Math.round(val);
                calculateFlywheel();
            }
            function syncMassFromSlider() {
                state.mass = parseFloat(sliderMass.value);
                inputMass.value = state.mass.toFixed(1);
                calculateFlywheel();
            }
            function syncOuterRFromInput() {
                let val = parseFloat(inputOuterR.value);
                if (isNaN(val)) { val = ranges.outerR.min; }
                if (val < ranges.outerR.min) { val = ranges.outerR.min; }
                if (val > ranges.outerR.max) { val = ranges.outerR.max; }
                state.outerR = val;
                inputOuterR.value = val.toFixed(2);
                sliderOuterR.value = Math.round(val * 100);
                calculateFlywheel();
            }
            function syncOuterRFromSlider() {
                state.outerR = parseFloat(sliderOuterR.value) / 100;
                inputOuterR.value = state.outerR.toFixed(2);
                calculateFlywheel();
            }
            function syncInnerRFromInput() {
                let val = parseFloat(inputInnerR.value);
                if (isNaN(val)) { val = ranges.innerR.min; }
                if (val < ranges.innerR.min) { val = ranges.innerR.min; }
                if (val > ranges.innerR.max) { val = ranges.innerR.max; }
                state.innerR = val;
                inputInnerR.value = val.toFixed(2);
                sliderInnerR.value = Math.round(val * 100);
                calculateFlywheel();
            }
            function syncInnerRFromSlider() {
                state.innerR = parseFloat(sliderInnerR.value) / 100;
                inputInnerR.value = state.innerR.toFixed(2);
                calculateFlywheel();
            }
            function syncRpmFromInput() {
                let val = parseFloat(inputRpm.value);
                if (isNaN(val)) { val = ranges.rpm.min; }
                if (val < ranges.rpm.min) { val = ranges.rpm.min; }
                if (val > ranges.rpm.max) { val = ranges.rpm.max; }
                state.rpm = val;
                inputRpm.value = val.toFixed(0);
                sliderRpm.value = Math.round(val);
                calculateFlywheel();
            }
            function syncRpmFromSlider() {
                state.rpm = parseFloat(sliderRpm.value);
                inputRpm.value = state.rpm.toFixed(0);
                calculateFlywheel();
            }
            function syncDeFromInput() {
                let val = parseFloat(inputDe.value);
                if (isNaN(val)) { val = ranges.de.min; }
                if (val < ranges.de.min) { val = ranges.de.min; }
                if (val > ranges.de.max) { val = ranges.de.max; }
                state.de = val;
                inputDe.value = val.toFixed(0);
                sliderDe.value = Math.round(val);
                calculateFlywheel();
            }
            function syncDeFromSlider() {
                state.de = parseFloat(sliderDe.value);
                inputDe.value = state.de.toFixed(0);
                calculateFlywheel();
            }
            function updateUIValues() {
                // Kinetic energy text unit formatting
                if (state.ek >= 1000.0) {
                    txtKineticEnergy.innerText = (state.ek / 1000.0).toFixed(1) + ' kJ';
                } else {
                    txtKineticEnergy.innerText = state.ek.toFixed(0) + ' J';
                }
                txtCfPercent.innerText = '회전 속도 리플: ' + (state.cf * 100.0).toFixed(2) + '% (Cf = ' + state.cf.toFixed(3) + ')';
                valInertia.innerText = state.inertia.toFixed(2) + ' kg·m²';
                valSpeedLimits.innerText = state.rpmMin.toFixed(0) + ' ~ ' + state.rpmMax.toFixed(0) + ' RPM';
                valCf.innerText = state.cf.toFixed(3);
                resInertia.innerText = state.inertia.toFixed(2) + ' kg·m²';
                resRpmRange.innerText = state.rpmMin.toFixed(0) + ' ~ ' + state.rpmMax.toFixed(0) + ' RPM';
                // Damping assessment status
                if (state.cf < 0.01) {
                    resStatus.innerText = '우수 (정밀 전자기 가동 적합)';
                    resStatus.style.color = '#10b981';
                    overlayRunStatus.innerText = '안정적 운전 (Cf < 1%)';
                    overlayRunStatus.style.color = '#10b981';
                } else {
                    if (state.cf < 0.05) {
                        resStatus.innerText = '양호 (일반 기계설비 표준)';
                        resStatus.style.color = '#0284c7';
                        overlayRunStatus.innerText = '안정적 운전 (Cf < 5%)';
                        overlayRunStatus.style.color = '#0284c7';
                    } else {
                        if (state.cf < 0.10) {
                            resStatus.innerText = '경고 (맥동 진동 경계 구역)';
                            resStatus.style.color = '#f59e0b';
                            overlayRunStatus.innerText = '맥동 발생 (주의 요망)';
                            overlayRunStatus.style.color = '#f59e0b';
                        } else {
                            resStatus.innerText = '위험 (극심한 맥동 파손 우려)';
                            resStatus.style.color = '#db2777';
                            overlayRunStatus.innerText = '격렬한 회전 맥동 발생!';
                            overlayRunStatus.style.color = '#db2777';
                        }
                    }
                }
            }
            // Presets
            document.getElementById('preset-generator').addEventListener('click', function() {
                setActivePreset('preset-generator');
                state.mass = 120.0;
                state.outerR = 0.85;
                state.innerR = 0.65;
                state.rpm = 1500;
                state.de = 250.0;
                syncControlsToState();
                calculateFlywheel();
            });
            document.getElementById('preset-punch').addEventListener('click', function() {
                setActivePreset('preset-punch');
                state.mass = 350.0;
                state.outerR = 1.10;
                state.innerR = 0.80;
                state.rpm = 400;
                state.de = 2800.0;
                syncControlsToState();
                calculateFlywheel();
            });
            document.getElementById('preset-diesel').addEventListener('click', function() {
                setActivePreset('preset-diesel');
                state.mass = 45.0;
                state.outerR = 0.50;
                state.innerR = 0.00;
                state.rpm = 900;
                state.de = 1950.0;
                syncControlsToState();
                calculateFlywheel();
            });
            function setActivePreset(id) {
                document.getElementById('preset-generator').classList.remove('active');
                document.getElementById('preset-punch').classList.remove('active');
                document.getElementById('preset-diesel').classList.remove('active');
                document.getElementById(id).classList.add('active');
            }
            function syncControlsToState() {
                inputMass.value = state.mass.toFixed(1);
                sliderMass.value = Math.round(state.mass);
                inputOuterR.value = state.outerR.toFixed(2);
                sliderOuterR.value = Math.round(state.outerR * 100);
                inputInnerR.value = state.innerR.toFixed(2);
                sliderInnerR.value = Math.round(state.innerR * 100);
                inputRpm.value = state.rpm;
                sliderRpm.value = state.rpm;
                inputDe.value = state.de.toFixed(0);
                sliderDe.value = Math.round(state.de);
            }
            // Bind Event Listeners
            inputMass.addEventListener('change', syncMassFromInput);
            sliderMass.addEventListener('input', syncMassFromSlider);
            inputOuterR.addEventListener('change', syncOuterRFromInput);
            sliderOuterR.addEventListener('input', syncOuterRFromSlider);
            inputInnerR.addEventListener('change', syncInnerRFromInput);
            sliderInnerR.addEventListener('input', syncInnerRFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            inputDe.addEventListener('change', syncDeFromInput);
            sliderDe.addEventListener('input', syncDeFromSlider);
            // Canvas drawing
            const canvas = document.getElementById('physics-canvas');
            const ctx = canvas.getContext('2d');
            function getDPR() { return window.devicePixelRatio || 1; }
            function initCanvas() {
                const dpr = getDPR();
                const rect = canvas.getBoundingClientRect();
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            window.addEventListener('resize', initCanvas);
            initCanvas();
            let lastTime = 0;
            function animate(currentTime) {
                if (lastTime === 0) { lastTime = currentTime; }
                const dt = (currentTime - lastTime) / 1000;
                lastTime = currentTime;
                const dpr = getDPR();
                const width = canvas.width / dpr;
                const height = canvas.height / dpr;
                ctx.clearRect(0, 0, width, height);
                // Grid
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                ctx.lineWidth = 1;
                const gridSize = 25;
                for (let x = 0; x < width; x += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                const scale = Math.min(width / 640, height / 400);
                const cx = width / 2 + 60 * scale; // offset flywheel center to right to make room for graph
                const cy = height / 2;
                // Speed oscillation calculation: Single-cylinder torque fluctuation has 2 power cycles per revolution (2.0*angle)
                const baseOmega = (2.0 * Math.PI * state.rpm) / 60.0;
                const dynamicOmega = baseOmega * (1.0 + (state.cf / 2.0) * Math.sin(2.0 * state.angle));
                state.angle += dynamicOmega * dt;
                const currentRpm = (dynamicOmega * 60.0) / (2.0 * Math.PI);
                // Track history (FIFO queue of 110 data points)
                state.speedHistory.push(currentRpm);
                if (state.speedHistory.length > 110) {
                    state.speedHistory.shift();
                }
                // Visual scaling: map outer radius 2.0m to 120px, dynamically scaled
                const drawRo = (35.0 + (state.outerR / 2.0) * 95.0) * scale;
                const drawRi = drawRo * (state.innerR / state.outerR);
                // 1. Draw Rotating Flywheel
                ctx.save();
                ctx.translate(cx, cy);
                ctx.rotate(state.angle);
                // Central steel shaft hub
                ctx.fillStyle = '#64748b';
                ctx.beginPath();
                ctx.arc(0, 0, 16 * scale, 0, Math.PI * 2);
                ctx.fill();
                ctx.lineWidth = 2.5 * scale;
                ctx.strokeStyle = '#334155';
                ctx.stroke();
                // Hub boundary
                ctx.strokeStyle = 'rgba(255,255,255,0.2)';
                ctx.lineWidth = 2 * scale;
                ctx.beginPath();
                ctx.arc(0, 0, 10 * scale, 0, Math.PI * 2);
                ctx.stroke();
                // 6 spokes
                ctx.strokeStyle = '#94a3b8';
                ctx.lineWidth = 9 * scale;
                for (let i = 0; i < 6; i++) {
                    const spAngle = (i * Math.PI) / 3;
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.lineTo(Math.cos(spAngle) * drawRo, Math.sin(spAngle) * drawRo);
                    ctx.stroke();
                }
                // Inner ring edge line (if innerR > 0)
                if (state.innerR > 0) {
                    ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
                    ctx.beginPath();
                    ctx.arc(0, 0, drawRi, 0, Math.PI * 2);
                    ctx.fill();
                }
                // Massive outer rim (rendered as a ring)
                ctx.save();
                ctx.strokeStyle = '#475569';
                const rimWidth = drawRo - drawRi;
                ctx.lineWidth = rimWidth;
                ctx.beginPath();
                ctx.arc(0, 0, drawRo - rimWidth / 2, 0, Math.PI * 2);
                ctx.stroke();
                ctx.restore();
                // Add nice rim highlight lines to show rotation speed
                ctx.strokeStyle = '#94a3b8';
                ctx.lineWidth = 2 * scale;
                ctx.beginPath();
                ctx.arc(0, 0, drawRo - 1 * scale, 0, Math.PI * 2);
                ctx.stroke();
                if (state.innerR > 0.0) {
                    ctx.beginPath();
                    ctx.arc(0, 0, drawRi + 1 * scale, 0, Math.PI * 2);
                    ctx.stroke();
                }
                // Glowing energy dots inside rim
                const glowIntensity = Math.min(state.ek / 80000.0, 1.0);
                if (glowIntensity > 0.05) {
                    ctx.save();
                    ctx.fillStyle = 'rgba(2, 132, 199, ' + (0.2 + glowIntensity * 0.4) + ')';
                    ctx.shadowBlur = 8 * scale;
                    ctx.shadowColor = '#0284c7';
                    const dotCount = 8;
                    const rMid = (drawRo + drawRi) / 2;
                    for (let i = 0; i < dotCount; i++) {
                        const dotAngle = (i * Math.PI * 2) / dotCount;
                        ctx.beginPath();
                        ctx.arc(Math.cos(dotAngle) * rMid, Math.sin(dotAngle) * rMid, 4 * scale, 0, Math.PI * 2);
                        ctx.fill();
                    }
                    ctx.restore();
                }
                ctx.restore();
                // 2. Draw Real-time Speed Pulsation Wave Chart (Bottom Left: scaled)
                const gx = 30 * scale;
                const gy = height - 130 * scale;
                const gw = 200 * scale;
                const gh = 90 * scale;
                ctx.save();
                // Chart Panel back
                ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
                ctx.roundRect(gx, gy, gw, gh, 8 * scale);
                ctx.fill();
                ctx.strokeStyle = '#e2e8f0';
                ctx.lineWidth = 1.5 * scale;
                ctx.stroke();
                // Grid inside graph
                ctx.strokeStyle = 'rgba(0,0,0,0.03)';
                ctx.lineWidth = 1 * scale;
                for (let lx = gx + 40 * scale; lx < gx + gw; lx += 40 * scale) {
                    ctx.beginPath(); ctx.moveTo(lx, gy); ctx.lineTo(lx, gy + gh); ctx.stroke();
                }
                ctx.beginPath();
                ctx.moveTo(gx, gy + gh / 2);
                ctx.lineTo(gx + gw, gy + gh / 2);
                ctx.stroke();
                 // Draw line wave representing history
                 ctx.strokeStyle = '#db2777';
                 ctx.lineWidth = 3.0 * scale;
                 ctx.beginPath();
                 // Map history points: Y axis scales dynamic around state.rpm
                 // Limit minimum scale margin to 0.003 (0.3%) so the wave is always beautifully visible and pulsating
                 const margin = state.rpm * Math.max(state.cf, 0.003) * 1.3;
                 const minScale = state.rpm - margin;
                 const maxScale = state.rpm + margin;
                 for (let i = 0; i < state.speedHistory.length; i++) {
                     const spVal = state.speedHistory[i];
                     const hx = gx + (i / 110.0) * gw;
                     let normY = 0.5;
                     const scaleDiff = maxScale - minScale;
                     if (scaleDiff > 0) {
                         normY = (spVal - minScale) / scaleDiff;
                     }
                     // Clamp normY beautifully inside the white graph box boundaries [0.05, 0.95]
                     normY = Math.min(Math.max(normY, 0.05), 0.95);
                     const hy = gy + gh - (normY * gh);
                     if (i === 0) {
                         ctx.moveTo(hx, hy);
                     } else {
                         ctx.lineTo(hx, hy);
                     }
                 }
                 ctx.stroke();
                // Chart text overlays
                ctx.fillStyle = '#475569';
                ctx.font = 'bold ' + Math.max(8, Math.round(9 * scale)) + 'px Inter';
                ctx.fillText(maxScale.toFixed(0) + ' RPM', gx + 6 * scale, gy + 12 * scale);
                ctx.fillText(minScale.toFixed(0) + ' RPM', gx + 6 * scale, gy + gh - 6 * scale);
                ctx.fillStyle = '#1e293b';
                ctx.font = 'bold ' + Math.max(9, Math.round(10 * scale)) + 'px Inter';
                ctx.fillText('실시간 회전 속도 파형 (N)', gx + 6 * scale, gy - 8 * scale);
                ctx.restore();
                requestAnimationFrame(animate);
            }
            requestAnimationFrame(animate);
            // Initial calculation
            calculateFlywheel();
            // Right click / Copy Protection
            (function() {
                function blockEvents() {
                    document.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }, { capture: true });
                    document.addEventListener('selectstart', function(e) {
                        e.preventDefault();
                        return false;
                    }, { capture: true });
                }
                if (document.readyState === 'complete' || document.readyState === 'interactive') {
                    blockEvents();
                } else {
                    document.addEventListener('DOMContentLoaded', blockEvents);
                }
            })();
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>플라이휠 외형 설계: 플라이휠의 외경(Ro), 내경(Ri), 그리고 질량(M) 슬라이더를 부품 형상에 맞게 설정합니다. (관성 모멘트가 자동 계산됩니다.)</strong></li>
<li style="margin-bottom: 6px;">평균 운전 RPM 설정: 시스템의 평균 운전 속도(N)를 입력합니다.</li>
<li style="margin-bottom: 6px;">변동 에너지 부하 입력: 크랭크 축 1사이클 동안 발생하는 회전 에너지 변동량(dE)을 기정합니다. (통상 단기통 엔진일수록 큽니다.)</li>
<li style="margin-bottom: 6px;">실시간 회전 맥동 및 감쇠 확인: 2D 시뮬레이터 속 플라이휠이 회전합니다. 관성이 작거나 변동 에너지가 크면 회전 속도가 &#8216;울컥&#8217;거리며 심하게 가감속되는 맥동 현상(Cf 가시화)을 눈으로 직접 확인합니다.</li>
<li style="margin-bottom: 6px;">속도 변동 그래프 분석: 실시간으로 플라이휠 속도의 맥동 파형 그래프가 감쇠되는 정도를 비교 관찰하여 목표 속도변동계수 이내로 관성이 확보되었는지 판단합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 플라이휠 설계 규격 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 내연기관 및 왕복 압축기에서 플라이휠(Flywheel)의 물리학적 역할</h3>
<p>왕복동 엔진(Reciprocating Engine)이나 단기통 크랭크 프레스 등은 피스톤의 직선 운동을 크랭크 축의 회전 운동으로 변환하는 과정에서 크랭크 각도에 따라 발생하는 토크가 매우 불균일합니다. 4행정 단기통 엔진의 경우 폭발 행정에서 막대한 토크가 발생하지만, 나머지 흡입, 압축, 배기 행정에서는 동력을 소비하여 축 회전 속도가 급격히 요동치게 됩니다.</p><p><strong>플라이휠(Flywheel)</strong>은 이러한 회전계에 장착되는 거대한 질량의 회전 원판으로, <em>폭발 행정의 잉여 에너지를 회전 운동 에너지로 흡수·저장하고, 동력이 없는 행정 동안 에너지를 방출하여 축의 회전 속도를 평활화(Damping / Smoothing)</em>하는 역할을 담당합니다. 즉 회전식 에너지를 임시 축적하는 기계적 축전기(Battery)라 할 수 있습니다.</p>
<h3>2. 회전 관성 모멘트 및 회전 에너지 공식</h3>
<p>일반적으로 두께를 가진 중공 원통(Rim) 형태 플라이휠의 <strong>관성 모멘트(Moment of Inertia, I)</strong>는 질량 <code>M</code>, 외경 <code>R<sub>o</sub></code>, 내경 <code>R<sub>i</sub></code>에 의해 결정됩니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">I = 1/2 &middot; M &middot; (R<sub>o</sub><sup>2</sup> + R<sub>i</sub><sup>2</sup>) &nbsp;[kg&middot;m<sup>2</sup>]</p><p>평균 각속도 <code>&omega; = (2&pi; &middot; N) / 60</code>에 의해 저장되는 총 <strong>회전 운동 에너지 (Kinetic Energy, E<sub>k</sub>)</strong>는 다음과 같습니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">E<sub>k</sub> = 1/2 &middot; I &middot; &omega;<sup>2</sup> &nbsp;[Joule]</p><p>여기에 크랭크 사이클 당 공급-소비 에너지 오차인 변동 에너지 <code>&Delta;E</code>가 인가되면, 시스템의 <strong>속도 변동 계수 (Coefficient of Speed Fluctuation, C<sub>f</sub>)</strong>는 다음과 같이 유도됩니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.1em; color: #0369a1;">C<sub>f</sub> = (N<sub>max</sub> &#8211; N<sub>min</sub>) / N &nbsp;=&nbsp; &Delta;E / (I &middot; &omega;<sup>2</sup>)</p>
<h3>3. 산업 기계별 권장 속도 변동 계수 (Cf) 표준</h3>
<p>플라이휠이 가벼울수록 회전 가속은 빠르나 맥동이 커지며, 너무 무거우면 축 베어링 부하와 재료 원가가 증가하므로 용도에 따른 최적화 설계가 필수적입니다:</p><ul><li><strong>발전용 교류 동기기 (주파수 정밀 제어 필수):</strong> C<sub>f</sub> &le; 0.003 ~ 0.005 (0.3% ~ 0.5% 변동)</li><li><strong>정밀 제직기 및 공작기계:</strong> C<sub>f</sub> &le; 0.01 ~ 0.02 (1% ~ 2% 변동)</li><li><strong>일반 산업용 다기통 디젤 엔진:</strong> C<sub>f</sub> &le; 0.03 ~ 0.05</li><li><strong>파쇄기 및 공기 압축기:</strong> C<sub>f</sub> &le; 0.05 ~ 0.10 (5% ~ 10% 변동 허용)</li></ul>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>


<h2 style="font-size: 1.4em; font-weight: 700; color: #1f2937; margin-top: 40px; margin-bottom: 15px; border-left: 4px solid #3b82f6; padding-left: 10px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 함께 보면 좋은 공학 글</h2>


<a href="https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">드릴 회전수 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>


<a href="https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">선삭 절삭 속도 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/flywheel-energy-storage-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>드릴 회전수 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/</link>
					<comments>https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Wed, 01 Jul 2026 03:53:11 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[관통시간]]></category>
		<category><![CDATA[구멍가공]]></category>
		<category><![CDATA[드릴회전수]]></category>
		<category><![CDATA[소재제거율]]></category>
		<category><![CDATA[이송속도]]></category>
		<guid isPermaLink="false">https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/</guid>

					<description><![CDATA[드릴 직경과 공작물 재질별 추천 절삭 속도를 기반으로 주축 스핀들 회전수(RPM) 및 선형 분당 이송속도(mm/min), 가공 소요 시간을 실시간 2D 드릴 드릴링 물리 시뮬레이션으로 가시화합니다. <a href="https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 드릴 회전수 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for drillrpm-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .drillrpm-calculator-wrapper *, .drillrpm-calculator-wrapper *::before, .drillrpm-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .drillrpm-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7; /* Cobalt blue accent */
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777; /* Pink/magenta accent */
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --color-danger: #ef4444;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .drillrpm-calculator-wrapper {
            width: 100%;
            max-width: 1440px;
            margin: 0 auto;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
        }
        .drillrpm-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-diameter::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-vc::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 10px var(--color-purple); }
        #slider-feed::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        #slider-depth::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-name {
            font-size: 13px !important;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-card {
            background: #ffffff;
            border: 1px solid var(--color-border);
            border-radius: 16px;
            overflow: hidden;
            box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.05);
            position: relative;
        }
        canvas {
            display: block;
            width: 100%;
            background: #ffffff;
        }
        /* Canvas HUD Overlay */
        .hud-overlay {
            position: absolute;
            top: 10px;
            left: 12px;
            background: rgba(255, 255, 255, 0.9);
            border: 1px solid rgba(0,0,0,0.05);
            border-radius: 8px;
            padding: 6px 10px;
            font-size: 0.75rem;
            font-family: 'Outfit', sans-serif;
            color: var(--color-text-main);
            pointer-events: none;
            display: flex;
            flex-direction: column;
            gap: 4px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.05);
            z-index: 10;
        }
        .hud-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .hud-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: var(--color-success);
        }
        .hud-dot.active {
            animation: pulse-dot-anim 1.5s infinite;
        }
        /* Action Buttons */
        .action-btn-row {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 12px;
            margin-top: 10px;
        }
        .custom-btn {
            padding: 12px 20px;
            border-radius: 8px;
            border: none;
            font-size: 0.9rem;
            font-weight: 700;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            transition: all 0.2s ease;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .btn-primary {
            background: var(--gradient-primary);
            color: white;
        }
        .btn-primary:hover {
            opacity: 0.95;
            transform: translateY(-1px);
        }
        .btn-secondary {
            background: #f1f5f9;
            border: 1px solid var(--color-border);
            color: var(--color-text-muted);
        }
        .btn-secondary:hover {
            background: #e2e8f0;
            color: var(--color-text-main);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(2, 132, 199, 0.08) 0%, rgba(124, 58, 237, 0.03) 100%);
            border: 1px solid rgba(2, 132, 199, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(2, 132, 199, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 30px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(2, 132, 199, 0.2);
            background: rgba(2, 132, 199, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
            flex-shrink: 0;
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: rgba(2, 132, 199, 0.3);
            background: rgba(2, 132, 199, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .card-unit-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-dark);
            margin-left: 4px;
        }
        .formula-card {
            background: #ffffff !important;
            border: 1px solid var(--color-border) !important;
            border-radius: 12px !important;
            padding: 16px !important;
            box-shadow: var(--shadow-card) !important;
            transition: all 0.2s ease !important;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        #text-judgment {
            font-size: 12px !important;
            font-weight: 500 !important;
            color: var(--color-text-muted) !important;
            line-height: 1.6 !important;
            word-break: keep-all !important;
        }
        .formula-equation {
            font-family: monospace;
            color: var(--color-cyan);
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        .efficiency-bar-container {
            background: #e2e8f0;
            height: 6px;
            border-radius: 3px;
            overflow: hidden;
        }
        .efficiency-bar {
            height: 100%;
            width: 0%;
            background: var(--gradient-primary);
            transition: width 0.3s ease;
        }
        .warning-box {
            background: #fffbeb;
            border: 1px dashed var(--color-warning);
            border-radius: 10px;
            padding: 12px;
            font-size: 12px;
            color: #b45309;
            display: flex;
            align-items: flex-start;
            gap: 10px;
            margin-top: 15px;
            display: none;
        }
        @container drill-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container drill-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container drill-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.drillrpm-calculator-wrapper .app-main-grid,
.drillrpm-calculator-wrapper .main-grid,
.drillrpm-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.drillrpm-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.drillrpm-calculator-wrapper .simulation-panel,
.drillrpm-calculator-wrapper .canvas-panel,
.drillrpm-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.drillrpm-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.drillrpm-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.drillrpm-calculator-wrapper .simulation-results-section .ratio-readout-box,
.drillrpm-calculator-wrapper .simulation-results-section .re-readout-box,
.drillrpm-calculator-wrapper .simulation-results-section .status-readout-box,
.drillrpm-calculator-wrapper .simulation-results-section .flow-readout-box,
.drillrpm-calculator-wrapper .simulation-results-section [class*="readout-box"],
.drillrpm-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.drillrpm-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.drillrpm-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.drillrpm-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .drillrpm-calculator-wrapper .app-main-grid,
    .drillrpm-calculator-wrapper .main-grid,
    .drillrpm-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .drillrpm-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .drillrpm-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .drillrpm-calculator-wrapper .simulation-panel,
    .drillrpm-calculator-wrapper .canvas-panel,
    .drillrpm-calculator-wrapper .sim-panel,
    .drillrpm-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .drillrpm-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .drillrpm-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .drillrpm-calculator-wrapper .simulation-results-section .re-readout-box,
    .drillrpm-calculator-wrapper .simulation-results-section .status-readout-box,
    .drillrpm-calculator-wrapper .simulation-results-section .flow-readout-box,
    .drillrpm-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .drillrpm-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .drillrpm-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .drillrpm-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.drillrpm-calculator-wrapper .app-container,
.drillrpm-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.drillrpm-calculator-wrapper .simulation-results-section .formula-card,
.drillrpm-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.drillrpm-calculator-wrapper .simulation-results-section .formula-card h4,
.drillrpm-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.drillrpm-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.drillrpm-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="drillrpm-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
<div class="drillrpm-calculator-wrapper">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-screwdriver-wrench text-cyan"></i></div>
                <div>
                    <h1>DRILL RPM</h1>
                    <div class="subtitle">드릴 회전수 및 이송속도 가공 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">DRILL CORE ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>공정 천공 제어 변수</h2>
                </div>
                <!-- Drill Diameter (d) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-circle-dot text-cyan"></i> 드릴 직경 (d)</label>
                        <span class="helper-text">(1 ~ 50 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-diameter" class="custom-number-input" min="1" max="50" value="12">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-diameter" class="custom-slider" min="1" max="50" value="12">
                </div>
                <!-- Target Cutting Speed (Vc) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-gauge-high text-purple"></i> 목표 절삭 속도 (V_c)</label>
                        <span class="helper-text">(10 ~ 150 m/min)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-vc" class="custom-number-input" min="10" max="150" value="80">
                        <div class="unit-badge">m/min</div>
                    </div>
                    <input type="range" id="slider-vc" class="custom-slider" min="10" max="150" value="80">
                </div>
                <!-- Feed per rev (f) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-right-long text-magenta"></i> 회전당 이송량 (f)</label>
                        <span class="helper-text">(0.02 ~ 1.00 mm/rev)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-feed" class="custom-number-input" min="0.02" max="1.00" step="0.01" value="0.20">
                        <div class="unit-badge">mm/rev</div>
                    </div>
                    <input type="range" id="slider-feed" class="custom-slider" min="0.02" max="1.00" step="0.01" value="0.20">
                </div>
                <!-- Hole Depth (L) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-arrows-up-down text-cyan"></i> 구멍 관통 깊이 (L)</label>
                        <span class="helper-text">(5 ~ 200 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-depth" class="custom-number-input" min="5" max="200" value="40">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-depth" class="custom-slider" min="5" max="200" value="40">
                </div>
                <!-- Material Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 피삭재별 권장 가공 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" data-preset="al-drilling">
                            <div class="preset-icon"><i class="fa-solid fa-bolt"></i></div>
                            <div class="preset-details">
                                <span class="preset-name">알루미늄 12mm 가공</span>
                                <span class="preset-spec">d12, Vc100, f0.25, L45</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="steel-drilling">
                            <div class="preset-icon"><i class="fa-solid fa-fire"></i></div>
                            <div class="preset-details">
                                <span class="preset-name">연강 10mm 일반 가공</span>
                                <span class="preset-spec">d10, Vc35, f0.15, L35</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="hard-drilling">
                            <div class="preset-icon"><i class="fa-solid fa-weight-hanging"></i></div>
                            <div class="preset-details">
                                <span class="preset-name">고경도강 8mm 천공</span>
                                <span class="preset-spec">d8, Vc18, f0.07, L25</span>
                            </div>
                        </button>
                    </div>
                </div>
                <!-- Over-load/vibration warning -->
                <div id="warning-vibration" class="warning-box">
                    <i class="fa-solid fa-triangle-exclamation"></i>
                    <span><strong>위험:</strong> 과도한 드릴 직경 및 공급 속도로 인해 주축 토크 부하가 모터 임계를 초과합니다! 채터 진동이 심해지며 드릴 비트 파손 위험이 극도로 큽니다.</span>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>실시간 드릴 가공 거동 및 칩 배출 모니터링</h2>
                                    </div>
                                    <div class="canvas-scale-indicator">ACTIVE</div>
                                </div>
                                <div class="canvas-card">
                                    <div class="hud-overlay">
                                        <div class="hud-item">
                                            <div id="hud-dot" class="hud-dot"></div>
                                            <span style="letter-spacing:0.5px; font-weight:700;">2D DRILLING PHYSICAL RENDERER</span>
                                        </div>
                                        <div class="hud-item" style="color:var(--color-text-muted);">
                                            <i class="fa-solid fa-hourglass-half"></i> <span id="hud-time">대기 중</span>
                                        </div>
                                    </div>
                                    <canvas id="drill-canvas" width="680" height="420"></canvas>
                                </div>
                                <div class="action-btn-row">
                                    <button type="button" id="btn-start" class="custom-btn btn-primary">
                                        <i class="fa-solid fa-play"></i> 천공 시작 (Start)
                                    </button>
                                    <button type="button" id="btn-reset" class="custom-btn btn-secondary">
                                        <i class="fa-solid fa-rotate-left"></i> 가공 재설정 (Reset)
                                    </button>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">주축 회전수 (N)</div>
                                    <div>
                                        <span id="val-rpm" class="ratio-value">2,122</span>
                                        <span>RPM</span>
                                    </div>
                                    <div class="efficiency-bar-container">
                                        <div id="bar-rpm" class="efficiency-bar"></div>
                                    </div>
                                    <div id="hud-rpm-desc">적정 스핀들 속도 범위 (공구 수명 안정)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- Spindle Feedrate F -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-arrows-down-to-line text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">선형 이송 속도 (F)</span>
                                            <span class="card-value"><span id="val-feedrate">424.4</span><span class="card-unit-text">mm/min</span></span>
                                        </div>
                                    </div>
                                    <!-- Net Drilling time t -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-clock text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">구멍 관통 소요 시간 (t)</span>
                                            <span class="card-value"><span id="val-duration">0.10</span><span class="card-unit-text">min</span></span>
                                            <span>날끝 여유각(0.3d) 보정 반영 완료</span>
                                        </div>
                                    </div>
                                    <!-- Material Removal Rate MRR -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-cubes text-success"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">칩 제거율 (MRR)</span>
                                            <span class="card-value"><span id="val-mrr">47,996</span><span class="card-unit-text">mm³/min</span></span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 드릴 가공 안정성 진단</h4>
                                    <div id="text-judgment">
                                        안정적인 천공 성능 영역입니다. 칩 막힘 없이 연속 배출이 가능하며 과열 변색 위험도가 낮습니다.
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
    </div>
</div>
    </div>
</div>
<script>
(function() {
    "use strict";
    let state = {
        d: 12,
        vc: 80,
        f: 0.20,
        L: 40,
        visualL: 40, // Smooth Lerp target for visual workpiece thickness
        currentDepth: 0, // In millimeters
        isDrilling: false,
        isCompleted: false,
        drillY: 100, // Visual position in canvas pixels
        spindleAngle: 0,
        shakeOffset: 0,
        particles: [],
        elapsedSeconds: 0,
        lastFrameTime: null, // Timestamp of the last rendering frame
        chipAccumulator: 0
    };
    let initialized = false;
    // DOM elements
    let inputDiameter, sliderDiameter;
    let inputVc, sliderVc;
    let inputFeed, sliderFeed;
    let inputDepth, sliderDepth;
    let valRpm, valFeedrate, valDuration, valMrr, barRpm;
    let hudTime, hudDot, btnStart, btnReset;
    let warningVibration, textJudgment, hudRpmDesc, judgmentIcon;
    let canvas, ctx;
    function initSimulator() {
        if (initialized) return;
        // Inputs
        inputDiameter = document.getElementById("input-diameter");
        sliderDiameter = document.getElementById("slider-diameter");
        inputVc = document.getElementById("input-vc");
        sliderVc = document.getElementById("slider-vc");
        inputFeed = document.getElementById("input-feed");
        sliderFeed = document.getElementById("slider-feed");
        inputDepth = document.getElementById("input-depth");
        sliderDepth = document.getElementById("slider-depth");
        if (!inputDiameter) return;
        // Outputs
        valRpm = document.getElementById("val-rpm");
        valFeedrate = document.getElementById("val-feedrate");
        valDuration = document.getElementById("val-duration");
        valMrr = document.getElementById("val-mrr");
        barRpm = document.getElementById("bar-rpm");
        hudTime = document.getElementById("hud-time");
        hudDot = document.getElementById("hud-dot");
        btnStart = document.getElementById("btn-start");
        btnReset = document.getElementById("btn-reset");
        warningVibration = document.getElementById("warning-vibration");
        textJudgment = document.getElementById("text-judgment");
        judgmentIcon = document.getElementById("judgment-icon");
        hudRpmDesc = document.getElementById("hud-rpm-desc");
        canvas = document.getElementById("drill-canvas");
        ctx = canvas.getContext("2d");
        // Input sync bindings without logical AND
        function linkInputSlider(inputEl, sliderEl, stateKey, decimalPlaces) {
            sliderEl.addEventListener("input", function() {
                let val = parseFloat(sliderEl.value);
                inputEl.value = decimalPlaces > 0 ? val.toFixed(decimalPlaces) : val;
                state[stateKey] = val;
                resetDrillState();
                updateCalculations();
            });
            inputEl.addEventListener("change", function() {
                let min = parseFloat(inputEl.min);
                let max = parseFloat(inputEl.max);
                let val = parseFloat(inputEl.value);
                if (isNaN(val)) {
                    val = parseFloat(sliderEl.value);
                }
                if (val < min) {
                    val = min;
                }
                if (val > max) {
                    val = max;
                }
                inputEl.value = decimalPlaces > 0 ? val.toFixed(decimalPlaces) : val;
                sliderEl.value = val;
                state[stateKey] = val;
                resetDrillState();
                updateCalculations();
            });
        }
        linkInputSlider(inputDiameter, sliderDiameter, "d", 0);
        linkInputSlider(inputVc, sliderVc, "vc", 0);
        linkInputSlider(inputFeed, sliderFeed, "f", 2);
        linkInputSlider(inputDepth, sliderDepth, "L", 0);
        // Action Handlers
        btnStart.addEventListener("click", function() {
            startDrilling();
        });
        btnReset.addEventListener("click", function() {
            resetDrillState();
        });
        // Preset bindings
        let presetBtns = document.querySelectorAll(".preset-btn");
        presetBtns.forEach(function(btn) {
            btn.addEventListener("click", function() {
                presetBtns.forEach(b => b.classList.remove("active"));
                btn.classList.add("active");
                applyPreset(btn.dataset.preset);
            });
        });
        // Copyright shield
        document.addEventListener("contextmenu", function(e) {
            e.preventDefault();
            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
        }, { capture: true });
        document.addEventListener("keydown", function(e) {
            if (e.ctrlKey) {
                if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.shiftKey) {
                    if (['i','I','j','J','c','C'].includes(e.key)) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                }
            }
        }, { capture: true });
        updateCalculations();
        requestAnimationFrame(renderLoop);
        initialized = true;
    }
    function applyPreset(presetType) {
        if (presetType === "al-drilling") {
            state.d = 12; state.vc = 100; state.f = 0.25; state.L = 45;
        } else if (presetType === "steel-drilling") {
            state.d = 10; state.vc = 35; state.f = 0.15; state.L = 35;
        } else if (presetType === "hard-drilling") {
            state.d = 8; state.vc = 18; state.f = 0.07; state.L = 25;
        }
        // Sync inputs
        inputDiameter.value = state.d; sliderDiameter.value = state.d;
        inputVc.value = state.vc; sliderVc.value = state.vc;
        inputFeed.value = state.f.toFixed(2); sliderFeed.value = state.f;
        inputDepth.value = state.L; sliderDepth.value = state.L;
        resetDrillState();
        updateCalculations();
    }
    function updateCalculations() {
        // N = (1000 * Vc) / (pi * d)
        let rpm = (1000 * state.vc) / (Math.PI * state.d);
        // F = N * f
        let feedrate = rpm * state.f;
        // t = (L + 0.3 * d) / F
        let duration = (state.L + 0.3 * state.d) / feedrate;
        // MRR = (pi * d^2 / 4) * F
        let mrr = (Math.PI * state.d * state.d / 4) * feedrate;
        // Update DOM
        valRpm.innerText = Math.round(rpm).toLocaleString();
        valFeedrate.innerText = feedrate.toFixed(1);
        valDuration.innerText = duration.toFixed(2);
        valMrr.innerText = Math.round(mrr).toLocaleString();
        // Spindle speed bar (Normalized by max 6000 RPM)
        let pct = Math.min(100, (rpm / 6000) * 100);
        barRpm.style.width = pct + "%";
        // Warnings and stability judgments
        let isVibrationWarning = false;
        if (state.d > 24) {
            if (feedrate > 400) {
                isVibrationWarning = true;
            }
        }
        // warning-vibration toggle
        if (isVibrationWarning) {
            warningVibration.style.display = "flex";
        } else {
            warningVibration.style.display = "none";
        }
        // Stability Judgments and Spindle Speed Desc Sync
        let classColor = "var(--color-success)";
        if (isVibrationWarning) {
            hudRpmDesc.innerText = "위험: 과도한 토크 부하 (진동 위험)";
            hudRpmDesc.style.color = "var(--color-danger)";
            textJudgment.innerHTML = "과도한 드릴 직경 및 피드 속도로 인해 주축 토크 부하가 임계를 초과했습니다!<br>채터 진동이 심해져 드릴 파손 한계 영역입니다.";
            classColor = "var(--color-danger)";
        } else if (rpm > 4500) {
            hudRpmDesc.innerText = "주의: 초고속 주축 회전 (발열 경고)";
            hudRpmDesc.style.color = "var(--color-warning)";
            textJudgment.innerHTML = "초고속 스핀 천공 조건입니다.<br>날끝 선단 마모와 칩 엉킴으로 인한 소성 융착이 올 수 있으므로 고압 분사 냉각유가 필수적입니다.";
            classColor = "var(--color-danger)";
        } else if (state.f > 0.4) {
            hudRpmDesc.innerText = "주의: 고이송 드릴 조건";
            hudRpmDesc.style.color = "var(--color-warning)";
            textJudgment.innerHTML = "중량이송 드릴 조건으로서 드릴 비트 중심선 흔들림 및 출구부 소재 잔류 버(Burr)가 다량 발생할 위험이 있습니다.";
            classColor = "var(--color-warning)";
        } else if (rpm < 300) {
            hudRpmDesc.innerText = "주의: 너무 낮은 회전 속도";
            hudRpmDesc.style.color = "var(--color-warning)";
            textJudgment.innerHTML = "절삭 속도가 낮아 천공 효율이 떨어지며 공구 소성 치핑이 우려됩니다.<br>조금 더 회전수를 올리셔도 안전합니다.";
            classColor = "var(--color-warning)";
        } else {
            hudRpmDesc.innerText = "적정 스핀들 속도 범위 (공구 수명 안정)";
            hudRpmDesc.style.color = "var(--color-success)";
            textJudgment.innerHTML = "대단히 안정적이고 이상적인 천공 물리 영역입니다.<br>가공면이 깨끗하고 원활한 잔류 칩 나선 배출 흐름이 기대됩니다.";
            classColor = "var(--color-success)";
        }
        if (judgmentIcon) {
            judgmentIcon.style.color = classColor;
        }
    }
    function startDrilling() {
        if (state.isDrilling) return;
        state.isDrilling = true;
        state.isCompleted = false;
        state.currentDepth = 0;
        state.elapsedSeconds = 0;
        state.chipAccumulator = 0;
        hudDot.classList.add("active");
        btnStart.disabled = true;
        btnStart.style.opacity = 0.5;
    }
    function completeDrilling() {
        state.isDrilling = false;
        state.isCompleted = true;
        state.currentDepth = state.L;
        hudDot.classList.remove("active");
        hudTime.innerText = "천공 완료! (소요 시간: " + state.elapsedSeconds.toFixed(1) + "초)";
        btnStart.disabled = false;
        btnStart.style.opacity = 1;
    }
    function resetDrillState() {
        state.isDrilling = false;
        state.isCompleted = false;
        state.currentDepth = 0;
        state.elapsedSeconds = 0;
        state.chipAccumulator = 0;
        state.drillY = 100;
        state.particles = [];
        hudDot.classList.remove("active");
        hudTime.innerText = "대기 중";
        btnStart.disabled = false;
        btnStart.style.opacity = 1;
    }
    // Particle builder for steel/aluminum ribbon chips
    function spawnChips(x, y, count) {
        for (let i = 0; i < count; i++) {
            // Spawn both left and right flowing metallic flutes
            let dir = Math.random() > 0.5 ? 1 : -1;
            state.particles.push({
                x: x + (dir * state.d * 0.4),
                y: y,
                vx: dir * (Math.random() * 3 + 1), // lateral speed
                vy: -Math.random() * 3.5 - 2, // upwards flinging
                alpha: 1.0,
                angle: Math.random() * Math.PI * 2,
                rotSpeed: (Math.random() - 0.5) * 0.3,
                size: Math.random() * 4 + 3,
                color: "#94a3b8" // Steel gray
            });
        }
    }
    function renderLoop() {
        let w = canvas.width;
        let h = canvas.height;
        // Calculate frame-rate independent dt (delta time)
        let now = performance.now();
        let dt = 0;
        if (state.lastFrameTime) {
            dt = Math.min((now - state.lastFrameTime) / 1000, 0.1); // Cap dt at 100ms to avoid huge jumps
        } else {
            dt = 0.01667; // Fallback to ~60fps
        }
        state.lastFrameTime = now;
        // Smooth Lerp for visual depth L slider changes
        if (!state.visualL) state.visualL = state.L;
        state.visualL += (state.L - state.visualL) * 0.12;
        if (Math.abs(state.L - state.visualL) < 0.05) {
            state.visualL = state.L;
        }
        ctx.clearRect(0, 0, w, h);
        // 1. Grid Background (Batched path for high performance)
        ctx.strokeStyle = "rgba(2, 132, 199, 0.04)";
        ctx.lineWidth = 1;
        ctx.beginPath();
        for (let x = 0; x < w; x += 20) {
            ctx.moveTo(x, 0); ctx.lineTo(x, h);
        }
        for (let y = 0; y < h; y += 20) {
            ctx.moveTo(0, y); ctx.lineTo(w, y);
        }
        ctx.stroke();
        // Center line
        ctx.strokeStyle = "rgba(2, 132, 199, 0.15)";
        ctx.setLineDash([5, 5]);
        ctx.beginPath(); ctx.moveTo(w/2, 0); ctx.lineTo(w/2, h); ctx.stroke();
        ctx.setLineDash([]);
        // 2. Render Workpiece (Metal block in lower section)
        let blockTopY = 220;
        // Calculate dynamic blockHeight based on smooth visual L
        let L_ratio = (state.visualL - 5) / (200 - 5);
        if (L_ratio < 0) L_ratio = 0;
        if (L_ratio > 1) L_ratio = 1;
        let blockHeight = 50 + L_ratio * 110; // workpiece thickness: 50px ~ 160px
        let maxTravelPixels = blockHeight; // breakthrough exactly at the bottom of workpiece
        ctx.fillStyle = "#f1f5f9";
        ctx.strokeStyle = "#cbd5e1";
        ctx.lineWidth = 3;
        ctx.fillRect(w/2 - 180, blockTopY, 360, blockHeight);
        ctx.strokeRect(w/2 - 180, blockTopY, 360, blockHeight);
        // Metal texture cross-hatching inside block (Batched path)
        ctx.save();
        ctx.beginPath();
        ctx.rect(w/2 - 180, blockTopY, 360, blockHeight);
        ctx.clip();
        ctx.strokeStyle = "rgba(203, 213, 225, 0.4)";
        ctx.lineWidth = 1.5;
        ctx.beginPath();
        for (let offset = -200; offset < 360; offset += 30) {
            ctx.moveTo(w/2 - 180 + offset, blockTopY);
            ctx.lineTo(w/2 - 180 + offset + 60, blockTopY + blockHeight);
        }
        ctx.stroke();
        ctx.restore();
        // 3. Spindle / Drill animation update
        let rpm = (1000 * state.vc) / (Math.PI * state.d);
        let drillW = state.d * 2.8; // scaled diameter representation
        if (drillW < 8) drillW = 8;
        if (drillW > 120) drillW = 120;
        let drillTipOffset = 80 + (drillW * 0.25);
        // Calculate dynamic drillY using simulation elapsed time ratio
        let ratio = 0;
        let totalSeconds = 0;
        let feedrate = rpm * state.f;
        let totalTimeMinutes = (state.L + 0.3 * state.d) / feedrate;
        totalSeconds = totalTimeMinutes * 60;
        let approachHeight = 60;
        let approachRatio = 0.15;
        let drillingEndRatio = 0.80;
        if (state.isDrilling) {
            state.elapsedSeconds += dt;
            if (state.elapsedSeconds >= totalSeconds) {
                state.elapsedSeconds = totalSeconds;
                completeDrilling();
            }
            ratio = state.elapsedSeconds / totalSeconds;
            // Synchronized real-time HUD updates (replaces laggy 100ms setInterval)
            let pct = (ratio * 100).toFixed(0);
            if (ratio < approachRatio) {
                hudTime.innerText = "진행률: " + pct + "% (스핀들 접근 중...)";
            } else if (ratio < drillingEndRatio) {
                hudTime.innerText = "진행률: " + pct + "% (" + state.elapsedSeconds.toFixed(1) + "초 / " + (totalSeconds).toFixed(1) + "초)";
            } else {
                hudTime.innerText = "진행률: " + pct + "% (스핀들 복귀 중...)";
            }
        } else if (state.isCompleted) {
            ratio = 1.0;
        }
        let targetTipY = blockTopY - approachHeight; // Default idle position in the air
        if (ratio > 0) {
            if (ratio < approachRatio) {
                let subRatio = ratio / approachRatio;
                targetTipY = blockTopY - approachHeight * (1 - subRatio);
            } else if (ratio < drillingEndRatio) {
                let subRatio = (ratio - approachRatio) / (drillingEndRatio - approachRatio);
                targetTipY = blockTopY + subRatio * maxTravelPixels;
            } else {
                let subRatio = (ratio - drillingEndRatio) / (1.0 - drillingEndRatio);
                // Smoothly retract drill spindle back to approach height in the air
                targetTipY = (blockTopY + maxTravelPixels) - subRatio * (maxTravelPixels + approachHeight);
            }
        }
        state.drillY = targetTipY - drillTipOffset;
        // Calculate smooth real-time currentDepth for hole drawing
        if (ratio < approachRatio) {
            state.currentDepth = 0;
        } else if (ratio < drillingEndRatio) {
            let subRatio = (ratio - approachRatio) / (drillingEndRatio - approachRatio);
            state.currentDepth = subRatio * state.L;
        } else {
            state.currentDepth = state.L;
        }
        if (state.isDrilling) {
            // Frame-rate independent rotation
            state.spindleAngle += (rpm / 1000) * 27 * dt;
            // Vibration shake
            state.shakeOffset = (Math.random() - 0.5) * (state.f * 4.0);
            // Spawn chips if drill tip is inside metal block
            let tipY = state.drillY + drillTipOffset;
            if ((tipY >= blockTopY) ? (tipY < blockTopY + blockHeight) : false) {
                // Frame-rate independent chip spawning using accumulator
                state.chipAccumulator = (state.chipAccumulator || 0) + (rpm / 25) * dt;
                if (state.chipAccumulator >= 1) {
                    let count = Math.floor(state.chipAccumulator);
                    state.chipAccumulator -= count;
                    spawnChips(w/2 + state.shakeOffset, blockTopY, count);
                }
            }
        } else {
            state.shakeOffset = 0;
        }
        // Draw cut hole in the metal block
        if (state.currentDepth > 0) {
            let currentDepthRatio = state.currentDepth / state.L;
            let holeY = currentDepthRatio * maxTravelPixels;
            let holeW = state.d * 2.8; // Scaled width representation
            let shoulderY = blockTopY + Math.max(0, holeY - (drillW * 0.25));
            ctx.fillStyle = "#334155"; // Dark interior of the drilled hole
            ctx.beginPath();
            ctx.moveTo(w/2 - holeW/2, blockTopY);
            ctx.lineTo(w/2 - holeW/2, shoulderY);
            // Drill bit point shape at bottom (matches drill tip point)
            ctx.lineTo(w/2, blockTopY + holeY);
            ctx.lineTo(w/2 + holeW/2, shoulderY);
            ctx.lineTo(w/2 + holeW/2, blockTopY);
            ctx.closePath();
            ctx.fill();
            // Thread groove lines inside the cut hole representing wall finish roughness (Batched path)
            ctx.strokeStyle = "rgba(255,255,255,0.08)";
            ctx.lineWidth = 1;
            ctx.beginPath();
            let holeSpacing = Math.max(2, state.f * 20);
            for (let hy = blockTopY; hy < blockTopY + holeY; hy += holeSpacing) {
                ctx.moveTo(w/2 - holeW/2 + 2, hy);
                ctx.lineTo(w/2 + holeW/2 - 2, hy);
            }
            ctx.stroke();
        }
        // 4. Render Drill Bit
        let drillX = w/2 + state.shakeOffset;
        let dy = state.drillY;
        // Draw Drill Shank (Upper body silver steel rod)
        ctx.fillStyle = "#cbd5e1";
        ctx.strokeStyle = "#475569";
        ctx.lineWidth = 2.5;
        ctx.fillRect(drillX - (drillW * 0.8)/2, dy - 120, drillW * 0.8, 120);
        ctx.strokeRect(drillX - (drillW * 0.8)/2, dy - 120, drillW * 0.8, 120);
        // Draw active drill flutes body
        ctx.fillStyle = "#94a3b8";
        ctx.fillRect(drillX - drillW/2, dy, drillW, 80);
        ctx.strokeRect(drillX - drillW/2, dy, drillW, 80);
        // Helicoidal Flute visual patterns inside the drill body (Batched path)
        ctx.save();
        ctx.beginPath();
        ctx.rect(drillX - drillW/2, dy, drillW, 80);
        ctx.clip();
        ctx.strokeStyle = "#334155";
        ctx.lineWidth = Math.max(2.5, drillW * 0.12);
        ctx.beginPath();
        let pitch = 30; // flute helical pitch height
        let fluteOffset = (state.spindleAngle * pitch) % (pitch * 2);
        for (let fy = dy - pitch * 2; fy < dy + 120; fy += pitch) {
            let relativeFy = fy + fluteOffset;
            let arcX = drillX;
            let arcY = relativeFy;
            let radius = drillW * 0.55;
            let startAngle = 0.2;
            let endAngle = Math.PI - 0.2;
            ctx.moveTo(arcX + radius * Math.cos(startAngle), arcY + radius * Math.sin(startAngle));
            ctx.arc(arcX, arcY, radius, startAngle, endAngle);
        }
        ctx.stroke();
        ctx.restore();
        // Drill Tip (118 degree cone head)
        ctx.fillStyle = "#64748b";
        ctx.strokeStyle = "#334155";
        ctx.lineWidth = 2.5;
        ctx.lineJoin = "round"; // Prevent sharp miter corner spikes
        // Fill closed path
        ctx.beginPath();
        ctx.moveTo(drillX - drillW/2, dy + 80);
        ctx.lineTo(drillX, dy + 80 + (drillW * 0.25)); // 118 degrees tip point
        ctx.lineTo(drillX + drillW/2, dy + 80);
        ctx.closePath();
        ctx.fill();
        // Stroke only bottom cutting edges (V-shape) to prevent wing-like spikes
        ctx.beginPath();
        ctx.moveTo(drillX - drillW/2, dy + 80);
        ctx.lineTo(drillX, dy + 80 + (drillW * 0.25));
        ctx.lineTo(drillX + drillW/2, dy + 80);
        ctx.stroke();
        // 5. Particles Update &#038; Render (Frame-rate independent movement)
        let fpsFactor = dt * 60;
        for (let i = state.particles.length - 1; i >= 0; i--) {
            let p = state.particles[i];
            p.x += p.vx * fpsFactor;
            p.y += p.vy * fpsFactor;
            p.vy += 0.15 * fpsFactor; // Gravity pull down
            p.alpha -= 0.02 * fpsFactor;
            p.angle += p.rotSpeed * fpsFactor;
            if (p.alpha <= 0) {
                state.particles.splice(i, 1);
            } else {
                ctx.save();
                ctx.globalAlpha = p.alpha;
                ctx.fillStyle = p.color;
                ctx.strokeStyle = "rgba(71, 85, 105, 0.4)";
                ctx.lineWidth = 1;
                ctx.translate(p.x, p.y);
                ctx.rotate(p.angle);
                // Draw curly helical metal ribbon chips
                ctx.beginPath();
                ctx.arc(0, 0, p.size, 0, Math.PI * 1.3);
                ctx.stroke();
                ctx.restore();
            }
        }
        // Draw target line at L
        ctx.strokeStyle = "#db2777";
        ctx.lineWidth = 1.5;
        ctx.setLineDash([4, 4]);
        ctx.beginPath();
        ctx.moveTo(w/2 - 200, blockTopY + maxTravelPixels);
        ctx.lineTo(w/2 + 200, blockTopY + maxTravelPixels);
        ctx.stroke();
        ctx.setLineDash([]);
        ctx.fillStyle = "#db2777";
        ctx.font = "bold 10px Outfit";
        ctx.fillText("가공 목표 관통 깊이 L = " + state.L + " mm", w/2 - 180, blockTopY + maxTravelPixels - 6);
        requestAnimationFrame(renderLoop);
    }
    let attempts = 0;
    function tryStart() {
        attempts++;
        initSimulator();
        if (!initialized) {
            if (attempts < 40) {
                setTimeout(tryStart, 100);
            }
        }
    }
    if (document.readyState === "complete" || document.readyState === "interactive") {
        tryStart();
    } else {
        document.addEventListener("DOMContentLoaded", tryStart);
        window.addEventListener("load", tryStart);
    }
})();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>드릴 지름(d) 지정: 구멍을 천공할 드릴 비트의 공칭 직경(1mm ~ 50mm)을 입력합니다.</strong></li>
<li style="margin-bottom: 6px;">목표 절삭 속도(V_c) 및 1회전 이송량(f) 설정: 피삭재(알루미늄, 연강, 주철 등)에 따른 절삭 주속도(m/min)와 회전당 이송 피드량(mm/rev)을 정의합니다.</li>
<li style="margin-bottom: 6px;">구멍 관통 깊이(L) 지정: 공작물에 구멍을 뚫을 천공 깊이(5mm ~ 200mm)를 지정합니다.</li>
<li style="margin-bottom: 6px;">실시간 드릴링 동작 모니터링: 드릴 비트가 고속 스핀 회전하며 아래로 피드 운행해 소재를 천공하는 과정과 양방향 칩 배출 파티클을 관찰하고 관통 소요 시간을 측정합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 드릴링 가공 공식 및 드릴 비트 형상 역학 해설</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 드릴 주축 회전수(N)와 원주 절삭 속도(V_c) 공식</h3>
<p>드릴링(Drilling) 공정에서 <strong>절삭 속도(Cutting Speed, V_c)</strong>는 드릴 외경의 가장자리(원주선)가 가공 구멍 벽면을 긁고 지나가는 선속도를 의미합니다.</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">N = (1000 &times; V_c) / (&pi; &times; d) &nbsp;[RPM]</p><p>여기서 <code>d</code>는 드릴 직경(mm)이며, <code>V_c</code>는 절삭 속도(m/min)입니다. 드릴 지름이 작아질수록 동일한 절삭 속도를 얻기 위해 필요한 회전 속도 <code>N</code>은 기하급수적으로 높아져야 합니다.</p>
<h3>2. 이송 속도(F) 및 드릴 날끝 원추각을 고려한 순 가공 소요 시간(t)</h3>
<p>드릴 비트가 주축 회전당 축방향으로 전진하는 거리를 <code>f</code> (mm/rev)라고 할 때, 공구가 공작물 내부로 들어가는 실질적인 선형 분당 이송 속도 <code>F</code> (mm/min)는 아래와 같이 단순 승산으로 계산됩니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">F = N &times; f &nbsp;[mm/min]</p><p>드릴 구멍 가공 시 단순히 관통 깊이 <code>L</code>을 이송 속도로 나누는 것만으로는 부족합니다. 드릴 선단에는 뾰족한 날끝각(보통 118도 내외)이 있어 <strong>원추 선단 높이(cone tip height, h &approx; 0.3 &times; d)</strong>만큼 드릴이 완전히 빠져나가기 위한 여유 거리가 필수적입니다. 따라서 구멍이 완전히 관통하는 데 걸리는 총 시간은 다음과 같이 모델링됩니다.</p><p style="text-align: center; font-weight: bold; background: #fee2e2; padding: 16px; border-radius: 8px; color: #991b1b;">t = (L + 0.3 &times; d) / F &nbsp;[min]</p><p>이는 기계 가공 현장의 공정 수립 및 생산 사이클 타임(Cycle Time) 산정에 결정적인 기본 물리 공식입니다.</p>
<h3>3. 칩 제거율(MRR)과 열 응력 설계</h3>
<p>드릴 가공 시 배출되는 금속 체적 속도인 <strong>소재 제거율(MRR)</strong>은 구멍 가공 단면적과 이송 속도의 곱으로 결정됩니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">MRR = (&pi; &times; d&sup2; / 4) &times; F &nbsp;[mm&sup3;/min]</p><p>드릴링은 사방이 갇힌 구멍 내부에서 가공이 일어나므로 절삭열이 축적되기 매우 쉽습니다. 고속 이송 시 칩 배출이 막히면 드릴 비트가 고열로 인해 부러질 수 있으므로 적절한 절삭유(Coolant) 공급 및 칩의 나선 배출 흐름 설계가 강조됩니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>


<h2 style="font-size: 1.4em; font-weight: 700; color: #1f2937; margin-top: 40px; margin-bottom: 15px; border-left: 4px solid #3b82f6; padding-left: 10px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 함께 보면 좋은 공학 글</h2>


<a href="https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">선삭 절삭 속도 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>


<a href="https://myengnote.com/inverter-motor-vfd-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">인버터 슬립 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/machining-drill-rpm-feedrate-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>선삭 절삭 속도 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/</link>
					<comments>https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Tue, 30 Jun 2026 00:14:12 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[공구노즈알]]></category>
		<category><![CDATA[선삭절삭속도]]></category>
		<category><![CDATA[칩배출량]]></category>
		<category><![CDATA[표면거칠기]]></category>
		<category><![CDATA[회전수계산]]></category>
		<guid isPermaLink="false">https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/</guid>

					<description><![CDATA[공작물 직경과 주축 회전수(RPM)를 기반으로 선반 가공의 원주 방향 절삭 속도(m/min)와 이송량에 따른 이론적 표면 조도(Ra, Ry) 및 소재 제거율(MRR)을 실시간 2D 절삭 칩 시뮬레이션으로 분석합니다. <a href="https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 선삭 절삭 속도 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for cuttingspeed-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .cuttingspeed-calculator-wrapper *, .cuttingspeed-calculator-wrapper *::before, .cuttingspeed-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .cuttingspeed-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7; /* Cobalt blue accent */
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777; /* Pink/magenta accent */
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --color-danger: #ef4444;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .cuttingspeed-calculator-wrapper {
            width: 100%;
            max-width: 1440px;
            margin: 0 auto;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
        }
        .cuttingspeed-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 15s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-diameter::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-rpm::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 10px var(--color-purple); }
        #slider-feed::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        #slider-nose::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-ap::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-name {
            font-size: 13px !important;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-card {
            background: #ffffff;
            border: 1px solid var(--color-border);
            border-radius: 16px;
            overflow: hidden;
            box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.05);
            position: relative;
        }
        canvas {
            display: block;
            width: 100%;
            background: #ffffff;
        }
        /* Canvas HUD Overlay */
        .hud-overlay {
            position: absolute;
            top: 10px;
            left: 12px;
            background: rgba(255, 255, 255, 0.9);
            border: 1px solid rgba(0,0,0,0.05);
            border-radius: 8px;
            padding: 6px 10px;
            font-size: 0.75rem;
            font-family: 'Outfit', sans-serif;
            color: var(--color-text-main);
            pointer-events: none;
            display: flex;
            flex-direction: column;
            gap: 4px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.05);
            z-index: 10;
        }
        .hud-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .hud-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(2, 132, 199, 0.08) 0%, rgba(124, 58, 237, 0.03) 100%);
            border: 1px solid rgba(2, 132, 199, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(2, 132, 199, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 30px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(2, 132, 199, 0.2);
            background: rgba(2, 132, 199, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
            flex-shrink: 0;
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: rgba(2, 132, 199, 0.3);
            background: rgba(2, 132, 199, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .card-unit-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-dark);
            margin-left: 4px;
        }
        .formula-card {
            background: #ffffff !important;
            border: 1px solid var(--color-border) !important;
            border-radius: 12px !important;
            padding: 16px !important;
            box-shadow: var(--shadow-card) !important;
            transition: all 0.2s ease !important;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        #text-judgment {
            font-size: 12px !important;
            font-weight: 500 !important;
            color: var(--color-text-muted) !important;
            line-height: 1.6 !important;
            word-break: keep-all !important;
        }
        .formula-equation {
            font-family: monospace;
            color: var(--color-cyan);
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        .efficiency-bar-container {
            background: #e2e8f0;
            height: 6px;
            border-radius: 3px;
            overflow: hidden;
        }
        .efficiency-bar {
            height: 100%;
            width: 0%;
            background: var(--gradient-primary);
            transition: width 0.3s ease;
        }
        .warning-box {
            background: #fffbeb;
            border: 1px dashed var(--color-warning);
            border-radius: 10px;
            padding: 12px;
            font-size: 12px;
            color: #b45309;
            display: flex;
            align-items: flex-start;
            gap: 10px;
            margin-top: 15px;
            display: none;
        }
        @container motor-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container motor-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container motor-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.cuttingspeed-calculator-wrapper .app-main-grid,
.cuttingspeed-calculator-wrapper .main-grid,
.cuttingspeed-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.cuttingspeed-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.cuttingspeed-calculator-wrapper .simulation-panel,
.cuttingspeed-calculator-wrapper .canvas-panel,
.cuttingspeed-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.cuttingspeed-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.cuttingspeed-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.cuttingspeed-calculator-wrapper .simulation-results-section .ratio-readout-box,
.cuttingspeed-calculator-wrapper .simulation-results-section .re-readout-box,
.cuttingspeed-calculator-wrapper .simulation-results-section .status-readout-box,
.cuttingspeed-calculator-wrapper .simulation-results-section .flow-readout-box,
.cuttingspeed-calculator-wrapper .simulation-results-section [class*="readout-box"],
.cuttingspeed-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.cuttingspeed-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.cuttingspeed-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.cuttingspeed-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .cuttingspeed-calculator-wrapper .app-main-grid,
    .cuttingspeed-calculator-wrapper .main-grid,
    .cuttingspeed-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .cuttingspeed-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .cuttingspeed-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .cuttingspeed-calculator-wrapper .simulation-panel,
    .cuttingspeed-calculator-wrapper .canvas-panel,
    .cuttingspeed-calculator-wrapper .sim-panel,
    .cuttingspeed-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .cuttingspeed-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .cuttingspeed-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .cuttingspeed-calculator-wrapper .simulation-results-section .re-readout-box,
    .cuttingspeed-calculator-wrapper .simulation-results-section .status-readout-box,
    .cuttingspeed-calculator-wrapper .simulation-results-section .flow-readout-box,
    .cuttingspeed-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .cuttingspeed-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .cuttingspeed-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .cuttingspeed-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.cuttingspeed-calculator-wrapper .app-container,
.cuttingspeed-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.cuttingspeed-calculator-wrapper .simulation-results-section .formula-card,
.cuttingspeed-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.cuttingspeed-calculator-wrapper .simulation-results-section .formula-card h4,
.cuttingspeed-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.cuttingspeed-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.cuttingspeed-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="cuttingspeed-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
<div class="cuttingspeed-calculator-wrapper">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-screwdriver-wrench text-cyan"></i></div>
                <div>
                    <h1>CUTTING SPEED</h1>
                    <div class="subtitle">선삭 절삭 속도 및 표면 조도 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">LATHE CORE ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>가공 공정 제어 변수</h2>
                </div>
                <!-- Workpiece Diameter (D) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-circle-dot text-cyan"></i> 공작물 외경 직경 (D)</label>
                        <span class="helper-text">(10 ~ 250 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-diameter" class="custom-number-input" min="10" max="250" value="50">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-diameter" class="custom-slider" min="10" max="250" value="50">
                </div>
                <!-- Spindle Speed (N) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-rotate text-purple"></i> 스핀들 회전수 (N)</label>
                        <span class="helper-text">(100 ~ 4000 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="100" max="4000" value="2500">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider" min="100" max="4000" step="50" value="2500">
                </div>
                <!-- Feed Rate (f) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-right-long text-magenta"></i> 1회전당 이송량 (f)</label>
                        <span class="helper-text">(0.05 ~ 1.00 mm/rev)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-feed" class="custom-number-input" min="0.05" max="1.00" step="0.01" value="0.08">
                        <div class="unit-badge">mm/rev</div>
                    </div>
                    <input type="range" id="slider-feed" class="custom-slider" min="0.05" max="1.00" step="0.01" value="0.08">
                </div>
                <!-- Tool Nose Radius (r) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-bezier-curve text-cyan"></i> 공구 노즈 반경 (r)</label>
                        <span class="helper-text">(0.2 ~ 2.4 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-nose" class="custom-number-input" min="0.2" max="2.4" step="0.2" value="0.8">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-nose" class="custom-slider" min="0.2" max="2.4" step="0.2" value="0.8">
                </div>
                <!-- Depth of Cut (ap) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-arrows-left-right-to-line text-magenta"></i> 절입 깊이 (a_p)</label>
                        <span class="helper-text">(0.1 ~ 5.0 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-ap" class="custom-number-input" min="0.1" max="5.0" step="0.1" value="0.5">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-ap" class="custom-slider" min="0.1" max="5.0" step="0.1" value="0.5">
                </div>
                <!-- Material Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 피삭재별 권장 가공 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" data-preset="al-finish">
                            <div class="preset-icon"><i class="fa-solid fa-bolt"></i></div>
                            <div class="preset-details">
                                <span class="preset-name">알루미늄 초정밀 정삭</span>
                                <span class="preset-spec">D50, N2500, f0.08, r0.8</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="steel-rough">
                            <div class="preset-icon"><i class="fa-solid fa-fire"></i></div>
                            <div class="preset-details">
                                <span class="preset-name">탄소강 중절삭 황삭</span>
                                <span class="preset-spec">D85, N750, f0.35, r1.2</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="heavy-diameter">
                            <div class="preset-icon"><i class="fa-solid fa-weight-hanging"></i></div>
                            <div class="preset-details">
                                <span class="preset-name">대형 피스톤 샤프트 선삭</span>
                                <span class="preset-spec">D180, N350, f0.50, r1.6</span>
                            </div>
                        </button>
                    </div>
                </div>
                <!-- Over-speed warning -->
                <div id="warning-overspeed" class="warning-box">
                    <i class="fa-solid fa-triangle-exclamation"></i>
                    <span><strong>주의:</strong> 원주 절삭 속도가 지나치게 높습니다! 공구 수명 단축 및 팁 마모가 극대화되어 열화 파손 한계에 이릅니다.</span>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>실시간 선반 가공 거동 및 칩 배출 모니터링</h2>
                                    </div>
                                    <div class="canvas-scale-indicator">ACTIVE</div>
                                </div>
                                <div class="canvas-card">
                                    <div class="hud-overlay">
                                        <div class="hud-item">
                                            <div class="hud-dot"></div>
                                            <span style="letter-spacing:0.5px; font-weight:700;">2D LATHE RENDERER</span>
                                        </div>
                                        <div class="hud-item" style="color:var(--color-text-muted);">
                                            <i class="fa-solid fa-gauge"></i> <span id="hud-speed">0.0 m/min</span>
                                        </div>
                                    </div>
                                    <canvas id="lathe-canvas" width="680" height="400"></canvas>
                                </div>
                                <div class="canvas-card">
                                    <div class="hud-overlay">
                                        <div class="hud-item">
                                            <i class="fa-solid fa-chart-line text-magenta"></i>
                                            <span style="letter-spacing:0.5px; font-weight:700;">이론 표면 거칠기 프로파일 (마이크로 조도 200배 확대)</span>
                                        </div>
                                    </div>
                                    <canvas id="roughness-canvas" width="680" height="150"></canvas>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">원주 절삭 속도 (V_c)</div>
                                    <div>
                                        <span id="val-vc" class="ratio-value">392.7</span>
                                        <span>m/min</span>
                                    </div>
                                    <div class="efficiency-bar-container">
                                        <div id="bar-vc" class="efficiency-bar"></div>
                                    </div>
                                    <div id="hud-speed-desc">적정 절삭 속도 범위 (공구 수명 안정)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- Maximum Roughness Ry -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-mountain text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">이론 최대 높이 조도 (R_y)</span>
                                            <span class="card-value"><span id="val-ry">1.56</span><span class="card-unit-text">μm</span></span>
                                        </div>
                                    </div>
                                    <!-- Average Roughness Ra -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-water text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">중심선 평균 거칠기 (R_a)</span>
                                            <span class="card-value"><span id="val-ra">0.39</span><span class="card-unit-text">μm</span></span>
                                        </div>
                                    </div>
                                    <!-- Material Removal Rate MRR -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-cubes text-success"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">소재 제거율 (MRR)</span>
                                            <span class="card-value"><span id="val-mrr">19,635</span><span class="card-unit-text">mm³/min</span></span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 표면거칠기 및 소음 조언</h4>
                                    <div id="text-judgment">
                                        정밀 정삭가공면 수준(Ra &lt; 0.8μm)입니다. 높은 치수 정밀도 및 접동부 베어링 하우징 마찰면에 적합합니다.
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
    </div>
</div>
    </div>
</div>
<script>
(function() {
    "use strict";
    let state = {
        d: 50,
        n: 2500,
        f: 0.08,
        r: 0.8,
        ap: 0.5,
        toolX: 620, // Simulation tool coordinates
        spindleAngle: 0,
        particles: []
    };
    let initialized = false;
    // DOM selectors
    let inputDiameter, sliderDiameter;
    let inputRpm, sliderRpm;
    let inputFeed, sliderFeed;
    let inputNose, sliderNose;
    let inputAp, sliderAp;
    let valVc, valRy, valRa, valMrr, barVc;
    let hudSpeed, hudSpeedDesc, warningOverspeed, textJudgment, judgmentIcon;
    let latheCanvas, latheCtx;
    let roughnessCanvas, roughnessCtx;
    function initSimulator() {
        if (initialized) return;
        // Fetch inputs
        inputDiameter = document.getElementById("input-diameter");
        sliderDiameter = document.getElementById("slider-diameter");
        inputRpm = document.getElementById("input-rpm");
        sliderRpm = document.getElementById("slider-rpm");
        inputFeed = document.getElementById("input-feed");
        sliderFeed = document.getElementById("slider-feed");
        inputNose = document.getElementById("input-nose");
        sliderNose = document.getElementById("slider-nose");
        inputAp = document.getElementById("input-ap");
        sliderAp = document.getElementById("slider-ap");
        if (!inputDiameter) return;
        // Fetch results
        valVc = document.getElementById("val-vc");
        valRy = document.getElementById("val-ry");
        valRa = document.getElementById("val-ra");
        valMrr = document.getElementById("val-mrr");
        barVc = document.getElementById("bar-vc");
        hudSpeed = document.getElementById("hud-speed");
        hudSpeedDesc = document.getElementById("hud-speed-desc");
        warningOverspeed = document.getElementById("warning-overspeed");
        textJudgment = document.getElementById("text-judgment");
        judgmentIcon = document.getElementById("judgment-icon");
        // Fetch canvases
        latheCanvas = document.getElementById("lathe-canvas");
        latheCtx = latheCanvas.getContext("2d");
        roughnessCanvas = document.getElementById("roughness-canvas");
        roughnessCtx = roughnessCanvas.getContext("2d");
        // Event binder helper without logical AND
        function linkInputSlider(inputEl, sliderEl, stateKey, decimalPlaces) {
            // Live update state during slider sliding
            sliderEl.addEventListener("input", function() {
                let val = parseFloat(sliderEl.value);
                inputEl.value = decimalPlaces > 0 ? val.toFixed(decimalPlaces) : val;
                state[stateKey] = val;
                updateCalculations();
            });
            // Validation only on focus-out / blur / enter
            inputEl.addEventListener("change", function() {
                let min = parseFloat(inputEl.min);
                let max = parseFloat(inputEl.max);
                let val = parseFloat(inputEl.value);
                if (isNaN(val)) {
                    val = parseFloat(sliderEl.value);
                }
                if (val < min) {
                    val = min;
                }
                if (val > max) {
                    val = max;
                }
                inputEl.value = decimalPlaces > 0 ? val.toFixed(decimalPlaces) : val;
                sliderEl.value = val;
                state[stateKey] = val;
                updateCalculations();
            });
        }
        linkInputSlider(inputDiameter, sliderDiameter, "d", 0);
        linkInputSlider(inputRpm, sliderRpm, "n", 0);
        linkInputSlider(inputFeed, sliderFeed, "f", 2);
        linkInputSlider(inputNose, sliderNose, "r", 1);
        linkInputSlider(inputAp, sliderAp, "ap", 1);
        // Presets click events
        let presetBtns = document.querySelectorAll(".preset-btn");
        presetBtns.forEach(function(btn) {
            btn.addEventListener("click", function() {
                presetBtns.forEach(b => b.classList.remove("active"));
                btn.classList.add("active");
                applyPreset(btn.dataset.preset);
            });
        });
        // Strict Right Click and Short Key Copyright protection
        document.addEventListener("contextmenu", function(e) {
            e.preventDefault();
            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
        }, { capture: true });
        document.addEventListener("keydown", function(e) {
            if (e.ctrlKey) {
                if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.shiftKey) {
                    if (['i','I','j','J','c','C'].includes(e.key)) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                }
            }
        }, { capture: true });
        updateCalculations();
        requestAnimationFrame(renderLoop);
        initialized = true;
    }
    function applyPreset(presetType) {
        if (presetType === "al-finish") {
            state.d = 50; state.n = 2500; state.f = 0.08; state.r = 0.8; state.ap = 0.5;
        } else if (presetType === "steel-rough") {
            state.d = 85; state.n = 750; state.f = 0.35; state.r = 1.2; state.ap = 2.0;
        } else if (presetType === "heavy-diameter") {
            state.d = 180; state.n = 350; state.f = 0.50; state.r = 1.6; state.ap = 3.5;
        }
        // Sync visual DOM
        inputDiameter.value = state.d; sliderDiameter.value = state.d;
        inputRpm.value = state.n; sliderRpm.value = state.n;
        inputFeed.value = state.f.toFixed(2); sliderFeed.value = state.f;
        inputNose.value = state.r.toFixed(1); sliderNose.value = state.r;
        inputAp.value = state.ap.toFixed(1); sliderAp.value = state.ap;
        updateCalculations();
    }
    function updateCalculations() {
        // Vc = (pi * d * n) / 1000
        let vc = (Math.PI * state.d * state.n) / 1000;
        // Ry = (f^2 * 1000) / (8 * r)
        let ry = (state.f * state.f * 1000) / (8 * state.r);
        // Ra = (f^2 * 1000) / (32 * r)
        let ra = (state.f * state.f * 1000) / (32 * state.r);
        // MRR = Vc * f * ap * 1000
        let mrr = vc * state.f * state.ap * 1000;
        // Render to DOM
        valVc.innerText = vc.toFixed(1);
        valRy.innerText = ry.toFixed(2);
        valRa.innerText = ra.toFixed(2);
        valMrr.innerText = Math.round(mrr).toLocaleString();
        hudSpeed.innerText = vc.toFixed(1) + " m/min";
        // Feed velocity bar (normalize by max 400 m/min)
        let pct = Math.min(100, (vc / 400) * 100);
        barVc.style.width = pct + "%";
        // Warnings and highlight card description based on cutting speed Vc
        warningOverspeed.style.display = "none";
        if (vc > 280) {
            warningOverspeed.style.display = "flex";
            hudSpeedDesc.innerText = "위험: 과도한 절삭 속도 (공구 마모 극대화)";
            hudSpeedDesc.style.color = "var(--color-danger)";
        } else if (vc < 80) {
            hudSpeedDesc.innerText = "주의: 너무 낮은 절삭 속도 (가공 효율 저하)";
            hudSpeedDesc.style.color = "var(--color-warning)";
        } else {
            hudSpeedDesc.innerText = "적정 절삭 속도 범위 (공구 수명 안정)";
            hudSpeedDesc.style.color = "var(--color-success)";
        }
        // Roughness quality assessment texts
        let classColor = "var(--color-success)";
        if (ra < 0.2) {
            textJudgment.innerHTML = "초정밀 연삭/경면 급 광택 다듬질 조도를 달성합니다.<br>반도체, 광학 미러용 수준입니다.";
            classColor = "var(--color-success)";
        } else if (ra < 0.8) {
            textJudgment.innerHTML = "정밀 정삭가공면 수준(Ra < 0.8μm)입니다.<br>높은 치수 정밀도 및 접동부 베어링 하우징 마찰면에 적합합니다.";
            classColor = "var(--color-success)";
        } else if (ra < 1.6) {
            textJudgment.innerHTML = "일반 정삭가공면 수준(Ra < 1.6μm)입니다.<br>일반 기계 결합면 조도로서 우수합니다.";
            classColor = "var(--color-cyan)";
        } else if (ra < 3.2) {
            textJudgment.innerHTML = "보통 가공면 수준(Ra < 3.2μm)입니다.<br>슬라이딩이 없는 고정 부위 결합면 수준으로 무난합니다.";
            classColor = "var(--color-warning)";
        } else {
            textJudgment.innerHTML = "거친 황삭 가공면(Ra ≥ 3.2μm)입니다.<br>뜯김 현상이나 나선 골 깊이가 뚜렷하므로 후속 정밀 가공이 반드시 요구됩니다.";
            classColor = "var(--color-danger)";
        }
        if (judgmentIcon) {
            judgmentIcon.style.color = classColor;
        }
    }
    // Particle factory for cutting sparks
    function spawnParticles(x, y, count) {
        for (let i = 0; i < count; i++) {
            state.particles.push({
                x: x,
                y: y,
                vx: -Math.random() * 4 - 2, // Fly leftwards
                vy: -Math.random() * 4 - 1, // Fly upwards
                alpha: 1,
                size: Math.random() * 2 + 1.5,
                color: "hsl(" + (Math.random() * 20 + 25) + ", 100%, " + (Math.random() * 20 + 55) + "%)" // Bright orange/yellow
            });
        }
    }
    function renderLoop() {
        renderLathe();
        renderRoughness();
        // Slow tool toolX coordinate cycle to show cutting motion
        state.toolX = state.toolX - 0.45;
        if (state.toolX < 120) {
            state.toolX = 620; // Reset tool to the very beginning (right edge)
        }
        // Spin Spindle Angle based on RPM
        state.spindleAngle = state.spindleAngle + (state.n / 1000) * 0.12;
        requestAnimationFrame(renderLoop);
    }
    function renderLathe() {
        let ctx = latheCtx;
        let w = latheCanvas.width;
        let h = latheCanvas.height;
        ctx.clearRect(0, 0, w, h);
        // 1. Blueprint Grid Background
        ctx.strokeStyle = "rgba(2, 132, 199, 0.04)";
        ctx.lineWidth = 1;
        for (let x = 0; x < w; x += 20) {
            ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke();
        }
        for (let y = 0; y < h; y += 20) {
            ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke();
        }
        // Center line
        ctx.strokeStyle = "rgba(2, 132, 199, 0.15)";
        ctx.setLineDash([6, 6]);
        ctx.beginPath(); ctx.moveTo(0, h/2); ctx.lineTo(w, h/2); ctx.stroke();
        ctx.setLineDash([]);
        // 2. Chuck Jaws (Slightly left)
        ctx.fillStyle = "#cbd5e1";
        ctx.strokeStyle = "#475569";
        ctx.lineWidth = 2;
        ctx.fillRect(10, h/2 - 120, 60, 240);
        ctx.strokeRect(10, h/2 - 120, 60, 240);
        // Stepped jaw details
        ctx.fillStyle = "#94a3b8";
        ctx.fillRect(70, h/2 - 110, 25, 60);
        ctx.strokeRect(70, h/2 - 110, 25, 60);
        ctx.fillRect(70, h/2 + 50, 25, 60);
        ctx.strokeRect(70, h/2 + 50, 25, 60);
        // 3. Workpiece (Rotational shaft)
        // Scaled base diameter
        let pixelRadiusMax = 100; // max 250mm
        let currentR = (state.d / 250) * pixelRadiusMax;
        if (currentR < 15) currentR = 15; // Min size visibility
        let cutDepthPixels = (state.ap / 5.0) * 12; // Scaled ap cutting depth visual
        if (cutDepthPixels > currentR - 5) cutDepthPixels = currentR - 5; 
        let toolX = state.toolX;
        // Uncut piece (Left side of the tool, between chuck jaws and the tool tip)
        ctx.fillStyle = "#f1f5f9";
        ctx.strokeStyle = "#94a3b8";
        ctx.lineWidth = 2.5;
        ctx.beginPath();
        ctx.moveTo(95, h/2 - currentR);
        ctx.lineTo(toolX, h/2 - currentR);
        ctx.lineTo(toolX, h/2 + currentR);
        ctx.lineTo(95, h/2 + currentR);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        // Render spiral rotating lines on uncut piece to simulate spin motion
        ctx.save();
        ctx.beginPath();
        ctx.rect(95, h/2 - currentR, toolX - 95, currentR * 2);
        ctx.clip();
        ctx.strokeStyle = "rgba(148, 163, 184, 0.25)";
        ctx.lineWidth = 3;
        for (let offset = -200; offset < w; offset += 45) {
            let spiralX = offset + Math.sin(state.spindleAngle) * 12;
            ctx.beginPath();
            ctx.moveTo(spiralX, h/2 - currentR);
            ctx.lineTo(spiralX + 25, h/2 + currentR);
            ctx.stroke();
        }
        ctx.restore();
        // Cut piece (Right side of the tool, already machined part)
        let cutR = currentR - cutDepthPixels;
        ctx.fillStyle = "#e2e8f0";
        ctx.strokeStyle = "#64748b";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(toolX, h/2 - cutR);
        ctx.lineTo(w - 60, h/2 - cutR);
        ctx.lineTo(w - 60, h/2 + cutR);
        ctx.lineTo(toolX, h/2 + cutR);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        // Fine thread lines on cut piece representing cut profile grooves
        ctx.save();
        ctx.beginPath();
        ctx.rect(toolX, h/2 - cutR, w - 60 - toolX, cutR * 2);
        ctx.clip();
        ctx.strokeStyle = "rgba(100, 116, 139, 0.15)";
        ctx.lineWidth = 1;
        // Density corresponds to state.f (Feed speed)
        let spacing = Math.max(3, state.f * 35);
        for (let gx = toolX; gx < w - 60; gx += spacing) {
            ctx.beginPath();
            ctx.moveTo(gx, h/2 - cutR);
            ctx.lineTo(gx, h/2 + cutR);
            ctx.stroke();
        }
        ctx.restore();
        // 4. Cutting Tool (Turning Bar &#038; Insert tip)
        let toolY = h/2 - cutR;
        // Tool shank (Holder)
        ctx.fillStyle = "#334155";
        ctx.strokeStyle = "#1e293b";
        ctx.lineWidth = 1.5;
        ctx.beginPath();
        ctx.moveTo(toolX - 5, toolY + 120);
        ctx.lineTo(toolX + 30, toolY + 120);
        ctx.lineTo(toolX + 30, toolY + 15);
        ctx.lineTo(toolX - 2, toolY + 10);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        // Carbide Insert (Golden Triangle)
        ctx.fillStyle = "#d97706"; // Golden yellow
        ctx.strokeStyle = "#78350f";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(toolX, toolY);
        ctx.lineTo(toolX + 25, toolY + 8);
        ctx.lineTo(toolX + 10, toolY + 28);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        // Highlight nose radius tip
        ctx.fillStyle = "#ffffff";
        ctx.beginPath();
        ctx.arc(toolX, toolY, state.r * 2.5, 0, Math.PI * 2);
        ctx.fill();
        // 5. Sparks particle effects (Emit when cutting)
        if (state.n > 0) {
            spawnParticles(toolX, toolY, Math.ceil(state.n / 1000));
        }
        // Draw and update particles
        for (let i = state.particles.length - 1; i >= 0; i--) {
            let p = state.particles[i];
            p.x += p.vx;
            p.y += p.vy;
            p.vy += 0.08; // gravity drop
            p.alpha -= 0.025;
            if (p.alpha <= 0) {
                state.particles.splice(i, 1);
            } else {
                ctx.save();
                ctx.globalAlpha = p.alpha;
                ctx.fillStyle = p.color;
                ctx.beginPath();
                ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
                ctx.fill();
                ctx.restore();
            }
        }
    }
    function renderRoughness() {
        let ctx = roughnessCtx;
        let w = roughnessCanvas.width;
        let h = roughnessCanvas.height;
        ctx.clearRect(0, 0, w, h);
        // 1. Grid
        ctx.strokeStyle = "rgba(219, 39, 119, 0.03)";
        ctx.lineWidth = 1;
        for (let x = 0; x < w; x += 20) {
            ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke();
        }
        for (let y = 0; y < h; y += 20) {
            ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke();
        }
        // Base line
        let baselineY = h - 45;
        ctx.strokeStyle = "rgba(71, 85, 105, 0.15)";
        ctx.lineWidth = 1.5;
        ctx.beginPath(); ctx.moveTo(20, baselineY); ctx.lineTo(w - 20, baselineY); ctx.stroke();
        // Math calculations
        let ry = (state.f * state.f * 1000) / (8 * state.r);
        // Exaggerated wave rendering representing actual feed spirals
        // Spacing on screen depends on feed
        let waveSpacing = state.f * 110; 
        if (waveSpacing < 10) waveSpacing = 10;
        if (waveSpacing > 130) waveSpacing = 130;
        // Amplitude (Depth) depends on Ry
        let ampScale = 4.5;
        let amp = ry * ampScale;
        if (amp < 1.5) amp = 1.5;
        if (amp > 55) amp = 55; // visual clamping
        // 2. Draw theoretical roughness profile shape
        ctx.strokeStyle = "#db2777";
        ctx.lineWidth = 3.5;
        ctx.lineJoin = "round";
        ctx.beginPath();
        let noseRadPix = state.r * 18; // scaled visual nose rad
        let startX = 30;
        let first = true;
        for (let x = startX; x < w - 30; x += 1) {
            let relativeX = (x - startX) % waveSpacing;
            let peakX = waveSpacing / 2;
            // Formula for round tool scallop heights
            // y = r - sqrt(r^2 - dx^2)
            let dx = relativeX - peakX;
            let dy = 0;
            if (Math.abs(dx) < noseRadPix) {
                dy = noseRadPix - Math.sqrt(noseRadPix * noseRadPix - dx * dx);
            } else {
                dy = noseRadPix - Math.sqrt(noseRadPix * noseRadPix - (noseRadPix * 0.99) * (noseRadPix * 0.99));
            }
            // Scale to match amp
            let visualY = baselineY + dy * (amp / 8);
            if (visualY > h - 10) visualY = h - 10;
            if (first) {
                ctx.moveTo(x, visualY);
                first = false;
            } else {
                ctx.lineTo(x, visualY);
            }
        }
        ctx.stroke();
        // Shade the material below the roughness
        ctx.lineTo(w - 30, h);
        ctx.lineTo(startX, h);
        ctx.closePath();
        ctx.fillStyle = "rgba(219, 39, 119, 0.05)";
        ctx.fill();
        // 3. Annotations (Draw on the right side to prevent overlap with HUD overlay)
        ctx.fillStyle = "#1e293b";
        ctx.font = "bold 11.5px Outfit";
        ctx.fillText("이송 간격 (f) = " + state.f.toFixed(2) + " mm/rev", w - 220, 26);
        ctx.fillText("최대 높이 거칠기 (R_y) = " + ry.toFixed(2) + " μm", w - 220, 42);
        ctx.fillStyle = "#475569";
        ctx.font = "500 10.5px Inter";
        ctx.fillText("공구 반경 (r) = " + state.r.toFixed(1) + " mm", w - 220, 58);
    }
    // Try starting simulation with robust ready checks
    let attempts = 0;
    function tryStart() {
        attempts++;
        initSimulator();
        if (!initialized) {
            if (attempts < 40) {
                setTimeout(tryStart, 100);
            }
        }
    }
    if (document.readyState === "complete" || document.readyState === "interactive") {
        tryStart();
    } else {
        document.addEventListener("DOMContentLoaded", tryStart);
        window.addEventListener("load", tryStart);
    }
})();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>공작물 외경 직경(D) 지정: 회전 선삭할 환봉형 소재의 지름(10mm ~ 250mm)을 설정합니다.</strong></li>
<li style="margin-bottom: 6px;">주축 스핀들 회전수(N) 설정: 선반 헤드스톡의 회전 속도(100 ~ 4000 RPM)를 입력합니다.</li>
<li style="margin-bottom: 6px;">바이트 이송속도 및 노즈 반경(R) 정의: 한 회전당 가공 인서트의 축방향 이동 이송속도(mm/rev)와 절삭 팁 모서리부의 코너 둥글기 노즈 알(mm)을 조절합니다.</li>
<li style="margin-bottom: 6px;">가공 진행 및 조도 모니터링: 바이트가 진입해 외경을 깎아내며 나선 칩(Chip)을 배출하는 실시간 연동 과정과 표면 마이크로 조도 프로파일 변화를 분석합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계선삭 가공 공식 및 표면 거칠기 수식 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 원주 절삭 속도(V_c)와 스핀들 회전 속도(N)의 상관 공식</h3>
<p>선삭(Turning) 가공에서 <strong>절삭 속도(Cutting Speed, V_c)</strong>는 절삭 바이트 팁과 닿는 공작물 원주면의 접선 주속도(tangential speed)를 가리킵니다.</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">V_c = (&pi; &times; D &times; N) / 1000 &nbsp;[m/min]</p><p>여기서 <code>D</code>는 공작물 외경(mm), <code>N</code>은 주축 속도(RPM)입니다. 수식에서 1000으로 나누는 이유는 직경 단위(mm)를 속도 표준 단위인 미터(m)로 맞추기 위한 단위 환산 계수입니다. 주축 속도 <code>N</code>을 역산하는 공식은 다음과 같습니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">N = (1000 &times; V_c) / (&pi; &times; D) &nbsp;[RPM]</p>
<h3>2. 피드량과 공구 노즈알(r)에 따른 이론적 표면 거칠기(Ra, Ry)</h3>
<p>둥근 반경(노즈 반경, <code>r</code>)을 가진 선반 인서트 바이트가 1회전당 이송량 <code>f</code>로 가공면을 쓸고 지나갈 때, 절삭면에는 나선형 골짜기가 남게 됩니다. 기하학적으로 완벽한 이상적인 표면의 거칠기 수식은 다음과 같습니다.</p><p><strong>① 최대 높이 조도 (Peak-to-Valley, R_y / R_max):</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">R_y = (f&sup2; &times; 10^3) / (8 &times; r) &nbsp;[&mu;m]</p><p><strong>② 중심선 평균 조도 (Arithmetic Average, R_a):</strong> 이론적으로 최대 조도의 약 1/4배 수준으로 근사됩니다.</p><p style="text-align: center; font-weight: bold; background: #fee2e2; padding: 12px; border-radius: 8px; color: #991b1b;">R_a &approx; (f&sup2; &times; 10^3) / (32 &times; r) &nbsp;[&mu;m]</p><p>이론적 조도는 노즈 반경 <code>r</code>이 클수록, 이송속도 <code>f</code>가 느릴수록 감소하여 극도로 미려한 고광택 정밀 다듬질면(Finish face)을 형성하게 됩니다.</p>
<h3>3. 칩 제거 배출율(MRR)과 가공 생산 효율</h3>
<p>단위 시간당 피삭재의 깎여나가는 체적 가공 효율인 <strong>소재 제거율(Material Removal Rate, MRR)</strong>은 절입 깊이 <code>a_p</code>를 적용하여 다음과 같이 산출됩니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">MRR = V_c &times; f &times; a_p &times; 1000 &nbsp;[mm&sup3;/min]</p><p>가공 능률을 향상하기 위해 MRR을 올릴 경우 소요 동력이 상승하고 공구 온도가 급격히 올라가며 마모 수명이 저하되므로 절삭 변수 간의 균형 설계가 대단히 중요합니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>


<h2 style="font-size: 1.4em; font-weight: 700; color: #1f2937; margin-top: 40px; margin-bottom: 15px; border-left: 4px solid #3b82f6; padding-left: 10px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 함께 보면 좋은 공학 글</h2>


<a href="https://myengnote.com/inverter-motor-vfd-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">인버터 슬립 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>


<a href="https://myengnote.com/motor-selection-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">모터 선정 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/machining-cutting-speed-roughness-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>인버터 슬립 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/inverter-motor-vfd-calculator-simulator/</link>
					<comments>https://myengnote.com/inverter-motor-vfd-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Sun, 28 Jun 2026 22:23:06 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[VFD계산]]></category>
		<category><![CDATA[슬립계산]]></category>
		<category><![CDATA[유도전동기]]></category>
		<category><![CDATA[인버터제어]]></category>
		<category><![CDATA[회전자계]]></category>
		<guid isPermaLink="false">https://myengnote.com/inverter-motor-vfd-calculator-simulator/</guid>

					<description><![CDATA[주파수와 모터 극수를 제어하여 유도전동기의 동기 속도, 실제 회전 속도 및 슬립(Slip)을 계산하고, V/F 패턴 곡선 및 고정자 회전자계의 속도 편차를 실시간으로 시각화하는 시뮬레이터입니다. <a href="https://myengnote.com/inverter-motor-vfd-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 인버터 슬립 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for invertermotor-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .invertermotor-calculator-wrapper *, .invertermotor-calculator-wrapper *::before, .invertermotor-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .invertermotor-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7; /* Cobalt blue accent */
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777; /* Pink/magenta accent */
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --color-danger: #ef4444;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .invertermotor-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 15s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-freq::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-torque::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        .segmented-control {
            display: grid;
            grid-template-columns: 1fr 1fr 1fr 1fr;
            background: rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 8px;
            padding: 2px;
            gap: 2px;
        }
        .segmented-control.two-cols {
            grid-template-columns: 1fr 1fr;
        }
        .segment-btn {
            background: transparent;
            border: none;
            outline: none;
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 600;
            padding: 6px;
            cursor: pointer;
            border-radius: 6px;
            transition: all 0.2s ease;
            text-align: center;
        }
        .segment-btn.active {
            background: #ffffff;
            color: var(--color-cyan);
            box-shadow: 0 2px 6px rgba(0,0,0,0.05);
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 10;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(0, 242, 254, 0.08) 0%, rgba(138, 43, 226, 0.03) 100%);
            border: 1px solid rgba(0, 242, 254, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(0, 242, 254, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 32px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(0, 242, 254, 0.2);
            background: rgba(0, 242, 254, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: rgba(0, 242, 254, 0.3);
            background: rgba(0, 242, 254, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: var(--color-cyan);
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        @container inverter-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container inverter-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container inverter-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
            .simulation-metrics-strip {
                flex-direction: column;
                gap: 12px;
            }
            .mini-divider {
                width: 80%;
                height: 1px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.invertermotor-calculator-wrapper .app-main-grid,
.invertermotor-calculator-wrapper .main-grid,
.invertermotor-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.invertermotor-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.invertermotor-calculator-wrapper .simulation-panel,
.invertermotor-calculator-wrapper .canvas-panel,
.invertermotor-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.invertermotor-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.invertermotor-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.invertermotor-calculator-wrapper .simulation-results-section .ratio-readout-box,
.invertermotor-calculator-wrapper .simulation-results-section .re-readout-box,
.invertermotor-calculator-wrapper .simulation-results-section .status-readout-box,
.invertermotor-calculator-wrapper .simulation-results-section .flow-readout-box,
.invertermotor-calculator-wrapper .simulation-results-section [class*="readout-box"],
.invertermotor-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.invertermotor-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.invertermotor-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.invertermotor-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .invertermotor-calculator-wrapper .app-main-grid,
    .invertermotor-calculator-wrapper .main-grid,
    .invertermotor-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .invertermotor-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .invertermotor-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .invertermotor-calculator-wrapper .simulation-panel,
    .invertermotor-calculator-wrapper .canvas-panel,
    .invertermotor-calculator-wrapper .sim-panel,
    .invertermotor-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .invertermotor-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .invertermotor-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .invertermotor-calculator-wrapper .simulation-results-section .re-readout-box,
    .invertermotor-calculator-wrapper .simulation-results-section .status-readout-box,
    .invertermotor-calculator-wrapper .simulation-results-section .flow-readout-box,
    .invertermotor-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .invertermotor-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .invertermotor-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .invertermotor-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.invertermotor-calculator-wrapper .app-container,
.invertermotor-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.invertermotor-calculator-wrapper .simulation-results-section .formula-card,
.invertermotor-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.invertermotor-calculator-wrapper .simulation-results-section .formula-card h4,
.invertermotor-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.invertermotor-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.invertermotor-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="invertermotor-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-arrows-spin fa-spin-slow text-cyan"></i></div>
                <div>
                    <h1>VFD INVERTER</h1>
                    <div class="subtitle">유도전동기 V/F 인버터 제어 물리 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">2D FLUX VECTOR ENGINE ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>인버터 제어 변수</h2>
                </div>
                <!-- Motor Poles selection -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-magnet text-cyan"></i> 모터 극수 (P)</label>
                    </div>
                    <div class="segmented-control" id="control-poles">
                        <button class="segment-btn" data-value="2">2 P</button>
                        <button class="segment-btn active" data-value="4">4 P</button>
                        <button class="segment-btn" data-value="6">6 P</button>
                        <button class="segment-btn" data-value="8">8 P</button>
                    </div>
                </div>
                <!-- Operating Frequency (Hz) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-wave-square text-cyan"></i> 출력 운전 주파수</label>
                        <span class="helper-text">(5 ~ 120 Hz)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-freq" class="custom-number-input" min="5" max="120" step="0.5" value="60">
                        <div class="unit-badge">Hz</div>
                    </div>
                    <input type="range" id="slider-freq" class="custom-slider" min="5" max="120" step="1" value="60">
                </div>
                <!-- Load Torque (Nm) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-rotate text-magenta"></i> 부하 작용 토크</label>
                        <span class="helper-text">(0 ~ 40 Nm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-torque" class="custom-number-input" min="0" max="40" value="15">
                        <div class="unit-badge">Nm</div>
                    </div>
                    <input type="range" id="slider-torque" class="custom-slider" min="0" max="40" step="1" value="15">
                </div>
                <!-- Base Frequency (Hz) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-gauge-high"></i> 계통 기저 주파수</label>
                    </div>
                    <div class="segmented-control two-cols" id="control-base">
                        <button class="segment-btn" data-value="50">50 Hz (유럽/일부)</button>
                        <button class="segment-btn active" data-value="60">60 Hz (한국/미국)</button>
                    </div>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> VFD 운전 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="rated">
                            <div class="preset-icon"><i class="fa-solid fa-play"></i></div>
                            <div class="preset-details"><span class="preset-name">표준 정격 운전</span><span class="preset-spec">60Hz, 4P, 15Nm</span></div>
                        </button>
                        <button class="preset-btn" data-preset="boost">
                            <div class="preset-icon"><i class="fa-solid fa-arrow-up-right-dots"></i></div>
                            <div class="preset-details"><span class="preset-name">저속 기동 토크 부스트</span><span class="preset-spec">15Hz, 4P, 30Nm</span></div>
                        </button>
                        <button class="preset-btn" data-preset="weak">
                            <div class="preset-icon"><i class="fa-solid fa-forward-fast"></i></div>
                            <div class="preset-details"><span class="preset-name">고속 약자속 제어 영역</span><span class="preset-spec">100Hz, 4P, 8Nm</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>실시간 모터 고정자계 및 회전자 동역학</h2>
                                    </div>
                                    <div id="txt-inverter-state" class="canvas-scale-indicator">안전 운전</div>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                </div>
                                <!-- Mini Metrics -->
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <div class="label">동기 속도 (Ns, 자계)</div>
                                        <div id="txt-ns-out" class="value">0 RPM</div>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <div class="label">슬립 주파수 (F_slip)</div>
                                        <div id="txt-fslip-out" class="value">0.0 Hz</div>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">모터 로터 실제 회전수 (Nr)</div>
                                    <div id="txt-nr-out" class="ratio-value">1745 RPM</div>
                                    <div id="txt-slip-percent" class="ratio-type">(실시간 슬립율: 3.1%)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- Volt out -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-bolt text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">인버터 인가 출력 전압 (V_out)</span>
                                            <span id="txt-volt-out" class="card-value">220.0 V</span>
                                        </div>
                                    </div>
                                    <!-- Power out kW -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-solar-panel text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">소요 축 동력 (P_out)</span>
                                            <span id="txt-power-out" class="card-value">2.7 kW (3.6 HP)</span>
                                        </div>
                                    </div>
                                    <!-- V/F Ratio -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-chart-line text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">V / F 비례 제어 상수</span>
                                            <span id="txt-vf-ratio" class="card-value">3.67 V/Hz</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> VFD 유도기 주파수 공식</h4>
                                    <div class="formula-equation">N_s = (120 × f) / P [RPM]</div>
                                    <div class="formula-equation">N_r = N_s × (1 &#8211; s) [RPM]</div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- JavaScript Circuit Simulation Engine -->
    </div>
</div>
<script>
        (function() {
        let isInit = false;
        function initSimulator() {
            if (isInit) return;
            const canvas = document.getElementById('physics-canvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
            isInit = true;
            window.__inverter_initialized = true;
            // DOM Elements
            const sliderFreq = document.getElementById('slider-freq');
            const inputFreq = document.getElementById('input-freq');
            const sliderTorque = document.getElementById('slider-torque');
            const inputTorque = document.getElementById('input-torque');
            const controlPoles = document.getElementById('control-poles');
            const controlBase = document.getElementById('control-base');
            const presetButtons = document.querySelectorAll('.preset-btn');
            const txtNrOut = document.getElementById('txt-nr-out');
            const txtSlipPercent = document.getElementById('txt-slip-percent');
            const txtVoltOut = document.getElementById('txt-volt-out');
            const txtPowerOut = document.getElementById('txt-power-out');
            const txtVfRatio = document.getElementById('txt-vf-ratio');
            const txtInverterState = document.getElementById('txt-inverter-state');
            const txtNsOut = document.getElementById('txt-ns-out');
            const txtFslipOut = document.getElementById('txt-fslip-out');
            // State variables
            const state = {
                poles: 4,
                freq: 60.0,
                torque: 15.0,
                baseFreq: 60.0,
                // Calculated
                ns: 1800,
                nr: 1745,
                volt: 220,
                slip: 0.03,
                // Rotation visualization
                statorAngle: 0.0,
                rotorAngle: 0.0,
                lastTime: 0
            };
            function resizeCanvas() {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            resizeCanvas();
            window.addEventListener('resize', resizeCanvas);
            setTimeout(resizeCanvas, 300);
            // Sync Inputs
            function syncFreqFromSlider() {
                const val = parseFloat(sliderFreq.value);
                inputFreq.value = val.toFixed(1);
                state.freq = val;
                clearPresets();
                updateCalculations();
            }
            function syncFreqFromInput() {
                let val = parseFloat(inputFreq.value);
                if (isNaN(val)) { val = 5; }
                if (val < 5) { val = 5; }
                if (val > 120) { val = 120; }
                sliderFreq.value = Math.round(val);
                state.freq = val;
                clearPresets();
                updateCalculations();
            }
            function syncTorqueFromSlider() {
                const val = parseInt(sliderTorque.value);
                inputTorque.value = val;
                state.torque = val;
                clearPresets();
                updateCalculations();
            }
            function syncTorqueFromInput() {
                let val = parseInt(inputTorque.value);
                if (isNaN(val)) { val = 0; }
                if (val < 0) { val = 0; }
                if (val > 40) { val = 40; }
                sliderTorque.value = val;
                state.torque = val;
                clearPresets();
                updateCalculations();
            }
            // Calculations
            function updateCalculations() {
                // Sync Speed Ns = 120 * f / P
                state.ns = (120.0 * state.freq) / state.poles;
                // V/F Voltage sizing (KEC regulation constants)
                // If freq <= baseFreq, V = 220 * (freq / baseFreq).
                // If freq > baseFreq, V = 220 (Voltage clamped at 220V)
                // Add minor torque boost at low frequencies
                if (state.freq <= state.baseFreq) {
                    const vfConst = 220.0 / state.baseFreq;
                    let boost = 0.0;
                    if (state.freq < 20.0) {
                        // Boost increases as frequency decreases
                        boost = 25.0 * (1.0 - state.freq / 20.0);
                    }
                    state.volt = vfConst * state.freq + boost;
                    if (state.volt > 220.0) {
                        state.volt = 220.0;
                    }
                } else {
                    state.volt = 220.0; // field weakening
                }
                // Slip model: slip s increases with torque and decreases with higher frequency
                // At extremely low speeds, slip increases due to drop in stator flux.
                let baseSlip = 0.025; // 2.5% full load slip
                const torqueRatio = state.torque / 20.0; // normalized around nominal 20 Nm
                // Slip = s_nominal * (T_load/T_rated) * (f_base / f_actual)
                let calculatedSlip = baseSlip * torqueRatio * (state.baseFreq / state.freq);
                if (calculatedSlip > 0.15) {
                    calculatedSlip = 0.15; // cap slip at 15% to avoid virtual stalling
                }
                if (calculatedSlip < 0.0) {
                    calculatedSlip = 0.0;
                }
                state.slip = calculatedSlip;
                state.nr = state.ns * (1.0 - state.slip);
                if (state.nr < 0) {
                    state.nr = 0;
                }
                const slipHz = state.freq * state.slip;
                // Mechanical power out: P = T * omega
                const omega = (2.0 * Math.PI * state.nr) / 60.0;
                const powerWatts = state.torque * omega;
                const powerKw = powerWatts / 1000.0;
                const powerHp = powerKw * 1.341;
                const vfRatioVal = state.volt / state.freq;
                // UI Updates
                txtNsOut.innerText = Math.round(state.ns) + ' RPM';
                txtFslipOut.innerText = slipHz.toFixed(2) + ' Hz';
                txtNrOut.innerText = Math.round(state.nr) + ' RPM';
                txtSlipPercent.innerText = '(실시간 슬립율: ' + (state.slip * 100.0).toFixed(1) + '%)';
                txtVoltOut.innerText = state.volt.toFixed(1) + ' V';
                txtPowerOut.innerText = powerKw.toFixed(2) + ' kW (' + powerHp.toFixed(1) + ' HP)';
                txtVfRatio.innerText = vfRatioVal.toFixed(2) + ' V/Hz';
                // Safety checks
                if (state.slip > 0.08) {
                    txtInverterState.innerText = '경고 (슬립 과밀/과하중)';
                    txtInverterState.style.color = 'var(--color-danger)';
                } else {
                    if (state.freq > state.baseFreq) {
                        txtInverterState.innerText = '운전 중 (약자속 속도제어)';
                        txtInverterState.style.color = '#f59e0b';
                    } else {
                        txtInverterState.innerText = '운전 중 (정속 토크제어)';
                        txtInverterState.style.color = '#10b981';
                    }
                }
            }
            // Presets
            function loadPreset(key) {
                clearPresets();
                presetButtons.forEach(btn => {
                    if (btn.dataset.preset === key) {
                        btn.classList.add('active');
                    }
                });
                if (key === 'rated') {
                    state.poles = 4;
                    state.freq = 60.0;
                    state.torque = 15.0;
                    state.baseFreq = 60.0;
                }
                if (key === 'boost') {
                    state.poles = 4;
                    state.freq = 15.0;
                    state.torque = 30.0;
                    state.baseFreq = 60.0;
                }
                if (key === 'weak') {
                    state.poles = 4;
                    state.freq = 100.0;
                    state.torque = 8.0;
                    state.baseFreq = 60.0;
                }
                // Sync UI elements
                document.querySelectorAll('#control-poles .segment-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (parseInt(btn.dataset.value) === state.poles) {
                        btn.classList.add('active');
                    }
                });
                document.querySelectorAll('#control-base .segment-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (parseInt(btn.dataset.value) === state.baseFreq) {
                        btn.classList.add('active');
                    }
                });
                inputFreq.value = state.freq.toFixed(1);
                sliderFreq.value = Math.round(state.freq);
                inputTorque.value = state.torque;
                sliderTorque.value = state.torque;
                updateCalculations();
            }
            function clearPresets() {
                presetButtons.forEach(btn => btn.classList.remove('active'));
            }
            // Bind Event Listeners
            sliderFreq.addEventListener('input', syncFreqFromSlider);
            inputFreq.addEventListener('change', syncFreqFromInput);
            sliderTorque.addEventListener('input', syncTorqueFromSlider);
            inputTorque.addEventListener('change', syncTorqueFromInput);
            // Poles
            document.querySelectorAll('#control-poles .segment-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll('#control-poles .segment-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    state.poles = parseInt(btn.dataset.value);
                    clearPresets();
                    updateCalculations();
                });
            });
            // Base Freq
            document.querySelectorAll('#control-base .segment-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll('#control-base .segment-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    state.baseFreq = parseInt(btn.dataset.value);
                    clearPresets();
                    updateCalculations();
                });
            });
            presetButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    loadPreset(btn.dataset.preset);
                });
            });
            // Animation Loop
            function animate(currentTime) {
                requestAnimationFrame(animate);
                let dt = (currentTime - state.lastTime) / 1000;
                if (isNaN(dt)) { dt = 0.016; }
                if (dt < 0) { dt = 0.016; }
                if (dt > 1.0) { dt = 0.016; }
                state.lastTime = currentTime;
                const width = canvas.width / (window.devicePixelRatio || 1);
                const height = canvas.height / (window.devicePixelRatio || 1);
                ctx.clearRect(0, 0, width, height);
                // Draw Grid
                ctx.save();
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
                ctx.lineWidth = 1;
                const gridSpacing = 25;
                for (let x = 0; x < width; x += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                ctx.restore();
                // Geometry
                const motorCx = width * 0.36;
                const motorCy = height * 0.50;
                const statorR = Math.min(width, height) * 0.23;
                const rotorR = statorR * 0.65;
                // Sync spinning speeds visually (apply stroboscopic capping for visual rendering)
                const visNs = Math.min(state.ns * 0.005, 10.0);
                const visNr = Math.min(state.nr * 0.005, 10.0);
                state.statorAngle += visNs * dt;
                state.rotorAngle += visNr * dt;
                // Draw Legend/Scale in Top Left Corner (Enlarge font size and apply solid colors)
                ctx.save();
                ctx.textAlign = "left";
                // Stator field vector legend
                ctx.fillStyle = "#0284c7";
                ctx.font = "bold 12px Inter";
                ctx.fillText("■ Bs (고정자 회전자계 벡터)", 16, 24);
                // Rotor field vector legend
                ctx.fillStyle = "#db2777";
                ctx.font = "bold 12px Inter";
                ctx.fillText("■ Br (회전자 극성/속도 벡터)", 16, 40);
                // Slip/Lag explanation
                ctx.fillStyle = "#475569";
                ctx.font = "bold 10.5px Inter";
                ctx.fillText("※ 회전자계(Ns)와 로터(Nr)의 속도차(슬립)만큼 두 벡터 사이의 부하각이 벌어집니다.", 16, 56);
                ctx.restore();
                // A. Draw Stator Core Ring
                ctx.save();
                ctx.translate(motorCx, motorCy);
                ctx.fillStyle = "rgba(241, 245, 249, 0.95)";
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.arc(0, 0, statorR, 0, Math.PI * 2);
                ctx.fill();
                ctx.stroke();
                // Draw stator magnetic poles indicators
                ctx.fillStyle = "rgba(2, 132, 199, 0.06)";
                ctx.beginPath();
                ctx.arc(0, 0, statorR - 8, 0, Math.PI * 2);
                ctx.fill();
                // Draw actual copper coil poles wrapped around the stator ring
                const polesCount = state.poles;
                ctx.save();
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 2.5;
                for (let i = 0; i < polesCount; i++) {
                    const poleAngle = (i * 2 * Math.PI) / polesCount;
                    // Stator current phase value for this pole
                    const val = Math.cos(state.statorAngle * (polesCount / 2) - i * Math.PI);
                    // Pole core peg
                    const px = Math.cos(poleAngle) * (statorR - 12);
                    const py = Math.sin(poleAngle) * (statorR - 12);
                    const pxOuter = Math.cos(poleAngle) * statorR;
                    const pyOuter = Math.sin(poleAngle) * statorR;
                    ctx.beginPath();
                    ctx.moveTo(pxOuter, pyOuter);
                    ctx.lineTo(px, py);
                    ctx.stroke();
                    // Copper coil wrapped around the core
                    ctx.save();
                    ctx.translate(px, py);
                    ctx.rotate(poleAngle + Math.PI / 2);
                    // Copper orange color
                    ctx.fillStyle = "rgba(217, 119, 6, 0.85)";
                    ctx.beginPath();
                    ctx.roundRect(-8, -4, 16, 8, 2);
                    ctx.fill();
                    ctx.stroke();
                    // Dynamic magnetic field glow based on phase current polarity (North is red, South is blue)
                    if (val > 0) {
                        ctx.fillStyle = `rgba(239, 68, 68, ${0.1 + 0.55 * val})`; // North (Red)
                        ctx.shadowBlur = 8 * val;
                        ctx.shadowColor = "#ef4444";
                    } else {
                        ctx.fillStyle = `rgba(59, 130, 246, ${0.1 + 0.55 * Math.abs(val)})`; // South (Blue)
                        ctx.shadowBlur = 8 * Math.abs(val);
                        ctx.shadowColor = "#3b80f6";
                    }
                    ctx.beginPath();
                    ctx.arc(0, -6, 5, 0, Math.PI * 2);
                    ctx.fill();
                    // Draw N/S label text inside the glowing dot
                    ctx.fillStyle = "#ffffff";
                    ctx.font = "bold 6.5px Inter";
                    ctx.textAlign = "center";
                    ctx.fillText(val > 0 ? "N" : "S", 0, -4);
                    ctx.restore();
                }
                ctx.restore();
                // Draw magnetic flux field lines in the air gap
                ctx.save();
                ctx.strokeStyle = "rgba(2, 132, 199, 0.12)";
                ctx.lineWidth = 1;
                const fluxLinesCount = 8;
                for (let i = 0; i < fluxLinesCount; i++) {
                    const angle = state.statorAngle + (i * 2 * Math.PI) / fluxLinesCount;
                    ctx.beginPath();
                    ctx.arc(
                        Math.cos(angle) * (statorR - 16),
                        Math.sin(angle) * (statorR - 16),
                        8,
                        angle - Math.PI / 4,
                        angle + Math.PI / 4
                    );
                    ctx.stroke();
                }
                ctx.restore();
                // B. Draw Inner Rotor Ring (spinning at Nr)
                ctx.save();
                ctx.rotate(state.rotorAngle);
                // Rotor steel body
                ctx.fillStyle = "#ffffff";
                ctx.strokeStyle = "#db2777";
                ctx.lineWidth = 3;
                ctx.beginPath();
                ctx.arc(0, 0, rotorR, 0, Math.PI * 2);
                ctx.fill();
                ctx.stroke();
                // Draw copper rotor winding bars (circular bars near the rotor edge)
                ctx.fillStyle = "#d97706"; // copper bars
                const bars = 18;
                for (let i = 0; i < bars; i++) {
                    const angle = (i * 2 * Math.PI) / bars;
                    const bx = Math.cos(angle) * (rotorR - 8);
                    const by = Math.sin(angle) * (rotorR - 8);
                    ctx.beginPath();
                    ctx.arc(bx, by, 3.5, 0, Math.PI * 2);
                    ctx.fill();
                }
                // Rotational index dot
                ctx.fillStyle = "#db2777";
                ctx.beginPath();
                ctx.arc(rotorR - 18, 0, 5, 0, Math.PI * 2);
                ctx.fill();
                ctx.restore(); // restore rotor rotation
                // Draw 3-Phase Rotating Magnetic Field Vectors (Bs and Br) in the center of the motor
                ctx.save();
                // Vector Bs (Stator Rotating Field Vector) - bright cyan arrow
                ctx.strokeStyle = "var(--color-cyan)";
                ctx.lineWidth = 3.5;
                ctx.shadowBlur = 8;
                ctx.shadowColor = "var(--color-cyan)";
                const bsLx = Math.cos(state.statorAngle) * (rotorR * 0.75);
                const bsLy = Math.sin(state.statorAngle) * (rotorR * 0.75);
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(bsLx, bsLy);
                ctx.stroke();
                // Vector Bs arrow head
                ctx.save();
                ctx.translate(bsLx, bsLy);
                ctx.rotate(state.statorAngle);
                ctx.fillStyle = "var(--color-cyan)";
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(-6, -4);
                ctx.lineTo(-6, 4);
                ctx.closePath();
                ctx.fill();
                ctx.restore();
                // Vector Br (Rotor Field Vector) - bright magenta arrow
                ctx.strokeStyle = "var(--color-magenta)";
                ctx.lineWidth = 3;
                ctx.shadowBlur = 8;
                ctx.shadowColor = "var(--color-magenta)";
                const brLx = Math.cos(state.rotorAngle) * (rotorR * 0.68);
                const brLy = Math.sin(state.rotorAngle) * (rotorR * 0.68);
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(brLx, brLy);
                ctx.stroke();
                // Vector Br arrow head
                ctx.save();
                ctx.translate(brLx, brLy);
                ctx.rotate(state.rotorAngle);
                ctx.fillStyle = "var(--color-magenta)";
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(-5, -3.5);
                ctx.lineTo(-5, 3.5);
                ctx.closePath();
                ctx.fill();
                ctx.restore();
                ctx.restore(); // restore vectors
                ctx.restore(); // restore translate
                // C. Render V/F Curve Graph
                ctx.save();
                const plotX = width * 0.65;
                const plotW = width * 0.26;
                const plotH = height * 0.40;
                const plotY = height * 0.45;
                // Draw graph background container (widen left &#038; right sides to prevent label overflow/clipping)
                ctx.fillStyle = "rgba(255, 255, 255, 0.95)";
                ctx.strokeStyle = "rgba(2, 132, 199, 0.15)";
                ctx.lineWidth = 1.5;
                ctx.beginPath();
                ctx.roundRect(plotX - 40, plotY - 30, plotW + 85, plotH + 50, 8);
                ctx.fill();
                ctx.stroke();
                // Draw Graph Title (larger, bold, clear color, moved higher to distinguish from Y-axis label)
                ctx.fillStyle = "#1e293b";
                ctx.font = "bold 11px Inter";
                ctx.textAlign = "center";
                ctx.fillText("V/F 패턴 제어 곡선 (운전 특성)", plotX + plotW / 2, plotY - 18);
                // Draw constant torque and field weakening region boundaries
                const baseF = state.baseFreq;
                const baseFx = plotX + (baseF / 120.0) * plotW;
                // Define getGraphY and dynamic operating coordinates early to conditionally hide ticks
                const getGraphY = (fVal) => {
                    let v = 0;
                    if (fVal <= baseF) {
                        const vf = 220.0 / baseF;
                        let b = 0;
                        if (fVal < 20.0) {
                            b = 25.0 * (1.0 - fVal / 20.0);
                        }
                        v = vf * fVal + b;
                        if (v > 220.0) { v = 220.0; }
                    } else {
                        v = 220.0;
                    }
                    return plotY + plotH - (v / 250.0) * plotH;
                };
                const currentGx = plotX + (state.freq / 120.0) * plotW;
                const currentGy = getGraphY(state.freq);
                const ratedVy = plotY + plotH - (220.0 / 250.0) * plotH;
                // Constant torque region background (soft blue tint)
                ctx.fillStyle = "rgba(2, 132, 199, 0.03)";
                ctx.beginPath();
                ctx.rect(plotX, plotY, baseFx - plotX, plotH);
                ctx.fill();
                // Field weakening region background (soft purple tint)
                ctx.fillStyle = "rgba(124, 58, 237, 0.03)";
                ctx.beginPath();
                ctx.rect(baseFx, plotY, plotX + plotW - baseFx, plotH);
                ctx.fill();
                // Region Labels at the bottom of graph
                ctx.fillStyle = "#475569";
                ctx.font = "bold 9.5px Inter";
                ctx.textAlign = "center";
                ctx.fillText("정토크 영역", plotX + (baseFx - plotX) / 2, plotY + plotH - 8);
                ctx.fillText("약자속 영역", baseFx + (plotX + plotW - baseFx) / 2, plotY + plotH - 8);
                // Draw Axes (darker, clearer stroke)
                ctx.strokeStyle = "#334155";
                ctx.lineWidth = 2;
                ctx.beginPath();
                // Y-axis
                ctx.moveTo(plotX, plotY - 5);
                ctx.lineTo(plotX, plotY + plotH);
                // X-axis
                ctx.lineTo(plotX + plotW + 8, plotY + plotH);
                ctx.stroke();
                // Axis arrows
                ctx.fillStyle = "#334155";
                ctx.beginPath();
                // Y-axis arrow
                ctx.moveTo(plotX - 3.5, plotY - 4);
                ctx.lineTo(plotX + 3.5, plotY - 4);
                ctx.lineTo(plotX, plotY - 10);
                ctx.closePath();
                // X-axis arrow
                ctx.moveTo(plotX + plotW + 7, plotY + plotH - 3.5);
                ctx.lineTo(plotX + plotW + 7, plotY + plotH + 3.5);
                ctx.lineTo(plotX + plotW + 13, plotY + plotH);
                ctx.closePath();
                ctx.fill();
                // Axis Labels (positioned clearly outside axis boundaries to distinguish from title)
                ctx.font = "bold 10.5px Inter";
                ctx.fillStyle = "#1e293b";
                // Y-axis label (positioned to the left of the vertical axis, right-aligned)
                ctx.textAlign = "right";
                ctx.fillText("V [V]", plotX - 8, plotY - 2);
                // X-axis label (positioned above the horizontal axis line, left-aligned)
                ctx.textAlign = "left";
                ctx.fillText("f [Hz]", plotX + plotW + 12, plotY + plotH - 3);
                // Static Ticks on Axes
                ctx.font = "bold 9.5px Inter";
                ctx.fillStyle = "#64748b";
                ctx.textAlign = "center";
                // X-axis static ticks: 0, 120 (conditionally hidden to avoid overlapping)
                if (currentGx - plotX > 20) {
                    ctx.fillText("0", plotX, plotY + plotH + 11);
                }
                if (plotX + plotW - currentGx > 28) {
                    ctx.fillText("120", plotX + plotW, plotY + plotH + 11);
                }
                // Y-axis static tick: 220V line y coordinate (conditionally hidden to avoid overlapping with currentGy)
                if (Math.abs(currentGy - ratedVy) > 10) {
                    ctx.textAlign = "right";
                    ctx.fillText("220V", plotX - 6, ratedVy + 3);
                }
                // Static gridlines (dashed) at 220V and Base Freq (60Hz)
                ctx.strokeStyle = "rgba(71, 85, 105, 0.12)";
                ctx.lineWidth = 1;
                ctx.setLineDash([3, 3]);
                // Vertical line at Base Freq (60Hz)
                ctx.beginPath();
                ctx.moveTo(baseFx, plotY);
                ctx.lineTo(baseFx, plotY + plotH);
                ctx.stroke();
                // Horizontal line at 220V
                ctx.beginPath();
                ctx.moveTo(plotX, ratedVy);
                ctx.lineTo(plotX + plotW, ratedVy);
                ctx.stroke();
                ctx.setLineDash([]); // Reset line dash
                // Draw V/F curve line (distinct purple color)
                ctx.strokeStyle = "#7c3aed";
                ctx.lineWidth = 3;
                ctx.beginPath();
                for (let f = 0; f <= 120; f += 2) {
                    const gx = plotX + (f / 120.0) * plotW;
                    const gy = getGraphY(f);
                    if (f === 0) {
                        ctx.moveTo(gx, gy);
                    } else {
                        ctx.lineTo(gx, gy);
                    }
                }
                ctx.stroke();
                // Dynamic Operating Point &#038; Crosshair Guidelines
                // Draw Crosshairs (cyan dashed lines indicating current coordinates)
                ctx.strokeStyle = "#0284c7";
                ctx.lineWidth = 1.2;
                ctx.setLineDash([3, 3]);
                // Vertical crosshair to X-axis
                ctx.beginPath();
                ctx.moveTo(currentGx, currentGy);
                ctx.lineTo(currentGx, plotY + plotH);
                ctx.stroke();
                // Horizontal crosshair to Y-axis
                ctx.beginPath();
                ctx.moveTo(currentGx, currentGy);
                ctx.lineTo(plotX, currentGy);
                ctx.stroke();
                ctx.setLineDash([]); // Reset
                // Draw Dynamic Ticks/Values on Axes in highlighted color (#0284c7)
                ctx.font = "bold 10px Inter";
                ctx.fillStyle = "#0284c7";
                ctx.textAlign = "center";
                // X-axis dynamic frequency value
                ctx.fillText(state.freq.toFixed(1) + "Hz", currentGx, plotY + plotH + 11);
                // Y-axis dynamic voltage value
                ctx.textAlign = "right";
                ctx.fillText(Math.round(state.volt) + "V", plotX - 6, currentGy + 3.5);
                // Draw current operating point dot on graph (pulsing glowing dot)
                // Outer glow halo
                ctx.fillStyle = "rgba(2, 132, 199, 0.25)";
                ctx.beginPath();
                ctx.arc(currentGx, currentGy, 9, 0, Math.PI * 2);
                ctx.fill();
                // Inner solid dot
                ctx.fillStyle = "#0284c7";
                ctx.beginPath();
                ctx.arc(currentGx, currentGy, 5.5, 0, Math.PI * 2);
                ctx.fill();
                // Core highlight dot
                ctx.fillStyle = "#ffffff";
                ctx.beginPath();
                ctx.arc(currentGx, currentGy, 2, 0, Math.PI * 2);
                ctx.fill();
                // Draw coordinate text next to the dot (no background box, larger and high-contrast dark font, placed above the dashed line)
                ctx.fillStyle = "#0f172a";
                ctx.font = "bold 11px Inter";
                if (currentGx + 8 + 65 > plotX + plotW + 15) {
                    ctx.textAlign = "right";
                    ctx.fillText(`${state.freq.toFixed(1)}Hz, ${Math.round(state.volt)}V`, currentGx - 8, currentGy - 8);
                } else {
                    ctx.textAlign = "left";
                    ctx.fillText(`${state.freq.toFixed(1)}Hz, ${Math.round(state.volt)}V`, currentGx + 8, currentGy - 8);
                }
                ctx.restore();
            }
            // Sync preset and run initial calculations
            loadPreset('rated');
            requestAnimationFrame(animate);
            // Right-click & Keyboard shortcuts block
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
                alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                return false;
            }, { capture: true });
            document.addEventListener('selectstart', function(e) {
                e.preventDefault();
                return false;
            }, { capture: true });
            document.addEventListener('keydown', function(e) {
                if (e.key === 'F12') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.ctrlKey) {
                    if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                    if (e.shiftKey) {
                        if (['i','I','j','J','c','C'].includes(e.key)) {
                            e.preventDefault();
                            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                            return false;
                        }
                    }
                }
            }, { capture: true });
        }
        let initAttempts = 0;
        function tryInit() {
            initAttempts++;
            initSimulator();
            if (!window.__inverter_initialized) {
                if (initAttempts < 50) {
                    setTimeout(tryInit, 100);
                }
            }
        }
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            tryInit();
        } else {
            document.addEventListener('DOMContentLoaded', tryInit);
            window.addEventListener('load', tryInit);
        }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>모터 극수(P) 설정: 전동기의 극수(2P, 4P, 6P, 8P)를 선정하여 동기 속도의 기준을 세웁니다.</strong></li>
<li style="margin-bottom: 6px;">출력 주파수(Hz) 조절: 인버터(VFD)가 출력할 운전 주파수(5Hz ~ 120Hz)를 조절하여 자계 속도를 정합니다.</li>
<li style="margin-bottom: 6px;">부하 토크(Nm) 입력: 모터 축에 작용하는 기계적 부하 토크를 조정하여 슬립(Slip) 속도 감쇠를 관찰합니다.</li>
<li style="margin-bottom: 6px;">실시간 2D 동역학 자계 모니터링: 고정자가 만드는 초고속 회전자계(Ns)와 실제 슬립이 반영되어 따라가는 회전자(Nr)의 속도 격차 및 실시간 V/F 매핑 커브점을 관찰합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 유도전동기 V/F 인버터 제어 공식 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 인버터(VFD) 제어의 기본 원리 및 V/F 일정 제어</h3>
<p>가변 주파수 드라이브(VFD, Variable Frequency Drive) 또는 인버터는 삼상 유도전동기에 인가되는 전원의 주파수(<code>f</code>)와 전압(<code>V</code>)을 동적으로 변환하여 모터의 회전 속도를 고효율로 정밀 제어하는 핵심 전력 제어 장치입니다.</p><ul><li><strong>V/F 일정 제어 (Constant Volts-per-Hertz Control):</strong> 주파수를 낮출 때 전압을 그대로 유지하면 철심이 자기적으로 포화되어 과전류가 흐르고 모터가 손상됩니다. 따라서 주파수에 비례하여 공급 전압을 선형적으로 줄여 철심 내부의 자속 밀도를 일정하게 유지합니다.</li><li><strong>저속 토크 부스트 (Torque Boost):</strong> 극저속 영역(10Hz 이하)에서는 고정자 권선 저항에 의한 전압 강하가 상대적으로 커져 토크가 급감합니다. 인버터는 이를 보상하기 위해 저주파 구동 시 전압을 약간 높여 시동 토크를 유지하는 부스트 처리를 수행합니다.</li></ul>
<h3>2. 유도전동기 동기 속도(Ns), 로터 속도(Nr) 및 슬립(s) 공식 유도</h3>
<p>인버터 유도 제어 설계 공식은 다음과 같은 회전기계 동역학 공식을 따릅니다.</p><p><strong>① 동기 회전 속도 (Synchronous Speed, Ns):</strong> 고정자 권선에 삼상 전류가 인가되었을 때 형성되는 회전자계의 이론상 회전 속도입니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">N_s = (120 &times; f) / P &nbsp;[RPM]</p><p><strong>② 슬립 (Slip, s) 및 회전자 실제 속도 (Rotor Speed, Nr):</strong> 유도전동기는 자계의 변화로 로터에 전류가 유도되므로 회전자는 항상 자계 속도보다 뒤처져서 돕니다. 이 속도 편차 비율을 슬립(<code>s</code>)이라 합니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">s = (N_s - N_r) / N_s &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; N_r = N_s &times; (1 - s) &nbsp;[RPM]</p><p><strong>③ 기계적 출력 동력 (Power, P):</strong> 실제 회전 속도 <code>Nr</code>과 작용 부하 토크 <code>T</code>의 곱으로 소요 출력 동력을 결정합니다.</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">P_out = T &times; &omega; = T &times; (2 &pi; &times; N_r / 60) / 1000 &nbsp;[kW]</p>
<h3>3. 자계 기동 한계 및 약자속 제어 (Field Weakening)</h3>
<p>인버터 속도 제어 범위는 기저 주파수(Base Frequency, 50Hz/60Hz)를 기준으로 두 영역으로 나뉩니다.</p><ul><li><strong>정토크 제어 영역 (Constant Torque Region):</strong> 기저 주파수 이하의 영역으로 V/F 비율을 일정하게 유지하여 최대 사용 가능 토크가 일정합니다.</li><li><strong>정출력/약자속 제어 영역 (Constant Power / Field Weakening Region):</strong> 기저 주파수 이상의 초고주파 영역입니다. 전압은 전원 계통 한계로 더 높일 수 없으므로(정전압 고정), 주파수만 단독으로 높여 자속 밀도를 약화시키고, 이에 따라 출력 토크는 주파수에 반비례하여 감소하지만 총 기계적 출력 동력(kW)은 일정하게 유지됩니다.</li></ul>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>


<h2 style="font-size: 1.4em; font-weight: 700; color: #1f2937; margin-top: 40px; margin-bottom: 15px; border-left: 4px solid #3b82f6; padding-left: 10px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 함께 보면 좋은 공학 글</h2>


<a href="https://myengnote.com/motor-selection-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">모터 선정 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>


<a href="https://myengnote.com/cable-sizing-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">케이블 허용전류 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/inverter-motor-vfd-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>모터 선정 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/motor-selection-calculator-simulator/</link>
					<comments>https://myengnote.com/motor-selection-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Sat, 27 Jun 2026 21:18:07 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[관성모멘트]]></category>
		<category><![CDATA[동력설계]]></category>
		<category><![CDATA[모터선정]]></category>
		<category><![CDATA[부하시뮬레이션]]></category>
		<category><![CDATA[토크계산]]></category>
		<guid isPermaLink="false">https://myengnote.com/motor-selection-calculator-simulator/</guid>

					<description><![CDATA[부하의 질량, 직경, 가속 시간 및 목표 회전수를 설정하여 소요 토크, 관성모멘트, 가속 동력 및 효율을 고려한 최적의 모터 규격(kW)을 실시간으로 계산하고 시각화하는 시뮬레이터입니다. <a href="https://myengnote.com/motor-selection-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 모터 선정 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for motorselection-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .motorselection-calculator-wrapper *, .motorselection-calculator-wrapper *::before, .motorselection-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .motorselection-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7; /* Cobalt blue accent */
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777; /* Pink/magenta accent */
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --color-danger: #ef4444;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .motorselection-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 15s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-mass::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-radius::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        #slider-rpm::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 10px var(--color-purple); }
        .control-actions {
            display: grid;
            grid-template-columns: 1fr;
            gap: 10px;
            margin-top: 10px;
        }
        .action-btn {
            background: rgba(0, 0, 0, 0.02);
            border: 1px solid var(--color-border);
            color: var(--color-text-main);
            padding: 12px;
            border-radius: 10px;
            font-size: 13px;
            font-weight: 700;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .action-btn:hover {
            background: rgba(0, 0, 0, 0.04);
            border-color: var(--color-border-hover);
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 10;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(0, 242, 254, 0.08) 0%, rgba(138, 43, 226, 0.03) 100%);
            border: 1px solid rgba(0, 242, 254, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(0, 242, 254, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 30px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(0, 242, 254, 0.2);
            background: rgba(0, 242, 254, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: rgba(0, 242, 254, 0.3);
            background: rgba(0, 242, 254, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: var(--color-cyan);
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        @container motor-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container motor-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container motor-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
            .simulation-metrics-strip {
                flex-direction: column;
                gap: 12px;
            }
            .mini-divider {
                width: 80%;
                height: 1px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.motorselection-calculator-wrapper .app-main-grid,
.motorselection-calculator-wrapper .main-grid,
.motorselection-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.motorselection-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.motorselection-calculator-wrapper .simulation-panel,
.motorselection-calculator-wrapper .canvas-panel,
.motorselection-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.motorselection-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.motorselection-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.motorselection-calculator-wrapper .simulation-results-section .ratio-readout-box,
.motorselection-calculator-wrapper .simulation-results-section .re-readout-box,
.motorselection-calculator-wrapper .simulation-results-section .status-readout-box,
.motorselection-calculator-wrapper .simulation-results-section .flow-readout-box,
.motorselection-calculator-wrapper .simulation-results-section [class*="readout-box"],
.motorselection-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.motorselection-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.motorselection-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.motorselection-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .motorselection-calculator-wrapper .app-main-grid,
    .motorselection-calculator-wrapper .main-grid,
    .motorselection-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .motorselection-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .motorselection-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .motorselection-calculator-wrapper .simulation-panel,
    .motorselection-calculator-wrapper .canvas-panel,
    .motorselection-calculator-wrapper .sim-panel,
    .motorselection-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .motorselection-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .motorselection-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .motorselection-calculator-wrapper .simulation-results-section .re-readout-box,
    .motorselection-calculator-wrapper .simulation-results-section .status-readout-box,
    .motorselection-calculator-wrapper .simulation-results-section .flow-readout-box,
    .motorselection-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .motorselection-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .motorselection-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .motorselection-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.motorselection-calculator-wrapper .app-container,
.motorselection-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.motorselection-calculator-wrapper .simulation-results-section .formula-card,
.motorselection-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.motorselection-calculator-wrapper .simulation-results-section .formula-card h4,
.motorselection-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.motorselection-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.motorselection-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="motorselection-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-server fa-spin-slow text-cyan"></i></div>
                <div>
                    <h1>MOTOR SELECTION</h1>
                    <div class="subtitle">모터 선정 계산기 &#038; 동역학 부하 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">MOTOR IEC COMPLIANT</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>부하 및 모션 설계 변수</h2>
                </div>
                <!-- Load Mass (kg) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-weight-hanging text-cyan"></i> 부하 질량 (M)</label>
                        <span class="helper-text">(10 ~ 1000 kg)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-mass" class="custom-number-input" min="10" max="1000" value="200">
                        <div class="unit-badge">kg</div>
                    </div>
                    <input type="range" id="slider-mass" class="custom-slider" min="10" max="1000" step="10" value="200">
                </div>
                <!-- Drum Radius (m) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-circle-dot text-magenta"></i> 회전 반경 (R)</label>
                        <span class="helper-text">(0.05 ~ 1.0 m)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-radius" class="custom-number-input" min="0.05" max="1.0" step="0.01" value="0.2">
                        <div class="unit-badge">m</div>
                    </div>
                    <input type="range" id="slider-radius" class="custom-slider" min="5" max="100" step="1" value="20">
                </div>
                <!-- Target RPM -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-gauge-high text-purple"></i> 목표 회전수 (N)</label>
                        <span class="helper-text">(10 ~ 1500 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="10" max="1500" value="200">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider" min="10" max="1500" step="10" value="200">
                </div>
                <!-- Accel Time (s) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-clock"></i> 가속 목표 시간</label>
                        <span class="helper-text">(0.1 ~ 10.0 s)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-taccel" class="custom-number-input" min="0.1" max="10.0" step="0.1" value="1.5">
                        <div class="unit-badge">sec</div>
                    </div>
                </div>
                <!-- Efficiency (%) and Friction -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-gear"></i> 전동부 기계효율</label>
                        <span class="helper-text">(50 ~ 100 %)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-efficiency" class="custom-number-input" min="50" max="100" value="85">
                        <div class="unit-badge">%</div>
                    </div>
                </div>
                <!-- Run Cycle Action -->
                <div class="control-actions">
                    <button id="btn-trigger" class="action-btn">
                        <i class="fa-solid fa-play"></i> <span>구동 시뮬레이션 시작</span>
                    </button>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 부하 시나리오 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="conveyor">
                            <div class="preset-icon"><i class="fa-solid fa-dolly"></i></div>
                            <div class="preset-details"><span class="preset-name">컨베이어 이송기</span><span class="preset-spec">200kg, 0.15m, 120 RPM</span></div>
                        </button>
                        <button class="preset-btn" data-preset="fan">
                            <div class="preset-icon"><i class="fa-solid fa-wind"></i></div>
                            <div class="preset-details"><span class="preset-name">고속 환풍 펜</span><span class="preset-spec">40kg, 0.6m, 900 RPM</span></div>
                        </button>
                        <button class="preset-btn" data-preset="hoist">
                            <div class="preset-icon"><i class="fa-solid fa-anchor"></i></div>
                            <div class="preset-details"><span class="preset-name">중량물 권상 크레인</span><span class="preset-spec">800kg, 0.25m, 60 RPM</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>실시간 기계 구동 및 물리 모니터링</h2>
                                    </div>
                                    <div id="txt-motion-state" class="canvas-scale-indicator">정지상태</div>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                </div>
                                <!-- Mini Metrics -->
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <div class="label">실시간 속도</div>
                                        <div id="txt-live-speed" class="value">0.0 RPM</div>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <div class="label">가속도 ( 각가속도 )</div>
                                        <div id="txt-live-accel" class="value">0.0 rad/s²</div>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">추천 모터 정격 출력 (kW)</div>
                                    <div id="txt-motor-kw" class="ratio-value">0.75 kW</div>
                                    <div id="txt-motor-hp" class="ratio-type">(1.0 HP 표준 규격)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- Required Torque -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-rotate text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">총 피크 기동 토크 (T_max)</span>
                                            <span id="txt-torque-out" class="card-value">12.5 Nm</span>
                                        </div>
                                    </div>
                                    <!-- Load Inertia -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-circle text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">부하 관성 모멘트 (J)</span>
                                            <span id="txt-inertia-out" class="card-value">4.0 kg·m²</span>
                                        </div>
                                    </div>
                                    <!-- Peak Mech Power -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-bolt text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">소요 피크 동력 (P_peak)</span>
                                            <span id="txt-power-out" class="card-value">0.52 kW</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 모터 동역학 설계 공식</h4>
                                    <div class="formula-equation">J = 0.5 × M × R² [kg·m²]</div>
                                    <div class="formula-equation">T = J × α + T_friction [Nm]</div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- JavaScript Circuit Simulation Engine -->
    </div>
</div>
<script>
        (function() {
        let isInit = false;
        function initSimulator() {
            if (isInit) return;
            const canvas = document.getElementById('physics-canvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
            isInit = true;
            window.__motor_initialized = true;
            // DOM Elements
            const sliderMass = document.getElementById('slider-mass');
            const inputMass = document.getElementById('input-mass');
            const sliderRadius = document.getElementById('slider-radius');
            const inputRadius = document.getElementById('input-radius');
            const sliderRpm = document.getElementById('slider-rpm');
            const inputRpm = document.getElementById('input-rpm');
            const inputTaccel = document.getElementById('input-taccel');
            const inputEfficiency = document.getElementById('input-efficiency');
            const btnTrigger = document.getElementById('btn-trigger');
            const presetButtons = document.querySelectorAll('.preset-btn');
            const txtMotorKw = document.getElementById('txt-motor-kw');
            const txtMotorHp = document.getElementById('txt-motor-hp');
            const txtTorqueOut = document.getElementById('txt-torque-out');
            const txtInertiaOut = document.getElementById('txt-inertia-out');
            const txtPowerOut = document.getElementById('txt-power-out');
            const txtMotionState = document.getElementById('txt-motion-state');
            const txtLiveSpeed = document.getElementById('txt-live-speed');
            const txtLiveAccel = document.getElementById('txt-live-accel');
            // State variables
            const state = {
                mass: 200.0,
                radius: 0.20,
                rpm: 200.0,
                taccel: 1.5,
                efficiency: 85.0,
                // Motion profile simulation
                timeInCycle: 0.0,
                currentSpeed: 0.0, // RPM
                isRunning: false,
                phase: "stopped", // stopped, accel, run, brake
                rotationAngle: 0.0,
                // Graph data
                graphPoints: [],
                lastTime: 0
            };
            // Standard Motors Catalog (kW)
            const standardMotors = [0.1, 0.2, 0.4, 0.75, 1.5, 2.2, 3.7, 5.5, 7.5, 11.0, 15.0, 22.0, 30.0, 37.0, 45.0, 55.0, 75.0];
            function resizeCanvas() {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            resizeCanvas();
            window.addEventListener('resize', resizeCanvas);
            setTimeout(resizeCanvas, 300);
            // Sync Z1 Input and Slider
            function syncMassFromSlider() {
                const val = parseInt(sliderMass.value);
                inputMass.value = val;
                state.mass = val;
                clearPresets();
                updateCalculations();
            }
            function syncMassFromInput() {
                let val = parseInt(inputMass.value);
                if (isNaN(val)) { val = 10; }
                if (val < 10) { val = 10; }
                if (val > 1000) { val = 1000; }
                sliderMass.value = val;
                state.mass = val;
                clearPresets();
                updateCalculations();
            }
            function syncRadiusFromSlider() {
                const val = parseFloat(sliderRadius.value) / 100.0;
                inputRadius.value = val.toFixed(2);
                state.radius = val;
                clearPresets();
                updateCalculations();
            }
            function syncRadiusFromInput() {
                let val = parseFloat(inputRadius.value);
                if (isNaN(val)) { val = 0.05; }
                if (val < 0.05) { val = 0.05; }
                if (val > 1.0) { val = 1.0; }
                sliderRadius.value = Math.round(val * 100.0);
                state.radius = val;
                clearPresets();
                updateCalculations();
            }
            function syncRpmFromSlider() {
                const val = parseInt(sliderRpm.value);
                inputRpm.value = val;
                state.rpm = val;
                clearPresets();
                updateCalculations();
            }
            function syncRpmFromInput() {
                let val = parseInt(inputRpm.value);
                if (isNaN(val)) { val = 10; }
                if (val < 10) { val = 10; }
                if (val > 1500) { val = 1500; }
                sliderRpm.value = val;
                state.rpm = val;
                clearPresets();
                updateCalculations();
            }
            // Core Calculations
            function updateCalculations() {
                // J = 0.5 * M * R^2 (Solid cylinder model)
                const inertia = 0.5 * state.mass * (state.radius * state.radius);
                // Angular velocity
                const omega = (2 * Math.PI * state.rpm) / 60.0;
                // Angular Accel
                const alpha = omega / state.taccel;
                // Accel torque
                const torqueAccel = inertia * alpha;
                // Static Friction torque (Assume safety friction coefficient)
                // Normal weight loading force F = M * G
                const gravity = 9.81;
                const frictionCoeff = 0.05; // default conveyor sliding friction
                const torqueFriction = frictionCoeff * state.mass * gravity * state.radius;
                // Total torque
                const torqueTotal = torqueAccel + torqueFriction;
                // Peak Mech Power (kW)
                const powerPeak = (torqueTotal * omega) / 1000.0;
                // Electric power with efficiency and standard safety factor (SF = 1.25)
                const effFrac = state.efficiency / 100.0;
                const powerRequired = (powerPeak / effFrac) * 1.25;
                // Select standard motor
                let chosenMotor = standardMotors[standardMotors.length - 1];
                for (let i = 0; i < standardMotors.length; i++) {
                    const motorSize = standardMotors[i];
                    if (motorSize >= powerRequired) {
                        chosenMotor = motorSize;
                        break;
                    }
                }
                // Update results UI
                txtInertiaOut.innerText = inertia.toFixed(3) + ' kg·m²';
                txtTorqueOut.innerText = torqueTotal.toFixed(1) + ' Nm';
                txtPowerOut.innerText = powerPeak.toFixed(2) + ' kW';
                txtMotorKw.innerText = chosenMotor.toFixed(2) + ' kW';
                const motorHp = chosenMotor * 1.341;
                txtMotorHp.innerText = '(' + motorHp.toFixed(1) + ' HP 표준 규격)';
            }
            // Presets
            function loadPreset(key) {
                clearPresets();
                presetButtons.forEach(btn => {
                    if (btn.dataset.preset === key) {
                        btn.classList.add('active');
                    }
                });
                if (key === 'conveyor') {
                    state.mass = 200;
                    state.radius = 0.15;
                    state.rpm = 120;
                    state.taccel = 1.5;
                    state.efficiency = 80;
                }
                if (key === 'fan') {
                    state.mass = 40;
                    state.radius = 0.50;
                    state.rpm = 900;
                    state.taccel = 6.0;
                    state.efficiency = 90;
                }
                if (key === 'hoist') {
                    state.mass = 850;
                    state.radius = 0.25;
                    state.rpm = 60;
                    state.taccel = 1.0;
                    state.efficiency = 75;
                }
                inputMass.value = state.mass;
                sliderMass.value = state.mass;
                inputRadius.value = state.radius.toFixed(2);
                sliderRadius.value = Math.round(state.radius * 100.0);
                inputRpm.value = state.rpm;
                sliderRpm.value = state.rpm;
                inputTaccel.value = state.taccel.toFixed(1);
                inputEfficiency.value = state.efficiency;
                updateCalculations();
            }
            function clearPresets() {
                presetButtons.forEach(btn => btn.classList.remove('active'));
            }
            // Trigger run cycle
            btnTrigger.addEventListener('click', () => {
                state.isRunning = true;
                state.timeInCycle = 0.0;
                state.phase = "accel";
                state.graphPoints = [];
                state.rotationAngle = 0.0; // Reset rotation angle on new run
                txtMotionState.innerText = "가속 구동 중...";
                txtMotionState.style.color = "var(--color-magenta)";
            });
            // Sync listeners
            sliderMass.addEventListener('input', syncMassFromSlider);
            inputMass.addEventListener('change', syncMassFromInput);
            sliderRadius.addEventListener('input', syncRadiusFromSlider);
            inputRadius.addEventListener('change', syncRadiusFromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            inputTaccel.addEventListener('change', () => {
                let val = parseFloat(inputTaccel.value);
                if (isNaN(val)) { val = 0.1; }
                if (val < 0.1) { val = 0.1; }
                if (val > 10.0) { val = 10.0; }
                inputTaccel.value = val.toFixed(1);
                state.taccel = val;
                updateCalculations();
            });
            inputEfficiency.addEventListener('change', () => {
                let val = parseInt(inputEfficiency.value);
                if (isNaN(val)) { val = 50; }
                if (val < 50) { val = 50; }
                if (val > 100) { val = 100; }
                inputEfficiency.value = val;
                state.efficiency = val;
                updateCalculations();
            });
            presetButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    loadPreset(btn.dataset.preset);
                });
            });
            // Animation Loop
            function animate(currentTime) {
                requestAnimationFrame(animate);
                let dt = (currentTime - state.lastTime) / 1000;
                if (isNaN(dt)) { dt = 0.016; }
                if (dt < 0) { dt = 0.016; }
                if (dt > 1.0) { dt = 0.016; }
                state.lastTime = currentTime;
                const width = canvas.width / (window.devicePixelRatio || 1);
                const height = canvas.height / (window.devicePixelRatio || 1);
                ctx.clearRect(0, 0, width, height);
                // Draw Grid
                ctx.save();
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
                ctx.lineWidth = 1;
                const gridSpacing = 25;
                for (let x = 0; x < width; x += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                ctx.restore();
                // Dynamic physics calculation for state machine phases
                const totalCycleTime = state.taccel * 2 + 3.0; // accel + steady + deceleration
                const gravity = 9.81;
                if (state.isRunning) {
                    state.timeInCycle += dt;
                    if (state.phase === "accel") {
                        const progress = state.timeInCycle / state.taccel;
                        state.currentSpeed = progress * state.rpm;
                        txtLiveAccel.innerText = ((state.rpm * 2 * Math.PI) / (60 * state.taccel)).toFixed(2) + " rad/s²";
                        if (state.timeInCycle >= state.taccel) {
                            state.phase = "run";
                            txtMotionState.innerText = "정속 등속 운전";
                            txtMotionState.style.color = "var(--color-success)";
                        }
                    }
                    if (state.phase === "run") {
                        state.currentSpeed = state.rpm;
                        txtLiveAccel.innerText = "0.00 rad/s²";
                        if (state.timeInCycle >= state.taccel + 3.0) {
                            state.phase = "brake";
                            txtMotionState.innerText = "감속 제동 중";
                            txtMotionState.style.color = "var(--color-danger)";
                        }
                    }
                    if (state.phase === "brake") {
                        const brakeProgress = (state.timeInCycle - (state.taccel + 3.0)) / state.taccel;
                        state.currentSpeed = state.rpm * (1.0 - brakeProgress);
                        txtLiveAccel.innerText = "-" + ((state.rpm * 2 * Math.PI) / (60 * state.taccel)).toFixed(2) + " rad/s²";
                        if (brakeProgress >= 1.0) {
                            state.phase = "stopped";
                            state.currentSpeed = 0.0;
                            state.isRunning = false;
                            txtMotionState.innerText = "정지 상태";
                            txtMotionState.style.color = "var(--color-text-muted)";
                            txtLiveAccel.innerText = "0.00 rad/s²";
                        }
                    }
                    // Increment angle of rotation
                    const deltaAngle = (2 * Math.PI * state.currentSpeed * dt) / 60.0;
                    state.rotationAngle += deltaAngle;
                    // Plot logging
                    if (state.graphPoints.length < 300) {
                        state.graphPoints.push({
                            t: state.timeInCycle,
                            val: state.currentSpeed / state.rpm // Store normalized speed ratio
                        });
                    }
                } else {
                    state.currentSpeed = 0.0;
                }
                txtLiveSpeed.innerText = state.currentSpeed.toFixed(1) + " RPM";
                // 2D Physics graphics drawing
                // Center and Radius of rotating load drum
                const drumCx = width / 2 + 50;
                const drumCy = height / 2 - 40;
                const drumVisualR = 60 + state.radius * 50; // map 0.05m-1.0m to 62.5px-110px
                // A. Draw Motor Block on Left (Industrial Servo Motor design)
                const motorX = drumCx - 210; // Shifted left to prevent drum overlaps at max radius
                const motorY = drumCy - 30;
                const motorW = 75;
                const motorH = 60;
                ctx.save();
                // If running, draw power stress glow and add micro-vibrations
                if (state.isRunning) {
                    const vibX = (Math.random() - 0.5) * 1.2;
                    const vibY = (Math.random() - 0.5) * 1.2;
                    ctx.translate(vibX, vibY);
                    ctx.shadowBlur = 12;
                    ctx.shadowColor = state.phase === "accel" ? "rgba(239, 68, 68, 0.6)" : "rgba(2, 132, 199, 0.6)";
                }
                // 1. Motor Base Bracket / Foot Mount
                ctx.fillStyle = "#64748b";
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 2;
                ctx.beginPath();
                if (ctx.roundRect) {
                    ctx.roundRect(motorX + 10, motorY + motorH - 4, motorW - 20, 8, 2);
                } else {
                    ctx.rect(motorX + 10, motorY + motorH - 4, motorW - 20, 8);
                }
                ctx.fill();
                ctx.stroke();
                // 2. Rear Cooling Fan Cap
                const gradFan = ctx.createLinearGradient(motorX - 10, motorY, motorX, motorY + motorH);
                gradFan.addColorStop(0, "#475569");
                gradFan.addColorStop(0.5, "#334155");
                gradFan.addColorStop(1, "#1e293b");
                ctx.fillStyle = gradFan;
                ctx.strokeStyle = "#334155";
                ctx.lineWidth = 1.5;
                ctx.beginPath();
                if (ctx.roundRect) {
                    ctx.roundRect(motorX - 10, motorY + 5, 12, motorH - 10, [6, 0, 0, 6]);
                } else {
                    ctx.rect(motorX - 10, motorY + 5, 12, motorH - 10);
                }
                ctx.fill();
                ctx.stroke();
                // 3. Metallic Motor Cylindrical Frame
                const gradBody = ctx.createLinearGradient(motorX, motorY, motorX, motorY + motorH);
                gradBody.addColorStop(0, "#0f172a");
                gradBody.addColorStop(0.3, "#3b82f6"); // Metallic highlight
                gradBody.addColorStop(0.7, "#1d4ed8");
                gradBody.addColorStop(1, "#071e54");
                ctx.fillStyle = gradBody;
                ctx.strokeStyle = "#1e293b";
                ctx.lineWidth = 2.5;
                ctx.beginPath();
                if (ctx.roundRect) {
                    ctx.roundRect(motorX, motorY, motorW - 10, motorH, 4);
                } else {
                    ctx.rect(motorX, motorY, motorW - 10, motorH);
                }
                ctx.fill();
                ctx.stroke();
                // 4. Terminal Box (Top electrical connector)
                ctx.fillStyle = "#1e293b";
                ctx.strokeStyle = "#3b82f6";
                ctx.lineWidth = 1.5;
                ctx.beginPath();
                if (ctx.roundRect) {
                    ctx.roundRect(motorX + 20, motorY - 12, 25, 12, 2);
                } else {
                    ctx.rect(motorX + 20, motorY - 12, 25, 12);
                }
                ctx.fill();
                ctx.stroke();
                // 5. Horizontal cooling fins detail
                ctx.strokeStyle = "rgba(255, 255, 255, 0.15)";
                ctx.lineWidth = 1.5;
                for (let fy = motorY + 8; fy < motorY + motorH - 4; fy += 8) {
                    ctx.beginPath();
                    ctx.moveTo(motorX + 5, fy);
                    ctx.lineTo(motorX + motorW - 15, fy);
                    ctx.stroke();
                }
                // 6. Front Shaft Flange Plate (silver)
                ctx.fillStyle = "#94a3b8";
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 2;
                ctx.beginPath();
                if (ctx.roundRect) {
                    ctx.roundRect(motorX + motorW - 10, motorY + 2, 8, motorH - 4, 2);
                } else {
                    ctx.rect(motorX + motorW - 10, motorY + 2, 8, motorH - 4);
                }
                ctx.fill();
                ctx.stroke();
                ctx.restore();
                // B. Draw coupling shaft connecting motor to drum
                ctx.save();
                ctx.fillStyle = "#cbd5e1";
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 1.5;
                ctx.beginPath();
                ctx.rect(motorX + motorW, drumCy - 6, drumCx - (motorX + motorW) - drumVisualR, 12);
                ctx.fill();
                ctx.stroke();
                ctx.restore();
                // C. Draw Rotating Drum
                ctx.save();
                ctx.translate(drumCx, drumCy);
                ctx.rotate(state.rotationAngle);
                // Draw solid outer rim
                ctx.fillStyle = "rgba(241, 245, 249, 0.9)";
                ctx.strokeStyle = "#db2777";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.arc(0, 0, drumVisualR, 0, Math.PI * 2);
                ctx.fill();
                ctx.stroke();
                // Draw spokes inside the drum
                ctx.strokeStyle = "rgba(219, 39, 119, 0.2)";
                ctx.lineWidth = 3;
                for (let a = 0; a < Math.PI * 2; a += Math.PI / 4) {
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.lineTo(Math.cos(a) * drumVisualR, Math.sin(a) * drumVisualR);
                    ctx.stroke();
                }
                // Draw a notch dot to see the speed of rotation easily
                ctx.beginPath();
                ctx.arc(drumVisualR - 12, 0, 6, 0, Math.PI * 2);
                ctx.fillStyle = "#db2777";
                ctx.fill();
                ctx.restore();
                // D. Hanging rope and load weight
                // Rope tangent from right of the drum
                const ropeX = drumCx + drumVisualR;
                const ropeFloorY = height - 60;
                // Reciprocating load weight motion simulation based on angle
                const maxLift = ropeFloorY - drumCy - 60; // max physical lifting displacement
                let yOffset = (state.rotationAngle * 3.5) % (maxLift * 2);
                if (yOffset > maxLift) {
                    yOffset = maxLift * 2 - yOffset;
                }
                const currentWeightY = ropeFloorY - 40 - yOffset;
                ctx.save();
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 2.5;
                ctx.beginPath();
                ctx.moveTo(ropeX, drumCy);
                ctx.lineTo(ropeX, currentWeightY);
                ctx.stroke();
                // Rope stress glow if accelerating
                if (state.phase === "accel") {
                    ctx.strokeStyle = "#db2777";
                    ctx.lineWidth = 4;
                    ctx.shadowBlur = 8;
                    ctx.shadowColor = "#db2777";
                    ctx.beginPath();
                    ctx.moveTo(ropeX, drumCy);
                    ctx.lineTo(ropeX, currentWeightY);
                    ctx.stroke();
                }
                ctx.restore();
                // Draw Load Weight Box
                ctx.save();
                ctx.fillStyle = "#ffffff";
                ctx.strokeStyle = "#334155";
                ctx.lineWidth = 3;
                ctx.beginPath();
                ctx.rect(ropeX - 25, currentWeightY, 50, 40);
                ctx.fill();
                ctx.stroke();
                ctx.fillStyle = "#0f172a";
                ctx.font = "bold 11px Outfit, sans-serif";
                ctx.textAlign = "center";
                ctx.fillText(state.mass + " kg", ropeX, currentWeightY + 24);
                ctx.restore();
                // E. Real-time plot in bottom-left corner of canvas
                ctx.save();
                const plotX = 35;
                const plotY = height - 170;
                const plotW = 240;
                const plotH = 135;
                const chartX = plotX + 48; // Expanded space to 48px to prevent "1500 RPM" from overflowing the left box border
                const chartY = plotY + 28; // Increased clearance for the title text
                const chartW = plotW - 66; 
                const chartH = plotH - 50; // Extra room at bottom for X-axis labels
                // Draw plot background panel
                ctx.fillStyle = "rgba(255, 255, 255, 0.92)";
                ctx.strokeStyle = "rgba(0, 0, 0, 0.08)";
                ctx.lineWidth = 1;
                ctx.beginPath();
                if (ctx.roundRect) {
                    ctx.roundRect(plotX, plotY, plotW, plotH, 10);
                } else {
                    ctx.rect(plotX, plotY, plotW, plotH);
                }
                ctx.fill();
                ctx.stroke();
                // Draw Grid Lines & Reference dashed line
                ctx.strokeStyle = "rgba(71, 85, 105, 0.08)";
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.moveTo(chartX, chartY + chartH / 2);
                ctx.lineTo(chartX + chartW, chartY + chartH / 2);
                ctx.stroke();
                ctx.strokeStyle = "rgba(2, 132, 199, 0.25)";
                ctx.setLineDash([3, 3]);
                ctx.beginPath();
                ctx.moveTo(chartX, chartY + 3);
                ctx.lineTo(chartX + chartW, chartY + 3);
                ctx.stroke();
                ctx.setLineDash([]);
                // Draw Axis Lines
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 1.5;
                ctx.beginPath();
                ctx.moveTo(chartX, chartY);
                ctx.lineTo(chartX, chartY + chartH);
                ctx.lineTo(chartX + chartW, chartY + chartH);
                ctx.stroke();
                // Axis title (Enlarged font size: 10.5px)
                ctx.fillStyle = "#0f172a";
                ctx.font = "bold 10.5px Inter, sans-serif";
                ctx.textAlign = "left";
                ctx.textBaseline = "top";
                ctx.fillText("속도 프로파일 (Speed vs Time)", plotX + 12, plotY + 8);
                // Axis Values (Enlarged font size: 9px, weight: 700)
                ctx.fillStyle = "#475569";
                ctx.font = "700 9px Inter, sans-serif";
                ctx.textBaseline = "middle";
                // y-axis scale labels
                ctx.textAlign = "right";
                ctx.fillText(Math.round(state.rpm) + " RPM", chartX - 8, chartY + 3);
                ctx.fillText("0", chartX - 8, chartY + chartH);
                // x-axis scale labels
                ctx.textAlign = "center";
                ctx.textBaseline = "top";
                ctx.fillText("0s", chartX, chartY + chartH + 6);
                const tAccX = chartX + (state.taccel / totalCycleTime) * chartW;
                ctx.fillText(state.taccel.toFixed(1) + "s", tAccX, chartY + chartH + 6);
                ctx.fillText(totalCycleTime.toFixed(1) + "s", chartX + chartW, chartY + chartH + 6);
                // Draw actual speed plot curve
                if (state.graphPoints.length > 1) {
                    ctx.strokeStyle = "#0284c7";
                    ctx.lineWidth = 2.5;
                    ctx.beginPath();
                    for (let i = 0; i < state.graphPoints.length; i++) {
                        const pt = state.graphPoints[i];
                        const gx = chartX + (pt.t / totalCycleTime) * chartW;
                        const gy = chartY + chartH - pt.val * (chartH - 5) - 2;
                        const clampedGy = Math.max(chartY, Math.min(gy, chartY + chartH));
                        if (i === 0) {
                            ctx.moveTo(gx, clampedGy);
                        } else {
                            ctx.lineTo(gx, clampedGy);
                        }
                    }
                    ctx.stroke();
                }
                ctx.restore();
            }
            // Sync presets and setup calculations
            loadPreset('conveyor');
            requestAnimationFrame(animate);
            // Right-click &#038; Keyboard shortcuts block
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
                alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                return false;
            }, { capture: true });
            document.addEventListener('selectstart', function(e) {
                e.preventDefault();
                return false;
            }, { capture: true });
            document.addEventListener('keydown', function(e) {
                if (e.key === 'F12') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.ctrlKey) {
                    if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                    if (e.shiftKey) {
                        if (['i','I','j','J','c','C'].includes(e.key)) {
                            e.preventDefault();
                            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                            return false;
                        }
                    }
                }
            }, { capture: true });
        }
        let initAttempts = 0;
        function tryInit() {
            initAttempts++;
            initSimulator();
            if (!window.__motor_initialized) {
                if (initAttempts < 50) {
                    setTimeout(tryInit, 100);
                }
            }
        }
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            tryInit();
        } else {
            document.addEventListener('DOMContentLoaded', tryInit);
            window.addEventListener('load', tryInit);
        }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>구동 부하 변수 입력: 드럼의 직경(반경 R)과 물체의 질량(M)을 설정하여 관성 모멘트를 결정합니다.</strong></li>
<li style="margin-bottom: 6px;">동역학 목표치 설정: 도달하고자 하는 목표 속도(RPM)와 정지 상태에서 목표 속도까지의 가속 시간(sec)을 입력합니다.</li>
<li style="margin-bottom: 6px;">마찰 및 효율 정의: 기계 전동부의 마찰 계수(μ)와 감속기/모터의 전동 효율(%)을 입력합니다.</li>
<li style="margin-bottom: 6px;">실시간 부하 회전 애니메이션 관찰: 가속 단계에서의 모터 과부하 발열(발광) 및 실시간 토크-속도 상태 그래프 곡선을 모니터링하여 추천 모터 사양을 선정합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 및 전기공학 모터 용량 계산 공식 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 모터 선정(Motor Selection)의 엔지니어링적 핵심 요소</h3>
<p>산업용 모터(유도전동기, 서보모터 등)를 선정할 때 가장 빈번하게 발생하는 설계 오차가 바로 <strong>관성모멘트와 가속 토크의 과소평가</strong>입니다. 모터가 구동해야 할 총 부하 토크는 등속 구동에 필요한 정적 토크와 가속 시 필요한 동적 가속 토크의 합으로 결정됩니다.</p><ul><li><strong>관성모멘트 (Moment of Inertia, J):</strong> 회전하는 물체의 질량 분포 상태에 따라 회전에 저항하는 척도입니다. 원기둥 드럼 형상의 경우 J = 0.5 * M * R^2 이 됩니다.</li><li><strong>정적 마찰 토크 (Static Friction Torque, T_static):</strong> 전동부의 기계 마찰 및 외력을 극복하고 일정 속도를 유지하기 위해 요구되는 기본 토크입니다.</li><li><strong>가속 토크 (Acceleration Torque, T_accel):</strong> 뉴턴의 회전 제2법칙(T = J * &alpha;)에 따라 관성 질량을 목표 속도까지 가속시키는 데 필요한 힘입니다. 가속 시간이 짧을수록 소요 토크가 기하급수적으로 커집니다.</li></ul>
<h3>2. 관성모멘트, 토크 및 소요 동력(kW) 공식 관계식</h3>
<p>부하 동역학을 분석하고 모터 출력 규격을 구하기 위한 공식 설계 단계는 다음과 같습니다.</p><p><strong>① 부하의 관성 모멘트 J 계산:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">J = 1/2 &times; M &times; R^2 &nbsp;[kg&middot;m^2] &nbsp;&nbsp;(드럼 형태 기준)</p><p><strong>② 각가속도 (&alpha;) 및 가속 토크 (Ta) 계산:</strong> 가속시간 <code>t_accel</code> 동안 목표 각속도 <code>&omega;</code>에 달성하기 위해 필요한 평균 토크입니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">&omega; = 2 &pi; &times; N / 60 &nbsp;[rad/s] &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; &alpha; = &omega; / t_accel &nbsp;[rad/s^2]</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 12px; border-radius: 8px; color: #0369a1;">T_accel = J &times; &alpha; &nbsp;[N&middot;m]</p><p><strong>③ 소비 동력 및 모터 요구 전력 (P) 계산:</strong> 효율(<code>&eta;</code>)과 안전계수(<code>SF</code>, 통상 1.2배)를 감안한 모터 요구 동력입니다.</p><p style="text-align: center; font-weight: bold; background: #fee2e2; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #991b1b;">P_req = (T_total &times; &omega;) / (&eta; &times; 1000) &times; SF &nbsp;[kW]</p>
<h3>3. 전동 모터 정격 출력 표준 규격 (IEC/KS)</h3>
<p>계산된 소요 동력(kW)을 바탕으로 실제 기계설계 시에는 상용화되어 있는 표준 모터의 <strong>정격 출력(Rated Power)</strong>을 선정해야 합니다. IEC 규격에 따른 대표적인 삼상 유도전동기의 표준 정격 출력은 다음과 같습니다.</p><ul><li><strong>소형 동력:</strong> 0.2 kW, 0.4 kW, 0.75 kW, 1.5 kW, 2.2 kW, 3.7 kW</li><li><strong>중형 동력:</strong> 5.5 kW, 7.5 kW, 11 kW, 15 kW, 18.5 kW, 22 kW, 30 kW, 37 kW</li></ul><p>선정 시에는 부하의 피크 토크(시동 시 최대 토크)가 모터의 기동 토크(Starting Torque) 및 정동 토크(Breakdown Torque) 한계 이내에 위치하는지 교차 검증을 반드시 거쳐야 장기 운전 시 과열 소손을 방지할 수 있습니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>


<h2 style="font-size: 1.4em; font-weight: 700; color: #1f2937; margin-top: 40px; margin-bottom: 15px; border-left: 4px solid #3b82f6; padding-left: 10px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 함께 보면 좋은 공학 글</h2>


<a href="https://myengnote.com/cable-sizing-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">케이블 허용전류 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>


<a href="https://myengnote.com/power-factor-correction-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">역률 개선 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/motor-selection-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>케이블 허용전류 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/cable-sizing-calculator-simulator/</link>
					<comments>https://myengnote.com/cable-sizing-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Fri, 26 Jun 2026 21:28:09 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[전선단면적]]></category>
		<category><![CDATA[전압강하]]></category>
		<category><![CDATA[케이블공칭규격]]></category>
		<category><![CDATA[케이블발열]]></category>
		<category><![CDATA[허용전류]]></category>
		<guid isPermaLink="false">https://myengnote.com/cable-sizing-calculator-simulator/</guid>

					<description><![CDATA[부하 전류, 전송 거리, 허용 전압 강하율 및 포설 환경을 입력하여 규격에 적합한 케이블 단면적(sq/mm²)을 설계하고 전하 밀도와 케이블 발열 상태를 2D 시각화하는 시뮬레이터입니다. <a href="https://myengnote.com/cable-sizing-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 케이블 허용전류 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for cablesizing-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .cablesizing-calculator-wrapper *, .cablesizing-calculator-wrapper *::before, .cablesizing-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .cablesizing-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7; /* Cobalt blue accent */
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777; /* Pink/magenta accent */
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --color-danger: #ef4444;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .cablesizing-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 15s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-current::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-length::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        #slider-drop::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 10px var(--color-purple); }
        /* Segmented switch styling */
        .segmented-control {
            display: grid;
            grid-template-columns: 1fr 1fr;
            background: rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 8px;
            padding: 2px;
            gap: 2px;
        }
        .segment-btn {
            background: transparent;
            border: none;
            outline: none;
            color: var(--color-text-muted);
            font-size: 12px;
            font-weight: 600;
            padding: 8px;
            cursor: pointer;
            border-radius: 6px;
            transition: all 0.2s ease;
            text-align: center;
        }
        .segment-btn.active {
            background: #ffffff;
            color: var(--color-cyan);
            box-shadow: 0 2px 6px rgba(0,0,0,0.05);
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel { grid-column: 2; align-self: start; }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 10;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(0, 242, 254, 0.08) 0%, rgba(138, 43, 226, 0.03) 100%);
            border: 1px solid rgba(0, 242, 254, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(0, 242, 254, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 32px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(0, 242, 254, 0.2);
            background: rgba(0, 242, 254, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: rgba(0, 242, 254, 0.3);
            background: rgba(0, 242, 254, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: var(--color-cyan);
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        @container cable-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
            }
            .results-panel {
                grid-column: 1 / span 2;
            }
        }
        @container cable-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        @container cable-container (max-width: 480px) {
            .app-container {
                padding: 12px;
                gap: 16px;
            }
            .panel {
                padding: 16px;
            }
            .simulation-metrics-strip {
                flex-direction: column;
                gap: 12px;
            }
            .mini-divider {
                width: 80%;
                height: 1px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.cablesizing-calculator-wrapper .app-main-grid,
.cablesizing-calculator-wrapper .main-grid,
.cablesizing-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.cablesizing-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.cablesizing-calculator-wrapper .simulation-panel,
.cablesizing-calculator-wrapper .canvas-panel,
.cablesizing-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.cablesizing-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.cablesizing-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.cablesizing-calculator-wrapper .simulation-results-section .ratio-readout-box,
.cablesizing-calculator-wrapper .simulation-results-section .re-readout-box,
.cablesizing-calculator-wrapper .simulation-results-section .status-readout-box,
.cablesizing-calculator-wrapper .simulation-results-section .flow-readout-box,
.cablesizing-calculator-wrapper .simulation-results-section [class*="readout-box"],
.cablesizing-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.cablesizing-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.cablesizing-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.cablesizing-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .cablesizing-calculator-wrapper .app-main-grid,
    .cablesizing-calculator-wrapper .main-grid,
    .cablesizing-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .cablesizing-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .cablesizing-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .cablesizing-calculator-wrapper .simulation-panel,
    .cablesizing-calculator-wrapper .canvas-panel,
    .cablesizing-calculator-wrapper .sim-panel,
    .cablesizing-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .cablesizing-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .cablesizing-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .cablesizing-calculator-wrapper .simulation-results-section .re-readout-box,
    .cablesizing-calculator-wrapper .simulation-results-section .status-readout-box,
    .cablesizing-calculator-wrapper .simulation-results-section .flow-readout-box,
    .cablesizing-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .cablesizing-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .cablesizing-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .cablesizing-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.cablesizing-calculator-wrapper .app-container,
.cablesizing-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.cablesizing-calculator-wrapper .simulation-results-section .formula-card,
.cablesizing-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.cablesizing-calculator-wrapper .simulation-results-section .formula-card h4,
.cablesizing-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.cablesizing-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.cablesizing-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="cablesizing-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-gauge text-cyan"></i></div>
                <div>
                    <h1>CABLE SIZING</h1>
                    <div class="subtitle">케이블 공칭 단면적 선정 &#038; 전압강하 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">KEC STANDARDS CONFORMITY</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>배선 조건 변수</h2>
                </div>
                <!-- Voltage Type selection -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-bolt text-cyan"></i> 배전 전력 계통</label>
                    </div>
                    <div class="segmented-control" id="control-phase">
                        <button class="segment-btn active" data-value="1">단상 220 V</button>
                        <button class="segment-btn" data-value="3">삼상 380 V</button>
                    </div>
                </div>
                <!-- Load Current (A) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-bolt text-magenta"></i> 부하 전류 (I)</label>
                        <span class="helper-text">(1 ~ 300 A)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-current" class="custom-number-input" min="1" max="300" value="45">
                        <div class="unit-badge">A</div>
                    </div>
                    <input type="range" id="slider-current" class="custom-slider" min="1" max="300" step="1" value="45">
                </div>
                <!-- Distance length (m) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-route text-purple"></i> 케이블 이송 거리 (L)</label>
                        <span class="helper-text">(5 ~ 200 m)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-length" class="custom-number-input" min="5" max="200" value="50">
                        <div class="unit-badge">m</div>
                    </div>
                    <input type="range" id="slider-length" class="custom-slider" min="5" max="200" step="5" value="50">
                </div>
                <!-- Allowable drop (%) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-chart-line"></i> 허용 전압 강하율 (%)</label>
                        <span class="helper-text">(1.0 ~ 5.0 %)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-drop" class="custom-number-input" min="1.0" max="5.0" step="0.1" value="3.0">
                        <div class="unit-badge">%</div>
                    </div>
                    <input type="range" id="slider-drop" class="custom-slider" min="10" max="50" step="1" value="30">
                </div>
                <!-- Material Type -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-atom"></i> 도체 재질</label>
                    </div>
                    <div class="segmented-control" id="control-material">
                        <button class="segment-btn active" data-value="cu">구리 (Cu)</button>
                        <button class="segment-btn" data-value="al">알루미늄 (Al)</button>
                    </div>
                </div>
                <!-- Installation style -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-layer-group"></i> 배선 포설 형태</label>
                    </div>
                    <div class="segmented-control" id="control-install">
                        <button class="segment-btn active" data-value="tray">오픈 케이블 트레이</button>
                        <button class="segment-btn" data-value="conduit">매입 배관(콘크리트)</button>
                    </div>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 배선 케이스 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="household">
                            <div class="preset-icon"><i class="fa-solid fa-house"></i></div>
                            <div class="preset-details"><span class="preset-name">가정용 전열 콘센트</span><span class="preset-spec">단상, 15A, 25m</span></div>
                        </button>
                        <button class="preset-btn" data-preset="subpanel">
                            <div class="preset-icon"><i class="fa-solid fa-industry"></i></div>
                            <div class="preset-details"><span class="preset-name">공장 소형 동력반 분기</span><span class="preset-spec">삼상, 60A, 60m</span></div>
                        </button>
                        <button class="preset-btn" data-preset="pump">
                            <div class="preset-icon"><i class="fa-solid fa-water"></i></div>
                            <div class="preset-details"><span class="preset-name">원거리 펌프 모터 전원</span><span class="preset-spec">삼상, 180A, 140m</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>케이블 단면 발열 &#038; 선로 물리 모니터</h2>
                                    </div>
                                    <div id="txt-cable-safety" class="canvas-scale-indicator text-cyan">정상 동작</div>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                </div>
                                <!-- Mini Metrics -->
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <div class="label">선로 도량 저항치</div>
                                        <div id="txt-resistance-out" class="value">0.0 Ω</div>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <div class="label">케이블 열 방출 지수</div>
                                        <div id="txt-heat-index" class="value">0 %</div>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">KEC 설계 추천 전선 굵기</div>
                                    <div id="txt-cable-size" class="ratio-value">6.0 mm²</div>
                                    <div id="txt-ampacity-limit" class="ratio-type">(허용 전류 한계: 52 A)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- Voltage Drop -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-arrow-down-wide-short text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">최종 전압 강하치 (e)</span>
                                            <span id="txt-drop-volts" class="card-value">5.2 V (2.4%)</span>
                                        </div>
                                    </div>
                                    <!-- Cable Loss Power -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-fire text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">전선 줄열 손실 전력 (P_loss)</span>
                                            <span id="txt-power-loss" class="card-value">250 W</span>
                                        </div>
                                    </div>
                                    <!-- Safety Margin -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-shield text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">케이블 정격 전류 대비 마진</span>
                                            <span id="txt-safety-margin" class="card-value">115 %</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> KEC 선로 전압강하 공식</h4>
                                    <div class="formula-equation">e = 30.8 × L × I / 1000A [삼상]</div>
                                    <div class="formula-equation">e = 35.6 × L × I / 1000A [단상]</div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- JavaScript Cable Sizing Engine -->
    </div>
</div>
<script>
        (function() {
        let isInit = false;
        function initSimulator() {
            if (isInit) return;
            const canvas = document.getElementById('physics-canvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
            isInit = true;
            window.__cable_initialized = true;
            // DOM Elements
            const sliderCurrent = document.getElementById('slider-current');
            const inputCurrent = document.getElementById('input-current');
            const sliderLength = document.getElementById('slider-length');
            const inputLength = document.getElementById('input-length');
            const sliderDrop = document.getElementById('slider-drop');
            const inputDrop = document.getElementById('input-drop');
            const controlPhase = document.getElementById('control-phase');
            const controlMaterial = document.getElementById('control-material');
            const controlInstall = document.getElementById('control-install');
            const presetButtons = document.querySelectorAll('.preset-btn');
            const txtCableSize = document.getElementById('txt-cable-size');
            const txtAmpacityLimit = document.getElementById('txt-ampacity-limit');
            const txtDropVolts = document.getElementById('txt-drop-volts');
            const txtPowerLoss = document.getElementById('txt-power-loss');
            const txtSafetyMargin = document.getElementById('txt-safety-margin');
            const txtCableSafety = document.getElementById('txt-cable-safety');
            const txtResistanceOut = document.getElementById('txt-resistance-out');
            const txtHeatIndex = document.getElementById('txt-heat-index');
            // State variables
            const state = {
                phase: 1, // 1 for single phase, 3 for three phase
                current: 45.0,
                length: 50.0,
                allowableDropPercent: 3.0,
                material: "cu", // cu or al
                installation: "tray", // tray or conduit
                // Calculated Outputs
                chosenSize: 6.0,
                ampacityLimit: 52.0,
                actualVoltageDrop: 3.2,
                resistance: 0.15,
                powerLoss: 120,
                // Animation states
                electronPhase: 0,
                lastTime: 0
            };
            // Standard Cable Sizes (sq/mm2)
            const standardSizes = [1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240];
            // Material resistivity (ohm * mm2 / m)
            const resistivityCu = 1.0 / 58.0;
            const resistivityAl = 1.0 / 35.0;
            function resizeCanvas() {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            resizeCanvas();
            window.addEventListener('resize', resizeCanvas);
            setTimeout(resizeCanvas, 300);
            // Synchronizing Inputs
            function syncCurrentFromSlider() {
                const val = parseInt(sliderCurrent.value);
                inputCurrent.value = val;
                state.current = val;
                clearPresets();
                updateCalculations();
            }
            function syncCurrentFromInput() {
                let val = parseInt(inputCurrent.value);
                if (isNaN(val)) { val = 1; }
                if (val < 1) { val = 1; }
                if (val > 300) { val = 300; }
                sliderCurrent.value = val;
                state.current = val;
                clearPresets();
                updateCalculations();
            }
            function syncLengthFromSlider() {
                const val = parseInt(sliderLength.value);
                inputLength.value = val;
                state.length = val;
                clearPresets();
                updateCalculations();
            }
            function syncLengthFromInput() {
                let val = parseInt(inputLength.value);
                if (isNaN(val)) { val = 5; }
                if (val < 5) { val = 5; }
                if (val > 200) { val = 200; }
                sliderLength.value = val;
                state.length = val;
                clearPresets();
                updateCalculations();
            }
            function syncDropFromSlider() {
                const val = parseFloat(sliderDrop.value) / 10.0;
                inputDrop.value = val.toFixed(1);
                state.allowableDropPercent = val;
                clearPresets();
                updateCalculations();
            }
            function syncDropFromInput() {
                let val = parseFloat(inputDrop.value);
                if (isNaN(val)) { val = 1.0; }
                if (val < 1.0) { val = 1.0; }
                if (val > 5.0) { val = 5.0; }
                sliderDrop.value = Math.round(val * 10);
                state.allowableDropPercent = val;
                clearPresets();
                updateCalculations();
            }
            // Calculations based on KEC/Korean inner regulation tables
            function updateCalculations() {
                const voltsLimit = state.phase === 1 ? 220.0 : 380.0;
                const allowableDropVolts = (state.allowableDropPercent / 100.0) * voltsLimit;
                // Step 1: Calculate sizing based on voltage drop
                // A_drop = (30.8 or 35.6) * L * I / (1000 * e_allow)
                const factor = state.phase === 1 ? 35.6 : 30.8;
                const sizeReqVoltage = (factor * state.length * state.current) / (1000.0 * allowableDropVolts);
                // Step 2: Sizing based on Ampacity safety
                // Standard ampacity lookup approximation
                // Ampacity depends on size, material (Cu, Al), and installation environment (tray/conduit)
                let baseAmpacityMultiplier = state.material === "cu" ? 1.0 : 0.65;
                if (state.installation === "conduit") {
                    baseAmpacityMultiplier *= 0.78; // derating for conduit
                }
                // Choose smallest standard size that fits both criteria
                let bestSize = standardSizes[standardSizes.length - 1];
                let ampacityOfChosen = 0.0;
                for (let i = 0; i < standardSizes.length; i++) {
                    const size = standardSizes[i];
                    // Approximate safe ampacity: I_safe = k * size ^ 0.62
                    const safeAmp = 15.0 * Math.pow(size, 0.65) * baseAmpacityMultiplier;
                    if (size >= sizeReqVoltage) {
                        if (safeAmp >= state.current) {
                            bestSize = size;
                            ampacityOfChosen = safeAmp;
                            break;
                        }
                    }
                }
                state.chosenSize = bestSize;
                state.ampacityLimit = ampacityOfChosen;
                // Actual electrical calculations of chosen cable
                const resistivity = state.material === "cu" ? resistivityCu : resistivityAl;
                // Resistance R = rho * L / A
                const singleLineResistance = resistivity * (state.length / state.chosenSize);
                state.resistance = singleLineResistance * (state.phase === 1 ? 2.0 : 1.73);
                // Actual voltage drop = I * R
                state.actualVoltageDrop = state.current * state.resistance;
                const actualDropPct = (state.actualVoltageDrop / voltsLimit) * 100.0;
                // Loss Power (W) = I^2 * R
                state.powerLoss = state.current * state.current * state.resistance;
                // Margins & heats
                const margin = (ampacityOfChosen / state.current) * 100.0;
                const heatIndex = Math.min((state.current / ampacityOfChosen) * 100.0, 150.0);
                // Update UI text values
                txtCableSize.innerText = state.chosenSize.toFixed(1) + ' mm²';
                txtAmpacityLimit.innerText = '(허용 전류 한계: ' + Math.round(ampacityOfChosen) + ' A)';
                txtDropVolts.innerText = state.actualVoltageDrop.toFixed(1) + ' V (' + actualDropPct.toFixed(2) + '%)';
                if (state.powerLoss > 1000) {
                    txtPowerLoss.innerText = (state.powerLoss / 1000).toFixed(2) + ' kW';
                } else {
                    txtPowerLoss.innerText = Math.round(state.powerLoss) + ' W';
                }
                txtSafetyMargin.innerText = Math.round(margin) + ' %';
                txtResistanceOut.innerText = state.resistance.toFixed(4) + ' Ω';
                txtHeatIndex.innerText = Math.round(heatIndex) + ' %';
                // Safety warnings
                if (heatIndex > 100.0) {
                    txtCableSafety.innerText = '위험 (과부하 과열)';
                    txtCableSafety.style.color = 'var(--color-danger)';
                } else {
                    if (heatIndex > 80.0) {
                        txtCableSafety.innerText = '경고 (부하 한계 근접)';
                        txtCableSafety.style.color = '#f59e0b';
                    } else {
                        txtCableSafety.innerText = '안전 (기준치 이내)';
                        txtCableSafety.style.color = '#10b981';
                    }
                }
            }
            // Presets
            function loadPreset(key) {
                clearPresets();
                presetButtons.forEach(btn => {
                    if (btn.dataset.preset === key) {
                        btn.classList.add('active');
                    }
                });
                if (key === 'household') {
                    state.phase = 1;
                    state.current = 15;
                    state.length = 25;
                    state.allowableDropPercent = 2.0;
                    state.material = "cu";
                    state.installation = "conduit";
                }
                if (key === 'subpanel') {
                    state.phase = 3;
                    state.current = 60;
                    state.length = 60;
                    state.allowableDropPercent = 3.0;
                    state.material = "cu";
                    state.installation = "tray";
                }
                if (key === 'pump') {
                    state.phase = 3;
                    state.current = 180;
                    state.length = 140;
                    state.allowableDropPercent = 4.0;
                    state.material = "cu";
                    state.installation = "tray";
                }
                // Sync UI elements
                // Set Phase active buttons
                document.querySelectorAll('#control-phase .segment-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (parseInt(btn.dataset.value) === state.phase) {
                        btn.classList.add('active');
                    }
                });
                document.querySelectorAll('#control-material .segment-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (btn.dataset.value === state.material) {
                        btn.classList.add('active');
                    }
                });
                document.querySelectorAll('#control-install .segment-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (btn.dataset.value === state.installation) {
                        btn.classList.add('active');
                    }
                });
                inputCurrent.value = state.current;
                sliderCurrent.value = state.current;
                inputLength.value = state.length;
                sliderLength.value = state.length;
                inputDrop.value = state.allowableDropPercent.toFixed(1);
                sliderDrop.value = Math.round(state.allowableDropPercent * 10);
                updateCalculations();
            }
            function clearPresets() {
                presetButtons.forEach(btn => btn.classList.remove('active'));
            }
            // Bind Event Listeners
            sliderCurrent.addEventListener('input', syncCurrentFromSlider);
            inputCurrent.addEventListener('change', syncCurrentFromInput);
            sliderLength.addEventListener('input', syncLengthFromSlider);
            inputLength.addEventListener('change', syncLengthFromInput);
            sliderDrop.addEventListener('input', syncDropFromSlider);
            inputDrop.addEventListener('change', syncDropFromInput);
            // Phase Buttons
            document.querySelectorAll('#control-phase .segment-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll('#control-phase .segment-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    state.phase = parseInt(btn.dataset.value);
                    clearPresets();
                    updateCalculations();
                });
            });
            // Material Buttons
            document.querySelectorAll('#control-material .segment-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll('#control-material .segment-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    state.material = btn.dataset.value;
                    clearPresets();
                    updateCalculations();
                });
            });
            // Installation Buttons
            document.querySelectorAll('#control-install .segment-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll('#control-install .segment-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    state.installation = btn.dataset.value;
                    clearPresets();
                    updateCalculations();
                });
            });
            presetButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    loadPreset(btn.dataset.preset);
                });
            });
            // Technical Arrow drawing helper for CAD dimensions
            function drawArrow(x1, y1, x2, y2, arrowSize = 4) {
                const angle = Math.atan2(y2 - y1, x2 - x1);
                ctx.beginPath();
                ctx.moveTo(x1, y1);
                ctx.lineTo(x2, y2);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(x2, y2);
                ctx.lineTo(x2 - arrowSize * Math.cos(angle - Math.PI / 6), y2 - arrowSize * Math.sin(angle - Math.PI / 6));
                ctx.lineTo(x2 - arrowSize * Math.cos(angle + Math.PI / 6), y2 - arrowSize * Math.sin(angle + Math.PI / 6));
                ctx.closePath();
                ctx.fillStyle = ctx.strokeStyle;
                ctx.fill();
            }
            // Particle list along wire length
            const lineParticles = [];
            for (let i = 0; i < 50; i++) {
                lineParticles.push({
                    xRatio: Math.random(),
                    offsetY: (Math.random() - 0.5) * 8.0 // Normalized offset factor
                });
            }
            // Heat/thermal smoke particles
            const heatParticles = [];
            const maxHeatParticles = 100;
            // Animation Loop
            function animate(currentTime) {
                requestAnimationFrame(animate);
                let dt = (currentTime - state.lastTime) / 1000;
                if (isNaN(dt)) { dt = 0.016; }
                if (dt < 0) { dt = 0.016; }
                if (dt > 1.0) { dt = 0.016; }
                state.lastTime = currentTime;
                const width = canvas.width / (window.devicePixelRatio || 1);
                const height = canvas.height / (window.devicePixelRatio || 1);
                ctx.clearRect(0, 0, width, height);
                // Draw blueprint grid
                ctx.save();
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
                ctx.lineWidth = 1;
                const gridSpacing = 25;
                for (let x = 0; x < width; x += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                ctx.restore();
                // Dynamic Geometry Mapping to prevent conductor overlaps
                const coreCount = state.phase === 1 ? 3 : 4; // Single phase = 3 (Live, N, PE), Three phase = 4 (L1, L2, L3, PE)
                // Calculate dynamic core radius based on square root of chosen sizing to give scaling feedback
                const coreRadius = 6 + 1.25 * Math.sqrt(state.chosenSize);
                // Calculate minimum center-to-center distance to avoid overlaps using trigonometric exterior-contact formula
                const cDist = 1.18 * coreRadius / Math.sin(Math.PI / coreCount);
                // Outer cable jacket radius (sheath thickness: 8px)
                const crossR = cDist + coreRadius + 8;
                // Dynamic cable center coordinates to prevent boundary overlap and preserve margin for left dimension text
                const crossCx = Math.max(120, crossR + 55);
                const crossCy = height / 2;
                // Dynamic side-view wire size settings matching the cross-section scale
                const wireWidth = Math.max(10, Math.min(24, crossR * 0.35)); // Scaled thickness of horizontal wire
                const lineX1 = crossCx + crossR + (wireWidth / 2) + 8; // tangent start with explicit margin to prevent overlaps
                const lineX2 = width - 110;
                const lineY = height / 2;
                // Port style background visualization (Cable section background)
                if (state.installation === "tray") {
                    ctx.save();
                    ctx.strokeStyle = "#cbd5e1";
                    ctx.lineWidth = 4;
                    ctx.beginPath();
                    ctx.moveTo(crossCx - crossR - 20, crossCy + crossR + 8);
                    ctx.lineTo(crossCx + crossR + 20, crossCy + crossR + 8);
                    ctx.stroke();
                    ctx.strokeStyle = "#e2e8f0";
                    ctx.lineWidth = 2;
                    for (let lx = crossCx - crossR - 15; lx <= crossCx + crossR + 15; lx += 10) {
                        ctx.beginPath();
                        ctx.moveTo(lx, crossCy + crossR + 8);
                        ctx.lineTo(lx - 5, crossCy + crossR + 18);
                        ctx.stroke();
                    }
                    ctx.restore();
                } else if (state.installation === "conduit") {
                    ctx.save();
                    ctx.fillStyle = "rgba(226, 232, 240, 0.5)";
                    ctx.fillRect(crossCx - crossR - 25, crossCy - crossR - 25, (crossR + 25) * 2, (crossR + 25) * 2);
                    ctx.strokeStyle = "rgba(148, 163, 184, 0.25)";
                    ctx.lineWidth = 1;
                    const step = 15;
                    const startX = crossCx - crossR - 25;
                    const endX = crossCx + crossR + 25;
                    const startY = crossCy - crossR - 25;
                    const endY = crossCy + crossR + 25;
                    for (let offset = - (endY - startY); offset < (endX - startX); offset += step) {
                        ctx.beginPath();
                        ctx.moveTo(Math.max(startX, startX + offset), Math.max(startY, startY - offset));
                        ctx.lineTo(Math.min(endX, endX + offset), Math.min(endY, endY - offset));
                        ctx.stroke();
                    }
                    const pipeInnerR = crossR + 8;
                    const pipeOuterR = crossR + 16;
                    const heatIndexVal = Math.min((state.current / state.ampacityLimit) * 100.0, 150.0);
                    if (heatIndexVal > 50) {
                        const pipeGlow = ctx.createRadialGradient(crossCx, crossCy, crossR, crossCx, crossCy, pipeInnerR);
                        pipeGlow.addColorStop(0, "rgba(239, 68, 68, 0)");
                        pipeGlow.addColorStop(1, "rgba(239, 68, 68, " + Math.min((heatIndexVal - 50) / 100 * 0.4, 0.4) + ")");
                        ctx.fillStyle = pipeGlow;
                        ctx.beginPath();
                        ctx.arc(crossCx, crossCy, pipeInnerR, 0, Math.PI * 2);
                        ctx.fill();
                    }
                    ctx.fillStyle = "#94a3b8";
                    ctx.strokeStyle = "#475569";
                    ctx.lineWidth = 2;
                    ctx.beginPath();
                    ctx.arc(crossCx, crossCy, pipeOuterR, 0, Math.PI * 2);
                    ctx.arc(crossCx, crossCy, pipeInnerR, 0, Math.PI * 2, true);
                    ctx.fill();
                    ctx.stroke();
                    ctx.restore();
                }
                // A. Render 2D Cable Cross section
                ctx.save();
                ctx.fillStyle = "#ffffff";
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.arc(crossCx, crossCy, crossR, 0, Math.PI * 2);
                ctx.fill();
                ctx.stroke();
                // Draw outer black rubber jacket
                ctx.strokeStyle = "#0f172a";
                ctx.lineWidth = 5;
                ctx.beginPath();
                ctx.arc(crossCx, crossCy, crossR - 3, 0, Math.PI * 2);
                ctx.stroke();
                // Render Inner Core Circles
                const colorsCoresSingle = ["var(--color-cyan)", "#94a3b8", "var(--color-success)"];
                const colorsCoresThree = ["#ef4444", "var(--color-purple)", "var(--color-cyan)", "var(--color-success)"];
                const colors = state.phase === 1 ? colorsCoresSingle : colorsCoresThree;
                // Temperature hot glow overlay based on safe ampacity ratio
                const ratio = state.current / state.ampacityLimit;
                const heatFactor = Math.min(ratio * ratio, 1.5); // exponential heat
                for (let i = 0; i < coreCount; i++) {
                    const angle = (i * 2 * Math.PI) / coreCount - Math.PI / 2;
                    const ccx = crossCx + Math.cos(angle) * cDist;
                    const ccy = crossCy + Math.sin(angle) * cDist;
                    ctx.beginPath();
                    ctx.arc(ccx, ccy, coreRadius, 0, Math.PI * 2);
                    ctx.fillStyle = colors[i];
                    ctx.fill();
                    // If overloaded, draw thermal hotspot core overlay
                    if (heatFactor > 0.1) {
                        ctx.fillStyle = "rgba(239, 68, 68, " + Math.min(heatFactor * 0.45, 0.8) + ")";
                        ctx.beginPath();
                        ctx.arc(ccx, ccy, coreRadius, 0, Math.PI * 2);
                        ctx.fill();
                    }
                    // Draw inner copper core element
                    ctx.fillStyle = "#ffffff";
                    ctx.beginPath();
                    ctx.arc(ccx, ccy, coreRadius - 6 > 3 ? coreRadius - 6 : 3, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.fillStyle = "#d97706"; // copper gold
                    ctx.beginPath();
                    ctx.arc(ccx, ccy, coreRadius - 7 > 2 ? coreRadius - 7 : 2, 0, Math.PI * 2);
                    ctx.fill();
                }
                ctx.restore();
                // Wire Installation Style Background (Tray/Conduit frames)
                if (state.installation === "tray") {
                    ctx.save();
                    ctx.strokeStyle = "#cbd5e1";
                    ctx.lineWidth = 4;
                    ctx.beginPath();
                    ctx.moveTo(lineX1, lineY + (wireWidth / 2) + 5);
                    ctx.lineTo(lineX2, lineY + (wireWidth / 2) + 5);
                    ctx.stroke();
                    ctx.lineWidth = 2;
                    ctx.strokeStyle = "#e2e8f0";
                    for (let lx = lineX1 + 10; lx < lineX2; lx += 25) {
                        ctx.beginPath();
                        ctx.moveTo(lx, lineY + (wireWidth / 2) + 5);
                        ctx.lineTo(lx - 4, lineY + (wireWidth / 2) + 15);
                        ctx.stroke();
                    }
                    ctx.restore();
                } else if (state.installation === "conduit") {
                    ctx.save();
                    // Conduit pipe dimensions matching the cross-section
                    const pipeOuterR = crossR + 16;
                    const pipeOffsetY = (wireWidth / 2) + 5;
                    // Tangent start positioned explicitly outer to the pipe outer radius to prevent overlaps
                    const conduitLineX1 = crossCx + pipeOuterR + 4;
                    // Conduit side background
                    ctx.fillStyle = "rgba(226, 232, 240, 0.4)";
                    ctx.fillRect(conduitLineX1, lineY - pipeOffsetY - 4, lineX2 - conduitLineX1, (pipeOffsetY + 4) * 2);
                    ctx.strokeStyle = "rgba(148, 163, 184, 0.2)";
                    ctx.lineWidth = 1;
                    for (let lx = conduitLineX1 - 20; lx < lineX2 + 20; lx += 15) {
                        if (lx >= conduitLineX1) {
                            ctx.beginPath();
                            ctx.moveTo(lx, lineY - pipeOffsetY - 4);
                            ctx.lineTo(lx + 10, lineY + pipeOffsetY + 4);
                            ctx.stroke();
                        }
                    }
                    // Conduit pipes (drawn exactly from the circular pipe wall)
                    ctx.strokeStyle = "#94a3b8";
                    ctx.lineWidth = 3;
                    ctx.beginPath();
                    ctx.moveTo(conduitLineX1, lineY - pipeOffsetY);
                    ctx.lineTo(lineX2, lineY - pipeOffsetY);
                    ctx.moveTo(conduitLineX1, lineY + pipeOffsetY);
                    ctx.lineTo(lineX2, lineY + pipeOffsetY);
                    ctx.stroke();
                    ctx.restore();
                }
                ctx.save();
                // Draw base thick cable line (Scale width with chosen sizing)
                ctx.strokeStyle = "#cbd5e1";
                ctx.lineWidth = wireWidth;
                ctx.lineCap = "round";
                ctx.beginPath();
                ctx.moveTo(lineX1, lineY);
                ctx.lineTo(lineX2, lineY);
                ctx.stroke();
                // Voltage drop gradient color overlay along wire
                const lineGlowGrad = ctx.createLinearGradient(lineX1, lineY, lineX2, lineY);
                lineGlowGrad.addColorStop(0, "#0284c7");
                lineGlowGrad.addColorStop(1, "rgba(71, 85, 105, 0.45)");
                ctx.strokeStyle = lineGlowGrad;
                ctx.lineWidth = wireWidth - 4 > 2 ? wireWidth - 4 : 2;
                ctx.beginPath();
                ctx.moveTo(lineX1, lineY);
                ctx.lineTo(lineX2, lineY);
                ctx.stroke();
                // 1. Long wire bypass CAD-style break indicator (Distance L effect)
                if (state.length > 80) {
                    ctx.save();
                    const midX = (lineX1 + lineX2) / 2;
                    const halfW = wireWidth / 2;
                    const cutOutW = 12; // width of the break gap
                    const ext = 5; // vertical extension beyond the wire
                    // A. Cut the wire cleanly by filling background color
                    ctx.fillStyle = "#ffffff";
                    ctx.fillRect(midX - cutOutW / 2, lineY - halfW - 2, cutOutW, wireWidth + 4);
                    // B. Draw sophisticated CAD-style double break lines
                    ctx.strokeStyle = "#475569";
                    ctx.lineWidth = 1.5;
                    ctx.lineCap = "round";
                    ctx.lineJoin = "round";
                    ctx.beginPath();
                    // Left wire end cap
                    ctx.moveTo(midX - cutOutW / 2, lineY - halfW);
                    ctx.lineTo(midX - cutOutW / 2, lineY + halfW);
                    // Right wire end cap
                    ctx.moveTo(midX + cutOutW / 2, lineY - halfW);
                    ctx.lineTo(midX + cutOutW / 2, lineY + halfW);
                    ctx.stroke();
                    // Sharp break lines crossing the gap
                    ctx.strokeStyle = "#475569";
                    ctx.lineWidth = 1.8;
                    // First diagonal slash
                    ctx.beginPath();
                    ctx.moveTo(midX - cutOutW / 2, lineY - halfW + 3);
                    ctx.lineTo(midX - 2, lineY - halfW - ext);
                    ctx.lineTo(midX + 2, lineY + halfW + ext);
                    ctx.lineTo(midX + cutOutW / 2, lineY + halfW - 3);
                    ctx.stroke();
                    // Second parallel diagonal slash for CAD double break look
                    ctx.beginPath();
                    ctx.moveTo(midX - cutOutW / 2 + 3, lineY - halfW + 6);
                    ctx.lineTo(midX - 2 + 3, lineY - halfW - ext + 3);
                    ctx.lineTo(midX + 2 + 3, lineY + halfW + ext - 3);
                    ctx.lineTo(midX + cutOutW / 2 + 3, lineY + halfW - 6);
                    ctx.stroke();
                    ctx.restore();
                }
                // 2. Electron flow attenuation (voltage drop representation)
                state.electronPhase += (state.current * 0.05 + 1.0) * dt * 0.45;
                if (state.electronPhase > 1.0) {
                    state.electronPhase -= 1.0;
                }
                // Calculate loss fading factor based on actual voltage drop percentage
                const voltsLimitVal = state.phase === 1 ? 220.0 : 380.0;
                const actualDropRatio = state.actualVoltageDrop / voltsLimitVal;
                const lossFactor = Math.min(actualDropRatio * 8.0, 0.85);
                ctx.save();
                for (let i = 0; i < lineParticles.length; i++) {
                    const p = lineParticles[i];
                    let currentRatio = p.xRatio + state.electronPhase;
                    if (currentRatio > 1.0) {
                        currentRatio -= 1.0;
                    }
                    // Slower electron flow on high drop
                    const speedFactor = 1.0 - (currentRatio * lossFactor * 0.6);
                    const px = lineX1 + ((p.xRatio + state.electronPhase * speedFactor) % 1.0) * (lineX2 - lineX1);
                    // Particle spread dynamically scaled with wireWidth
                    const py = lineY + p.offsetY * (wireWidth / 8.0);
                    const progressRatio = (px - lineX1) / (lineX2 - lineX1);
                    const alpha = 1.0 - (progressRatio * lossFactor * 0.75);
                    ctx.fillStyle = "rgba(255, 255, 255, " + Math.max(alpha, 0.1) + ")";
                    ctx.shadowBlur = 6 * alpha;
                    ctx.shadowColor = "#ffffff";
                    ctx.beginPath();
                    ctx.arc(px, py, 2.5 * Math.max(alpha, 0.5), 0, Math.PI * 2);
                    ctx.fill();
                }
                ctx.restore();
                // 3. Distance ruler & guide (Position dynamically adjusted with wireWidth)
                ctx.save();
                ctx.strokeStyle = "rgba(71, 85, 105, 0.3)";
                ctx.lineWidth = 1;
                ctx.setLineDash([3, 3]);
                const scaleY = lineY + (wireWidth / 2) + 20;
                ctx.beginPath();
                ctx.moveTo(lineX1, scaleY);
                ctx.lineTo(lineX2, scaleY);
                ctx.stroke();
                ctx.setLineDash([]);
                ctx.beginPath();
                ctx.moveTo(lineX1, scaleY - 4);
                ctx.lineTo(lineX1, scaleY + 4);
                ctx.moveTo(lineX2, scaleY - 4);
                ctx.lineTo(lineX2, scaleY + 4);
                ctx.stroke();
                const textStr = "L = " + state.length + " m";
                const textWidth = ctx.measureText(textStr).width + 8;
                ctx.fillStyle = "#f8fafc";
                ctx.fillRect((lineX1 + lineX2) / 2 - textWidth / 2, scaleY - 7, textWidth, 14);
                ctx.fillStyle = "#475569";
                ctx.font = "500 11px Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
                ctx.textAlign = "center";
                ctx.textBaseline = "middle";
                ctx.fillText(textStr, (lineX1 + lineX2) / 2, scaleY);
                ctx.restore();
                // D. Heat Wave Particle System Update & Render
                const heatIndexVal = Math.min((state.current / state.ampacityLimit) * 100.0, 150.0);
                let spawnChance = (heatIndexVal / 100.0) * 0.45;
                if (state.installation === "conduit") {
                    spawnChance *= 1.4; // Heat trapped within conduit
                }
                if ((Math.random() < spawnChance) ? (heatParticles.length < maxHeatParticles) : false) {
                    const type = Math.random() < 0.35 ? 0 : 1;
                    if (type === 0) {
                        const angle = Math.random() * Math.PI - Math.PI;
                        const dist = crossR * Math.random();
                        heatParticles.push({
                            x: crossCx + Math.cos(angle) * dist,
                            y: crossCy + Math.sin(angle) * dist,
                            vx: (Math.random() - 0.5) * 12,
                            vy: -15 - Math.random() * 25,
                            life: 1.0,
                            decay: 0.02 + Math.random() * 0.03,
                            size: 3 + Math.random() * 6,
                            isCore: true
                        });
                    } else {
                        const rx = lineX1 + Math.random() * (lineX2 - lineX1);
                        heatParticles.push({
                            x: rx,
                            y: lineY + (Math.random() - 0.5) * (wireWidth - 4),
                            vx: (Math.random() - 0.5) * 8,
                            vy: -10 - Math.random() * 20,
                            life: 1.0,
                            decay: 0.03 + Math.random() * 0.04,
                            size: 2 + Math.random() * 5,
                            isCore: false
                        });
                    }
                }
                ctx.save();
                ctx.globalCompositeOperation = "screen";
                for (let i = heatParticles.length - 1; i >= 0; i--) {
                    const p = heatParticles[i];
                    p.x += p.vx * dt;
                    p.y += p.vy * dt;
                    p.life -= p.decay;
                    if (p.life <= 0) {
                        heatParticles.splice(i, 1);
                        continue;
                    }
                    let hue = 35;
                    if (heatIndexVal > 100) {
                        hue = 0;
                    } else if (heatIndexVal > 80) {
                        hue = 20;
                    } else if (heatIndexVal < 50) {
                        hue = 45;
                    }
                    const alpha = p.life * (heatIndexVal / 150) * 0.35;
                    if ((state.installation === "conduit") ? (!p.isCore) : false) {
                        const pipeOffsetY = (wireWidth / 2) + 5;
                        if (p.y < lineY - pipeOffsetY) {
                            p.vy *= 0.2;
                            p.vx += (Math.random() - 0.5) * 15;
                            p.size += 0.1;
                        }
                    }
                    const radGrad = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.size);
                    radGrad.addColorStop(0, "hsla(" + hue + ", 100%, 60%, " + alpha + ")");
                    radGrad.addColorStop(1, "hsla(" + hue + ", 100%, 50%, 0)");
                    ctx.fillStyle = radGrad;
                    ctx.beginPath();
                    ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
                    ctx.fill();
                }
                ctx.restore();
                // E. Technical Dimension Layout (CAD/Blueprint styling)
                ctx.save();
                ctx.strokeStyle = "rgba(71, 85, 105, 0.4)";
                ctx.fillStyle = "#475569";
                ctx.lineWidth = 1;
                // 1. Cable Outer Diameter Dimension (Left Side vertical - text rotated vertically)
                const dimX = crossCx - crossR - 22;
                ctx.beginPath();
                ctx.moveTo(crossCx - crossR, crossCy - crossR);
                ctx.lineTo(dimX - 4, crossCy - crossR);
                ctx.moveTo(crossCx - crossR, crossCy + crossR);
                ctx.lineTo(dimX - 4, crossCy + crossR);
                ctx.stroke();
                const arrowLimitY = Math.max(38, crossR + 6); // Secure at least 38px radius to prevent mm text overlapping the extension lines
                drawArrow(dimX, crossCy - 10, dimX, crossCy - arrowLimitY, 4);
                drawArrow(dimX, crossCy + 10, dimX, crossCy + arrowLimitY, 4);
                ctx.beginPath();
                ctx.moveTo(dimX, crossCy - 10);
                ctx.lineTo(dimX, crossCy + 10);
                ctx.stroke();
                const physicalD = (1.8 * Math.sqrt(state.chosenSize) + 8).toFixed(1);
                const dimText = "Ø " + physicalD + " mm";
                ctx.save();
                ctx.translate(dimX - 6, crossCy); // Position text exactly 6px to the left of the vertical arrow line
                ctx.rotate(-Math.PI / 2); // Rotate vertically matching the CAD standard
                ctx.font = "bold 11px Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
                ctx.textAlign = "center";
                ctx.textBaseline = "middle";
                // Add white halo outline for premium readability
                ctx.strokeStyle = "#ffffff";
                ctx.lineWidth = 2.0; // Reduced thickness to prevent letter overlap (m-m blurring)
                ctx.strokeText(dimText, 0, 0);
                ctx.fillStyle = "#475569";
                ctx.fillText(dimText, 0, 0);
                ctx.restore();
                // 2. Conductor Sizing Leader Line (Pointer to Live core - positioned to top-right to prevent overlap)
                const targetCoreAngle = -Math.PI / 2; // top-most core
                const pcx = crossCx + Math.cos(targetCoreAngle) * cDist;
                const pcy = crossCy + Math.sin(targetCoreAngle) * cDist;
                const pointerAngle = -Math.PI * 0.25; // point to top-right edge
                const edgeX = pcx + Math.cos(pointerAngle) * coreRadius;
                const edgeY = pcy + Math.sin(pointerAngle) * coreRadius;
                const leaderX1 = edgeX + 15;
                const leaderY1 = edgeY - 15;
                const leaderX2 = leaderX1 + 25;
                ctx.beginPath();
                ctx.moveTo(edgeX, edgeY);
                ctx.lineTo(leaderX1, leaderY1);
                ctx.lineTo(leaderX2, leaderY1);
                ctx.stroke();
                ctx.beginPath();
                ctx.arc(edgeX, edgeY, 2, 0, Math.PI * 2);
                ctx.fillStyle = "rgba(71, 85, 105, 0.8)";
                ctx.fill();
                ctx.font = "bold 11px Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
                ctx.textAlign = "left";
                ctx.textBaseline = "bottom";
                const sizeText = state.chosenSize.toFixed(1) + " mm²";
                ctx.strokeStyle = "#ffffff";
                ctx.lineWidth = 2.0; // Reduced thickness to prevent blurring
                ctx.strokeText(sizeText, leaderX2 + 2, leaderY1 + 3);
                ctx.fillStyle = "#475569";
                ctx.fillText(sizeText, leaderX2 + 2, leaderY1 + 3);
                // 3. Technical Labels (Section name &#038; route name)
                ctx.fillStyle = "rgba(71, 85, 105, 0.4)";
                ctx.font = "bold 9px Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
                ctx.textAlign = "left";
                ctx.fillText("SEC A-A: CROSS SECTION", 10, height - 10);
                ctx.textAlign = "right";
                const cableSpecText = (state.material.toUpperCase() === "CU" ? "COPPER" : "ALUMINUM") + " " + (state.phase === 1 ? "1Ø2W" : "3Ø4W");
                ctx.fillText("ROUTE PLAN: " + cableSpecText, width - 10, height - 10);
                ctx.restore();
                // C. Render Load Indicator (Right side box)
                ctx.save();
                const loadBoxX = lineX2 + 10;
                const loadBoxY = lineY - 30;
                ctx.fillStyle = "#ffffff";
                ctx.strokeStyle = "#475569";
                ctx.lineWidth = 3;
                ctx.beginPath();
                ctx.rect(loadBoxX, loadBoxY, 70, 60);
                ctx.fill();
                ctx.stroke();
                // Draw little load motor inside
                ctx.fillStyle = "#0284c7";
                ctx.font = "bold 11px Outfit, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
                ctx.textAlign = "center";
                ctx.fillText("LOAD", loadBoxX + 35, loadBoxY + 24);
                ctx.fillStyle = "#475569";
                ctx.font = "10px Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
                ctx.fillText(Math.round(state.current) + " A", loadBoxX + 35, loadBoxY + 44);
                ctx.restore();
            }
            // Sync preset and run initial calculations
            loadPreset('household');
            requestAnimationFrame(animate);
            // Right-click &#038; Keyboard shortcuts block
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
                alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                return false;
            }, { capture: true });
            document.addEventListener('selectstart', function(e) {
                e.preventDefault();
                return false;
            }, { capture: true });
            document.addEventListener('keydown', function(e) {
                if (e.key === 'F12') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.ctrlKey) {
                    if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                    if (e.shiftKey) {
                        if (['i','I','j','J','c','C'].includes(e.key)) {
                            e.preventDefault();
                            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                            return false;
                        }
                    }
                }
            }, { capture: true });
        }
        let initAttempts = 0;
        function tryInit() {
            initAttempts++;
            initSimulator();
            if (!window.__cable_initialized) {
                if (initAttempts < 50) {
                    setTimeout(tryInit, 100);
                }
            }
        }
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            tryInit();
        } else {
            document.addEventListener('DOMContentLoaded', tryInit);
            window.addEventListener('load', tryInit);
        }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>시스템 전압 및 상수 선택: 단상 220V 또는 3상 380V 중 전력 송전 환경을 선택합니다.</strong></li>
<li style="margin-bottom: 6px;">부하 용량 및 전송 거리 정의: 슬라이더를 이용하여 소요 전류(Ampere) 및 송전 단으로부터 부하까지의 케이블 포설 거리(m)를 설정합니다.</li>
<li style="margin-bottom: 6px;">허용 기준치 및 배선재 세팅: 케이블 도체 재질(동 Cu, 알루미늄 Al)과 포설 형태(노출 트레이, 배관 매입, 지하 매설)를 입력합니다.</li>
<li style="margin-bottom: 6px;">실시간 케이블 내부 상태 분석: 계산된 최적 공칭 규격(mm²)과 함께 전하 밀도 과다에 따른 발열 가중치와 실시간 전압강하 비율을 계측 모니터에서 분석합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 전선 단면적 계산법 및 전압 강하 공식 (내선규정/KEC)</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 케이블 규격 선정(Cable Sizing)의 3대 핵심 엔지니어링 팩터</h3>
<p>안전한 전력 공급을 위해 전선을 선정할 때는 한국전기설비규정(KEC, Korea Electro-technical Code)에 부합하는 다음 3가지 핵심 검토항목을 모두 통과해야 합니다.</p><ul><li><strong>허용 전류 (Ampacity):</strong> 도체에 지속적으로 전류가 흐를 때 도체 피복의 최고허용온도(예: XLPE의 경우 90℃)를 초과하지 않는 안전 한계 전류입니다. 포설 환경(밀폐도, 주변 온도)에 따른 보정 계수가 적용됩니다.</li><li><strong>전압 강하 (Voltage Drop):</strong> 송전 선로가 길어질수록 도체 자체 저항에 의해 부하 단의 전압이 강하하는 현상입니다. 기계 장비의 오작동 및 효율 저하를 유발하므로 통상 3%~5% 이내로 제어해야 합니다.</li><li><strong>기계적 강도 및 단락 전류:</strong> 사고 시 발생하는 순간 단락 전류에 견디는 열적 능력을 갖춰야 합니다.</li></ul>
<h3>2. 허용 전압 강하율 및 단면적(A) 산출 계산 공식</h3>
<p>내선규정에서 사용되는 저압 배선에서의 허용 전류 및 전압강하 기준 공식은 다음과 같이 요약 정리됩니다.</p><p><strong>① 직류 및 단상 2선식 선로 전압강하 공식:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">e = (35.6 &times; L &times; I) / (1000 &times; A) &nbsp;[V]</p><p><strong>② 삼상 3선식 선로 전압강하 공식:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">e = (30.8 &times; L &times; I) / (1000 &times; A) &nbsp;[V]</p><p>여기서 <code>L</code>은 선로의 편도 길이(m), <code>I</code>는 부하 전류(A), <code>A</code>는 전선의 단면적(mm²)입니다. 이 식을 전선 단면적 <code>A</code>에 대해 유도하면 다음과 같이 필요한 케이블의 최하 단면적을 알 수 있습니다.</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">A_req = (30.8 &times; L &times; I) / (1000 &times; e_allow) &nbsp;[mm²] &nbsp;&nbsp;(삼상 기준)</p>
<h3>3. 포설 환경 및 도체 고유 저항에 따른 보정</h3>
<p>케이블의 안전 전류 용량은 도체의 고유 저항계수(<code>&rho;</code>)와 도체가 외계로 방열하는 기하학적 형태에 절대적인 지배를 받습니다.</p><ul><li><strong>구리(Copper) 도체:</strong> 전기적 전도도가 뛰어나고(저항률 <code>1/58</code>) 내구성이 강해 대부분의 건축, 공업 설비에 채택됩니다.</li><li><strong>알루미늄(Aluminium) 도체:</strong> 전도도는 구리의 약 61% 수준(저항률 <code>1/35</code>)으로 떨어지지만 무게가 가볍고 저렴하여 대형 고압 한전 송배전선로에 채택됩니다. 단, 동일 전류 수준에서 구리 대비 1~2단계 큰 공칭 규격을 채용해야 안전합니다.</li></ul>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>


<h2 style="font-size: 1.4em; font-weight: 700; color: #1f2937; margin-top: 40px; margin-bottom: 15px; border-left: 4px solid #3b82f6; padding-left: 10px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 함께 보면 좋은 공학 글</h2>


<a href="https://myengnote.com/power-factor-correction-calculator-simulator/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">역률 개선 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>


<a href="https://myengnote.com/industrial-boiler-efficiency-calculator-losses/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 12px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;">
    <span style="display: table-cell; vertical-align: middle;">
        <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>
        <span style="display: block; overflow: hidden;">
            <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span>
            <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">보일러 효율 계산기 &#038; 시뮬레이터</span>
        </span>
    </span>
    <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span>
</a>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/cable-sizing-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>역률 개선 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/power-factor-correction-calculator-simulator/</link>
					<comments>https://myengnote.com/power-factor-correction-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 25 Jun 2026 22:13:09 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[무효전력]]></category>
		<category><![CDATA[역률개선]]></category>
		<category><![CDATA[위상차시각화]]></category>
		<category><![CDATA[콘덴서용량]]></category>
		<category><![CDATA[피상전력]]></category>
		<guid isPermaLink="false">https://myengnote.com/power-factor-correction-calculator-simulator/</guid>

					<description><![CDATA[부하의 유효전력과 기존 역률, 목표 역률을 입력하여 요구되는 역률 개선용 콘덴서(Capacitor Bank)의 용량(kVAR)과 전기 에너지 절감 효과를 2D 벡터 위상 시뮬레이션으로 정밀 분석하는 시뮬레이터입니다. <a href="https://myengnote.com/power-factor-correction-calculator-simulator/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 역률 개선 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for powerfactor-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .powerfactor-calculator-wrapper *, .powerfactor-calculator-wrapper *::before, .powerfactor-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .powerfactor-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7; /* Cobalt blue accent */
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777; /* Pink/magenta accent */
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --color-danger: #ef4444;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .powerfactor-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 15s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-power::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan); }
        #slider-pf1::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 10px var(--color-magenta); }
        #slider-pf2::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 10px var(--color-purple); }
        .segmented-control {
            display: grid;
            grid-template-columns: 1fr 1fr;
            background: rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 8px;
            padding: 2px;
            gap: 2px;
        }
        .segment-btn {
            background: transparent;
            border: none;
            outline: none;
            color: var(--color-text-muted);
            font-size: 12px;
            font-weight: 600;
            padding: 8px;
            cursor: pointer;
            border-radius: 6px;
            transition: all 0.2s ease;
            text-align: center;
        }
        .segment-btn.active {
            background: #ffffff;
            color: var(--color-cyan);
            box-shadow: 0 2px 6px rgba(0,0,0,0.05);
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
            justify-content: flex-start;
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 10;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(0, 242, 254, 0.08) 0%, rgba(138, 43, 226, 0.03) 100%);
            border: 1px solid rgba(0, 242, 254, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(0, 242, 254, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 32px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(0, 242, 254, 0.2);
            background: rgba(0, 242, 254, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: rgba(0, 242, 254, 0.3);
            background: rgba(0, 242, 254, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: var(--color-cyan);
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        /* Container Query for Responsiveness inside WP */
        @container pf-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1fr;
                gap: 20px;
            }
            .control-panel {
                grid-column: 1;
            }
            .simulation-panel {
                grid-column: 2;
                align-self: start;
            }
            .results-panel {
                grid-column: 1 / span 2;
                display: grid;
                grid-template-columns: 1fr 1.2fr;
                gap: 20px;
            }
            .results-panel .panel-header {
                grid-column: 1 / span 2;
            }
            .ratio-readout-box {
                grid-column: 1;
                grid-row: 2;
            }
            .formula-card {
                grid-column: 1;
                grid-row: 3;
            }
            .results-grid {
                grid-column: 2;
                grid-row: 2 / span 2;
            }
        }
        @container pf-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .results-panel {
                display: flex;
                flex-direction: column;
                gap: 16px;
            }
            .ratio-readout-box, .formula-card, .results-grid {
                grid-column: auto;
                grid-row: auto;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.powerfactor-calculator-wrapper .app-main-grid,
.powerfactor-calculator-wrapper .main-grid,
.powerfactor-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.powerfactor-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.powerfactor-calculator-wrapper .simulation-panel,
.powerfactor-calculator-wrapper .canvas-panel,
.powerfactor-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.powerfactor-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.powerfactor-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.powerfactor-calculator-wrapper .simulation-results-section .ratio-readout-box,
.powerfactor-calculator-wrapper .simulation-results-section .re-readout-box,
.powerfactor-calculator-wrapper .simulation-results-section .status-readout-box,
.powerfactor-calculator-wrapper .simulation-results-section .flow-readout-box,
.powerfactor-calculator-wrapper .simulation-results-section [class*="readout-box"],
.powerfactor-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.powerfactor-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.powerfactor-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.powerfactor-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .powerfactor-calculator-wrapper .app-main-grid,
    .powerfactor-calculator-wrapper .main-grid,
    .powerfactor-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .powerfactor-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .powerfactor-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .powerfactor-calculator-wrapper .simulation-panel,
    .powerfactor-calculator-wrapper .canvas-panel,
    .powerfactor-calculator-wrapper .sim-panel,
    .powerfactor-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .powerfactor-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .powerfactor-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .powerfactor-calculator-wrapper .simulation-results-section .re-readout-box,
    .powerfactor-calculator-wrapper .simulation-results-section .status-readout-box,
    .powerfactor-calculator-wrapper .simulation-results-section .flow-readout-box,
    .powerfactor-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .powerfactor-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .powerfactor-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .powerfactor-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.powerfactor-calculator-wrapper .app-container,
.powerfactor-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.powerfactor-calculator-wrapper .simulation-results-section .formula-card,
.powerfactor-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.powerfactor-calculator-wrapper .simulation-results-section .formula-card h4,
.powerfactor-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.powerfactor-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.powerfactor-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="powerfactor-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-lines-leaning fa-spin-slow text-cyan"></i></div>
                <div>
                    <h1>POWER FACTOR</h1>
                    <div class="subtitle">역률 개선 계산기 &#038; 위상 매칭 물리 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">PHASOR ANALYSIS ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>전력 계통 설계 변수</h2>
                </div>
                <!-- Load Active Power (kW) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-bolt text-cyan"></i> 유효 전력 (P)</label>
                        <span class="helper-text">(10 ~ 500 kW)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-power" class="custom-number-input" min="10" max="500" value="100">
                        <div class="unit-badge">kW</div>
                    </div>
                    <input type="range" id="slider-power" class="custom-slider" min="10" max="500" step="5" value="100">
                </div>
                <!-- Initial PF1 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-chart-line text-magenta"></i> 기존 저하 역률 (PF₁)</label>
                        <span class="helper-text">(0.50 ~ 0.98)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-pf1" class="custom-number-input" min="0.50" max="0.98" step="0.01" value="0.70">
                        <div class="unit-badge">cosθ</div>
                    </div>
                    <input type="range" id="slider-pf1" class="custom-slider" min="50" max="98" step="1" value="70">
                </div>
                <!-- Target PF2 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-chart-line text-purple"></i> 목표 개선 역률 (PF₂)</label>
                        <span class="helper-text">(0.80 ~ 1.00)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-pf2" class="custom-number-input" min="0.80" max="1.00" step="0.01" value="0.95">
                        <div class="unit-badge">cosθ</div>
                    </div>
                    <input type="range" id="slider-pf2" class="custom-slider" min="80" max="100" step="1" value="95">
                </div>
                <!-- Phase system voltage -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-plug"></i> 배전 계통 전압</label>
                    </div>
                    <div class="segmented-control" id="control-voltage">
                        <button class="segment-btn" data-value="220">단상 220 V</button>
                        <button class="segment-btn active" data-value="380">삼상 380 V</button>
                    </div>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 부하 개선 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="motor">
                            <div class="preset-icon"><i class="fa-solid fa-server"></i></div>
                            <div class="preset-details"><span class="preset-name">대형 모터 유도성 부하</span><span class="preset-spec">150kW, 0.70→0.96</span></div>
                        </button>
                        <button class="preset-btn" data-preset="welder">
                            <div class="preset-icon"><i class="fa-solid fa-fire-burner"></i></div>
                            <div class="preset-details"><span class="preset-name">공장 용접 설비 반동</span><span class="preset-spec">60kW, 0.52→0.90</span></div>
                        </button>
                        <button class="preset-btn" data-preset="plant">
                            <div class="preset-icon"><i class="fa-solid fa-industry"></i></div>
                            <div class="preset-details"><span class="preset-name">상업 빌딩 전체 전열</span><span class="preset-spec">300kW, 0.82→0.98</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>실시간 2D 위상 위상차 &#038; 벡터 Phasor 삼각도</h2>
                                    </div>
                                    <div id="txt-phase-diff" class="canvas-scale-indicator">위상 격차</div>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                </div>
                                <!-- Mini Metrics -->
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <div class="label">선로 소요 피상전력 차</div>
                                        <div id="txt-kva-diff" class="value">0 kVA</div>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <div class="label">전류 위상 지연 시간</div>
                                        <div id="txt-lag-time" class="value">0.0 ms</div>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">필요 전력용 콘덴서 용량 (Qc)</div>
                                    <div id="txt-qc-out" class="ratio-value">52.3 kVAR</div>
                                    <div id="txt-cphase-out" class="ratio-type">(상당 정전용량: 120.4 uF, 3상 Δ)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- S1 apparent power -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-chart-pie text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">개선 전 소요 피상전력 (S₁) / 선로 전류 (I₁)</span>
                                            <span id="txt-s1-out" class="card-value">142.8 kVA (374.8 A)</span>
                                        </div>
                                    </div>
                                    <!-- S2 apparent power -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-chart-pie text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">개선 후 소요 피상전력 (S₂) / 선로 전류 (I₂)</span>
                                            <span id="txt-s2-out" class="card-value">105.2 kVA (276.1 A)</span>
                                        </div>
                                    </div>
                                    <!-- Line current reduction -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-percent text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">선로 공급 전류 절감 한계</span>
                                            <span id="txt-current-reduction" class="card-value">26.3 % 절감</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 교류 위상 기하학 공식</h4>
                                    <div class="formula-equation">Q_c = P × (tanθ₁ &#8211; tanθ₂) [kVAR]</div>
                                    <div class="formula-equation">S = P / cosθ [kVA]</div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- JavaScript Circuit Simulation Engine -->
    </div>
</div>
<script>
        (function() {
        let isInit = false;
        function initSimulator() {
            if (isInit) return;
            const canvas = document.getElementById('physics-canvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
            isInit = true;
            window.__pf_initialized = true;
            // DOM Elements
            const sliderPower = document.getElementById('slider-power');
            const inputPower = document.getElementById('input-power');
            const sliderPf1 = document.getElementById('slider-pf1');
            const inputPf1 = document.getElementById('input-pf1');
            const sliderPf2 = document.getElementById('slider-pf2');
            const inputPf2 = document.getElementById('input-pf2');
            const controlVoltage = document.getElementById('control-voltage');
            const presetButtons = document.querySelectorAll('.preset-btn');
            const txtQcOut = document.getElementById('txt-qc-out');
            const txtCphaseOut = document.getElementById('txt-cphase-out');
            const txtS1Out = document.getElementById('txt-s1-out');
            const txtS2Out = document.getElementById('txt-s2-out');
            const txtCurrentReduction = document.getElementById('txt-current-reduction');
            const txtPhaseDiff = document.getElementById('txt-phase-diff');
            const txtKvaDiff = document.getElementById('txt-kva-diff');
            const txtLagTime = document.getElementById('txt-lag-time');
            // State variables
            const state = {
                power: 100.0, // kW
                pf1: 0.70,
                pf2: 0.95,
                voltage: 380.0, // V
                i1: 217.1,
                i2: 159.9,
                // Anim phase
                wavePhase: 0.0,
                lastTime: 0
            };
            function resizeCanvas() {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            resizeCanvas();
            window.addEventListener('resize', resizeCanvas);
            setTimeout(resizeCanvas, 300);
            // Sync Inputs
            function syncPowerFromSlider() {
                const val = parseInt(sliderPower.value);
                inputPower.value = val;
                state.power = val;
                clearPresets();
                updateCalculations();
            }
            function syncPowerFromInput() {
                let val = parseInt(inputPower.value);
                if (isNaN(val)) { val = 10; }
                if (val < 10) { val = 10; }
                if (val > 500) { val = 500; }
                sliderPower.value = val;
                state.power = val;
                clearPresets();
                updateCalculations();
            }
            function syncPf1FromSlider() {
                const val = parseFloat(sliderPf1.value) / 100.0;
                inputPf1.value = val.toFixed(2);
                state.pf1 = val;
                // Clamping targets
                if (state.pf2 < state.pf1) {
                    state.pf2 = state.pf1;
                    inputPf2.value = state.pf2.toFixed(2);
                    sliderPf2.value = Math.round(state.pf2 * 100.0);
                }
                clearPresets();
                updateCalculations();
            }
            function syncPf1FromInput() {
                let val = parseFloat(inputPf1.value);
                if (isNaN(val)) { val = 0.50; }
                if (val < 0.50) { val = 0.50; }
                if (val > 0.98) { val = 0.98; }
                sliderPf1.value = Math.round(val * 100.0);
                state.pf1 = val;
                if (state.pf2 < state.pf1) {
                    state.pf2 = state.pf1;
                    inputPf2.value = state.pf2.toFixed(2);
                    sliderPf2.value = Math.round(state.pf2 * 100.0);
                }
                clearPresets();
                updateCalculations();
            }
            function syncPf2FromSlider() {
                const val = parseFloat(sliderPf2.value) / 100.0;
                // clamp
                let clampedVal = val;
                if (clampedVal < state.pf1) {
                    clampedVal = state.pf1;
                }
                inputPf2.value = clampedVal.toFixed(2);
                sliderPf2.value = Math.round(clampedVal * 100.0);
                state.pf2 = clampedVal;
                clearPresets();
                updateCalculations();
            }
            function syncPf2FromInput() {
                let val = parseFloat(inputPf2.value);
                if (isNaN(val)) { val = 0.80; }
                if (val < 0.80) { val = 0.80; }
                if (val > 1.00) { val = 1.00; }
                if (val < state.pf1) {
                    val = state.pf1;
                }
                sliderPf2.value = Math.round(val * 100.0);
                state.pf2 = val;
                clearPresets();
                updateCalculations();
            }
            // Vector math and correction calculations
            function updateCalculations() {
                // S1 = P / PF1, S2 = P / PF2
                const s1 = state.power / state.pf1;
                const s2 = state.power / state.pf2;
                // Theta
                const theta1 = Math.acos(state.pf1);
                const theta2 = Math.acos(state.pf2);
                // Q1 = P * tan(theta1), Q2 = P * tan(theta2)
                const q1 = state.power * Math.tan(theta1);
                const q2 = state.power * Math.tan(theta2);
                // Qc = Q1 - Q2 (Capacitor size)
                let qc = q1 - q2;
                if (qc < 0) {
                    qc = 0.0;
                }
                // Per-phase capacitance (assuming 3-phase delta at 380V, 60Hz)
                // C_phase = Qc * 10^9 / (3 * 2 * pi * f * V^2)
                const freq = 60.0;
                let capPhase = 0.0;
                if (state.voltage === 380.0) {
                    // 3-Phase Delta connected Bank
                    capPhase = (qc * 1000.0 * 1000.0 * 1000.0) / (3.0 * 2.0 * Math.PI * freq * state.voltage * state.voltage);
                } else {
                    // Single Phase
                    capPhase = (qc * 1000.0 * 1000.0 * 1000.0) / (2.0 * Math.PI * freq * state.voltage * state.voltage);
                }
                // Line Current calculation (Single phase vs Three phase)
                let i1 = 0.0;
                let i2 = 0.0;
                if (state.voltage === 380.0) {
                    i1 = (state.power * 1000.0) / (Math.sqrt(3.0) * state.voltage * state.pf1);
                    i2 = (state.power * 1000.0) / (Math.sqrt(3.0) * state.voltage * state.pf2);
                } else {
                    i1 = (state.power * 1000.0) / (state.voltage * state.pf1);
                    i2 = (state.power * 1000.0) / (state.voltage * state.pf2);
                }
                state.i1 = i1;
                state.i2 = i2;
                // Line current reduction % = (1 - PF1 / PF2) * 100
                const currentRed = (1.0 - state.pf1 / state.pf2) * 100.0;
                // Update UI text values
                txtQcOut.innerText = qc.toFixed(1) + ' kVAR';
                const connectionType = state.voltage === 380.0 ? '3상 Δ 델타' : '단상 선로';
                txtCphaseOut.innerText = '(상당 전용 정전용량: ' + capPhase.toFixed(1) + ' μF, ' + connectionType + ')';
                txtS1Out.innerText = s1.toFixed(1) + ' kVA (' + i1.toFixed(1) + ' A)';
                txtS2Out.innerText = s2.toFixed(1) + ' kVA (' + i2.toFixed(1) + ' A)';
                txtCurrentReduction.innerText = currentRed.toFixed(1) + '% 절감 완료';
                // Mini metrics
                txtKvaDiff.innerText = Math.round(s1 - s2) + ' kVA';
                // Lag time calculation: dt = theta / (2 * pi * f)
                const lagAngleRad = theta1; // radians
                const lagSec = lagAngleRad / (2.0 * Math.PI * freq);
                txtLagTime.innerText = (lagSec * 1000.0).toFixed(2) + ' ms';
                // Display phase difference state text
                const degDiff = (theta1 * 180.0) / Math.PI;
                txtPhaseDiff.innerText = '위상차: ' + degDiff.toFixed(1) + '° (' + (state.pf1 * 100.0).toFixed(0) + '% PF)';
            }
            // Presets
            function loadPreset(key) {
                clearPresets();
                presetButtons.forEach(btn => {
                    if (btn.dataset.preset === key) {
                        btn.classList.add('active');
                    }
                });
                if (key === 'motor') {
                    state.power = 150;
                    state.pf1 = 0.70;
                    state.pf2 = 0.95;
                    state.voltage = 380;
                }
                if (key === 'welder') {
                    state.power = 60;
                    state.pf1 = 0.52;
                    state.pf2 = 0.90;
                    state.voltage = 380;
                }
                if (key === 'plant') {
                    state.power = 300;
                    state.pf1 = 0.82;
                    state.pf2 = 0.98;
                    state.voltage = 380;
                }
                // Sync UI elements
                document.querySelectorAll('#control-voltage .segment-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (parseInt(btn.dataset.value) === state.voltage) {
                        btn.classList.add('active');
                    }
                });
                inputPower.value = state.power;
                sliderPower.value = state.power;
                inputPf1.value = state.pf1.toFixed(2);
                sliderPf1.value = Math.round(state.pf1 * 100.0);
                inputPf2.value = state.pf2.toFixed(2);
                sliderPf2.value = Math.round(state.pf2 * 100.0);
                updateCalculations();
            }
            function clearPresets() {
                presetButtons.forEach(btn => btn.classList.remove('active'));
            }
            // Bind Event Listeners
            sliderPower.addEventListener('input', syncPowerFromSlider);
            inputPower.addEventListener('change', syncPowerFromInput);
            sliderPf1.addEventListener('input', syncPf1FromSlider);
            inputPf1.addEventListener('change', syncPf1FromInput);
            sliderPf2.addEventListener('input', syncPf2FromSlider);
            inputPf2.addEventListener('change', syncPf2FromInput);
            // Voltage Selection
            document.querySelectorAll('#control-voltage .segment-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll('#control-voltage .segment-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    state.voltage = parseInt(btn.dataset.value);
                    clearPresets();
                    updateCalculations();
                });
            });
            presetButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    loadPreset(btn.dataset.preset);
                });
            });
            // Animation Loop
            function animate(currentTime) {
                requestAnimationFrame(animate);
                let dt = (currentTime - state.lastTime) / 1000;
                if (isNaN(dt)) { dt = 0.016; }
                if (dt < 0) { dt = 0.016; }
                if (dt > 1.0) { dt = 0.016; }
                state.lastTime = currentTime;
                const width = canvas.width / (window.devicePixelRatio || 1);
                const height = canvas.height / (window.devicePixelRatio || 1);
                ctx.clearRect(0, 0, width, height);
                // Draw Grid
                ctx.save();
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
                ctx.lineWidth = 1;
                const gridSpacing = 25;
                for (let x = 0; x < width; x += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSpacing) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                ctx.restore();
                // Geometry Mapping
                // Split Screen: Left Side = Phasor triangle, Right Side = Waveform phase shift
                const splitX = width / 2 - 20;
                const theta1 = Math.acos(state.pf1);
                const theta2 = Math.acos(state.pf2);
                // A. Render 2D Vector Phasor Triangle (Left Side)
                // Origin near bottom-left of left pane
                const triOx = 50;
                const triOy = height - 80;
                // Available drawing space (leave 150px on the right for the Qc text label)
                const maxW = splitX - 150;
                const maxH = triOy - 40;
                // Dynamic auto-scaling (zoom) factor
                // To keep the drawing beautifully sized and always fit within the canvas boundaries.
                const scaleW = maxW / Math.max(10, state.power);
                const scaleH = maxH / Math.max(10, state.power * Math.max(0.1, Math.tan(theta1)));
                const scale = Math.min(scaleW, scaleH);
                const triPx = state.power * scale;
                const triQ1y = state.power * Math.tan(theta1) * scale;
                const triQ2y = state.power * Math.tan(theta2) * scale;
                ctx.save();
                // 1. Draw Active Power horizontal line (P) - Cyan
                ctx.strokeStyle = "#0284c7";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.moveTo(triOx, triOy);
                ctx.lineTo(triOx + triPx, triOy);
                ctx.stroke();
                // Draw P text label (High contrast Cyan-700)
                ctx.fillStyle = "#0369a1";
                ctx.font = "bold 11px Outfit, sans-serif";
                ctx.fillText("P: " + Math.round(state.power) + " kW", triOx + triPx / 2 - 25, triOy + 20);
                // 2. Draw Reactive Power vertical line (Q1 - Uncompensated) - Magenta
                ctx.strokeStyle = "rgba(219, 39, 119, 0.25)";
                ctx.lineWidth = 3;
                ctx.beginPath();
                ctx.moveTo(triOx + triPx, triOy);
                ctx.lineTo(triOx + triPx, triOy - triQ1y);
                ctx.stroke();
                // Draw Q2 (Corrected Reactive Power)
                ctx.strokeStyle = "#db2777";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.moveTo(triOx + triPx, triOy);
                ctx.lineTo(triOx + triPx, triOy - triQ2y);
                ctx.stroke();
                // 3. Draw Qc Capacitor Vector (Green arrow pointing UP from Q1 to Q2)
                if (triQ1y > triQ2y) {
                    ctx.strokeStyle = "#10b981";
                    ctx.lineWidth = 4;
                    ctx.beginPath();
                    ctx.moveTo(triOx + triPx, triOy - triQ1y);
                    ctx.lineTo(triOx + triPx, triOy - triQ2y);
                    ctx.stroke();
                    // Arrow tip
                    ctx.fillStyle = "#10b981";
                    ctx.beginPath();
                    ctx.moveTo(triOx + triPx - 5, triOy - triQ2y + 8);
                    ctx.lineTo(triOx + triPx + 5, triOy - triQ2y + 8);
                    ctx.lineTo(triOx + triPx, triOy - triQ2y);
                    ctx.closePath();
                    ctx.fill();
                    // Draw Qc text label on the canvas (High contrast Emerald-700)
                    ctx.fillStyle = "#047857";
                    ctx.font = "bold 10px Inter, sans-serif";
                    const midQcy = triOy - (triQ1y + triQ2y) / 2;
                    ctx.fillText("Qc: " + (state.power * (Math.tan(theta1) - Math.tan(theta2))).toFixed(1) + " kVAR", triOx + triPx + 8, midQcy + 3);
                }
                // 4. Draw Apparent Power vectors (Hypotenuse)
                // S1 (Uncompensated) - light purple dotted
                ctx.strokeStyle = "rgba(124, 58, 237, 0.25)";
                ctx.lineWidth = 2.5;
                ctx.setLineDash([4, 4]);
                ctx.beginPath();
                ctx.moveTo(triOx, triOy);
                ctx.lineTo(triOx + triPx, triOy - triQ1y);
                ctx.stroke();
                ctx.setLineDash([]);
                // Draw S1 text label (High contrast Purple-700, placed near top-right end to avoid clutter)
                ctx.save();
                ctx.fillStyle = "#6d28d9";
                ctx.font = "bold 10px Inter, sans-serif";
                ctx.textAlign = "right";
                ctx.textBaseline = "bottom";
                const s1LabelX = triOx + triPx - 10;
                const s1LabelY = triOy - triQ1y - 6;
                ctx.fillText("S₁: " + (state.power / state.pf1).toFixed(1) + " kVA", s1LabelX, s1LabelY);
                ctx.restore();
                // S2 (Corrected) - Bold purple
                ctx.strokeStyle = "#7c3aed";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.moveTo(triOx, triOy);
                ctx.lineTo(triOx + triPx, triOy - triQ2y);
                ctx.stroke();
                // Draw S2 text label (High contrast Purple-800, placed near middle-right end to avoid clutter)
                ctx.save();
                ctx.fillStyle = "#5b21b6";
                ctx.font = "bold 10px Inter, sans-serif";
                ctx.textAlign = "right";
                ctx.textBaseline = "top";
                const s2LabelX = triOx + triPx - 10;
                const s2LabelY = triOy - triQ2y + 8;
                ctx.fillText("S₂: " + (state.power / state.pf2).toFixed(1) + " kVA", s2LabelX, s2LabelY);
                ctx.restore();
                // Label angles theta (θ1 is larger angle, θ2 is smaller angle)
                // We draw θ1 with a larger radius and θ2 with a smaller radius to separate them cleanly.
                ctx.beginPath();
                ctx.arc(triOx, triOy, 38, 0, -theta1, true);
                ctx.strokeStyle = "rgba(219, 39, 119, 0.4)";
                ctx.lineWidth = 1.5;
                ctx.stroke();
                // Label angle text θ1 (High contrast Pink-700, placed at r=48 and shifted up to prevent overlap)
                ctx.fillStyle = "#be185d";
                ctx.font = "italic 10px Inter, sans-serif";
                const t1x = triOx + 48 * Math.cos(-theta1 * 0.75);
                const t1y = triOy + 48 * Math.sin(-theta1 * 0.75);
                ctx.fillText("θ₁", t1x - 3, t1y + 3);
                ctx.beginPath();
                ctx.arc(triOx, triOy, 20, 0, -theta2, true);
                ctx.strokeStyle = "rgba(124, 58, 237, 0.6)";
                ctx.lineWidth = 2;
                ctx.stroke();
                // Label angle text θ2 (High contrast Purple-700, placed at r=28 and shifted down to prevent overlap)
                ctx.fillStyle = "#6d28d9";
                const t2x = triOx + 28 * Math.cos(-theta2 * 0.3);
                const t2y = triOy + 28 * Math.sin(-theta2 * 0.3);
                ctx.fillText("θ₂", t2x - 3, t2y + 3);
                ctx.restore();
                // B. Render Waveform Oscilloscope (Right Side)
                const scopeX = splitX + 20;
                const scopeY = height / 2 - 90;
                const scopeW = width - scopeX - 30;
                const scopeH = 180;
                ctx.save();
                // Draw oscilloscope screen background
                ctx.fillStyle = "#ffffff";
                ctx.strokeStyle = "rgba(0, 0, 0, 0.05)";
                ctx.lineWidth = 3;
                ctx.beginPath();
                ctx.rect(scopeX, scopeY, scopeW, scopeH);
                ctx.fill();
                ctx.stroke();
                // Center zero line
                ctx.strokeStyle = "rgba(0, 0, 0, 0.05)";
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.moveTo(scopeX, scopeY + scopeH / 2);
                ctx.lineTo(scopeX + scopeW, scopeY + scopeH / 2);
                ctx.stroke();
                // Dynamic sine phase update
                state.wavePhase += 3.0 * dt; // speed of wave moving left
                // Plot Voltage wave (Blue), Current before correction (Pink), and Current after correction (Green)
                ctx.lineWidth = 2.5;
                // 1. Voltage wave (Reference - Blue)
                ctx.strokeStyle = "#0284c7";
                ctx.beginPath();
                for (let x = 0; x < scopeW; x++) {
                    const waveT = (x / scopeW) * Math.PI * 3.5; // fits 1.75 cycles
                    const vy = scopeY + scopeH / 2 + Math.sin(waveT - state.wavePhase) * (scopeH / 2.5);
                    if (x === 0) {
                        ctx.moveTo(scopeX + x, vy);
                    } else {
                        ctx.lineTo(scopeX + x, vy);
                    }
                }
                ctx.stroke();
                // Calculate dynamic amplitudes for current waves based on calculated amperes
                const ampScale1 = Math.min(scopeH / 2.2, (state.i1 / 200.0) * (scopeH / 5.0));
                const currentAmp1 = Math.max(10, Math.min(scopeH / 2.1, ampScale1));
                const ampScale2 = Math.min(scopeH / 2.2, (state.i2 / 200.0) * (scopeH / 5.0));
                const currentAmp2 = Math.max(10, Math.min(scopeH / 2.1, ampScale2));
                // 2. Current wave before correction (Pink - Lags by theta1)
                ctx.strokeStyle = "#db2777";
                ctx.beginPath();
                for (let x = 0; x < scopeW; x++) {
                    const waveT = (x / scopeW) * Math.PI * 3.5;
                    const cy = scopeY + scopeH / 2 + Math.sin(waveT - state.wavePhase - theta1) * currentAmp1;
                    if (x === 0) {
                        ctx.moveTo(scopeX + x, cy);
                    } else {
                        ctx.lineTo(scopeX + x, cy);
                    }
                }
                ctx.stroke();
                // 3. Current wave after correction (Green - Lags by theta2, smaller amplitude)
                ctx.strokeStyle = "#10b981";
                ctx.beginPath();
                for (let x = 0; x < scopeW; x++) {
                    const waveT = (x / scopeW) * Math.PI * 3.5;
                    const cy = scopeY + scopeH / 2 + Math.sin(waveT - state.wavePhase - theta2) * currentAmp2;
                    if (x === 0) {
                        ctx.moveTo(scopeX + x, cy);
                    } else {
                        ctx.lineTo(scopeX + x, cy);
                    }
                }
                ctx.stroke();
                // Oscilloscope labels (Outside scope box to prevent overlap)
                ctx.font = "bold 9.5px Inter, sans-serif";
                ctx.fillStyle = "#0284c7";
                ctx.fillText("● 전압 (V)", scopeX, scopeY - 10);
                const wV = ctx.measureText("● 전압 (V)").width + 12;
                ctx.fillStyle = "#db2777";
                ctx.fillText("● 개선 전 전류 (I₁)", scopeX + wV, scopeY - 10);
                const wI1 = wV + ctx.measureText("● 개선 전 전류 (I₁)").width + 12;
                ctx.fillStyle = "#10b981";
                ctx.fillText("● 개선 후 전류 (I₂)", scopeX + wI1, scopeY - 10);
                ctx.restore();
            }
            // Sync preset and run initial calculations
            loadPreset('motor');
            requestAnimationFrame(animate);
            // Right-click &#038; Keyboard shortcuts block
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
                alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                return false;
            }, { capture: true });
            document.addEventListener('selectstart', function(e) {
                e.preventDefault();
                return false;
            }, { capture: true });
            document.addEventListener('keydown', function(e) {
                if (e.key === 'F12') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.ctrlKey) {
                    if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                    if (e.shiftKey) {
                        if (['i','I','j','J','c','C'].includes(e.key)) {
                            e.preventDefault();
                            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                            return false;
                        }
                    }
                }
            }, { capture: true });
        }
        let initAttempts = 0;
        function tryInit() {
            initAttempts++;
            initSimulator();
            if (!window.__pf_initialized) {
                if (initAttempts < 50) {
                    setTimeout(tryInit, 100);
                }
            }
        }
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            tryInit();
        } else {
            document.addEventListener('DOMContentLoaded', tryInit);
            window.addEventListener('load', tryInit);
        }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>부하 유효 전력(kW) 입력: 회로에서 실질적으로 일을 수행하는 유효 전력(10kW ~ 500kW)을 설정합니다.</strong></li>
<li style="margin-bottom: 6px;">기존 역률(PF1) 입력: 유도성 부하(모터 등)에 의해 저하된 현재의 역률 수치(0.50 ~ 0.98)를 입력합니다.</li>
<li style="margin-bottom: 6px;">목표 역률(PF2) 입력: 전력 요금 절감 및 변압기 마진 확보를 위한 목표 개선 역률(0.80 ~ 1.00)을 설정합니다.</li>
<li style="margin-bottom: 6px;">실시간 위상 정렬 및 벡터 모니터링: 정전용량(μF)이 투입되면서 무효전력(kVAR) 벡터가 수축하는 벡터 삼각도와 전압-전류 위상 정현파의 실시간 일치(정렬) 과정을 확인합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 전력공학 역률 개선 원리 및 수식 해설 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 역률(Power Factor)의 물리적 정의와 전력 효율적 가치</h3>
<p>교류(AC) 전력 계통에서 <strong>역률(Power Factor, PF)</strong>은 피상 전력(전원공학적으로 공급된 총 전력)에 대한 유효 전력(실제 기계적 일로 변환된 전력)의 임의 비율입니다.</p><ul><li><strong>유효 전력 (Active Power, P):</strong> 저항 부하에서 실제 소비되어 온열이나 동력으로 전환되는 전력(단위: kW)입니다.</li><li><strong>무효 전력 (Reactive Power, Q):</strong> 모터나 변압기 내부 코일에 전기 자기장을 형성하기 위해 에너지를 일시적으로 저장했다가 다시 계통으로 되돌려보내는 전력(단위: kVAR)입니다. 계통에 불필요한 무효 전류를 유발합니다.</li><li><strong>피상 전력 (Apparent Power, S):</strong> 송배전설비가 실제로 견뎌야 하는 가상의 총 전력합(단위: kVA)입니다. 역률이 낮을수록 동일 유효전력을 공급하기 위해 더 큰 전류와 큰 변압기 용량이 필요합니다.</li></ul>
<h3>2. 역률 개선용 전력 콘덴서 용량(Qc) 계산 공식 유도</h3>
<p>부하의 역률을 <code>PF1</code>에서 <code>PF2</code>로 개선하기 위해 병렬로 연결해야 하는 콘덴서(Capacitor Bank) 용량 계산식은 다음과 같이 위상 기하학 관계식으로부터 유도됩니다.</p><p><strong>① 역률각(&theta;) 변환 공식:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">&theta;_1 = acos(PF_1) &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; &theta;_2 = acos(PF_2)</p><p><strong>② 기존 및 목표 무효전력 차이:</strong> 유효전력 <code>P</code>가 일정할 때, 무효전력은 <code>Q = P &times; tan(&theta;)</code>이므로 단량 차이는 다음과 같습니다.</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">Q_c = Q_1 - Q_2 = P &times; (tan&theta;_1 - tan&theta;_2) &nbsp;[kVAR]</p><p><strong>③ 3상 델타 결선 콘덴서 정전용량(C) 변환:</strong> 주파수 <code>f</code>와 계통 전압 <code>V</code>가 주어질 때 1상당 필요한 정전 용량 마이크로패럿(<code>&mu;F</code>) 수식입니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">C_phase = (Q_c &times; 10^9) / (3 &times; 2 &pi; f &times; V^2) &nbsp;[&mu;F]</p>
<h3>3. 역률 개선의 경제적 혜택과 전선 손실 경감</h3>
<p>역률을 90% 이상(통상 95%)으로 개선하면 전력 소모의 낭비를 방지하여 전기 요금 누진 감면 혜택을 얻을 수 있습니다. 또한 계통 내 전류가 감소하므로 송전선에서 발생하는 줄열 손실(I²R)이 감소합니다.</p><p style="text-align: center; font-weight: bold; background: #fee2e2; padding: 12px; border-radius: 8px; color: #991b1b;">절감되는 선선로 전류율 (%) = (1 - PF_1 / PF_2) &times; 100</p><p>이로 인해 변압기의 여유 용량(Margin Capacity)이 늘어나 부하의 과부하 안전율이 대폭 증대되며 추가적인 기계 증설 시 별도의 수전설비 개축 없이 기계를 운용할 수 있어 산업용 배전 설계에서 필수적으로 검토됩니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/power-factor-correction-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
