Photo is required. Category, brand, seller, and price are optional - add them later when you know.
Loading…
{{ form.heading || 'Item' }}
{{ form.saveError }}
{{ itemBulkEditSaving ? 'Saving…' : 'Save all' }}
{{ looksChipsCollapsed ? 'Filters ▸' : 'Filters ▾' }}
All
Mine
From friends
goToCutout(t.kind, t.id)"
@delete="deleteLook"
@toggle-select="toggleLookSelected"
@enter-select="enterLooksSelectModeWithLook"
@paint-start="onLookSelectPaintStart"
>
No looks with this piece yet.
No looks from friends yet.
Friends can create looks for you from your profile.
Everything has the usual details.
No looks you created yet.
No looks yet - create your first outfit!
All wear photos, newest first. Linked wears can jump to the original look.
saveWearCardNote(wear, value)"
/>
No wear photos yet - add one from a look detail page.
onCollageSaved(look, meta)"
@duplicate-look="onCollageDuplicateLook"
@switch-canvas="setLookComposeMode('canvas')"
@sync-outfit-ids="syncLookComposeItemIds"
>
onCollageSaved(look, meta)"
@duplicate-look="onCollageDuplicateLook"
@set-stars="(look, n) => setLookStars(look, n)"
@toggle-staple="toggleLookStaple"
@open-calendar="openAddToCalendar"
@open-wear="openAddWearPhoto"
@edit-item-photo="goToItemCutout"
@edit-cover="goToLookCutout(detailLook)"
@delete-look="deleteLook"
@clone-look="cloneLook"
@set-grid-cols="setLookCollageGridCols"
@set-browser-side="setLookCollageBrowserSide"
@set-packing-scope="setLookCreatePackingScope"
@switch-wheel="setLookComposeMode('wheel')"
@set-detail-layout="setLookDetailLayoutSession"
@sync-outfit-ids="syncLookComposeItemIds"
@browser-incomplete-filter-change="setBrowserIncompleteFilter('collageItems', $event)"
@browser-filter-mode-change="setBrowserFilterMode('collageItems', $event)"
@browser-slot-filter-change="setBrowserSlotFilter('collageItems', $event)"
@browser-filter-change="onBrowserFilterChange('collageItems', $event)"
@browser-add-filter="addBrowserFilter('collageItems', $event)"
@browser-remove-filter="removeBrowserFilter('collageItems', $event)"
@browser-clear-filters="clearBrowserFilters('collageItems')"
@browser-sort-change="setBrowserSort('collageItems', $event)"
@browser-search-change="setBrowserSearch('collageItems', $event)"
@browser-load-more="loadMoreBrowserItems('collageItems')"
@browser-page-size-change="onBrowserPageSizeChange('collageItems', $event)"
@browser-rail-catalog-change="setBrowserRailCatalog('collageItems', $event)"
@browser-rail-sort-change="setBrowserRailSort('collageItems', $event)"
@browser-rail-select="onBrowserCatalogRailSelect('collageItems', $event)"
@browser-rail-reorder="saveBrowserRailOrder('collageItems', $event)"
@browser-randomize="randomizeBrowserItem('collageItems')"
@ensure-browser="ensureCollageBrowser"
>
{{ w }}
{{ day.dayNumber }}
+
{{ moment.name }}
{{ momentTimeRangeLabel(moment) }}
{{ packingDateLabel(detailPacking) }} · {{ detailPacking.overview_count }} to bring · {{ detailPacking.in_bag_count || 0 }} in bag
Loading occasion…
onScrollSubTabSelect(payload, setPackingSubSection)"
>
Loading packing…
{{ packingAnalytics.overview_count || 0 }}
Pieces to bring
Unique items in the suitcase
{{ packingAnalytics.looks_packed || 0 }}
Packed looks
In this trip’s suitcase
{{ packingAnalytics.extras_packed || 0 }}
Extra items
Pieces besides packed looks
{{ packingAnalytics.overview_unplanned || 0 }}
Pieces to plan
Packed items with no day or moment yet
Packed looks
{{ detailPacking.looks?.length || 0 }}
Look Lab
+ Add looks
Add looks or extras first, then use Look Lab.
Pack looks to bring, then extras fill the gaps.
Extra items
{{ detailPacking.extra_items?.length || 0 }}
+ Add extra items
Extra packed pieces that are not only coming from a look.
To bring
{{ detailPacking.overview?.length || 0 }}
Nothing to bring yet. Add looks or extra items.
To plan
{{ packingUnplannedLooks.length }} looks · {{ packingUnplannedOverview.length }} pieces
Packed looks and pieces with no day or moment yet. Plan a look to cover its pieces.
+ Plan a look
Nothing left to plan.
onScrollSubTabSelect(payload, setSuitcaseSubSection)"
>
Loading suitcase…
Check pieces as they go in the bag. This is not Plan (when you wear them).
Add looks and extras on the Packing tab first.
{{ detailPacking.in_bag_count || 0 }} / {{ detailPacking.overview_count || 0 }}
In the bag
Pieces checked into the suitcase
{{ packingStillToPackOverview.length }}
Still to pack
On the list, not in the bag yet
Still to pack
{{ packingStillToPackOverview.length }}
Everything on the list is in the bag.
In the bag
{{ packingInBagOverview.length }}
Nothing in the bag yet.
Loading plan…
Add a moment (dinner, beach day) or assign a look to a day. Moments are optional.
▾
Unplanned looks
drag onto a day or moment · Alt-drag to copy
tap a look to place on a day or moment
{{ packingPlanUnplannedLooks().length }} look{{ packingPlanUnplannedLooks().length === 1 ? '' : 's' }}
▾
Undated moments
drag onto a day
{{ packingUndatedMoments.length }} moment{{ packingUndatedMoments.length === 1 ? '' : 's' }}
{{ moment.name }}
{{ momentTimeRangeLabel(moment) }}
savePackingMomentNotes(moment, value)"
>
▾
{{ day.label }}
{{ packingPlanDayLookCount(day) }} look{{ packingPlanDayLookCount(day) === 1 ? '' : 's' }}
+ Moment
+ Look
{{ moment.name }}
{{ momentTimeRangeLabel(moment) }}
savePackingMomentNotes(moment, value)"
>
Day outfits
Not in a moment
No plan yet
Outside trip dates
linked to this occasion but not on a trip day
Planned looks
Set trip dates to group by day
Set dates on edit, or add a moment / plan day.
Pieces in this trip: {{ detailPacking.overview_count || 0 }}
· Loose (not in a look): {{ packingLooseCount() }}
Canvas
Create a look by arranging trip pieces on collage.
Open →
Generator
Bind rules and generate outfits from this trip only - in-session, no saved recipe.
Open →
Nothing to bring yet - add looks or extras on Packing.
Building outfits around {{ generatorPinLabel() }} — showing rules that can use it, and previews always include it.
Unpin
No matching rules
None of your rules have a slot this piece can fill. Unpin to see all rules, or create a rule that includes its category.
Unpin
goToNewRule())">New rule
No staple rules yet
Mark a broad shape like “top + bottom + shoes” as staple — use the star on a card, or the Staple control when editing.
Show all rules
No non-staple rules
Hyper-specific recipes you unmark as staple will show up here.
Show all rules
No rules yet
A rule describes one outfit shape - a set of slots and cross-slot constraints. Generations pick from your rules and mix them together.
goToNewRule())">Create your first rule
saveRuleCardNote(r, value)"
>
openCandidateInWheel(cand, { host: 'rule_try', ruleId: generationPreviewRuleId })"
@edit-collage="editCandidateInCollage"
>
openCandidateInWheel(cand, { host: 'rule_try', ruleId: ruleForm?.editId })"
@edit-collage="editCandidateInCollage"
@retry-inspo-backups="retryInspoBackups"
@delete-inspo="deleteInspo"
@set-inspo-note="saveInspoNote"
>
Building outfits around {{ generatorPinLabel() }} - rule previews always include it.
Unpin
{{ (activeGeneration.rules || []).filter(r => r.kind==='whitelist').length }} whitelist rules
{{ (activeGeneration.rules || []).filter(r => r.kind==='blacklist').length }} blacklist rules
openCandidateInWheel(cand, { host: 'generator', ruleId: cand.source_rule_id })"
@edit-collage="editCandidateInCollage"
>
openCandidateInWheel(cand, { host: 'generator' })"
@edit-collage="editCandidateInCollage"
@navigate-rules="goToRulesFromGenerator"
>
▾
{{ catLabel(group.parent) }} ({{ countLabel(categoryGroupItemCount(group.parent.category_id)) }})
Attributes…
Edit
Delete
Effective: {{ categoryBodyPartsEffectiveLabel(group.parent) }}
Save
Cancel
Effective: {{ categoryBodyPartsEffectiveLabel(child) }}
Save
Cancel
{{ child.name }} ({{ countLabel(categoryItemCount(child.category_id)) }})
Attributes…
Edit
Delete
No nested categories yet
No categories
Save
Cancel
{{ b.name }} ({{ countLabel(brandItemCount(b.brand_id)) }})
Edit
Delete
No brands
Save
Cancel
{{ s.name }} ({{ countLabel(sellerItemCount(s.seller_id)) }})
Edit
Delete
No sellers
{{ row.attribute.name }}
{{ row.attribute.attach_mode === 'body_part' ? 'via body parts' : row.attribute.attach_mode === 'category' ? 'via categories' : 'not attached yet' }}
· {{ row.values.length }} {{ row.values.length === 1 ? 'value' : 'values' }}
{{ countLabel(attributeItemCount(row.attribute.attribute_id)) }}
No attributes
Values
{{ attributeOrdering === manageAttributeRow.attribute.attribute_id ? 'Done' : 'Order' }}
reorderAttributeValues(manageAttributeRow.attribute, ids)"
>
Drag a value or use the arrows. Pickers list values in this order.
Save
Cancel
{{ child.name }}
{{ countLabel(attributeValueItemCount(child.attribute_value_id)) }}
Rename
Delete
No values yet
Add value
Save
Cancel
{{ tag.name }} ({{ countLabel(tagItemCount(tag.tag_id)) }})
Edit
Delete
No tags
Save
Cancel
{{ o.name }} ({{ countLabel(occasionItemCount(o.occasion_id)) }} items · {{ occasionLookCount(o.occasion_id) }} looks)
Edit
Delete
No occasions
Save
Cancel
{{ t.name }} ({{ countLabel(careTagItemCount(t.care_tag_id)) }})
Edit
Delete
No care tags
Save
Cancel
{{ t.name }}
No tags
{{ ct.name }}
Edit
Delete
No care templates
Save
Cancel
{{ u.username }}
admin
inactive
Edit
Delete
No users