diff --git a/Source/DotNET/Model/Profiles/UiProfile.cs b/Source/DotNET/Model/Profiles/UiProfile.cs
index 68da08c..fb7e6b2 100644
--- a/Source/DotNET/Model/Profiles/UiProfile.cs
+++ b/Source/DotNET/Model/Profiles/UiProfile.cs
@@ -6,13 +6,36 @@
namespace Cratis.Scene.Model.Profiles;
///
-/// A named target: a platform, a default size class, and an ordered list of component packages. Declaration
-/// order in is override priority — a later package shadows an earlier one when both
-/// resolve the same bare component name. core is always the final fallback, so a minimum vocabulary
-/// resolves regardless of which packages a profile lists.
+/// A named target: a platform, a default size class, an ordered list of component packages, and the
+/// application shell and visual theme it selects. Declaration order in is override
+/// priority - a later package shadows an earlier one when both resolve the same bare component name.
+/// core is always the final fallback, so a minimum vocabulary resolves regardless of which packages
+/// a profile lists.
///
/// The profile's name.
/// The platform this profile targets (e.g. web, ios, android, desktop).
/// The component packages this profile draws from, in override-priority order.
/// The size class assumed when the renderer cannot otherwise determine one.
-public record UiProfile(string Name, string TargetPlatform, IReadOnlyList Packages, SizeClass? DefaultSizeClass = null);
+///
+/// The name of the this profile renders inside - the application's base
+/// navigational shell, normally provided by a in
+/// . when the profile does not select one.
+///
+///
+/// The name of the this profile applies, or when it selects
+/// none. A theme is only meaningful relative to a set of packages, which is why it is chosen here rather
+/// than by a screen.
+///
+///
+/// A profile is where the choices that make a description concrete are made: which component vocabulary,
+/// which shell, which theme. Deliberately none of them are stated by a - that
+/// is what keeps a screen portable across targets, and what lets one application ship a different shell to
+/// the web than to a phone.
+///
+public record UiProfile(
+ string Name,
+ string TargetPlatform,
+ IReadOnlyList Packages,
+ SizeClass? DefaultSizeClass = null,
+ string? Layout = null,
+ string? Theme = null);
diff --git a/Source/JavaScript/model/profiles/UiProfile.ts b/Source/JavaScript/model/profiles/UiProfile.ts
index 0de53ba..4904acc 100644
--- a/Source/JavaScript/model/profiles/UiProfile.ts
+++ b/Source/JavaScript/model/profiles/UiProfile.ts
@@ -4,16 +4,55 @@
import { SizeClass } from '../sizeClasses';
/**
- * A named target: a platform, a default size class, and an ordered list of component packages.
- * Declaration order in `packages` is override priority — a later package shadows an earlier one when
- * both resolve the same bare component name. `core` is always the final fallback, so a minimum
- * vocabulary resolves regardless of which packages a profile lists.
+ * A named target: a platform, a default size class, an ordered list of component packages, and the
+ * application shell and visual theme it selects. Declaration order in `packages` is override priority — a
+ * later package shadows an earlier one when both resolve the same bare component name. `core` is always
+ * the final fallback, so a minimum vocabulary resolves regardless of which packages a profile lists.
+ *
+ * A profile is where the choices that make a description concrete are made: which component vocabulary,
+ * which shell, which theme. Deliberately none of them are stated by a {@link Screen} — that is what keeps
+ * a screen portable across targets, and what lets one application ship a different shell to the web than
+ * to a phone.
*/
export interface UiProfile {
+ /**
+ * The profile's name.
+ */
name: string;
+
+ /**
+ * The platform this profile targets (e.g. `web`, `ios`, `android`, `desktop`).
+ */
targetPlatform: string;
+
+ /**
+ * The component packages this profile draws from, in override-priority order.
+ */
packages: string[];
+
+ /**
+ * The size class assumed when the renderer cannot otherwise determine one.
+ */
defaultSizeClass?: SizeClass;
+
+ /**
+ * The name of the {@link Layout} this profile renders inside — the application's base navigational
+ * shell, normally provided by a blueprint in `packages`. Absent when the profile does not select one.
+ */
+ layout?: string;
+
+ /**
+ * The name of the {@link Theme} this profile applies, or absent when it selects none. A theme is only
+ * meaningful relative to a set of packages, which is why it is chosen here rather than by a screen.
+ */
+ theme?: string;
}
-export const UiProfilePropertyNames: (keyof UiProfile)[] = ['name', 'targetPlatform', 'packages', 'defaultSizeClass'];
+export const UiProfilePropertyNames: (keyof UiProfile)[] = [
+ 'name',
+ 'targetPlatform',
+ 'packages',
+ 'defaultSizeClass',
+ 'layout',
+ 'theme',
+];
diff --git a/scene-model-shape.json b/scene-model-shape.json
index 7b9dab9..1e1a988 100644
--- a/scene-model-shape.json
+++ b/scene-model-shape.json
@@ -179,7 +179,9 @@
"name",
"targetPlatform",
"packages",
- "defaultSizeClass"
+ "defaultSizeClass",
+ "layout",
+ "theme"
],
"Theme": [
"name",