diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp
index 9ad7488..48a498a 100644
--- a/desktop/desktop.cpp
+++ b/desktop/desktop.cpp
@@ -740,7 +740,6 @@ int WindowTabMessage(EsElement *element, EsMessage *message) {
 				instance->title, instance->titleBytes, instance->iconID);
 	} else if (message->type == ES_MSG_ANIMATE) {
 		message->animate.complete = ReorderItemAnimate(tab, message->animate.deltaMs, "windowTabEntranceDuration");
-	} else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) {
 	} else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) {
 		EsElementSetDisabled(band->GetChild(0), true);
 
@@ -847,6 +846,13 @@ int WindowTabMessage(EsElement *element, EsMessage *message) {
 
 		EsMenuShow(menu);
 	} else if (message->type == ES_MSG_MOUSE_MIDDLE_UP && ((element->state & UI_STATE_HOVERED) || (tab->closeButton->state & UI_STATE_HOVERED))) {
+		if (EsButtonGetCheck(tab->closeButton) == ES_CHECK_CHECKED) {
+			// The tab contains a modified document, so it will probably popup a dialog after it receives the close request.
+			// Therefore, we should switch to that tab.
+			tab->BringToFront();
+			WindowTabActivate(tab);
+		}
+
 		WindowTabClose(tab);
 	} else if (message->type == ES_MSG_REORDER_ITEM_TEST) {
 	} else {
diff --git a/res/Theme Source.dat b/res/Theme Source.dat
index 4839f2c..7deafaa 100644
Binary files a/res/Theme Source.dat and b/res/Theme Source.dat differ
diff --git a/res/Themes/Theme.dat b/res/Themes/Theme.dat
index 1d4a958..1ec34d7 100644
Binary files a/res/Themes/Theme.dat and b/res/Themes/Theme.dat differ
diff --git a/util/designer/designer.c b/util/designer/designer.c
index 590c7d0..0b71755 100644
--- a/util/designer/designer.c
+++ b/util/designer/designer.c
@@ -1664,7 +1664,6 @@ enum ObjectType {
 	OBJ_VAR_COLOR = 0x40,
 	OBJ_VAR_INT,
 	OBJ_VAR_TEXT_STYLE,
-	OBJ_VAR_ICON_STYLE,
 	OBJ_VAR_CONTOUR_STYLE,
 	
 	OBJ_PAINT_OVERWRITE = 0x60,
@@ -1724,7 +1723,7 @@ void ObjectAddObjectProperty(Object2 *object, const char *cName, uint64_t value)
 	arrput(object->properties, property);
 }
 
-uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *idAllocator) {
+uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *idAllocator, Layer *layer) {
 	char cPropertyName[PROPERTY_NAME_SIZE];
 
 	if (!paint->tag) {
@@ -1768,6 +1767,67 @@ uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *
 
 		*x += 100;
 		arrput(*objects, object);
+
+		if (layer) {
+			for (uintptr_t i = 0; i < arrlenu(layer->sequences); i++) {
+				Sequence *s = layer->sequences[i];
+				assert(arrlenu(s->keyframes) == 1);
+				Keyframe *keyframe = s->keyframes[0];
+
+				uint32_t stateBits = 0;
+				if (s->flagFocused) stateBits |= THEME_STATE_FOCUSED;
+				if (s->flagChecked) stateBits |= THEME_STATE_CHECKED;
+				if (s->flagIndeterminate) stateBits |= THEME_STATE_INDETERMINATE;
+				if (s->flagDefault) stateBits |= THEME_STATE_DEFAULT_BUTTON;
+				if (s->flagItemFocus) stateBits |= THEME_STATE_FOCUSED_ITEM;
+				if (s->flagListFocus) stateBits |= THEME_STATE_LIST_FOCUSED;
+				if (s->flagBeforeEnter) stateBits |= THEME_STATE_BEFORE_ENTER;
+				if (s->flagAfterExit) stateBits |= THEME_STATE_AFTER_EXIT;
+				if (s->flagSelected) stateBits |= THEME_STATE_SELECTED;
+
+				Object2 override = { .type = object.type, .id = ++(*idAllocator) };
+				ObjectAddIntegerProperty(&override, "_graphX", *x);
+				ObjectAddIntegerProperty(&override, "_graphY", y);
+				ObjectAddIntegerProperty(&override, "_graphW", 80);
+				ObjectAddIntegerProperty(&override, "_graphH", 60);
+				ObjectAddObjectProperty(&override, "_parent", object.id);
+				ObjectAddIntegerProperty(&override, "_primaryState", s->primaryState);
+				ObjectAddIntegerProperty(&override, "_stateBits", stateBits);
+				ObjectAddIntegerProperty(&override, "_duration", s->duration);
+
+				bool addObject = false;
+
+				for (uintptr_t i = 0; i < arrlenu(keyframe->properties); i++) {
+					Property *property = &keyframe->properties[i];
+
+					if (layer->base.tag == LayerBase_box + 1 && property->path[0] == (uint32_t) -2 && property->path[1] == 8 
+							&& property->path[2] == 0 && property->path[3] == 2 && property->path[4] == 2) {
+						assert(property->path[5] == 2 && property->path[7] == 0);
+						RfGrowableBuffer state = { 0 };
+						state.s.op = RF_OP_LOAD;
+						state.s.access = RfReadGrowableBuffer;
+						state.data = property->data;
+						RfItem item = GradientStop_Type.fields[GradientStop_color].item;
+						uint32_t value; item.type->op(&state.s, &item, &value);
+						char cPropertyName[PROPERTY_NAME_SIZE];
+						snprintf(cPropertyName, sizeof(cPropertyName), "stops_%d_color", property->path[6]);
+						ObjectAddObjectProperty(&override, cPropertyName, ColorLookupPointer(value)->object2ID);
+						addObject = true;
+					} else {
+						continue;
+					}
+				}
+
+				if (addObject) {
+					arrput(*objects, override);
+					object.id = override.id;
+					*x += 100;
+				} else {
+					arrfree(override.properties);
+				}
+			}	
+		}
+
 		return object.id;
 	} else if (paint->tag == Paint_radialGradient + 1) {
 		Object2 object = { .type = OBJ_PAINT_RADIAL_GRADIENT, .id = ++(*idAllocator) };
@@ -1805,6 +1865,63 @@ uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *
 		ObjectAddObjectProperty(&object, "color", ColorLookupPointer(paint->overwrite.color)->object2ID);
 		*x += 100;
 		arrput(*objects, object);
+
+		if (layer) {
+			for (uintptr_t i = 0; i < arrlenu(layer->sequences); i++) {
+				Sequence *s = layer->sequences[i];
+				assert(arrlenu(s->keyframes) == 1);
+				Keyframe *keyframe = s->keyframes[0];
+
+				uint32_t stateBits = 0;
+				if (s->flagFocused) stateBits |= THEME_STATE_FOCUSED;
+				if (s->flagChecked) stateBits |= THEME_STATE_CHECKED;
+				if (s->flagIndeterminate) stateBits |= THEME_STATE_INDETERMINATE;
+				if (s->flagDefault) stateBits |= THEME_STATE_DEFAULT_BUTTON;
+				if (s->flagItemFocus) stateBits |= THEME_STATE_FOCUSED_ITEM;
+				if (s->flagListFocus) stateBits |= THEME_STATE_LIST_FOCUSED;
+				if (s->flagBeforeEnter) stateBits |= THEME_STATE_BEFORE_ENTER;
+				if (s->flagAfterExit) stateBits |= THEME_STATE_AFTER_EXIT;
+				if (s->flagSelected) stateBits |= THEME_STATE_SELECTED;
+
+				Object2 override = { .type = object.type, .id = ++(*idAllocator) };
+				ObjectAddIntegerProperty(&override, "_graphX", *x);
+				ObjectAddIntegerProperty(&override, "_graphY", y);
+				ObjectAddIntegerProperty(&override, "_graphW", 80);
+				ObjectAddIntegerProperty(&override, "_graphH", 60);
+				ObjectAddObjectProperty(&override, "_parent", object.id);
+				ObjectAddIntegerProperty(&override, "_primaryState", s->primaryState);
+				ObjectAddIntegerProperty(&override, "_stateBits", stateBits);
+				ObjectAddIntegerProperty(&override, "_duration", s->duration);
+
+				bool addObject = false;
+
+				for (uintptr_t i = 0; i < arrlenu(keyframe->properties); i++) {
+					Property *property = &keyframe->properties[i];
+
+					if (layer->base.tag == LayerBase_box + 1 && property->path[0] == (uint32_t) -2 && property->path[1] == 8 
+							&& property->path[2] == 0 && property->path[3] == 2 && property->path[4] == 3) {
+						assert(property->path[5] == 0);
+						RfGrowableBuffer state = { 0 };
+						state.s.op = RF_OP_LOAD;
+						state.s.access = RfReadGrowableBuffer;
+						state.data = property->data;
+						RfItem item = PaintOverwrite_Type.fields[PaintOverwrite_color].item;
+						uint32_t value; item.type->op(&state.s, &item, &value);
+						ObjectAddObjectProperty(&override, "color", ColorLookupPointer(value)->object2ID);
+						addObject = true;
+					} else {
+						continue;
+					}
+				}
+
+				if (addObject) {
+					arrput(*objects, override);
+					object.id = override.id;
+					*x += 100;
+				}
+			}	
+		}
+
 		return object.id;
 	} else {
 		assert(false);
@@ -1837,10 +1954,137 @@ uint64_t ExportFillMode2(PathFillMode *fill, int *x, int y, Object2 **objects, u
 	}
 }
 
+void ExportProperty2(Layer *layer, Property *property, Object2 *override) {
+	bool unhandled = false;
+
+	RfGrowableBuffer state = { 0 };
+	state.s.op = RF_OP_LOAD;
+	state.s.access = RfReadGrowableBuffer;
+	state.data = property->data;
+
+	if (property->path[0] == (uint32_t) -2 && property->path[1] == 8 && property->path[2] == 0) {
+		if (layer->base.tag == LayerBase_box + 1) {
+			if (property->path[3] == LayerBox_borders && property->path[4] == Rectangle8_l) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_l].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "borders0", value);
+			} else if (property->path[3] == LayerBox_borders && property->path[4] == Rectangle8_r) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_r].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "borders1", value);
+			} else if (property->path[3] == LayerBox_borders && property->path[4] == Rectangle8_t) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_t].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "borders2", value);
+			} else if (property->path[3] == LayerBox_borders && property->path[4] == Rectangle8_b) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_b].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "borders3", value);
+			} else if (property->path[3] == LayerBox_corners && property->path[4] == Corners8_tl) {
+				RfItem item = Corners8_Type.fields[Corners8_tl].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "corners0", value);
+			} else if (property->path[3] == LayerBox_corners && property->path[4] == Corners8_tr) {
+				RfItem item = Corners8_Type.fields[Corners8_tr].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "corners1", value);
+			} else if (property->path[3] == LayerBox_corners && property->path[4] == Corners8_bl) {
+				RfItem item = Corners8_Type.fields[Corners8_bl].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "corners2", value);
+			} else if (property->path[3] == LayerBox_corners && property->path[4] == Corners8_br) {
+				RfItem item = Corners8_Type.fields[Corners8_br].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "corners3", value);
+			} else if (property->path[3] == LayerBox_mainPaint && property->path[4] == Paint_solid && property->path[5] == PaintSolid_color) {
+				RfItem item = PaintSolid_Type.fields[PaintSolid_color].item;
+				uint32_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddObjectProperty(override, "mainPaint", ColorLookupPointer(value)->object2ID);
+			} else if (property->path[3] == LayerBox_borderPaint && property->path[4] == Paint_solid && property->path[5] == PaintSolid_color) {
+				RfItem item = PaintSolid_Type.fields[PaintSolid_color].item;
+				uint32_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddObjectProperty(override, "borderPaint", ColorLookupPointer(value)->object2ID);
+			} else if (property->path[3] == LayerBox_mainPaint && property->path[4] == Paint_overwrite && property->path[5] == PaintOverwrite_color) {
+				fprintf(stderr, "\t>>\n");
+			} else {
+				unhandled = true;
+			}
+		} else if (layer->base.tag == LayerBase_metrics + 1) {
+			if (property->path[3] == LayerMetrics_textSize || property->path[3] == LayerMetrics_selectedText) {
+				// Ignore.
+			} else if (property->path[3] == LayerMetrics_textColor) {
+				RfItem item = LayerMetrics_Type.fields[LayerMetrics_textColor].item;
+				uint32_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddObjectProperty(override, "textColor", ColorLookupPointer(value)->object2ID);
+			} else if (property->path[3] == LayerMetrics_iconColor) {
+				RfItem item = LayerMetrics_Type.fields[LayerMetrics_iconColor].item;
+				uint32_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddObjectProperty(override, "iconColor", ColorLookupPointer(value)->object2ID);
+			} else {
+				unhandled = true;
+			}
+		} else if (layer->base.tag == LayerBase_path + 1) {
+			if (property->path[3] == LayerPath_alpha) {
+				RfItem item = LayerPath_Type.fields[LayerPath_alpha].item;
+				int16_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "alpha", value);
+			} else if (property->path[3] == LayerPath_fills && property->path[4] == 0 && property->path[5] == PathFill_paint
+					&& property->path[6] == Paint_solid && property->path[7] == PaintSolid_color) {
+				RfItem item = PaintSolid_Type.fields[PaintSolid_color].item;
+				uint32_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddObjectProperty(override, "fills_0_paint", ColorLookupPointer(value)->object2ID);
+				ObjectAddIntegerProperty(override, "fills_count", 1);
+			} else {
+				unhandled = true;
+			}
+		} else {
+			unhandled = true;
+		}
+	} else if (property->path[0] == (uint32_t) -2 && property->path[1] == 5) {
+		if (layer->base.tag == LayerBase_box + 1) {
+			if (property->path[2] == Rectangle8_l) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_l].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "offset0", value - layer->offset.l);
+			} else if (property->path[2] == Rectangle8_r) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_r].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "offset1", value - layer->offset.r);
+			} else if (property->path[2] == Rectangle8_t) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_t].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "offset2", value - layer->offset.t);
+			} else if (property->path[2] == Rectangle8_b) {
+				RfItem item = Rectangle8_Type.fields[Rectangle8_b].item;
+				int8_t value; item.type->op(&state.s, &item, &value);
+				ObjectAddIntegerProperty(override, "offset3", value - layer->offset.b);
+			}
+		} else {
+			unhandled = true;
+		}
+	} else {
+		unhandled = true;
+	}
+
+	assert(!unhandled);
+
+#if 0
+	if (unhandled) {
+		fprintf(stderr, "\tunhandled on %s: ", LayerBase_Type.fields[layer->base.tag - 1].cName);
+
+		for (uintptr_t i = 0; property->path[i] != RF_PATH_TERMINATOR; i++) {
+			fprintf(stderr, "%d, ", property->path[i]);
+		}
+
+		fprintf(stderr, "\n");
+	}
+#endif
+}
+
 void ActionExportDesigner2(void *cp) {
-	// TODO Exporting sequences.
 	// TODO Inherited text styles.
 	// TODO Merging identical layers and styles.
+	// TODO Auto-name override layers.
 
 	Object2 *objects = NULL;
 	uint64_t objectIDAllocator = 0;
@@ -1896,12 +2140,12 @@ void ActionExportDesigner2(void *cp) {
 		Style *style = styleSet.styles[i];
 		
 		Object2 layerGroup = { .type = OBJ_LAYER_GROUP, .id = ++objectIDAllocator };
-		Object2 metrics = { 0 }, textStyle = { 0 }, iconStyle = { 0 };
+		Object2 metrics = { 0 }, textStyle = { 0 };
 		int32_t layerCount = 0;
 
 		for (uintptr_t i = 0; i < arrlenu(style->layers); i++) {
 			Layer *layer = LayerLookup(style->layers[i]);
-			bool addToLayerGroup = false, addToObjects = false;
+			bool addToLayerGroup = false;
 			Object2 object = { 0 };
 
 			if (layer->base.tag == LayerBase_box + 1) {
@@ -1919,16 +2163,14 @@ void ActionExportDesigner2(void *cp) {
 				ObjectAddIntegerProperty(&object, "autoCorners", box->autoCorners);
 				ObjectAddIntegerProperty(&object, "autoBorders", box->autoBorders);
 				ObjectAddIntegerProperty(&object, "shadowHiding", box->shadowHiding);
-				ObjectAddObjectProperty(&object, "mainPaint", ExportPaint2(&box->mainPaint, &x, y, &objects, &objectIDAllocator));
-				ObjectAddObjectProperty(&object, "borderPaint", ExportPaint2(&box->borderPaint, &x, y, &objects, &objectIDAllocator));
+				ObjectAddObjectProperty(&object, "mainPaint", ExportPaint2(&box->mainPaint, &x, y, &objects, &objectIDAllocator, layer));
+				ObjectAddObjectProperty(&object, "borderPaint", ExportPaint2(&box->borderPaint, &x, y, &objects, &objectIDAllocator, NULL));
 				addToLayerGroup = true;
-				addToObjects = true;
 			} else if (layer->base.tag == LayerBase_text + 1) {
 				object.type = OBJ_LAYER_TEXT, object.id = ++objectIDAllocator;
 				ObjectAddObjectProperty(&object, "color", ColorLookupPointer(layer->base.text.color)->object2ID);
 				ObjectAddIntegerProperty(&object, "blur", layer->base.text.blur);
 				addToLayerGroup = true;
-				addToObjects = true;
 			} else if (layer->base.tag == LayerBase_path + 1) {
 				object.type = OBJ_LAYER_PATH, object.id = ++objectIDAllocator;
 				LayerPath *path = &layer->base.path;
@@ -1955,72 +2197,138 @@ void ActionExportDesigner2(void *cp) {
 
 				for (uintptr_t i = 0; i < arrlenu(path->fills); i++) {
 					sprintf(cPropertyName, "fills_%d_paint", (int) i);
-					ObjectAddObjectProperty(&object, cPropertyName, ExportPaint2(&path->fills[i].paint, &x, y, &objects, &objectIDAllocator));
+					ObjectAddObjectProperty(&object, cPropertyName, ExportPaint2(&path->fills[i].paint, &x, y, &objects, &objectIDAllocator, NULL));
 					sprintf(cPropertyName, "fills_%d_mode", (int) i);
 					ObjectAddObjectProperty(&object, cPropertyName, ExportFillMode2(&path->fills[i].mode, &x, y, &objects, &objectIDAllocator));
 				}
 
 				addToLayerGroup = true;
-				addToObjects = true;
-			} else {
-				object.type = OBJ_LAYER_METRICS, object.id = ++objectIDAllocator;
+			} else if (layer->base.tag == LayerBase_metrics + 1) {
 				LayerMetrics *m = &layer->base.metrics;
-				ObjectAddIntegerProperty(&object, "clipEnabled", m->clipEnabled);
-				ObjectAddIntegerProperty(&object, "wrapText", m->wrapText);
-				ObjectAddIntegerProperty(&object, "ellipsis", m->ellipsis);
-				ObjectAddIntegerProperty(&object, "insets0", m->insets.l);
-				ObjectAddIntegerProperty(&object, "insets1", m->insets.r);
-				ObjectAddIntegerProperty(&object, "insets2", m->insets.t);
-				ObjectAddIntegerProperty(&object, "insets3", m->insets.b);
-				ObjectAddIntegerProperty(&object, "clipInsets0", m->clipInsets.l);
-				ObjectAddIntegerProperty(&object, "clipInsets1", m->clipInsets.r);
-				ObjectAddIntegerProperty(&object, "clipInsets2", m->clipInsets.t);
-				ObjectAddIntegerProperty(&object, "clipInsets3", m->clipInsets.b);
-				ObjectAddIntegerProperty(&object, "preferredWidth", m->preferredSize.width);
-				ObjectAddIntegerProperty(&object, "preferredHeight", m->preferredSize.height);
-				ObjectAddIntegerProperty(&object, "minimumWidth", m->minimumSize.width);
-				ObjectAddIntegerProperty(&object, "minimumHeight", m->minimumSize.height);
-				ObjectAddIntegerProperty(&object, "maximumWidth", m->maximumSize.width);
-				ObjectAddIntegerProperty(&object, "maximumHeight", m->maximumSize.height);
-				ObjectAddIntegerProperty(&object, "gapMajor", m->gaps.major);
-				ObjectAddIntegerProperty(&object, "gapMinor", m->gaps.minor);
-				ObjectAddIntegerProperty(&object, "gapWrap", m->gaps.wrap);
-				ObjectAddIntegerProperty(&object, "cursor", m->cursor);
-				ObjectAddIntegerProperty(&object, "horizontalTextAlign", m->textHorizontalAlign + 1);
-				ObjectAddIntegerProperty(&object, "verticalTextAlign", m->textVerticalAlign + 1);
 				assert(!m->globalOffset.l && !m->globalOffset.r && !m->globalOffset.t && !m->globalOffset.b);
-				addToObjects = true;
-				metrics = object;
 
-				textStyle.type = OBJ_VAR_TEXT_STYLE, textStyle.id = ++objectIDAllocator;
-				ObjectAddIntegerProperty(&textStyle, "_graphX", x);
-				ObjectAddIntegerProperty(&textStyle, "_graphY", y);
-				ObjectAddIntegerProperty(&textStyle, "_graphW", 80);
-				ObjectAddIntegerProperty(&textStyle, "_graphH", 60);
-				ObjectAddObjectProperty(&textStyle, "textColor", ColorLookupPointer(m->textColor)->object2ID);
-				ObjectAddObjectProperty(&textStyle, "selectedBackground", ColorLookupPointer(m->selectedBackground)->object2ID);
-				ObjectAddObjectProperty(&textStyle, "selectedText", ColorLookupPointer(m->selectedText)->object2ID);
-				ObjectAddIntegerProperty(&textStyle, "textSize", m->textSize);
-				ObjectAddIntegerProperty(&textStyle, "fontWeight", m->fontWeight);
-				ObjectAddIntegerProperty(&textStyle, "isItalic", m->italic);
-				ObjectAddIntegerProperty(&textStyle, "fontFamily", m->fontFamily == FONT_FAMILY_MONO ? 0xFFFD : 0xFFFF);
-				arrput(objects, textStyle);
-				x += 100;
+				object.type = OBJ_VAR_TEXT_STYLE, object.id = ++objectIDAllocator;
+				ObjectAddObjectProperty(&object, "textColor", ColorLookupPointer(m->textColor)->object2ID);
+				ObjectAddObjectProperty(&object, "selectedBackground", ColorLookupPointer(m->selectedBackground)->object2ID);
+				ObjectAddObjectProperty(&object, "selectedText", ColorLookupPointer(m->selectedText)->object2ID);
+				ObjectAddIntegerProperty(&object, "textSize", m->textSize);
+				ObjectAddIntegerProperty(&object, "fontWeight", m->fontWeight);
+				ObjectAddIntegerProperty(&object, "isItalic", m->italic);
+				ObjectAddIntegerProperty(&object, "fontFamily", m->fontFamily == FONT_FAMILY_MONO ? 0xFFFD : 0xFFFF);
+				ObjectAddIntegerProperty(&object, "iconSize", m->iconSize);
+				ObjectAddObjectProperty(&object, "iconColor", ColorLookupPointer(m->iconColor)->object2ID);
+				textStyle = object;
 
-				iconStyle.type = OBJ_VAR_ICON_STYLE, iconStyle.id = ++objectIDAllocator;
-				ObjectAddIntegerProperty(&iconStyle, "_graphX", x);
-				ObjectAddIntegerProperty(&iconStyle, "_graphY", y);
-				ObjectAddIntegerProperty(&iconStyle, "_graphW", 80);
-				ObjectAddIntegerProperty(&iconStyle, "_graphH", 60);
-				ObjectAddIntegerProperty(&iconStyle, "iconSize", m->iconSize);
-				ObjectAddObjectProperty(&iconStyle, "iconColor", ColorLookupPointer(m->iconColor)->object2ID);
-				arrput(objects, iconStyle);
+				metrics.type = OBJ_LAYER_METRICS, metrics.id = ++objectIDAllocator;
+				ObjectAddIntegerProperty(&metrics, "clipEnabled", m->clipEnabled);
+				ObjectAddIntegerProperty(&metrics, "wrapText", m->wrapText);
+				ObjectAddIntegerProperty(&metrics, "ellipsis", m->ellipsis);
+				ObjectAddIntegerProperty(&metrics, "insets0", m->insets.l);
+				ObjectAddIntegerProperty(&metrics, "insets1", m->insets.r);
+				ObjectAddIntegerProperty(&metrics, "insets2", m->insets.t);
+				ObjectAddIntegerProperty(&metrics, "insets3", m->insets.b);
+				ObjectAddIntegerProperty(&metrics, "clipInsets0", m->clipInsets.l);
+				ObjectAddIntegerProperty(&metrics, "clipInsets1", m->clipInsets.r);
+				ObjectAddIntegerProperty(&metrics, "clipInsets2", m->clipInsets.t);
+				ObjectAddIntegerProperty(&metrics, "clipInsets3", m->clipInsets.b);
+				ObjectAddIntegerProperty(&metrics, "preferredWidth", m->preferredSize.width);
+				ObjectAddIntegerProperty(&metrics, "preferredHeight", m->preferredSize.height);
+				ObjectAddIntegerProperty(&metrics, "minimumWidth", m->minimumSize.width);
+				ObjectAddIntegerProperty(&metrics, "minimumHeight", m->minimumSize.height);
+				ObjectAddIntegerProperty(&metrics, "maximumWidth", m->maximumSize.width);
+				ObjectAddIntegerProperty(&metrics, "maximumHeight", m->maximumSize.height);
+				ObjectAddIntegerProperty(&metrics, "gapMajor", m->gaps.major);
+				ObjectAddIntegerProperty(&metrics, "gapMinor", m->gaps.minor);
+				ObjectAddIntegerProperty(&metrics, "gapWrap", m->gaps.wrap);
+				ObjectAddIntegerProperty(&metrics, "cursor", m->cursor);
+				ObjectAddIntegerProperty(&metrics, "horizontalTextAlign", m->textHorizontalAlign + 1);
+				ObjectAddIntegerProperty(&metrics, "verticalTextAlign", m->textVerticalAlign + 1);
+				ObjectAddIntegerProperty(&metrics, "_graphX", x);
+				ObjectAddIntegerProperty(&metrics, "_graphY", y);
+				ObjectAddIntegerProperty(&metrics, "_graphW", 80);
+				ObjectAddIntegerProperty(&metrics, "_graphH", 60);
+				arrput(objects, metrics);
 				x += 100;
+			} else {
+				assert(false);
 			}
 
+			ObjectAddIntegerProperty(&object, "_graphX", x);
+			ObjectAddIntegerProperty(&object, "_graphY", y);
+			ObjectAddIntegerProperty(&object, "_graphW", 80);
+			ObjectAddIntegerProperty(&object, "_graphH", 60);
+			arrput(objects, object);
+			x += 100;
+
+			uint64_t previousOverrideID = object.id;
+
+			for (uintptr_t i = 0; i < arrlenu(layer->sequences); i++) {
+				Sequence *s = layer->sequences[i];
+				assert(arrlenu(s->keyframes) == 1);
+				Keyframe *keyframe = s->keyframes[0];
+
+				char buffer[256];
+				snprintf(buffer, sizeof(buffer), "%s%s%s%s%s%s%s%s%s%s", 
+						((StringOption *) PrimaryState_Type.fields[s->primaryState].item.options)->string,
+						s->flagFocused ? " (focused)" : "",
+						s->flagChecked ? " (checked)" : "",
+						s->flagIndeterminate ? " (indeterminate)" : "",
+						s->flagDefault ? " (default)" : "",
+						s->flagItemFocus ? " (list item focus)" : "",
+						s->flagListFocus ? " (list focus)" : "",
+						s->flagBeforeEnter ? " (before enter)" : "",
+						s->flagAfterExit ? " (after exit)" : "",
+						s->flagSelected ? " (selected)" : "");
+				fprintf(stderr, "%.*s:%.*s:%s:%d\n", (int) style->name.byteCount, (char *) style->name.buffer,
+						(int) layer->name.byteCount, (char *) layer->name.buffer, buffer, s->duration);
+
+				uint32_t stateBits = 0;
+				if (s->flagFocused) stateBits |= THEME_STATE_FOCUSED;
+				if (s->flagChecked) stateBits |= THEME_STATE_CHECKED;
+				if (s->flagIndeterminate) stateBits |= THEME_STATE_INDETERMINATE;
+				if (s->flagDefault) stateBits |= THEME_STATE_DEFAULT_BUTTON;
+				if (s->flagItemFocus) stateBits |= THEME_STATE_FOCUSED_ITEM;
+				if (s->flagListFocus) stateBits |= THEME_STATE_LIST_FOCUSED;
+				if (s->flagBeforeEnter) stateBits |= THEME_STATE_BEFORE_ENTER;
+				if (s->flagAfterExit) stateBits |= THEME_STATE_AFTER_EXIT;
+				if (s->flagSelected) stateBits |= THEME_STATE_SELECTED;
+
+				Object2 override = { .type = object.type, .id = ++objectIDAllocator };
+				ObjectAddIntegerProperty(&override, "_graphX", x);
+				ObjectAddIntegerProperty(&override, "_graphY", y);
+				ObjectAddIntegerProperty(&override, "_graphW", 80);
+				ObjectAddIntegerProperty(&override, "_graphH", 60);
+				ObjectAddObjectProperty(&override, "_parent", previousOverrideID);
+				ObjectAddIntegerProperty(&override, "_primaryState", s->primaryState);
+				ObjectAddIntegerProperty(&override, "_stateBits", stateBits);
+				ObjectAddIntegerProperty(&override, "_duration", s->duration);
+
+				bool addObject = false;
+
+				for (uintptr_t i = 0; i < arrlenu(keyframe->properties); i++) {
+					Property *property = &keyframe->properties[i];
+
+					if (layer->base.tag == LayerBase_box + 1 && property->path[0] == (uint32_t) -2 && property->path[1] == 8 && property->path[2] == 0
+							&& property->path[3] == 2 && (property->path[4] == 2 || property->path[4] == 3)) {
+						continue;
+					}
+
+					ExportProperty2(layer, property, &override);
+					addObject = true;
+				}
+
+				if (addObject) {
+					arrput(objects, override);
+					previousOverrideID = override.id;
+					x += 100;
+				} else {
+					arrfree(override.properties);
+				}
+			}	
+
 			if (addToLayerGroup) {
 				sprintf(cPropertyName, "layers_%d_layer", layerCount);
-				ObjectAddObjectProperty(&layerGroup, cPropertyName, object.id);
+				ObjectAddObjectProperty(&layerGroup, cPropertyName, previousOverrideID);
 				sprintf(cPropertyName, "layers_%d_offset0", layerCount);
 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->offset.l);
 				sprintf(cPropertyName, "layers_%d_offset1", layerCount);
@@ -2041,15 +2349,6 @@ void ActionExportDesigner2(void *cp) {
 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->mode);
 				layerCount++;
 			}
-
-			if (addToObjects) {
-				ObjectAddIntegerProperty(&object, "_graphX", x);
-				ObjectAddIntegerProperty(&object, "_graphY", y);
-				ObjectAddIntegerProperty(&object, "_graphW", 80);
-				ObjectAddIntegerProperty(&object, "_graphH", 60);
-				arrput(objects, object);
-				x += 100;
-			}
 		}
 
 		{
@@ -2074,7 +2373,6 @@ void ActionExportDesigner2(void *cp) {
 			ObjectAddObjectProperty(&object, "appearance", layerGroup.id);
 			ObjectAddObjectProperty(&object, "metrics", metrics.id);
 			ObjectAddObjectProperty(&object, "textStyle", textStyle.id);
-			ObjectAddObjectProperty(&object, "iconStyle", iconStyle.id);
 			arrput(objects, object);
 			x += 100;
 		}
diff --git a/util/designer2.cpp b/util/designer2.cpp
index 9da21c2..c99dcab 100644
--- a/util/designer2.cpp
+++ b/util/designer2.cpp
@@ -16,12 +16,13 @@
 // x86_64-w64-mingw32-gcc -O3 -o bin/designer2.exe -D UI_WINDOWS util/designer2.cpp -DUNICODE -lgdi32 -luser32 -lkernel32 -Wl,--subsystem,windows -fno-exceptions -fno-rtti
 
 // TODO Needed to replace the old designer:
-// 	Import and reorganize old theming data.
+// 	Import old theming data.
 // 	Export.
 // 	Prototyping display: previewing state transitions.
 
 // TODO Additional features:
-// 	Scrollbars?
+// 	In a conditional layer, properties from conditional linked objects (such as a gradient paint) should show if their conditions match.
+// 	Scrollbars on the canvas?
 // 	Icons for different object types (especially color overwrite objects).
 // 	Fix moving/resizing objects when zoomed in.
 // 	Path layers: dashed contours.
@@ -35,6 +36,9 @@
 // 	Get text rendering on non-Essence platforms.
 // 	Proper bezier path editor.
 // 	Path boolean operations.
+// 	Timeline editor for applying a given state change, with rows for possibly many different layers.
+
+// TODO Reorganize old theming data!
 		
 //////////////////////////////////////////////////////////////
 
@@ -271,7 +275,6 @@ enum ObjectType : uint8_t {
 	OBJ_VAR_COLOR = 0x40,
 	OBJ_VAR_INT,
 	OBJ_VAR_TEXT_STYLE,
-	OBJ_VAR_ICON_STYLE,
 	OBJ_VAR_CONTOUR_STYLE,
 	
 	OBJ_PAINT_OVERWRITE = 0x60,
@@ -409,11 +412,11 @@ bool ObjectMatchesPreviewState(Object *object) {
 		&& ((stateBits & canvas->previewStateBits) == stateBits);
 }
 
-Property *PropertyFindOrInherit(bool first, Object *object, const char *cName, uint8_t type = 0) {
+Property *PropertyFindOrInherit(Object *object, const char *cName, uint8_t type = 0) {
 	uintptr_t depth = 0;
 
 	while (object && (depth++ < 100)) {
-		if (first || !ObjectIsConditional(object) || (canvas->previewStateActive && ObjectMatchesPreviewState(object))) {
+		if (!ObjectIsConditional(object) || (canvas->previewStateActive && ObjectMatchesPreviewState(object))) {
 			// Return the value if the object has this property.
 			Property *property = PropertyFind(object, cName);
 			if (property) return type && property->type != type ? nullptr : property;
@@ -424,24 +427,23 @@ Property *PropertyFindOrInherit(bool first, Object *object, const char *cName, u
 		// Go to the inheritance parent object.
 		Property *property = PropertyFind(object, "_parent", PROP_OBJECT);
 		object = ObjectFind(property ? property->object : 0);
-		first = false;
 	}
 
 	return nullptr;
 }
 
-int32_t PropertyFindOrInheritReadInt32(bool first, Object *object, const char *cName, int32_t defaultValue = 0) {
-	Property *property = PropertyFindOrInherit(first, object, cName, PROP_INT);
+int32_t PropertyFindOrInheritReadInt32(Object *object, const char *cName, int32_t defaultValue = 0) {
+	Property *property = PropertyFindOrInherit(object, cName, PROP_INT);
 	return property ? property->integer : defaultValue;
 }
 
-float PropertyFindOrInheritReadFloat(bool first, Object *object, const char *cName, float defaultValue = 0) {
-	Property *property = PropertyFindOrInherit(first, object, cName, PROP_FLOAT);
+float PropertyFindOrInheritReadFloat(Object *object, const char *cName, float defaultValue = 0) {
+	Property *property = PropertyFindOrInherit(object, cName, PROP_FLOAT);
 	return property ? property->floating : defaultValue;
 }
 
-Object *PropertyFindOrInheritReadObject(bool first, Object *object, const char *cName) {
-	Property *property = PropertyFindOrInherit(first, object, cName, PROP_OBJECT);
+Object *PropertyFindOrInheritReadObject(Object *object, const char *cName) {
+	Property *property = PropertyFindOrInherit(object, cName, PROP_OBJECT);
 	return property ? ObjectFind(property->object) : nullptr;
 }
 
@@ -1372,7 +1374,7 @@ void InspectorPopulate() {
 			UIButtonCreate(0, UI_BUTTON_SMALL, "Rename", -1)->invoke = InspectorRenameObject;
 			UIParentPop();
 
-			bool inheritWithAnimation = object->type == OBJ_VAR_TEXT_STYLE || object->type == OBJ_VAR_ICON_STYLE 
+			bool inheritWithAnimation = object->type == OBJ_VAR_TEXT_STYLE
 				|| object->type == OBJ_LAYER_BOX || object->type == OBJ_LAYER_TEXT || object->type == OBJ_LAYER_PATH
 				|| object->type == OBJ_PAINT_OVERWRITE || object->type == OBJ_PAINT_LINEAR_GRADIENT || object->type == OBJ_PAINT_RADIAL_GRADIENT
 				|| object->type == OBJ_VAR_CONTOUR_STYLE;
@@ -1421,7 +1423,6 @@ void InspectorPopulate() {
 			InspectorAddLink(object, "Appearance:", "appearance");
 			InspectorAddLink(object, "Metrics:", "metrics");
 			InspectorAddLink(object, "Text style:", "textStyle");
-			InspectorAddLink(object, "Icon style:", "iconStyle");
 			InspectorAddBooleanToggle(object, "Public style", "isPublic");
 		} else if (object->type == OBJ_VAR_COLOR) {
 			InspectorBind(&UIColorPickerCreate(&UIPanelCreate(0, 0)->e, UI_COLOR_PICKER_HAS_OPACITY)->e, object->id, "color", INSPECTOR_COLOR_PICKER);
@@ -1504,7 +1505,7 @@ void InspectorPopulate() {
 			InspectorAddRadioSwitch(object, "Monospaced", "fontFamily", ES_FONT_MONOSPACED);
 			InspectorBind(&UIButtonCreate(0, UI_BUTTON_SMALL, "X", 1)->e, object->id, "fontFamily", INSPECTOR_REMOVE_BUTTON);
 			UIParentPop();
-		} else if (object->type == OBJ_VAR_ICON_STYLE) {
+
 			InspectorAddLink(object, "Icon color:", "iconColor");
 			InspectorAddInteger(object, "Icon size:", "iconSize");
 		} else if (object->type == OBJ_VAR_CONTOUR_STYLE) {
@@ -1833,14 +1834,11 @@ uint32_t GraphGetColorFromProperty(Property *property) {
 void ExportGradientStopArray(Object *object, EsBuffer *data, size_t stopCount) {
 	for (uintptr_t i = 0; i < stopCount; i++) {
 		char cPropertyName[PROPERTY_NAME_SIZE];
-		sprintf(cPropertyName, "stops_%d_color", (int32_t) i);
-		Property *color = PropertyFind(object, cPropertyName, PROP_OBJECT);
-		sprintf(cPropertyName, "stops_%d_position", (int32_t) i);
-		Property *position = PropertyFind(object, cPropertyName, PROP_OBJECT);
-
 		ThemeGradientStop stop = {};
-		stop.color = GraphGetColor(ObjectFind(color ? color->object : 0));
-		stop.position = GraphGetIntegerFromProperty(position);
+		sprintf(cPropertyName, "stops_%d_color", (int32_t) i);
+		stop.color = GraphGetColor(PropertyFindOrInheritReadObject(object, cPropertyName));
+		sprintf(cPropertyName, "stops_%d_position", (int32_t) i);
+		stop.position = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, cPropertyName, PROP_INT));
 		EsBufferWrite(data, &stop, sizeof(stop));
 	}
 }
@@ -1859,18 +1857,18 @@ int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) {
 
 		return THEME_PAINT_SOLID;
 	} else if (object->type == OBJ_PAINT_OVERWRITE) {
-		ExportPaint(PropertyFindOrInheritReadObject(false, object, "color"), data, depth + 1);
+		ExportPaint(PropertyFindOrInheritReadObject(object, "color"), data, depth + 1);
 		return THEME_PAINT_OVERWRITE;
 	} else if (object->type == OBJ_PAINT_LINEAR_GRADIENT) {
 		if (data) {
 			ThemePaintLinearGradient paint = {};
-			paint.transform[0] = PropertyFindOrInheritReadFloat(false, object, "transformX");
-			paint.transform[1] = PropertyFindOrInheritReadFloat(false, object, "transformY");
-			paint.transform[2] = PropertyFindOrInheritReadFloat(false, object, "transformStart");
-			paint.stopCount = PropertyFindOrInheritReadInt32(false, object, "stops_count");
-			paint.useGammaInterpolation = !!PropertyFindOrInheritReadInt32(false, object, "useGammaInterpolation");
-			paint.useSystemColor = !!PropertyFindOrInheritReadInt32(false, object, "useSystemColor");
-			paint.repeatMode = PropertyFindOrInheritReadInt32(false, object, "repeatMode");
+			paint.transform[0] = PropertyFindOrInheritReadFloat(object, "transformX");
+			paint.transform[1] = PropertyFindOrInheritReadFloat(object, "transformY");
+			paint.transform[2] = PropertyFindOrInheritReadFloat(object, "transformStart");
+			paint.stopCount = PropertyFindOrInheritReadInt32(object, "stops_count");
+			paint.useGammaInterpolation = !!PropertyFindOrInheritReadInt32(object, "useGammaInterpolation");
+			paint.useSystemColor = !!PropertyFindOrInheritReadInt32(object, "useSystemColor");
+			paint.repeatMode = PropertyFindOrInheritReadInt32(object, "repeatMode");
 			EsBufferWrite(data, &paint, sizeof(paint));
 			ExportGradientStopArray(object, data, paint.stopCount);
 		}
@@ -1879,15 +1877,15 @@ int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) {
 	} else if (object->type == OBJ_PAINT_RADIAL_GRADIENT) {
 		if (data) {
 			ThemePaintRadialGradient paint = {};
-			paint.transform[0] = PropertyFindOrInheritReadFloat(false, object, "transform0");
-			paint.transform[1] = PropertyFindOrInheritReadFloat(false, object, "transform1");
-			paint.transform[2] = PropertyFindOrInheritReadFloat(false, object, "transform2");
-			paint.transform[3] = PropertyFindOrInheritReadFloat(false, object, "transform3");
-			paint.transform[4] = PropertyFindOrInheritReadFloat(false, object, "transform4");
-			paint.transform[5] = PropertyFindOrInheritReadFloat(false, object, "transform5");
-			paint.stopCount = PropertyFindOrInheritReadInt32(false, object, "stops_count");
-			paint.useGammaInterpolation = !!PropertyFindOrInheritReadInt32(false, object, "useGammaInterpolation");
-			paint.repeatMode = PropertyFindOrInheritReadInt32(false, object, "repeatMode");
+			paint.transform[0] = PropertyFindOrInheritReadFloat(object, "transform0");
+			paint.transform[1] = PropertyFindOrInheritReadFloat(object, "transform1");
+			paint.transform[2] = PropertyFindOrInheritReadFloat(object, "transform2");
+			paint.transform[3] = PropertyFindOrInheritReadFloat(object, "transform3");
+			paint.transform[4] = PropertyFindOrInheritReadFloat(object, "transform4");
+			paint.transform[5] = PropertyFindOrInheritReadFloat(object, "transform5");
+			paint.stopCount = PropertyFindOrInheritReadInt32(object, "stops_count");
+			paint.useGammaInterpolation = !!PropertyFindOrInheritReadInt32(object, "useGammaInterpolation");
+			paint.repeatMode = PropertyFindOrInheritReadInt32(object, "repeatMode");
 			EsBufferWrite(data, &paint, sizeof(paint));
 			ExportGradientStopArray(object, data, paint.stopCount);
 		}
@@ -1898,37 +1896,37 @@ int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) {
 	}
 }
 
-void ExportLayerBox(bool first, Object *object, EsBuffer *data) {
-	Property *mainPaint = PropertyFindOrInherit(first, object, "mainPaint", PROP_OBJECT);
-	Property *borderPaint = PropertyFindOrInherit(first, object, "borderPaint", PROP_OBJECT);
+void ExportLayerBox(Object *object, EsBuffer *data) {
+	Property *mainPaint = PropertyFindOrInherit(object, "mainPaint", PROP_OBJECT);
+	Property *borderPaint = PropertyFindOrInherit(object, "borderPaint", PROP_OBJECT);
 	ThemeLayerBox box = {};
 	box.mainPaintType = ExportPaint(ObjectFind(mainPaint ? mainPaint->object : 0), nullptr);
 	box.borderPaintType = ExportPaint(ObjectFind(borderPaint ? borderPaint->object : 0), nullptr);
-	box.borders.l = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "borders0"));
-	box.borders.r = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "borders1"));
-	box.borders.t = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "borders2"));
-	box.borders.b = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "borders3"));
-	box.corners.tl = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "corners0"));
-	box.corners.tr = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "corners1"));
-	box.corners.bl = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "corners2"));
-	box.corners.br = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "corners3"));
-	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "isBlurred"   ))) box.flags |= THEME_LAYER_BOX_IS_BLURRED;
-	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "autoCorners" ))) box.flags |= THEME_LAYER_BOX_AUTO_CORNERS;
-	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "autoBorders" ))) box.flags |= THEME_LAYER_BOX_AUTO_BORDERS;
-	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "shadowHiding"))) box.flags |= THEME_LAYER_BOX_SHADOW_HIDING;
+	box.borders.l = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders0"));
+	box.borders.r = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders1"));
+	box.borders.t = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders2"));
+	box.borders.b = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders3"));
+	box.corners.tl = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners0"));
+	box.corners.tr = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners1"));
+	box.corners.bl = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners2"));
+	box.corners.br = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners3"));
+	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "isBlurred"   ))) box.flags |= THEME_LAYER_BOX_IS_BLURRED;
+	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "autoCorners" ))) box.flags |= THEME_LAYER_BOX_AUTO_CORNERS;
+	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "autoBorders" ))) box.flags |= THEME_LAYER_BOX_AUTO_BORDERS;
+	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "shadowHiding"))) box.flags |= THEME_LAYER_BOX_SHADOW_HIDING;
 	EsBufferWrite(data, &box, sizeof(box));
 	ExportPaint(ObjectFind(mainPaint ? mainPaint->object : 0), data);
 	ExportPaint(ObjectFind(borderPaint ? borderPaint->object : 0), data);
 }
 
-void ExportLayerPath(bool first, Object *object, EsBuffer *data) {
-	Property *pointCount = PropertyFindOrInherit(false, object, "points_count", PROP_INT);
-	Property *fillCount = PropertyFindOrInherit(false, object, "fills_count", PROP_INT);
+void ExportLayerPath(Object *object, EsBuffer *data) {
+	Property *pointCount = PropertyFindOrInherit(object, "points_count", PROP_INT);
+	Property *fillCount = PropertyFindOrInherit(object, "fills_count", PROP_INT);
 
 	ThemeLayerPath path = {};
-	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "pathFillEvenOdd"))) path.flags |= THEME_LAYER_PATH_FILL_EVEN_ODD;
-	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "pathClosed"))) path.flags |= THEME_LAYER_PATH_CLOSED;
-	path.alpha = GraphGetIntegerFromProperty(PropertyFindOrInherit(first, object, "alpha"));
+	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "pathFillEvenOdd"))) path.flags |= THEME_LAYER_PATH_FILL_EVEN_ODD;
+	if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "pathClosed"))) path.flags |= THEME_LAYER_PATH_CLOSED;
+	path.alpha = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "alpha"));
 	path.pointCount = pointCount ? pointCount->integer : 0;
 	path.fillCount = fillCount ? fillCount->integer : 0;
 	EsBufferWrite(data, &path, sizeof(path));
@@ -1939,7 +1937,7 @@ void ExportLayerPath(bool first, Object *object, EsBuffer *data) {
 		Property *property;
 #define LAYER_PATH_WRITE_POINT(x) \
 		sprintf(cPropertyName, "points_%d_" #x, (int32_t) i); \
-		property = PropertyFindOrInherit(first, object, cPropertyName, PROP_FLOAT); \
+		property = PropertyFindOrInherit(object, cPropertyName, PROP_FLOAT); \
 		EsBufferWrite(data, property ? &property->floating : &zero, sizeof(float));
 		LAYER_PATH_WRITE_POINT(x0);
 		LAYER_PATH_WRITE_POINT(y0);
@@ -1954,11 +1952,11 @@ void ExportLayerPath(bool first, Object *object, EsBuffer *data) {
 		ThemeLayerPathFill fill = {};
 
 		sprintf(cPropertyName, "fills_%d_paint", (int32_t) i);
-		Object *paint = PropertyFindOrInheritReadObject(first, object, cPropertyName);
+		Object *paint = PropertyFindOrInheritReadObject(object, cPropertyName);
 		fill.paintAndFillType |= ExportPaint(paint, nullptr);
 
 		sprintf(cPropertyName, "fills_%d_mode", (int32_t) i);
-		Object *mode = PropertyFindOrInheritReadObject(first, object, cPropertyName);
+		Object *mode = PropertyFindOrInheritReadObject(object, cPropertyName);
 
 		// TODO Dashed contours.
 
@@ -1973,12 +1971,12 @@ void ExportLayerPath(bool first, Object *object, EsBuffer *data) {
 
 		if (mode && mode->type == OBJ_VAR_CONTOUR_STYLE) {
 			ThemeLayerPathFillContour contour = {};
-			contour.miterLimit = PropertyFindOrInheritReadFloat(first, mode, "miterLimit");
-			contour.internalWidth = PropertyFindOrInheritReadInt32(first, mode, "internalWidth");
-			contour.externalWidth = PropertyFindOrInheritReadInt32(first, mode, "externalWidth");
-			contour.mode = PropertyFindOrInheritReadInt32(first, mode, "joinMode") 
-				| (PropertyFindOrInheritReadInt32(first, mode, "capMode") << 2)
-				| (PropertyFindOrInheritReadInt32(first, mode, "integerWidthsOnly") ? 0x80 : 0);
+			contour.miterLimit = PropertyFindOrInheritReadFloat(mode, "miterLimit");
+			contour.internalWidth = PropertyFindOrInheritReadInt32(mode, "internalWidth");
+			contour.externalWidth = PropertyFindOrInheritReadInt32(mode, "externalWidth");
+			contour.mode = PropertyFindOrInheritReadInt32(mode, "joinMode") 
+				| (PropertyFindOrInheritReadInt32(mode, "capMode") << 2)
+				| (PropertyFindOrInheritReadInt32(mode, "integerWidthsOnly") ? 0x80 : 0);
 			EsBufferWrite(data, &contour, sizeof(contour));
 		}
 	}
@@ -2077,16 +2075,16 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int
 	}
 
 	if (object->type == OBJ_LAYER_BOX) {
-		bounds.l += PropertyFindOrInheritReadInt32(depth == 0, object, "offset0") * canvas->zoom;
-		bounds.r += PropertyFindOrInheritReadInt32(depth == 0, object, "offset1") * canvas->zoom;
-		bounds.t += PropertyFindOrInheritReadInt32(depth == 0, object, "offset2") * canvas->zoom;
-		bounds.b += PropertyFindOrInheritReadInt32(depth == 0, object, "offset3") * canvas->zoom;
+		bounds.l += PropertyFindOrInheritReadInt32(object, "offset0") * canvas->zoom;
+		bounds.r += PropertyFindOrInheritReadInt32(object, "offset1") * canvas->zoom;
+		bounds.t += PropertyFindOrInheritReadInt32(object, "offset2") * canvas->zoom;
+		bounds.b += PropertyFindOrInheritReadInt32(object, "offset3") * canvas->zoom;
 
 		uint8_t buffer[4096];
 		EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) };
 		ThemeLayer layer = { .position = { .r = 100, .b = 100 }, .type = THEME_LAYER_BOX };
 		EsBufferWrite(&data, &layer, sizeof(layer));
-		ExportLayerBox(depth == 0, object, &data);
+		ExportLayerBox(object, &data);
 		CanvasDrawLayerFromData(painter, bounds, data);
 	} else if (object->type == OBJ_LAYER_TEXT) {
 #ifdef OS_ESSENCE
@@ -2115,7 +2113,7 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int
 		EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) };
 		ThemeLayer layer = { .position = { .r = 100, .b = 100 }, .type = THEME_LAYER_PATH };
 		EsBufferWrite(&data, &layer, sizeof(layer));
-		ExportLayerPath(depth == 0, object, &data);
+		ExportLayerPath(object, &data);
 		CanvasDrawLayerFromData(painter, bounds, data);
 	} else if (object->type == OBJ_LAYER_GROUP) {
 		int32_t layerCount = PropertyReadInt32(object, "layers_count");
@@ -2178,20 +2176,19 @@ void CanvasDrawStyle(Object *object, UIRectangle bounds, UIPainter *painter, int
 		textStyle.size = GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "textSize")) * canvas->zoom;
 		textStyle.color = GraphGetColorFromProperty(PropertyFindOrInherit(false, object, "textColor"));
 		EsDrawTextSimple((_EsPainter *) &themePainter, ui.instance->window, bounds, "Sample", -1, textStyle, ES_TEXT_H_CENTER | ES_TEXT_V_CENTER); 
-	} else if (object->type == OBJ_VAR_ICON_STYLE) {
+#if 0
 		EsDrawStandardIcon((_EsPainter *) &themePainter, ES_ICON_GO_NEXT_SYMBOLIC, 
 				GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "iconSize")), bounds, 
 				GraphGetColorFromProperty(PropertyFindOrInherit(false, object, "iconColor")));
+#endif
 	}
 #endif
 
 	if (object->type == OBJ_STYLE) {
-		Property *appearance = PropertyFindOrInherit(false, object, "appearance");
-		Property *textStyle = PropertyFindOrInherit(false, object, "textStyle");
-		Property *iconStyle = PropertyFindOrInherit(false, object, "iconStyle");
+		Property *appearance = PropertyFindOrInherit(object, "appearance");
+		Property *textStyle = PropertyFindOrInherit(object, "textStyle");
 		if (appearance) CanvasDrawLayer(ObjectFind(appearance->object), bounds, painter, depth + 1);
 		if (textStyle) CanvasDrawStyle(ObjectFind(textStyle->object), bounds, painter, depth + 1);
-		else if (iconStyle) CanvasDrawStyle(ObjectFind(iconStyle->object), bounds, painter, depth + 1);
 	}
 }
 
@@ -2268,6 +2265,7 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
 			UIRectangle selectionIntersection = UIRectangleIntersection(bounds, selectionBounds);
 			bool isSelected = (object->flags & OBJECT_IS_SELECTED) == (inspectorPickData == nullptr)
 				|| (canvas->selecting && UI_RECT_VALID(selectionIntersection));
+			bool isConditional = ObjectIsConditional(object);
 
 			if (!canvas->showPrototype) {
 				if (isSelected) {
@@ -2281,7 +2279,7 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
 				UIDrawBlock(painter, UI_RECT_4(bounds.l + 1, bounds.r + 1, bounds.b, bounds.b + 1), 0xFF404040);
 				UIDrawBlock(painter, UI_RECT_4(bounds.r, bounds.r + 1, bounds.t + 1, bounds.b + 1), 0xFF404040);
 
-				if (ObjectIsConditional(object)) {
+				if (isConditional) {
 					UIRectangle indicator = UI_RECT_4(bounds.l - ui.glyphWidth, bounds.l, bounds.t, bounds.t + ui.glyphHeight);
 					UIDrawBlock(painter, indicator, 0xFFFFFF00);
 					UIDrawString(painter, indicator, "?", -1, 0xFF000000, UI_ALIGN_CENTER, nullptr);
@@ -2297,6 +2295,12 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
 						buffer, -1, 0xFF000000, UI_ALIGN_CENTER, nullptr);
 			}
 
+			if (isConditional) {
+				canvas->previewStateActive = true;
+				canvas->previewPrimaryState = PropertyReadInt32(object, "_primaryState");
+				canvas->previewStateBits = PropertyReadInt32(object, "_stateBits");
+			}
+
 			if (object->type == OBJ_VAR_INT || object->type == OBJ_MOD_MULTIPLY) {
 				int32_t value = GraphGetInteger(object);
 				char buffer[32];
@@ -2315,17 +2319,23 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
 				snprintf(buffer, sizeof(buffer), "%.8X", color);
 				UIRectangle area = UI_RECT_4(bounds.l, bounds.r, bounds.t, bounds.t + UIMeasureStringHeight());
 				UIDrawString(painter, area, buffer, -1, isLight ? 0xFF000000 : 0xFFFFFFFF, UI_ALIGN_CENTER, nullptr);
-			} else if (object->type == OBJ_VAR_TEXT_STYLE || object->type == OBJ_VAR_ICON_STYLE || object->type == OBJ_STYLE) {
+			} else if (object->type == OBJ_VAR_TEXT_STYLE || object->type == OBJ_STYLE) {
 				CanvasDrawStyle(object, bounds, painter);
 			} else if (object->type == OBJ_INSTANCE) {
 				Property *style = PropertyFind(object, "style", PROP_OBJECT);
 				canvas->previewStateActive = object->id == selectedObjectID;
 				CanvasDrawStyle(ObjectFind(style ? style->object : 0), bounds, painter);
-				canvas->previewStateActive = false;
 			} else {
 				// TODO Preview for the metrics layer. Show the preferred size, insets and gaps?
 				// TODO Preview for OBJ_VAR_CONTOUR_STYLE.
 			}
+
+			canvas->previewStateActive = false;
+
+			if (!canvas->showPrototype) {
+				canvas->previewPrimaryState = THEME_PRIMARY_STATE_IDLE;
+				canvas->previewStateBits = 0;
+			}
 		}
 
 		if (canvas->showArrows && !canvas->showPrototype) {
@@ -2615,7 +2625,6 @@ void ObjectAddCommand(void *) {
 	UIMenuAddItem(menu, 0, "Color variable", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_VAR_COLOR);
 	UIMenuAddItem(menu, 0, "Integer variable", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_VAR_INT);
 	UIMenuAddItem(menu, 0, "Text style", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_VAR_TEXT_STYLE);
-	UIMenuAddItem(menu, 0, "Icon style", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_VAR_ICON_STYLE);
 	UIMenuAddItem(menu, 0, "Contour style", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_VAR_CONTOUR_STYLE);
 	UIMenuAddItem(menu, 0, "Metrics", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_LAYER_METRICS);
 	UIMenuAddItem(menu, 0, "Overwrite paint", -1, ObjectAddCommandInternal, (void *) (uintptr_t) OBJ_PAINT_OVERWRITE);