diff --git a/AGENTS.md b/AGENTS.md
index 8bece72..5854934 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -23,3 +23,4 @@ Public macOS window manager. Swift 6, SwiftPM, macOS 14+, Apple Silicon.
- AX success is not frame acceptance: verify actual geometry, including same-display resize clipping.
- Readiness text must use the full model.ready state, not permission alone.
- Cross-display acceptance must cover a full round trip between unequal screen sizes; verify the realized frame after settling.
+- Custom button backgrounds, padding and contentShape must live inside the label; verify physical clicks in empty painted edges, not only AX activation.
diff --git a/Assets/Info.plist b/Assets/Info.plist
index 31fcf02..22877f3 100644
--- a/Assets/Info.plist
+++ b/Assets/Info.plist
@@ -22,9 +22,9 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.0.0
+ 1.0.1
CFBundleVersion
- 10
+ 11
LSMinimumSystemVersion
14.0
LSUIElement
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec6be40..0a97124 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,19 @@ All notable changes to this project are documented here.
## [Unreleased]
+## [1.0.1] - 2026-09-06
+
+### Changed
+
+- Simplified Settings and Welcome windows with integrated native window controls.
+- Reduced unused space at the bottom of the menu bar panel.
+
+### Fixed
+
+- Made the entire painted pause/resume button clickable, including its empty edges.
+- Expanded add, dismiss and restore-defaults button targets.
+- Aligned the language selector with the switches in Preferences.
+
## [1.0.0] - 2026-09-06
First public release.
diff --git a/Sources/EncajeApp/EncajeApp.swift b/Sources/EncajeApp/EncajeApp.swift
index 2a58a45..eef9131 100644
--- a/Sources/EncajeApp/EncajeApp.swift
+++ b/Sources/EncajeApp/EncajeApp.swift
@@ -256,8 +256,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, NSMe
private func makeWindow(title: String, size: NSSize, view: V) -> NSWindow {
let window = NSWindow(
contentRect: NSRect(origin: .zero, size: size),
- styleMask: [.titled, .closable, .miniaturizable], backing: .buffered, defer: false)
+ styleMask: [.titled, .closable, .miniaturizable, .fullSizeContentView], backing: .buffered,
+ defer: false)
window.title = title
+ window.titleVisibility = .hidden
+ window.titlebarAppearsTransparent = true
+ window.titlebarSeparatorStyle = .none
window.isReleasedWhenClosed = false
let hosting = NSHostingView(rootView: view)
hosting.sizingOptions = []
diff --git a/Sources/EncajeApp/MenuBarPopover.swift b/Sources/EncajeApp/MenuBarPopover.swift
index ed97926..7162094 100644
--- a/Sources/EncajeApp/MenuBarPopover.swift
+++ b/Sources/EncajeApp/MenuBarPopover.swift
@@ -159,8 +159,11 @@ private struct MenuBarPopoverView: View {
systemImage: model.paused ? "play.fill" : "pause.fill"
)
.font(.system(size: 14, weight: .semibold)).frame(maxWidth: .infinity).padding(
- .vertical, 11)
- }.buttonStyle(.plain).background(.teal.gradient, in: RoundedRectangle(cornerRadius: 10))
+ .vertical, 11
+ )
+ .background(.teal.gradient, in: RoundedRectangle(cornerRadius: 10))
+ .contentShape(RoundedRectangle(cornerRadius: 10))
+ }.buttonStyle(.plain)
.foregroundStyle(.white)
if updates.available, updates.phase != .idle {
UpdateActionView()
@@ -178,7 +181,9 @@ private struct MenuBarPopoverView: View {
Rectangle())
}.buttonStyle(.plain).foregroundStyle(.red)
}.font(.system(size: 13, weight: .medium))
- }.padding(18).frame(width: 300).fixedSize(horizontal: false, vertical: true).tint(.teal)
+ }.padding(.horizontal, 18).padding(.top, 18).padding(.bottom, 8).frame(width: 300).fixedSize(
+ horizontal: false, vertical: true
+ ).tint(.teal)
}
private func row(_ text: String, symbol: String, action: @escaping () -> Void) -> some View {
diff --git a/Sources/EncajeApp/SettingsView.swift b/Sources/EncajeApp/SettingsView.swift
index 4415ed2..8829ff5 100644
--- a/Sources/EncajeApp/SettingsView.swift
+++ b/Sources/EncajeApp/SettingsView.swift
@@ -19,7 +19,7 @@ struct SettingsView: View {
Text(sectionSubtitle).font(.callout).foregroundStyle(.secondary)
}
Spacer()
- }.padding(22)
+ }.padding(22).padding(.top, 12)
Divider()
Group {
switch section {
@@ -37,13 +37,13 @@ struct SettingsView: View {
Button {
model.message = nil
} label: {
- Image(systemName: "xmark")
+ Image(systemName: "xmark").frame(width: 24, height: 24).contentShape(Rectangle())
}
.buttonStyle(.plain).accessibilityLabel(localized("Dismiss", "Cerrar"))
}.padding(12).background(.quaternary.opacity(0.5))
}
}
- }.frame(width: 880, height: 660).tint(.teal)
+ }.frame(width: 880, height: 660).ignoresSafeArea(.container, edges: .top).tint(.teal)
}
private var sidebar: some View {
@@ -72,7 +72,7 @@ struct SettingsView: View {
: model.ready ? localized("Ready", "Listo") : localized("Setup needed", "Falta acceso"),
systemImage: model.ready && !model.paused ? "checkmark.circle.fill" : "circle"
).font(.caption).foregroundStyle(model.ready && !model.paused ? .teal : .secondary)
- }.padding(16).frame(width: 152).frame(maxHeight: .infinity)
+ }.padding(16).padding(.top, 28).frame(width: 152).frame(maxHeight: .infinity)
.background(.quaternary.opacity(0.22))
}
diff --git a/Sources/EncajeApp/UI/PreferencesView.swift b/Sources/EncajeApp/UI/PreferencesView.swift
index ee8d458..2c21b34 100644
--- a/Sources/EncajeApp/UI/PreferencesView.swift
+++ b/Sources/EncajeApp/UI/PreferencesView.swift
@@ -52,7 +52,7 @@ struct PreferencesView: View {
ForEach(AppLanguage.allCases, id: \.self) { language in
Text(language.label).tag(language)
}
- }.labelsHidden().frame(width: 150)
+ }.labelsHidden().fixedSize().frame(width: 150, alignment: .trailing)
}
Divider()
HStack {
diff --git a/Sources/EncajeApp/UI/ZoneSettingsView.swift b/Sources/EncajeApp/UI/ZoneSettingsView.swift
index 80a58bb..20fd1a8 100644
--- a/Sources/EncajeApp/UI/ZoneSettingsView.swift
+++ b/Sources/EncajeApp/UI/ZoneSettingsView.swift
@@ -23,7 +23,7 @@ struct ZoneSettingsView: View {
Button {
selectedID = model.addRule()
} label: {
- Image(systemName: "plus")
+ Image(systemName: "plus").frame(width: 24, height: 24).contentShape(Rectangle())
}
.buttonStyle(.borderless).help(localized("Add a zone", "Añadir una zona"))
}.padding(14)
@@ -37,8 +37,12 @@ struct ZoneSettingsView: View {
}.padding(.horizontal, 6)
}
Divider()
- Button(localized("Restore defaults", "Restaurar originales")) { confirmReset = true }
- .font(.caption).buttonStyle(.borderless).padding(12)
+ Button {
+ confirmReset = true
+ } label: {
+ Text(localized("Restore defaults", "Restaurar originales"))
+ .frame(maxWidth: .infinity).padding(12).contentShape(Rectangle())
+ }.font(.caption).buttonStyle(.borderless)
}.frame(width: 202)
Divider()
if let rule = selectedRule {
diff --git a/Sources/EncajeApp/WelcomeView.swift b/Sources/EncajeApp/WelcomeView.swift
index 6d181d9..c1dce92 100644
--- a/Sources/EncajeApp/WelcomeView.swift
+++ b/Sources/EncajeApp/WelcomeView.swift
@@ -102,12 +102,14 @@ struct WelcomeView: View {
Button(localized("Set up later", "Configurar después"), action: finish).buttonStyle(.plain)
.foregroundStyle(.secondary).font(.caption)
}
- }.padding(32).frame(width: 510, height: 590).tint(.teal)
- .animation(
- reduceMotion ? nil : .spring(response: 0.4, dampingFraction: 0.85),
- value: permissions.granted
- )
- .onAppear { withAnimation(reduceMotion ? nil : .easeOut(duration: 0.3)) { entrance = true } }
+ }.padding(32).frame(width: 510, height: 590).ignoresSafeArea(.container, edges: .top).tint(
+ .teal
+ )
+ .animation(
+ reduceMotion ? nil : .spring(response: 0.4, dampingFraction: 0.85),
+ value: permissions.granted
+ )
+ .onAppear { withAnimation(reduceMotion ? nil : .easeOut(duration: 0.3)) { entrance = true } }
}
private func complete() {
diff --git a/docs/validation.md b/docs/validation.md
index 5e1caa6..727a09d 100644
--- a/docs/validation.md
+++ b/docs/validation.md
@@ -46,6 +46,10 @@ retries when the observed size proves that correction is needed.
- Open/close the menu panel by icon, outside click and Escape; Configuration/About
must retain focus, and closed views must release monitors/rendering work.
- Check the app icon in both its UI and the system's representation.
+- Click empty painted edges of pause/resume and padded buttons; verify the action,
+ not only Accessibility activation. Confirm the language picker aligns with switches.
+- Open Settings and Welcome in both languages; confirm integrated traffic lights,
+ no visible titlebar text or separator, unclipped content and native close behavior.
- After closing the UI and settling for at least one minute, sample process CPU
and memory over multiple intervals. Report bundle size separately from ignored
development caches and rollback artifacts.