diff --git a/source/components/console-panel/console-panel.css b/source/components/console-panel/console-panel.css
new file mode 100644
index 0000000..f707304
--- /dev/null
+++ b/source/components/console-panel/console-panel.css
@@ -0,0 +1,75 @@
+console-panel {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background: #0f1117;
+ color: #c8cbde;
+ font-size: 0.82rem;
+ font-family: ui-monospace, "Cascadia Code", "Fira Mono", monospace;
+}
+
+conp-header {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 4px 10px;
+ background: #13151f;
+ border-bottom: 1px solid #2a2d3a;
+ flex-shrink: 0;
+}
+
+conp-title {
+ flex: 1;
+ font-size: 0.78rem;
+ color: #7b7f96;
+ font-family: inherit;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+}
+
+.conp-clear {
+ padding: 2px 8px;
+ background: transparent;
+ border: 1px solid #2a2d3a;
+ border-radius: 3px;
+ color: #7b7f96;
+ cursor: pointer;
+ font-size: 0.75rem;
+ font-family: inherit;
+}
+
+.conp-clear:hover { color: #c8cbde; background: #1a1d27; border-color: #444; }
+
+conp-list {
+ display: block;
+ flex: 1;
+ overflow-y: auto;
+ padding: 4px 0;
+}
+
+conp-entry {
+ display: flex;
+ align-items: baseline;
+ gap: 10px;
+ padding: 2px 10px;
+ line-height: 1.6;
+}
+
+conp-entry:hover { background: #13151f; }
+
+conp-time {
+ flex-shrink: 0;
+ color: #555;
+ font-size: 0.75rem;
+ user-select: none;
+}
+
+conp-text {
+ flex: 1;
+ word-break: break-word;
+ white-space: pre-wrap;
+}
+
+.conp-entry-error conp-text { color: #e07070; }
+.conp-entry-hint conp-text { color: #7b7f96; }
+.conp-entry-info conp-text { color: #c8cbde; }
diff --git a/source/components/console-panel/console-panel.ts b/source/components/console-panel/console-panel.ts
new file mode 100644
index 0000000..2614dc1
--- /dev/null
+++ b/source/components/console-panel/console-panel.ts
@@ -0,0 +1,65 @@
+import { EditorConsole, ConsoleMessage } from '../../editor/EditorConsole.js';
+import { EditorPanelDefinition } from '../../editor/editor-panel.js';
+import { ContextMenuDirectory, ContextMenuReadOnlyEntry } from '../context-menu/context-menu.js';
+
+class ConsolePanel extends HTMLElement
+{
+ __interfaces__ = [ EditorPanelDefinition.type ];
+ _initialized = false;
+
+ connectedCallback(): void
+ {
+ if ( this._initialized ) return;
+ this._initialized = true;
+
+ this.className = 'console-panel';
+ this.innerHTML = `
+
+ Console
+ Clear
+
+
+ `;
+
+ this.querySelector( '.conp-clear' )!.addEventListener( 'click', () =>
+ {
+ this.querySelector( 'conp-list' )!.innerHTML = '';
+ } );
+
+ EditorConsole.get().messages.forEach( msg => this._append( msg ) );
+ this._scrollToBottom();
+
+ EditorConsole.get().onMessage.addListener( msg =>
+ {
+ this._append( msg );
+ this._scrollToBottom();
+ } );
+ }
+
+ addContextMenuEntries( dir: ContextMenuDirectory ): void
+ {
+ dir.add( new ContextMenuReadOnlyEntry( dir, 'Console' ) );
+ }
+
+ _append( msg: ConsoleMessage ): void
+ {
+ const list = this.querySelector( 'conp-list' )!;
+ const entry = document.createElement( 'conp-entry' );
+ entry.className = `conp-entry-${ msg.type }`;
+ const t = msg.timestamp;
+ const hh = String( t.getHours() ).padStart( 2, '0' );
+ const mm = String( t.getMinutes() ).padStart( 2, '0' );
+ const ss = String( t.getSeconds() ).padStart( 2, '0' );
+ entry.innerHTML = `${ hh }:${ mm }:${ ss } `;
+ ( entry.querySelector( 'conp-text' ) as HTMLElement ).textContent = msg.text;
+ list.appendChild( entry );
+ }
+
+ _scrollToBottom(): void
+ {
+ const list = this.querySelector( 'conp-list' ) as HTMLElement;
+ if ( list ) list.scrollTop = list.scrollHeight;
+ }
+}
+
+customElements.define( 'console-panel', ConsolePanel );
diff --git a/source/components/editor-shell/editor-shell.css b/source/components/editor-shell/editor-shell.css
index cedba32..ea2a4f2 100644
--- a/source/components/editor-shell/editor-shell.css
+++ b/source/components/editor-shell/editor-shell.css
@@ -37,6 +37,38 @@ editor-shell {
text-transform: uppercase;
}
+.es-info {
+ max-width: 300px;
+ font-size: 0.78rem;
+ color: #9ba4c7;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ opacity: 0;
+ transition: opacity 0.2s;
+ flex-shrink: 1;
+}
+
+.es-info.es-info-visible { opacity: 1; }
+.es-info.es-info-error { color: #e07070; }
+.es-info.es-info-hint { color: #7b7f96; }
+
+editor-shell.portrait .es-info { display: none; }
+
+editor-shell.portrait .es-info.es-info-visible {
+ display: block;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ max-width: none;
+ padding: 8px 16px;
+ background: #13151f;
+ border-top: 1px solid #2a2d3a;
+ z-index: 100;
+ opacity: 1;
+}
+
.es-portrait-btns {
display: none;
gap: 2px;
diff --git a/source/components/editor-shell/editor-shell.ts b/source/components/editor-shell/editor-shell.ts
index 3f544be..c105b7c 100644
--- a/source/components/editor-shell/editor-shell.ts
+++ b/source/components/editor-shell/editor-shell.ts
@@ -1,4 +1,5 @@
import { Editor } from '../../editor/Editor.js';
+import { EditorConsole } from '../../editor/EditorConsole.js';
// ── Layout helpers ────────────────────────────────────────────────────────────
@@ -90,6 +91,7 @@ class EditorShell extends HTMLElement {