diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index f5ef846..b5a81b7 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -1885,6 +1885,8 @@ onBeforeUnmount(() => {
class="phone-screen"
:class="{
'phone-screen--app': isAppRoute || isDevelopmentRoute,
+ 'phone-screen--camera-landscape':
+ activeAppId === 'camera' && phone.cameraLandscape,
'phone-app--light': !displayedDarkMode,
[`phone-app--${phone.preferences.settings.graphicsMode}`]: true,
}"
diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css
index 6d7181a..48ff04e 100644
--- a/frontend/src/assets/main.css
+++ b/frontend/src/assets/main.css
@@ -460,6 +460,7 @@ button {
}
}
.phone-screen {
+ --phone-screen-portrait-ratio: 2.30951;
position: relative;
container-type: size;
margin: auto;
@@ -470,6 +471,12 @@ button {
background: #08080a;
border-radius: 40px;
}
+.phone-screen--camera-landscape {
+ background: transparent;
+}
+.phone-screen--camera-landscape .springboard {
+ visibility: hidden;
+}
.phone-app {
position: absolute !important;
inset: 0 !important;
@@ -3239,6 +3246,9 @@ button {
backface-visibility: hidden;
will-change: transform, border-radius, opacity;
}
+.app-window--camera-landscape {
+ background: transparent;
+}
.app-window--citywarn {
backface-visibility: visible;
filter: none;
diff --git a/frontend/src/views/PhoneAppWindow.vue b/frontend/src/views/PhoneAppWindow.vue
index 0dcc86e..19e4d3a 100644
--- a/frontend/src/views/PhoneAppWindow.vue
+++ b/frontend/src/views/PhoneAppWindow.vue
@@ -30,7 +30,11 @@ const launchStyle = computed(() => {
{
expect(cameraView).not.toContain('k-navbar')
})
+ it('stays dark when the global phone appearance is light', () => {
+ const cameraPageTag = cameraView.match(/]*>/s)?.[0]
+
+ expect(cameraPageTag).toBeDefined()
+ expect(cameraPageTag).toMatch(/\bdark\b/)
+ expect(cameraView).toMatch(
+ /\.camera-page\s*\{[^}]*--sky-bg:\s*#000;[^}]*--sky-text:\s*#fff;[^}]*background:\s*var\(--sky-bg\);[^}]*color:\s*var\(--sky-text\);/s,
+ )
+ })
+
+ it('fills the translucent landscape shell without letterbox gaps', () => {
+ const landscapeViewport = cameraView.match(
+ /\.camera-page--landscape \.camera-viewport\s*\{([^}]*)\}/s,
+ )?.[1]
+
+ expect(cameraView).toMatch(
+ /\.camera-page--landscape\s*\{[^}]*--sky-bg:\s*rgba\(0, 0, 0, 0\.42\);/s,
+ )
+ expect(landscapeViewport).toBeDefined()
+ expect(landscapeViewport).toContain('top: 50%')
+ expect(landscapeViewport).toContain(
+ 'width: calc(100% * var(--phone-screen-portrait-ratio))',
+ )
+ expect(landscapeViewport).toContain(
+ 'aspect-ratio: var(--phone-screen-portrait-ratio)',
+ )
+ expect(landscapeViewport).not.toContain('16 / 9')
+ expect(cameraView).toMatch(
+ /\.camera-page--landscape \.camera-shade\s*\{[^}]*linear-gradient\([^)]*90deg,[^)]*rgba\(0, 0, 0, 0\.42\) 0 18%,[^)]*transparent 18% 75%,[^)]*rgba\(0, 0, 0, 0\.42\) 75% 100%/s,
+ )
+ expect(appShell).toMatch(
+ /'phone-screen--camera-landscape':\s*activeAppId === 'camera' && phone\.cameraLandscape/,
+ )
+ expect(appWindow).toMatch(
+ /'app-window--camera-landscape':\s*app\.id === 'camera' && phone\.cameraLandscape/,
+ )
+ expect(shellStyles).toMatch(
+ /\.phone-screen\s*\{[^}]*--phone-screen-portrait-ratio:\s*2\.30951;/s,
+ )
+ expect(shellStyles).toMatch(
+ /\.phone-screen--camera-landscape\s*\{[^}]*background:\s*transparent;/s,
+ )
+ expect(shellStyles).toMatch(
+ /\.phone-screen--camera-landscape \.springboard\s*\{[^}]*visibility:\s*hidden;/s,
+ )
+ expect(shellStyles).toMatch(
+ /\.app-window--camera-landscape\s*\{[^}]*background:\s*transparent;/s,
+ )
+ })
+
+ it('renders camera notices as plain text without a glass pill', () => {
+ const noticeMarkup = cameraView.slice(
+ cameraView.indexOf(' {
+ const zoomControl = cameraView.slice(
+ cameraView.indexOf(''),
+ cameraView.indexOf('
@@ -685,10 +693,15 @@ onBeforeUnmount(() => {