diff --git a/src/frontend/src/features/pip/components/PipView.tsx b/src/frontend/src/features/pip/components/PipView.tsx
index e1facf03..0c321663 100644
--- a/src/frontend/src/features/pip/components/PipView.tsx
+++ b/src/frontend/src/features/pip/components/PipView.tsx
@@ -54,23 +54,17 @@ const PipContainer = styled('div', {
display: 'grid',
gridTemplateRows: 'minmax(0, 1fr) auto auto',
backgroundColor: 'primaryDark.50',
+ // Disable LiveKit's own border-radius on tiles so our containers
+ // (GridCell, Thumbnail, StageFrame) own the clipping exclusively.
+ '--lk-border-radius': '4px',
'& .lk-participant-tile': {
height: '100%',
- overflow: 'hidden',
- backgroundColor: 'primaryDark.100',
},
'& .lk-participant-media': {
height: '100%',
- overflow: 'hidden',
- borderRadius: 0,
- backgroundColor: 'primaryDark.100',
},
'& .lk-participant-media-video': {
- display: 'block',
- width: '100%',
height: '100%',
- borderRadius: 0,
- backgroundColor: 'primaryDark.100',
objectFit: 'cover',
},
'& .lk-grid-layout': {
diff --git a/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx b/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx
index 285d557c..9cd10aea 100644
--- a/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx
+++ b/src/frontend/src/features/pip/components/layouts/PipFocusLayout.tsx
@@ -1,79 +1,81 @@
-import { memo } from 'react'
-import type { TrackReferenceOrPlaceholder } from '@livekit/components-core'
-import { styled } from '@/styled-system/jsx'
-import { ParticipantTile } from '@/features/rooms/livekit/components/ParticipantTile'
-import { getTrackKey } from '../../utils/pipTrackSelection'
-
-type PipFocusLayoutProps = {
- mainTrack: TrackReferenceOrPlaceholder
- thumbnailTrack?: TrackReferenceOrPlaceholder
-}
-
-/**
- * Focus layout used when 1-2 tracks are visible in the PiP window.
- *
- * The main tile is letterboxed (object-fit: contain) so the camera is
- * never stretched to a non-video aspect and leaves dark padding
- * above/below when the window shape doesn't match the source.
- * The thumbnail keeps the usual cover fill.
- */
-export const PipFocusLayout = memo(function PipFocusLayout({
- mainTrack,
- thumbnailTrack,
-}: PipFocusLayoutProps) {
- return (
-
-
-
-
- {thumbnailTrack && (
-
-
-
- )}
-
- )
-})
-
-const FocusContainer = styled('div', {
- base: {
- position: 'relative',
- width: '100%',
- height: '100%',
- backgroundColor: 'primaryDark.100',
- },
-})
-
-const MainSlot = styled('div', {
- base: {
- width: '100%',
- height: '100%',
- '& .lk-participant-media-video': {
- objectFit: 'contain',
- },
- },
-})
-
-const Thumbnail = styled('div', {
- base: {
- position: 'absolute',
- right: '1rem',
- bottom: '1rem',
- width: '42%',
- maxWidth: '220px',
- minWidth: '140px',
- aspectRatio: '16 / 9',
- borderRadius: 'md',
- overflow: 'hidden',
- boxShadow: 'md',
- zIndex: 2,
- },
-})
+import { memo } from 'react'
+import type { TrackReferenceOrPlaceholder } from '@livekit/components-core'
+import { styled } from '@/styled-system/jsx'
+import { ParticipantTile } from '@/features/rooms/livekit/components/ParticipantTile'
+import { getTrackKey } from '../../utils/pipTrackSelection'
+
+type PipFocusLayoutProps = {
+ mainTrack: TrackReferenceOrPlaceholder
+ thumbnailTrack?: TrackReferenceOrPlaceholder
+}
+
+/**
+ * Focus layout used when 1-2 tracks are visible in the PiP window.
+ *
+ * The main tile is letterboxed (object-fit: contain) so the camera is
+ * never stretched to a non-video aspect and leaves dark padding
+ * above/below when the window shape doesn't match the source.
+ * The thumbnail keeps the usual cover fill.
+ */
+export const PipFocusLayout = memo(function PipFocusLayout({
+ mainTrack,
+ thumbnailTrack,
+}: PipFocusLayoutProps) {
+ return (
+
+
+
+
+ {thumbnailTrack && (
+
+
+
+ )}
+
+ )
+})
+
+const FocusContainer = styled('div', {
+ base: {
+ position: 'relative',
+ width: '100%',
+ height: '100%',
+ borderRadius: '4px',
+ overflow: 'hidden',
+ backgroundColor: 'primaryDark.100',
+ },
+})
+
+const MainSlot = styled('div', {
+ base: {
+ width: '100%',
+ height: '100%',
+ '& .lk-participant-media-video': {
+ objectFit: 'contain',
+ },
+ },
+})
+
+const Thumbnail = styled('div', {
+ base: {
+ position: 'absolute',
+ right: '1rem',
+ bottom: '1rem',
+ width: '42%',
+ maxWidth: '220px',
+ minWidth: '140px',
+ aspectRatio: '16 / 9',
+ borderRadius: '4px',
+ overflow: 'hidden',
+ boxShadow: 'md',
+ zIndex: 2,
+ },
+})
diff --git a/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx b/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx
index 2e749946..350f86cd 100644
--- a/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx
+++ b/src/frontend/src/features/pip/components/layouts/PipGridLayout.tsx
@@ -1,82 +1,82 @@
-import { memo, useMemo, useRef } from 'react'
-import type { TrackReferenceOrPlaceholder } from '@livekit/components-core'
-import { styled } from '@/styled-system/jsx'
-import { ParticipantTile } from '@/features/rooms/livekit/components/ParticipantTile'
-import { usePipElementSize } from '../../hooks/usePipElementSize'
-import { usePipFlipAnimations } from '../../hooks/usePipFlipAnimations'
-import { computePipGridLayout } from '../../utils/pipGrid'
-import { getTrackKey } from '../../utils/pipTrackSelection'
-
-type PipGridLayoutProps = {
- tracks: TrackReferenceOrPlaceholder[]
-}
-
-/**
- * Adaptive grid used when 3+ tracks are visible in the PiP window.
- *
- * All grid math (shape choice + partial-row stretching) is delegated to
- * `computePipGridLayout`. This component only measures the container,
- * applies the returned placements, and plays a FLIP animation when the
- * tile set or grid shape changes (participant joins/leaves or shape shift).
- *
- * Tiles keep a stable key so resizing never remounts