/* ---- Self-hosted fonts (visual identity, UX spec §14) --------------------------
   IBM Plex Sans Arabic is the app's face and MUST come from this origin: the page
   ships with a strict CSP (font-src 'self') and the Android shell packages these
   files into the APK, so a runtime CDN would mean a blank fallback offline and a
   different face in the shell than on the web. Arabic + latin subsets only,
   weights 400/500/700 (600 in the UI resolves to the 700 file). Playfair Display
   is the brand-mark/avatar glyph face — one variable file covers 600–700.
   Every file listed here must also be in scripts/build-www.mjs SHIP and
   backend/main.py STATIC_FILES, or production 404s it (tests/frontend/
   font-packaging.test.js pins that). */
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal; font-weight: 400; font-display: swap;
  src: url("/vendor/fonts/ibm-plex-sans-arabic-400-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal; font-weight: 400; font-display: swap;
  src: url("/vendor/fonts/ibm-plex-sans-arabic-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal; font-weight: 500; font-display: swap;
  src: url("/vendor/fonts/ibm-plex-sans-arabic-500-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal; font-weight: 500; font-display: swap;
  src: url("/vendor/fonts/ibm-plex-sans-arabic-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal; font-weight: 600 700; font-display: swap;
  src: url("/vendor/fonts/ibm-plex-sans-arabic-700-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal; font-weight: 600 700; font-display: swap;
  src: url("/vendor/fonts/ibm-plex-sans-arabic-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Playfair Display";
  font-style: normal; font-weight: 600 700; font-display: swap;
  src: url("/vendor/fonts/playfair-display-600-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+FEFF, U+FFFD;
}

:root {
  /* ---- Safe areas (notch / status bar / home indicator) -------------------------
     In a browser tab the OS bars are outside the viewport, so these stay 0 and the
     layout is unchanged. INSTALLED (standalone) is where it matters: with
     viewport-fit=cover the page paints edge-to-edge under the status bar. iOS
     reports real insets via env(); several Android builds report 0 even while
     drawing under the bar — which is exactly the overlap seen on the owner's phone.
     `max()` therefore applies a floor in standalone mode: env() wins when the device
     reports it, and the floor rescues devices that report nothing. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  /* "Atelier" — the §14 visual identity: warm cream paper, deep-plum primary for
     the actions that matter, a restrained warm gold for the brand mark and small
     highlights only. Garment photos are the hero; every surface below stays quiet.
     AA ratios for each text/background pair are in the identity-pass commit.
     --accent realigned to the approved Wardrobe Master Board's deep plum/burgundy
     (#6B184B–#711B50 baseline) — was a violet (#43305e); WCAG re-verified after
     the change (white-on-accent 11.3:1, accent-on-paper 10.7:1 — both still AAA). */
  --ink: #211d26;
  --muted: #6d6675;   /* 5.5:1 on white, 4.9:1 on --surface-soft — keeps WCAG AA */
  /* State text — an error, a "fair" password, a done/paid/on state — at 4.5:1 or
     better on this theme's surfaces (full review 2026-10-12: #b04537 on the dark
     dialog was 3.0:1, the amber 2.9:1 on white, the green ~3.3:1). */
  --danger-text: #b04537;   /* 5.3:1 on --paper */
  --warn-text: #a35f12;     /* 4.7:1 on --paper */
  --ok-text: #1a6a46;       /* 6.2:1 on --paper, 5.0:1 on its green pill */
  --info-text: #2a6496;     /* 5.9:1 on --paper */
  --paper: #faf8f4;
  --white: #ffffff;
  --line: #eae5e0;
  --surface-soft: #f4f1ec;
  --accent: #6b184b;
  --accent-soft: #f6eaf1;
  --accent-line: #e3c6d6;  /* hairline on accent-soft surfaces (the stage-1 fork) */
  --accent-text: #753d5f;
  --on-accent: #ffffff;
  --sage: var(--accent);
  --sage-dark: #38212f;
  --sand: #d8c9a9;
  --clay: #6b184b;
  /* Warm gold: decorative marks only (brand glyph, active tick, spark) — at 2.1:1
     on cream it must NEVER carry text; --gold-text is the AA-safe ink for that. */
  --gold: #c9a86a;
  --gold-text: #8a6b33;
  --shadow: 0 12px 30px rgba(52, 38, 74, 0.09);
  --cream: #f4f1ec;
  --text: var(--ink);
  --border: var(--line);
  --app-radius: 18px;

  /* ---- Design token scales (foundation) ----------------------------------
     Added per the design review. These define a disciplined system to migrate
     TOWARD; existing hard-coded values are not changed here, so there is zero
     visual risk. New and refactored components should use these tokens rather
     than fresh magic numbers, which is how the 23 font sizes / 15 radii / ad-hoc
     spacing get consolidated over time instead of in one risky rewrite.
     See docs/handover/05-Design-System.md §§3,4,10. */

  /* Type scale — 8 steps (px / line-height) */
  --fs-display: 32px;  --lh-display: 40px;
  --fs-h1: 26px;       --lh-h1: 34px;
  --fs-h2: 22px;       --lh-h2: 30px;
  --fs-h3: 18px;       --lh-h3: 26px;
  --fs-body: 16px;     --lh-body: 24px;
  --fs-body-sm: 14px;  --lh-body-sm: 21px;
  --fs-label: 13px;    --lh-label: 18px;
  --fs-caption: 12px;  --lh-caption: 18px;

  /* Spacing scale */
  --space-0: 0;   --space-1: 4px;  --space-2: 8px;  --space-3: 12px;
  --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 40px;
  --space-8: 48px; --space-9: 64px; --space-10: 80px;

  /* Radius scale */
  --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px;
  --radius-xl: 18px; --radius-pill: 999px;
}

/* Installed app only: guarantee a strip for the status bar / gesture area even when
   the platform reports no inset. In a normal browser tab these rules don't apply, so
   nothing shifts for someone just visiting the site. */
@media (display-mode: standalone), (display-mode: fullscreen) {
  :root {
    --safe-top: max(env(safe-area-inset-top, 0px), 26px);
    --safe-bottom: max(env(safe-area-inset-bottom, 0px), 10px);
  }
}

html[data-theme="dark"] {
  /* "Atelier" dark: true dark plum-cast surfaces, the plum lifted for
     contrast (8.9:1 on --paper), gold unchanged — it already clears 7:1 here.
     --accent retargeted to the same deep-plum hue as light theme (was a lavender
     hue-family mismatch against the light theme's now-plum accent) — same
     lightness/saturation as before, so contrast is effectively unchanged
     (8.9:1 vs. the prior 8.2:1). */
  --ink: #ece9f1;
  --muted: #9b93a8;
  --danger-text: #e8806f;   /* 6.8:1 on --paper */
  --warn-text: #e0a050;     /* 8.1:1 on --paper */
  --ok-text: #57c290;       /* 8.3:1 on --paper */
  --info-text: #7fb3e6;     /* 8.4:1 on --paper */
  --paper: #16131c;
  --white: #201b28;
  --line: #322b3d;
  --surface-soft: #1b1723;
  --accent: #dca5c7;
  --accent-soft: #402536;
  --accent-line: #5a3148;
  --accent-text: #e8b9d6;
  --on-accent: #171221;
  --sage: var(--accent);
  --sage-dark: var(--accent);
  --sand: #5a4c33;
  --clay: #dca5c7;
  --gold: #c9a86a;
  --gold-text: #c9a86a;
  --shadow: 0 14px 34px rgba(0, 0, 0, 0.45);
  --cream: #201b28;
}

* { box-sizing: border-box; }
/* F-4 (WA-007): `overflow-x: hidden` previously lived on body only, but
   `body`, not `html`, was actually the leaky boundary — `html` is this
   document's real root scroller, and its overflow was left at the default
   `visible`. Measured live (real desktop Chromium, not just the Android
   emulator this was first found on): with a favorited wardrobe item
   present, reached via a hash-already-set reload, window.innerWidth /
   document.documentElement.scrollWidth balloon to ~708 CSS px against a
   correct ~390–411px window.visualViewport.width — i.e. some element's
   scrollable-overflow contribution escapes past `body`'s guard and inflates
   `html`'s own scrollable region. (An earlier hypothesis blamed the
   off-canvas `.sidebar`'s transform; disproved by hiding it live while the
   bug was active — no change. The exact render-path trigger was bisected to
   "a favorited item present" but not fully isolated beyond that — see the
   linked evidence.) Declaring `overflow-x: hidden` on `html` too closes the
   actual measured gap: verified twice, live, to bring both numbers straight
   back to the correct viewport width in the exact reproduction case. See
   docs/audits/final-validation-evidence/android/logs/f4-viewport-bug-before-after.txt. */
html { scroll-behavior: smooth; overflow-x: hidden; }
body {
  margin: 0;
  overflow-x: hidden;
  color: var(--ink);
  background: var(--paper);
  /* "Damascus" (Apple system Arabic) is the chosen face; web fallbacks keep the
     look reasonable on Android/Windows where Damascus isn't installed. */
  /* IBM Plex Sans Arabic is primary and self-hosted-via-Google-Fonts, so every
     platform renders the SAME face the design is evaluated in. Previously Damascus
     (Apple-only) was first, so iOS/macOS saw Damascus while the downloaded IBM Plex
     was discarded, and Android/Windows users — most of the Gulf market — saw a font
     the design had never been checked against. Damascus/Geeza remain fallbacks for
     the brief moment before the webfont loads. */
  font-family: "IBM Plex Sans Arabic", "Damascus", "Geeza Pro", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* Plex's required ligature for an unjoined ف/ق + final ى draws only the ف/ق («أرقى» read
   «أرق»). The whole affected word is wrapped (src/lib/final-ya.js) and takes a system
   face: one shaping run, so WebKit cannot break the joining, and lam-alef inside the
   word still renders. Owner-approved 2026-10-21; one definition for all screens. */
.keep-final-ya {font-family:Arial,Tahoma,sans-serif !important;font-feature-settings:normal !important;display:inline !important;letter-spacing:normal !important;padding:0 !important;margin:0 !important;}
img { max-width: 100%; }
button, input, select, textarea { font: inherit; }
button { cursor: pointer; }
button:disabled { cursor: not-allowed; opacity: .65; }
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, a:focus-visible {
  outline: 3px solid rgba(107,24,75,.35);
  outline-offset: 3px;
}

.app-shell { min-height: 100vh; }
.sidebar {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 20;
  width: 250px;
  /* Spans the full height, so it must clear the status bar and the gesture area too. */
  padding: calc(28px + var(--safe-top, 0px)) 22px calc(28px + var(--safe-bottom, 0px));
  display: flex;
  flex-direction: column;
  background: #221d2b;
  color: #eae6ef;
}
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: inherit;
  text-decoration: none;
}
.brand-mark {
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  /* The one place raw gold lives at full strength: the brand mark. */
  border: 1px solid var(--gold);
  color: var(--gold);
  font: 600 23px "Playfair Display", serif;
}
.brand strong { display: block; letter-spacing: 2px; }
.brand small, .profile-chip small { display: block; margin-top: 2px; color: #aaa3b5; font-size: 10px; }
.main-nav { display: grid; gap: 7px; margin-top: 54px; }
.nav-item {
  width: 100%;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  border: 0;
  border-radius: 12px;
  color: #b9b2c4;
  background: transparent;
  text-align: right;
  transition: .2s ease;
}
.nav-item:hover, .nav-item.active { color: white; background: rgba(255,255,255,.09); }
/* Gold as a small highlight: the 3px active tick, never a fill. */
.nav-item.active { box-shadow: inset -3px 0 var(--gold); }
.nav-icon { width: 22px; font-size: 19px; text-align: center; }
.sidebar-card {
  margin-top: auto;
  padding: 17px;
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 12px;
  background: rgba(255,255,255,.04);
}
.sidebar-card .eyebrow { color: #aaa3b5; }
.usage-row { margin: 10px 0 8px; display: flex; align-items: baseline; justify-content: space-between; }
.usage-row strong { font-size: 25px; }
.usage-row span { color: #aaa3b5; font-size: 11px; }
.progress { height: 4px; overflow: hidden; border-radius: var(--radius-sm); background: rgba(255,255,255,.13); }
.progress span { height: 100%; display: block; border-radius: inherit; background: var(--gold); }
.sidebar-card .text-button { margin-top: 10px; color: #d3c4ea; }
.profile-chip {
  margin-top: 14px;
  padding: 10px 4px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  border: 0;
  color: white;
  background: transparent;
  text-align: right;
}
.avatar { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: rgba(255,255,255,.13); }
.chevron { color: #948d9f; font-size: 22px; }

.main-content { margin-right: 250px; min-height: 100vh; }
.topbar {
  /* viewport-fit=cover lets the page paint UNDER the status bar / notch, so the bar
     must reserve that strip itself — otherwise the clock, battery and the app's own
     icons draw on top of each other on a phone (installed PWA especially). */
  min-height: 76px;
  padding: var(--safe-top, 0px) 4.5vw 0;
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--line);
  background: var(--white);
}
.topbar-actions { display: flex; gap: 8px; }
.icon-button, .mobile-menu {
  width: 44px; height: 44px; flex: 0 0 44px; box-sizing: border-box; position: relative; border: 1px solid var(--line); border-radius: 50%; background: var(--white); color: var(--ink);
}
.icon-button i { width: 6px; height: 6px; position: absolute; top: 10px; right: 10px; border-radius: 50%; background: var(--clay); }
.weather { margin-right: auto; display: flex; align-items: center; gap: 10px; }
.weather-icon { color: var(--accent); font-size: 25px; }
.weather strong, .weather small { display: block; }
.weather small { color: var(--muted); font-size: 11px; }
.mobile-menu { display: none; }
.sidebar-backdrop { display: none; }

.page { display: none; padding: 44px 4.5vw 70px; animation: pageIn .35s ease; }
.page.active { display: block; }
@keyframes pageIn { from { opacity: 0; transform: translateY(7px); } }
.page-intro, .section-heading {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 30px;
}
/* Editorial gold label — --gold-text, the AA-safe gold ink, never raw --gold. */
.eyebrow { display: block; margin-bottom: 6px; color: var(--gold-text); font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
h1, h2, h3, p { margin-top: 0; }
h1 { margin-bottom: 6px; font-size: clamp(29px, 3.2vw, 43px); line-height: 1.25; }
h2 { margin-bottom: 6px; font-size: 22px; }
h3 { margin-bottom: 7px; font-size: 17px; }
p { color: var(--muted); line-height: 1.8; }
.page-intro p { margin-bottom: 0; }
.wardrobe-add-actions { display: flex; flex-wrap: wrap; gap: 8px; }

.primary-button, .secondary-button, .square-button {
  min-height: 44px;
  padding: 0 19px;
  border-radius: 12px;
  font-weight: 600;
  transition: .2s ease;
}
.primary-button { border: 1px solid var(--accent); color: var(--on-accent); background: var(--accent); box-shadow: 0 8px 18px rgba(107,24,75,.18); }
.primary-button:hover { transform: translateY(-1px); opacity: .9; }
.secondary-button { border: 1px solid var(--line); color: var(--ink); background: var(--white); }
.secondary-button:hover, .square-button:hover { border-color: var(--sage); }
.square-button { width: 45px; padding: 0; border: 1px solid var(--line); background: var(--white); font-size: 20px; }
.text-button { padding: 0; border: 0; color: var(--sage-dark); background: none; font-weight: 600; font-size: 12px; }
.full { width: 100%; }

.home-grid { display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(280px, .75fr); gap: 22px; }
.today-card, .event-card, .insight-card, .chart-card {
  border: 1px solid var(--line); border-radius: 16px; background: var(--white); box-shadow: var(--shadow);
}
.today-card { padding: 27px; }
.card-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.match-pill { padding: 6px 10px; border-radius: 20px; color: var(--accent-text); background: var(--accent-soft); font-size: 11px; font-weight: 700; }
.outfit-stage {
  min-height: 290px;
  padding: 22px 10px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: center;
  gap: 15px;
}
.garment {
  position: relative;
  min-height: 220px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  animation: itemIn .5s ease both;
}
.garment:nth-child(2) { animation-delay: .07s; }
.garment:nth-child(3) { animation-delay: .14s; }
@keyframes itemIn { from { opacity: 0; transform: translateY(15px); } }
.garment-art { width: 125px; height: 160px; position: relative; filter: drop-shadow(0 16px 13px rgba(0,0,0,.09)); }
.garment-art.shirt { clip-path: polygon(22% 10%, 39% 0, 61% 0, 78% 10%, 100% 30%, 84% 45%, 73% 34%, 73% 100%, 27% 100%, 27% 34%, 16% 45%, 0 30%); background: var(--item-color); }
.garment-art.pants { clip-path: polygon(15% 0, 85% 0, 82% 47%, 96% 100%, 56% 100%, 50% 49%, 44% 100%, 4% 100%, 18% 47%); background: var(--item-color); }
.garment-art.shoes { width: 150px; height: 90px; clip-path: polygon(5% 50%, 33% 42%, 45% 10%, 58% 15%, 66% 45%, 91% 55%, 100% 81%, 94% 94%, 11% 92%, 0 72%); background: var(--item-color); }
.garment-art.jacket { clip-path: polygon(23% 8%, 40% 0, 50% 7%, 60% 0, 77% 8%, 100% 29%, 84% 44%, 73% 35%, 76% 100%, 24% 100%, 27% 35%, 16% 44%, 0 29%); background: var(--item-color); }
/* The placeholder for the whole one_piece category, not for dresses alone: a thobe, a
   kandura, a kaftan and a jumpsuit all land on this shape. It used to flare 38/62% to
   10/90%, a pronounced A-line, which is wrong for every one of those except a dress —
   a thobe is a straight column. Halving the flare to 22/78% reads as a column with a
   soft drape, which is honest for all of them. Deliberately NOT a second `thobe` type:
   the class comes from `item.type`, which is PERSISTED, so a new type value would draw
   correctly only for items added after the change and would need a migration to reach
   the thobes already stored. A shape that works for both needs no migration at all. */
.garment-art.dress { clip-path: polygon(30% 6%, 42% 0, 58% 0, 70% 6%, 62% 26%, 78% 100%, 22% 100%, 38% 26%); background: var(--item-color); }
.garment-art.accessory { clip-path: polygon(20% 20%, 80% 20%, 80% 80%, 20% 80%); background: var(--item-color); }
/* A placeholder keeps its edge on any tile (QA, 2026-10-05: a white sneaker on a light
   tile and a black shoe on a dark one vanished). The shape is drawn in a neutral edge
   that reads on both themes, and the item's own colour sits 2px inside it — same
   polygon, so the band follows the silhouette. */
.garment-art.shirt, .garment-art.pants, .garment-art.shoes, .garment-art.jacket,
.garment-art.dress, .garment-art.accessory { background: var(--art-edge, rgba(128, 128, 128, .55)); }
.garment-art::after { content: ""; position: absolute; inset: 2px; clip-path: inherit; background: var(--item-color); }
.garment small { color: var(--muted); }
.outfit-item-photo { width: 100%; max-width: 135px; height: 160px; display: block; object-fit: contain; border-radius: 10px; background: rgba(255,255,255,.52); box-shadow: 0 12px 25px rgba(0,0,0,.08); }
.outfit-reason { padding: 13px 15px; display: flex; gap: 10px; border-radius: 12px; background: var(--surface-soft); }
.outfit-reason p { margin: 0; font-size: 12px; line-height: 1.7; }
.spark { color: var(--gold-text); }
.card-actions { margin-top: 18px; display: flex; gap: 9px; }
.side-stack { display: grid; gap: 22px; }
.event-card, .insight-card { padding: 22px; }
.date-badge { width: 52px; height: 56px; display: grid; place-content: center; border-radius: 12px; color: var(--sage-dark); background: var(--accent-soft); text-align: center; font-size: 10px; }
.date-badge b { display: block; font-size: 19px; line-height: 1.1; }
.event-card > p { margin: 16px 0; font-size: 12px; }
.event-weather { margin-bottom: 18px; display: flex; gap: 7px; }
.event-weather span { padding: 5px 8px; border-radius: var(--radius-sm); color: var(--muted); background: var(--paper); font-size: 11px; }
.insight-card { color: var(--on-accent); background: var(--sage-dark); }
.insight-card .eyebrow, .insight-card p { color: var(--on-accent); opacity: .72; }
.insight-card .text-button { color: var(--on-accent); opacity: .88; }
.insight-number { margin-top: 9px; font-size: 43px; font-weight: 700; }
.recent-section { margin-top: 46px; }
.looks-row, .saved-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.look-card { overflow: hidden; border: 1px solid var(--line); border-radius: 16px; background: var(--white); transition: .22s ease; }
.look-card:hover { transform: translateY(-4px); box-shadow: var(--shadow); }
.look-preview { height: 180px; padding: 24px; display: flex; align-items: flex-end; justify-content: center; gap: 8px; background: var(--surface-soft); }
.look-preview i { width: 45px; height: 110px; display: block; border-radius: var(--radius-sm) 5px 12px 12px; background: var(--c); box-shadow: 0 10px 18px rgba(0,0,0,.08); }
.look-preview i:last-child { height: 40px; border-radius: 50% 50% 15px 15px; }
.look-preview img, .look-preview .photo-frame { width: 72px; height: 100%; object-fit: cover; border-radius: 10px; box-shadow: 0 10px 18px rgba(0,0,0,.10); background: var(--white); }
.look-info { padding: 14px 16px; }
.look-info h3 { margin-bottom: 2px; font-size: 14px; }
.look-info span { color: var(--muted); font-size: 11px; }
.saved-look-items { min-height: 32px; margin-top: 7px; color: var(--muted); font-size: 10px; line-height: 1.6; }
.saved-look-actions { margin-top: 11px; display: flex; gap: 6px; }
.saved-look-actions button { min-height: 32px; padding: 0 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--sage-dark); background: var(--white); font-size: 10px; font-weight: 700; }
.saved-look-actions .remove-saved-outfit { color: var(--muted); }
.saved-look-actions .wear-saved-outfit { color: var(--accent-text); background: var(--accent-soft); }
.saved-look-actions button:hover { border-color: var(--sage); background: var(--paper); }
/* Favorites (§11): the star sits beside the title; gold only when it means something. */
.saved-look-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.favorite-saved-outfit { flex: none; min-width: 30px; min-height: 30px; border: 0; background: none; color: var(--muted); font-size: 17px; line-height: 1; cursor: pointer; }
.favorite-saved-outfit.is-favorite { color: var(--gold); }
.favorite-saved-outfit:hover { color: var(--gold); }
/* «هلبستها» (§11): the worn history under the saved grid — a quiet ledger, not cards. */
.worn-history { margin-top: 26px; }
.worn-history h2 { margin-bottom: 10px; font-size: 16px; }
.worn-history-list { border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--white); overflow: hidden; }
.worn-entry { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 11px 16px; }
.worn-entry + .worn-entry { border-top: 1px solid var(--line); }
.worn-entry strong { font-size: 12.5px; }
.worn-entry span { flex: none; color: var(--muted); font-size: 11px; }

/* ===== دولابي — the wardrobe redesign's editorial gallery (spec §6/§7).
   Cream paper, dark readable text, generous whitespace; the cutout photos are
   the loudest thing on the page and deep plum stays reserved for the primary
   actions. Existing tokens only — docs/specs/wardrobe-token-delta.md records
   the (empty) delta. Never dashboard, never SaaS. ===== */
.wardrobe-header { margin-bottom: var(--space-4); display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); }
.wardrobe-header h1 { margin: 0; font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: .01em; }
.wardrobe-header .wardrobe-add-actions { margin: 0; width: auto; }
.wardrobe-header .primary-button { min-height: 44px; padding: var(--space-2) var(--space-4); font-size: var(--fs-body-sm); }
.search-box { min-width: 280px; padding: 0 13px; display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 12px; background: var(--white); }
.search-box input { width: 100%; padding: 12px 0; border: 0; outline: none; background: transparent; }
/* §9: the one slim rounded search field directly under the header. */
.wardrobe-search { margin-bottom: var(--space-3); border-radius: var(--radius-pill); }
.wardrobe-search span { color: var(--muted); }
.wardrobe-search input { padding: 10px 0; font-size: var(--fs-body-sm); }
/* §10: one row of small category chips beside the sheet trigger; the row scrolls
   sideways on narrow screens instead of wrapping into a second line. */
.wardrobe-rail { margin-bottom: var(--space-4); display: flex; align-items: center; gap: 10px; }
.wardrobe-rail .filters { flex: 1 1 auto; flex-wrap: nowrap; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; }
.wardrobe-rail .filter { flex: 0 0 auto; }
.filters { display: flex; flex-wrap: wrap; gap: 7px; }
.filter { padding: 8px 13px; border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--muted); background: var(--white); font-size: var(--fs-caption); }
.filter.active { color: var(--on-accent); border-color: var(--sage-dark); background: var(--sage-dark); }
/* §7 ActiveFilterSummary: quiet chips naming the applied filters + «مسح الكل»;
   the whole row exists only while filters are active. */
.active-filter-summary { margin: calc(-1 * var(--space-2)) 0 var(--space-4); display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.active-filter-summary[hidden] { display: none; }
.summary-chip { padding: 5px 11px; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface-soft); color: var(--ink); font-size: var(--fs-caption); }
.active-filter-summary .clear-filters { min-height: 28px; padding: 0 8px; border: 0; background: transparent; color: var(--accent-text); font-size: var(--fs-caption); font-weight: 700; cursor: pointer; }
/* §7 grid: fashion-first. The cleaned image is the card — no border, no shadow,
   no white box; editorial breathing room between pieces; under the photo only
   the name and (when known) the brand. */
.wardrobe-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 26px 20px; }
/* §22/§26 (Wave C): desktop is not a stretched mobile UI. The spec names no column
   numbers — «يزيد عدد الأعمدة» / «زيادة الأعمدة تدريجيًا» — so the ladder is:
   2 (mobile ≤620, §7's hard rule) → 3 (tablet, ≤1100 rule below) → 4 (desktop,
   the base rule above) → 5 on wide gallery screens, so a 27" monitor reads as a
   fashion wall instead of four stretched strips. Cards need no changes: the 3/4
   photo ratio scales with the column. */
@media (min-width: 1440px) {
  .wardrobe-grid { grid-template-columns: repeat(5, 1fr); gap: 30px 24px; }
}
/* min-width: 0 overrides a CSS Grid item's implicit min-width: auto — without it, a
   single card whose content resists shrinking (an unusually wide image, an
   unbreakable run of text) can force its OWN 1fr track wider than its fair share,
   squeezing every sibling in the same row down to a sliver. Prompted by a live
   report of exactly that squeeze; an isolated repro with matching text alone did
   NOT reproduce it, so the text is not confirmed as the trigger — this stays as a
   real, independently-correct defensive fix for the general class of bug, not a
   confirmed fix for that specific report. */
.item-card { border: 0; border-radius: 14px; background: transparent; min-width: 0; }
/* §30 «virtualization عند الحاجة» — the CSS answer, not a windowing library: cards
   far off-screen skip layout+paint entirely (their data-URL photos also stop
   decoding, together with loading="lazy"). `auto 340px` keeps an honest height
   estimate before first render and the REAL measured size afterwards, so scroll
   restore (§7/§30) lands where it should. A wardrobe of hundreds stays one cheap
   scrolling grid; DOM count at that scale is not the bottleneck, paint was. */
.item-card { content-visibility: auto; contain-intrinsic-size: auto 340px; }
/* Portrait ratio instead of a short fixed height: clothes are taller than they are
   wide, so 220px made every piece read as a thin strip. The ratio scales with the
   column width, staying large on a phone (one card per row) without a media query. */
/* The visual IS the card's one control now (§7: the photo is the doorway to the
   detail page) — a real <button>, reset from the UA styles, with a visible focus
   ring for keyboard users. */
.item-visual { aspect-ratio: 3 / 4; position: relative; display: grid; place-items: center; overflow: hidden; width: 100%; padding: 0; border: 0; border-radius: 14px; background: var(--surface-soft); cursor: pointer; }
.item-visual:focus-visible { outline: 2px solid var(--sage-dark); outline-offset: 2px; }
.item-visual .garment-art { transform: scale(.8); }
/* Absolutely positioned so the photo fills EXACTLY the 220px visual box. As a grid
   item under `place-items: center` its `height: 100%` had no definite containing
   block to resolve against, so it fell back to the intrinsic aspect ratio (a 300x380
   photo became 432px tall in a 220px box) and painted OVER the buttons underneath —
   on mobile that covered نسّقها / استبعد / تعديل / الحالة, leaving only حذف tappable. */
.item-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* GARMENT FRAMING. `is-framed` is set only when the item carries a garment box, so a
   photo without one keeps `cover` and renders exactly as it always has.
   With a box the fit becomes `contain`: `cover` crops the photo BEFORE any transform
   runs, and a horizontal photo of trousers in an upright card loses the legs that way —
   pixels no amount of zooming brings back. The zoom that follows (a transform written
   by frameGarmentPhoto) then trims the background back off. */
.item-photo.is-framed { object-fit: contain; }
/* Everywhere else the photo shares its box with a caption, so the zoom needs its own
   element to be clipped by. The wrapper wears the class the image used to wear —
   that is what keeps every size, radius, shadow and media query below unchanged.
   The inner image carries its own class so this beats the `.look-preview img` /
   `.anchor-choice img` / `.chat-outfit-piece img` element rules further down the file,
   which would otherwise win on source order and put `object-fit: cover` back. */
.photo-frame { position: relative; display: block; overflow: hidden; }
.photo-frame > img.framed-photo { width: 100%; height: 100%; max-width: none; display: block; object-fit: contain; }
/* §7: laundry/unavailable as a small overlay signal that never dominates the photo. */
.item-state { position: absolute; inset-inline-end: 8px; bottom: 8px; padding: 4px 8px; border-radius: var(--radius-pill); color: white; background: rgba(43,33,56,.82); font-size: 11px; }

/* ===== §30 filter sheet ===== */
.filter-sheet-button { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; padding: 9px 14px; border: 1px solid var(--line); border-radius: 20px; color: var(--sage-dark); background: var(--white); font-size: 12px; font-weight: 700; }
.filter-sheet-button:hover { border-color: var(--sage-dark); }
.filter-count-badge { min-width: 17px; height: 17px; display: grid; place-items: center; padding: 0 4px; border-radius: 9px; color: var(--on-accent); background: var(--sage-dark); font-size: 10px; }
.wardrobe-filter-dialog .wfilter-grid { margin-top: 16px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
.wardrobe-filter-dialog .wfilter-grid label { display: block; font-size: 12px; font-weight: 700; }
.wardrobe-filter-dialog .wfilter-grid label > span { display: block; margin-bottom: 4px; color: var(--muted); font-size: 11px; font-weight: 600; }
.wardrobe-filter-dialog select { width: 100%; min-height: 42px; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-soft); color: var(--ink); font-size: 13px; }
.wfilter-check { margin-top: 13px; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; }
.wfilter-check input[type="checkbox"] { width: auto; margin: 0; }
/* §10 colour filter: swatch pills built from the colours the user owns. */
.wfilter-color-block { margin-top: 16px; }
.wfilter-label { display: block; margin-bottom: 6px; color: var(--muted); font-size: 11px; font-weight: 600; }
.wfilter-swatches { display: flex; flex-wrap: wrap; gap: 7px; }
.wfilter-swatch { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--white); color: var(--ink); font-size: 12px; cursor: pointer; }
.wfilter-swatch i { width: 14px; height: 14px; flex: none; border-radius: 50%; border: 1px solid rgba(0,0,0,.12); background: var(--c); }
.wfilter-swatch.active { color: var(--on-accent); border-color: var(--sage-dark); background: var(--sage-dark); }
.wfilter-swatch:focus-visible { outline: 2px solid var(--sage-dark); outline-offset: 2px; }
@media (max-width: 640px) {
  .wardrobe-filter-dialog .wfilter-grid { grid-template-columns: 1fr; }
}
/* §7: under the photo, ONLY the name and (when known) the brand. */
.item-meta { padding: 10px 2px 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* overflow-wrap: a name with no natural break (one long run of characters, or a
   long single word) still wraps instead of setting a wide intrinsic minimum on the
   grid track above — the second half of the min-width: 0 fix on .item-card. */
.item-meta h2 { margin: 0; font-size: 14.5px; letter-spacing: .01em; line-height: 1.35; overflow-wrap: break-word; }
/* §26 RTL: brands are usually Latin («Zara», «H&M») inside an Arabic page — and
   sometimes Arabic inside the English UI. `plaintext` lets each brand line take its
   OWN first-strong direction, so «H&M 2» never scrambles its digits/punctuation
   against the surrounding dir. Applies to the card line and the detail line alike. */
.item-brand, .detail-brand { unicode-bidi: plaintext; }
.item-brand { color: var(--muted); font-size: var(--fs-caption); letter-spacing: .02em; }
/* §21 loading skeleton: the grid keeps its 2-column silhouette while the
   wardrobe is on its way; motion respects reduced-motion. */
.item-card-skeleton .item-visual { cursor: default; background: linear-gradient(100deg, var(--surface-soft) 40%, var(--white) 50%, var(--surface-soft) 60%); background-size: 200% 100%; animation: wardrobe-shimmer 1.4s ease-in-out infinite; }
.skeleton-line { display: block; height: 12px; width: 70%; border-radius: var(--radius-sm); background: var(--surface-soft); }
@keyframes wardrobe-shimmer { from { background-position: 120% 0; } to { background-position: -80% 0; } }
@media (prefers-reduced-motion: reduce) { .item-card-skeleton .item-visual { animation: none; } }
/* §21 error state + the empty-filter hint line. */
.wardrobe-error .empty-wardrobe-title { margin-bottom: 12px; }
.empty-filter-hint { margin-top: 6px; color: var(--muted); font-size: var(--fs-body-sm); }
/* One add menu, in the header for a populated wardrobe. */
.wardrobe-add-actions { margin-top: var(--space-5); display: flex; gap: 10px; justify-content: center; }
/* The empty wardrobe has its own «إضافة أول قطعة»; a second add button was one
   too many (emulator test, 2026-10-12). Hidden while restoring too: no add then. */
.wardrobe-add-actions[hidden] { display: none; }
/* The detail dialog's quiet closing row: تعديل / لا تقترحها / حذف. */
.detail-footer-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.detail-footer-actions .secondary-button { flex: 1 1 auto; }
.detail-delete { color: #c0473f; }
html[data-theme="dark"] .detail-delete { color: #e08a80; }

/* Colour swatch (detail identity block). The AI gets a pale or mixed colour wrong
   often enough that the stored colour has to be both visible and correctable in
   one tap — the pill opens the colour picker. */
.item-color { margin-top: 6px; padding: 3px 8px 3px 4px; display: inline-flex; align-items: center; gap: 6px; max-width: 100%; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface-soft); cursor: pointer; }
.item-color-dots { display: inline-flex; }
.item-color-dots i { width: 14px; height: 14px; display: block; flex: none; border-radius: 50%; border: 1px solid rgba(0,0,0,.14); background: var(--c); }
.item-color-dots i + i { margin-inline-start: -5px; }
.item-color-name { overflow: hidden; color: var(--accent-text); font-size: 10px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; }
.item-color:hover { border-color: var(--sage-dark); }
.item-color:focus-visible { outline: 2px solid var(--sage-dark); outline-offset: 2px; }

.generation-notice { padding: 22px 20px; border: 1px dashed var(--line); border-radius: 12px; color: var(--muted); font-size: 13.5px; line-height: 1.9; text-align: center; }

.review-note { margin-top: 8px; color: var(--muted); font-size: 11.5px; line-height: 1.7; }
.review-score-line b small { font-size: .5em; font-weight: 600; opacity: .6; }
.review-flag { margin-top: 8px; padding: 8px 11px; border-radius: 12px; background: #fdeceb; color: #8c2f28; font-size: 12px; }
html[data-theme="dark"] .review-flag { background: rgba(180,60,50,.18); color: #f0b3ad; }
.review-subscores ul { display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px 14px; }
.review-subscores li { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; list-style: none; }
.review-subscores li b { font-variant-numeric: tabular-nums; }
.review-subscores li i { color: var(--muted); font-size: 11px; font-style: normal; }
@media (max-width: 560px) { .review-subscores ul { grid-template-columns: 1fr; } }

/* Colour picker dialog */
/* The picker is a bare <dialog>, not a <form>, so `dialog form { padding }` never
   reached its heading: the eyebrow and the title ran off the edge (QA, 2026-10-05). */
#color-picker-modal > .modal-heading { padding: 20px 20px 4px; }
.color-picker-item { padding: 0 20px; font-size: 14px; font-weight: 700; }
.color-picker-sub { padding: 2px 20px 0; color: var(--muted); font-size: 11px; }
.color-grid { margin: 14px 20px 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.color-option { padding: 9px 4px 7px; display: flex; flex-direction: column; align-items: center; gap: 5px; border: 1px solid var(--line); border-radius: 12px; background: var(--white); cursor: pointer; }
.color-option i { width: 26px; height: 26px; display: block; border-radius: 50%; border: 1px solid rgba(0,0,0,.16); background: var(--c); }
.color-option span { color: var(--ink); font-size: 11px; font-weight: 700; text-align: center; }
.color-option.selected { border-color: var(--sage-dark); box-shadow: 0 0 0 2px var(--accent-soft); }
.color-option:focus-visible { outline: 2px solid var(--sage-dark); outline-offset: 1px; }
.color-custom { margin: 14px 20px 0; padding: 10px 12px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
.color-custom span { font-size: 12px; font-weight: 700; }
.color-custom input { width: 46px; height: 30px; padding: 0; border: 1px solid var(--line); border-radius: 7px; background: none; }
.color-custom small { flex-basis: 100%; color: var(--muted); font-size: 10px; }
/* 28 swatches push the actions off a short screen — keep Save reachable without
   scrolling to the end of the palette. */
#color-picker-modal .modal-actions { position: sticky; bottom: 0; background: var(--white); border-top: 1px solid var(--line); }
html[data-theme="dark"] #color-picker-modal .modal-actions { background: var(--white); }
/* Ten photos pushed «تحليل وإضافة القطع» two scrolls down (emulator test, 2026-10-12):
   the buttons stay at the bottom of the bulk dialog, as in the colour picker. */
#bulk-add-modal .modal-actions { position: sticky; bottom: 0; z-index: 2; padding-top: 12px; background: var(--white); border-top: 1px solid var(--line); }
.edit-item, .status-item { height: 32px; padding: 0 9px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--sage-dark); background: var(--white); font-size: 10px; font-weight: 700; }

/* ===== Item detail page (Item-Intelligence §27–§28) =====
   Editorial, not a database record: one large image, quiet typographic sections,
   the CTA as the only loud element. All colours are theme variables, so dark mode
   needs no extra rules; text-align/start-side properties keep RTL free. */
.item-detail-dialog { position: relative; padding: 25px; }
.item-detail-close { position: absolute; top: 14px; inset-inline-end: 14px; z-index: 2; }
.detail-visual { aspect-ratio: 3 / 4; max-height: 46vh; position: relative; display: grid; place-items: center; overflow: hidden; border-radius: 16px; background: var(--surface-soft); }
.detail-visual .detail-photo, .detail-visual img { width: 100%; height: 100%; object-fit: contain; }
.detail-visual .photo-frame.detail-photo { position: absolute; inset: 0; }
.detail-visual .garment-art { transform: scale(1.05); }
.detail-identity { margin-top: 18px; text-align: center; }
.detail-identity h2 { font-size: 21px; line-height: 1.3; }
.detail-brand { margin-top: 2px; color: var(--muted); font-size: 12px; font-weight: 600; letter-spacing: .06em; }
.detail-summary { margin-top: 6px; color: var(--muted); font-size: 13px; }
.detail-cta { width: 100%; margin-top: 16px; min-height: 48px; }
.detail-sections { margin-top: 20px; display: grid; grid-template-columns: 1fr 1fr; gap: 14px 18px; padding-top: 18px; border-top: 1px solid var(--line); }
.detail-section h3 { margin-bottom: 4px; color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .05em; }
.detail-section p { font-size: 13px; line-height: 1.55; }
.detail-all-details { margin-top: 18px; }
.detail-facts { display: grid; gap: 7px; }
.detail-facts div { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; }
.detail-facts dt { color: var(--muted); font-weight: 600; }
.detail-facts dd { margin: 0; font-weight: 600; text-align: end; }
.detail-notes { margin-top: 18px; }
.detail-notes p { white-space: pre-wrap; }
.detail-edit { width: 100%; margin-top: 18px; }
/* §17 daily actions (mockup 10): three quiet equals under the CTA — never second CTAs. */
.detail-quick-actions { margin-top: 12px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.detail-quick-actions .secondary-button { min-height: 46px; padding: 6px 8px; font-size: 12px; }
.detail-availability { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; }
.detail-availability small { color: var(--muted); font-size: 10px; font-weight: 600; }
.detail-favorite[aria-pressed="true"] { border-color: var(--sage-dark); color: var(--sage-dark); }
/* §18 availability sheet (mockup 11): three tappable rows, radio semantics. */
.availability-dialog { min-width: min(320px, 82vw); }
.availability-options { margin-top: 14px; display: grid; gap: 8px; }
.availability-option { display: flex; align-items: center; gap: 10px; min-height: 46px; padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-soft); font-size: 13px; font-weight: 600; cursor: pointer; }
.availability-option:has(input:checked) { border-color: var(--sage-dark); background: var(--white); }
.availability-option input { width: auto; margin: 0; accent-color: var(--sage-dark); }
/* The enhanced photo (2026-10-10): one quiet line under the item photo, and the compare
   sheet. The drawing has a transparent background, so both photos sit on the same card
   tint the app shows cutouts on. */
.detail-enhance-slot:empty { display: none; }
.detail-enhance { margin-top: 10px; display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 4px 10px; color: var(--muted); font-size: 12px; }
.detail-enhance.is-busy { color: var(--accent-text); }
.enhance-compare { margin-top: 14px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.enhance-compare figure { margin: 0; display: grid; gap: 6px; }
.enhance-compare img { width: 100%; aspect-ratio: 3 / 4; object-fit: contain; border-radius: 12px; background: var(--surface-soft); }
.enhance-compare figcaption { color: var(--muted); font-size: 11.5px; font-weight: 600; text-align: center; }
.enhance-compare .is-drawn figcaption { color: var(--accent-text); }
.enhance-note { margin-top: 12px; color: var(--muted); font-size: 12.5px; line-height: 1.6; }
@media (min-width: 1100px) {
  #item-detail-body > .detail-enhance-slot .detail-enhance { margin: 0 0 10px; justify-content: flex-start; }
}
/* §23 desktop item detail (Wave C, ledger default «split» per §35): on a wide screen
   the dialog stops being a phone sheet — hero on one side, identity/CTA/sections on
   the other, the stylist CTA still the loudest thing. Pure CSS: the rendered body's
   children are flat siblings, so the visual takes column 1 (sticky, spanning every
   row) and everything else stacks in column 2. Below 1100px nothing here applies and
   the mobile single-column flow is untouched. */
@media (min-width: 1100px) {
  #item-detail-modal { width: min(960px, calc(100% - 60px)); max-height: calc(100dvh - 48px); overflow-y: auto; overscroll-behavior: contain; }
  #item-detail-body { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); column-gap: 28px; align-items: start; }
  #item-detail-body > .detail-visual { grid-column: 1; grid-row: 1 / span 30; position: sticky; top: 0; max-height: calc(100dvh - 100px); aspect-ratio: auto; min-height: 480px; }
  #item-detail-body > :not(.detail-visual) { grid-column: 2; }
  #item-detail-body > .detail-identity { margin-top: 0; text-align: start; }
}
.edit-item:hover, .status-item:hover { border-color: var(--sage); }
.exclude-item { height: 32px; padding: 0 9px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted); background: var(--surface-soft); font-size: 10px; font-weight: 700; }

/* The stylist's true stages (spec §6): one centred column per stage — the form IS
   the screen on stage 1, the result IS the screen on stage 2. The old side-by-side
   form/result grid is gone with the collapse-summary model it served. */
.stylist-stage { max-width: 680px; margin: 0 auto; }
.stylist-stage[hidden] { display: none; }
.stylist-copy > p { max-width: 470px; }
.stylist-selection-summary { margin-top: 18px; display: grid; gap: 8px; }
.stylist-selection-summary[hidden] { display: none; }

/* The floating chat bubble + sheet styles are gone with the bubble itself: chat is
   the stylist's advanced layer, inline under the result, and nothing else. */

/* Onboarding height/weight inputs inside the styling-mode dialog. */
.styling-body-row { margin-top: 14px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.styling-body-row label { display: block; font-size: 12px; font-weight: 700; }
.styling-body-row label span { display: block; margin-bottom: 6px; }
.styling-body-row input { width: 100%; min-height: 44px; padding: 0 12px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--white); color: var(--text); font: inherit; }

.fashion-source-links { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 4px; }
.fashion-source-links a { color: var(--sage-dark); font-size: 12px; text-decoration: underline; }
.pinned-item-banner { padding: 11px 13px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border: 1px solid var(--border); border-radius: 12px; background: var(--accent-soft); }
.pinned-item-banner[hidden] { display: none; }
.excluded-banner { border-color: var(--line); background: var(--surface-soft); }
.excluded-banner strong { color: var(--muted); }
.pinned-item-banner span, .pinned-item-banner strong { display: block; }
.pinned-item-banner span { color: var(--muted); font-size: 12px; }
.pinned-item-banner strong { margin-top: 2px; color: var(--sage-dark); font-size: 12px; }
.pinned-item-banner button, .coordinate-item { min-height: 32px; padding: 0 10px; border: 1px solid var(--sage); border-radius: var(--radius-sm); color: var(--sage-dark); background: var(--white); font-size: 10px; font-weight: 700; }
.coordinate-item { border-color: var(--sage-dark); color: var(--on-accent); background: var(--sage-dark); }
.coordinate-item:hover { background: #352947; }
.form-block { margin-top: 28px; }
.form-block > label, .refine-label, .form-row label { display: block; margin-bottom: 8px; font-size: 12px; font-weight: 700; }
/* Six occasion cards (3×2), SVG outline icons only — no emoji. */
.occasion-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.occasion { min-height: 72px; display: grid; place-items: center; gap: 5px; border: 1px solid var(--line); border-radius: 12px; color: var(--muted); background: var(--white); }
.occasion svg { width: 22px; height: 22px; }
.occasion span { font-size: 11px; font-weight: 600; }
.occasion.active { color: var(--sage-dark); border-color: var(--sage); background: var(--surface-soft); }
/* «أخرى» is a small inline field, deliberately not a seventh card. */
.occasion-other { margin-top: 10px; display: flex; align-items: center; gap: 10px; font-size: 11px; font-weight: 700; color: var(--muted); }
.occasion-other input { flex: 1; width: auto; margin-top: 0; min-height: 38px; padding: 7px 11px; font-size: 12px; }
/* Occasion subtype chips + desired-feel chips share one pill look. */
.subtype-chips, .feel-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }
.subtype-chips[hidden] { display: none; }
.subtype-chip, .feel-chip { padding: 7px 13px; border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--muted); background: var(--white); font-size: 11px; font-weight: 600; cursor: pointer; transition: background .15s, border-color .15s, color .15s; }
.subtype-chip:hover, .feel-chip:hover { border-color: var(--accent); }
.subtype-chip.active, .feel-chip.active { color: var(--sage-dark); border-color: var(--sage); background: var(--accent-soft); }

/* ---- Stage-1 picker redesign (2026-10-02) --------------------------------------
   The stylist's input stage: illustrated occasion tiles, the chat fork, and the
   feel view. Everything is scoped under #occasion-grid / the new classes — the
   look-review page shares .occasion and keeps the old card look above. */
.input-view[hidden] { display: none; }
.stylist-eyebrow { display: block; font-size: 11px; font-weight: 700; color: var(--gold-text); }
.stylist-subtitle { margin: 2px 0 0; font-size: 13px; color: var(--muted); }
/* «كلم الستايلست» (owner review 2026-10-03, layout «أ»): a white card in a plum frame
   with the stylist's «S» and a chevron — clearly a door, never a filled button: the
   one heavy button on this screen stays «كوّن إطلالتي». */
.stylist-fork { margin-top: 12px; width: 100%; display: flex; align-items: center; gap: 12px; padding: 12px 14px; background: var(--white); color: var(--ink); border: 1.5px solid var(--accent); border-radius: 16px; font-family: inherit; text-align: start; cursor: pointer; box-shadow: 0 6px 16px rgba(107,24,75,.08); }
.stylist-fork .fork-avatar { flex: none; width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; background: var(--accent); color: var(--on-accent); font-family: Georgia, serif; font-size: 18px; }
.stylist-fork .fork-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.stylist-fork .fork-main { font-size: 15px; font-weight: 700; color: var(--accent); }
.stylist-fork .fork-sub { font-size: 12px; color: var(--muted); }
.stylist-fork .fork-chev { flex: none; color: var(--accent); }
[dir="ltr"] .stylist-fork .fork-chev { transform: scaleX(-1); }
@media (hover: hover) { .stylist-fork:hover { background: var(--accent-soft); } }
/* «عندك قطعة عاوز تبني عليها؟» — the anchor as its own optional step, a dashed plum
   tile that shows the picked piece once there is one. */
.anchor-tile { width: 100%; display: flex; align-items: center; gap: 12px; margin-top: 8px; padding: 10px 14px; background: var(--white); border: 1.5px dashed var(--accent); border-radius: 14px; color: var(--ink); font-family: inherit; text-align: start; cursor: pointer; }
.anchor-tile.has-pins { border-style: solid; }
.anchor-art { flex: none; display: flex; gap: 4px; }
.anchor-art > svg { width: 40px; height: 40px; padding: 9px; border-radius: 11px; background: var(--accent-soft); color: var(--accent); }
.anchor-thumb { position: relative; display: block; width: 40px; height: 40px; border-radius: 10px; overflow: hidden; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); }
.anchor-thumb img, .anchor-thumb .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; border-radius: 0; box-shadow: none; background: none; }
.anchor-thumb .garment-art { position: absolute; inset: 0; margin: auto; width: 62%; height: 72%; filter: none; }
.anchor-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.anchor-text strong { font-size: 14px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anchor-text small { font-size: 12px; color: var(--muted); }
.anchor-plus { flex: none; color: var(--accent); }
.anchor-tile.has-pins .anchor-plus { display: none; }
@media (hover: hover) { .anchor-tile:hover { background: var(--accent-soft); } }
.stylist-divider { margin-top: 10px; display: flex; align-items: center; gap: 10px; }
.stylist-divider i { flex: 1; height: 1px; background: var(--line); }
.stylist-divider span { font-size: 11px; font-weight: 600; color: var(--muted); white-space: nowrap; }
#occasion-grid .occasion { position: relative; overflow: hidden; display: block; padding: 0; min-height: 0; height: clamp(96px, 26vw, 140px); border-radius: 14px; background: var(--surface-soft); }
.occasion-art, .occasion-art svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.occasion-scrim { position: absolute; left: 0; right: 0; bottom: 0; height: 48%; background: linear-gradient(0deg, rgba(20,12,18,.78), rgba(20,12,18,0)); }
.occasion-caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 6px 8px 7px; display: flex; align-items: center; gap: 5px; color: #fff; }
.occasion-caption svg { width: 13px; height: 13px; flex: none; }
.occasion-caption span { font-size: 11.5px; font-weight: 700; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.occasion-check { position: absolute; top: 6px; inset-inline-end: 6px; width: 20px; height: 20px; border-radius: 999px; background: var(--gold); color: #211d26; display: none; place-items: center; }
.occasion-check svg { width: 11px; height: 11px; }
/* Board: a gold ring with a 2px page-colored gap. */
#occasion-grid .occasion.active { border-color: transparent; box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--gold); }
#occasion-grid .occasion.active .occasion-check { display: grid; }
#occasion-grid { grid-template-columns: repeat(3, 1fr); }
.feel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.optional-badge { font-size: 10.5px; font-weight: 600; color: var(--muted); background: var(--surface-soft); border-radius: var(--radius-pill); padding: 2px 10px; }
/* Six mood choices, auto first, with the selected choice filled in plum.
   Wrap labels and rows when larger text needs more space. */
#feel-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.feel-chip { flex: 1 1 auto; min-width: min-content; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; padding: 8px 2px; min-height: 60px; border-radius: 12px; border: 1px solid currentColor; background: var(--white); color: var(--ink); font-family: inherit; font-size: 10.5px; font-weight: 600; line-height: 1.25; }
.feel-chip span { text-align: center; white-space: normal; }
/* English labels run longer than the Arabic the row was drawn for («Leave it to the
   stylist» was clipped at phone width): there they may take a second line — at a space,
   never inside a word («Cal/m», «Comfortabl/e» at 360px, full review 2026-10-12) — and
   the row wraps when six whole words do not fit. */
html[lang="en"] #feel-chips { overflow-x: auto; scrollbar-width: none; }
html[lang="en"] .feel-chip { flex: 1 0 auto; min-width: 60px; padding: 8px 6px; }
html[lang="en"] .feel-chip span { white-space: normal; overflow-wrap: normal; max-width: 10ch; }
.feel-chip svg { width: 15px; height: 15px; flex: none; }
/* As the board renders it: the unselected outline is the text colour (its
   `border: 1px solid` shorthand resets the colour to currentColor). */
.feel-chip:hover { border-color: var(--accent); }
.feel-chip.active, .feel-chip.active:hover { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
/* «اختار المناسبة الأول»: a pressed CTA with nothing picked nudges the grid. */
#occasion-grid.needs-pick { animation: needs-pick .5s ease-in-out 2; border-radius: 16px; }
@keyframes needs-pick { 0%, 100% { box-shadow: 0 0 0 0 transparent; } 50% { box-shadow: 0 0 0 3px var(--gold); } }
@media (prefers-reduced-motion: reduce) { #occasion-grid.needs-pick { animation: none; box-shadow: 0 0 0 3px var(--gold); } }
#stylist-cta-zone { margin-top: 14px; }

/* ---- Owner review 2026-10-03: the picker at the board's exact values ------------
   (Option4-PhotoTiles, both screens). Every number here is read off the board. */
#stylist-input-home .stylist-eyebrow { font-size: 12px; font-weight: 600; color: var(--muted); }
#stylist-page .stylist-copy h1 { margin: 0; font-size: 22px; line-height: 1.3; font-weight: 700; }
#stylist-input-home .stylist-subtitle { font-size: 13px; }
.stylist-divider span { color: color-mix(in srgb, var(--muted) 70%, var(--paper)); }
#stylist-input-home .form-block { margin-top: 10px; }
#stylist-input-home .form-block + .form-block { margin-top: 18px; }
#occasion-grid { gap: 7px; }
#occasion-grid .occasion { height: 112px; }
.occasion-other-pill { margin-top: 7px; width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 9px; border: none; border-radius: 12px; background: color-mix(in srgb, var(--ink) 6%, var(--paper)); color: var(--ink); font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.occasion-other-pill[hidden], .occasion-other[hidden] { display: none; }
.occasion-other-pill .other-dots { letter-spacing: 2px; font-weight: 700; }
.feel-head label { font-size: 15px; font-weight: 700; color: var(--ink); margin: 0; }
.optional-badge { font-size: 11px; font-weight: 400; background: color-mix(in srgb, var(--ink) 6%, var(--paper)); }
#stylist-input-home .feel-sub { margin: 0; font-size: 12.5px; }
/* The CTA: radius 16, bold 16px, the chevron beside the label, a deeper shadow. */
.generate-button { display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 48px; padding: 13px; border-radius: 16px; font-size: 16px; font-weight: 700; box-shadow: 0 10px 24px rgba(107,24,75,.22); }
.generate-chev { flex: none; }
[dir="ltr"] .generate-chev { transform: scaleX(-1); }
/* Stylist input: image-led choices, readable captions and an explicit chat entry.
   The primary action stays last; all controls grow naturally with text. */
#stylist-input-home { --input-gap: clamp(4px, calc((100svh - var(--safe-top, 0px) - var(--safe-bottom, 0px) - 720px) / 10), 8px); }
#stylist-input-home .stylist-eyebrow { display: none; }
#stylist-page .stylist-copy h1 { font-size: 24px; line-height: 1.35; letter-spacing: -.4px; }
#stylist-input-home .stylist-subtitle { margin-top: 2px; font-size: 13px; }
#stylist-input-home .stylist-fork { min-height: 60px; margin-top: 14px; padding: 8px 12px; gap: 10px; border: 1.5px solid var(--accent); background: var(--white); box-shadow: none; border-radius: 16px; }
#stylist-input-home .fork-avatar { width: 36px; height: 36px; background: var(--accent); color: var(--on-accent); border-radius: 12px; }
#stylist-input-home .fork-main { font-size: 15px; }
#stylist-input-home .fork-sub { font-size: 12px; }
#stylist-input-home .fork-chev { width: 32px; height: 32px; padding: 8px; border-radius: 50%; background: var(--accent-soft); }
@media (hover: hover) { #stylist-input-home .stylist-fork:hover { background: var(--accent-soft); } }
#stylist-input-home .occasion-heading { min-height: max(44px, calc(1.5em + 16px)); display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 4px; font-size: 13px; }
#stylist-input-home .occasion-heading > span { color: var(--muted); font-size: 13px; }
#stylist-input-home .form-block { margin-top: var(--input-gap); }
#stylist-input-home .form-block + .form-block { margin-top: var(--input-gap); }
#occasion-grid { gap: 8px; }
#occasion-grid .occasion { display: flex; align-items: flex-end; height: auto; min-height: calc(67px + 3 * var(--input-gap)); padding: 0; background: var(--surface-soft); color: #fff; border: 1px solid transparent; border-radius: 14px; box-shadow: none; }
#occasion-grid .occasion-art, #occasion-grid .occasion-art svg { position: absolute; inset: 0; width: 100%; height: 100%; }
#occasion-grid .occasion-scrim, #occasion-grid .occasion-caption > svg { display: none; }
#occasion-grid .occasion-caption { position: relative; width: 100%; min-height: 28px; padding: 5px 7px; justify-content: center; background: rgba(20,12,18,.78); color: #fff; }
#occasion-grid .occasion-caption span { font-size: 13px; font-weight: 500; color: inherit; white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.4; }
#occasion-grid .occasion.active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
#occasion-grid .occasion.active .occasion-caption { background: var(--accent); color: var(--on-accent); }
#occasion-grid .occasion.active .occasion-caption span { font-weight: 700; }
#occasion-grid .occasion-check { width: 20px; height: 20px; top: 5px; inset-inline-end: 5px; background: var(--accent); color: var(--on-accent); border: 2px solid var(--white); }
#occasion-grid .occasion-check svg { width: 9px; height: 9px; }
#stylist-input-home .occasion-other-pill { flex: none; width: auto; min-height: 44px; margin: 0; padding: 8px 10px; background: transparent; color: var(--accent); font-weight: 500; line-height: 1.5; }
#stylist-input-home .feel-sub { display: none; }
#stylist-input-home .feel-head label { font-size: 14px; font-weight: 500; }
#stylist-input-home .optional-badge { padding: 0; background: transparent; font-size: 11px; }
#stylist-input-home #feel-chips { display: grid; grid-template-columns: repeat(auto-fit,minmax(min(100%,8em),1fr)); gap: 6px; font-size: 12px; overflow: visible; }
#stylist-input-home .feel-chip { flex-direction: row; min-width: 0; min-height: 44px; padding: 6px; gap: 6px; font-size: 12px; font-weight: 500; border: 1px solid transparent; border-radius: 12px; background: var(--surface-soft); color: var(--ink); }
#stylist-input-home .feel-chip span { max-width: none; line-height: 1.35; }
#stylist-input-home .feel-chip svg { width: 15px; height: 15px; }
#stylist-input-home .feel-chip.active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
#stylist-input-home .anchor-block .feel-head { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
#stylist-input-home .anchor-tile { min-height: 56px; margin-top: 0; padding: 8px 0; gap: 10px; border: 0; border-radius: 0; background: transparent; }
#stylist-input-home .anchor-art > svg { width: 38px; height: 38px; background: var(--surface-soft); color: var(--muted); border-radius: 12px; }
#stylist-input-home .anchor-text strong { font-size: 14px; font-weight: 500; }
#stylist-input-home .anchor-text small { font-size: 12px; }
#stylist-input-home .cta-slot { margin: calc(var(--input-gap) + 2px) 0 0; }
#stylist-cta-zone, #stylist-cta-zone .generate-button { margin-top: 0; }
#stylist-cta-zone .generate-button { min-height: 52px; border-radius: 16px; box-shadow: none; }
@media (min-width: 621px) {
  #occasion-grid .occasion { min-height: clamp(104px, 12vw, 136px); }
}
.mobile-brand { display: none; }
@media (max-width: 850px) {
  html { scroll-padding-bottom: calc(96px + var(--safe-bottom, 0px)); }
  #stylist-page.page { padding-top: 8px; padding-bottom: 0; }
  .topbar .icon-button, .topbar .mobile-menu { border: 0; background: transparent; display: grid; place-items: center; font-size: 16px; }
  .topbar .mobile-menu { margin-left: 0; }
  .mobile-brand { display: block; margin-inline: 8px auto; font-family: "Playfair Display", Georgia, serif; font-size: 22px; letter-spacing: -.5px; }
  .topbar .topbar-actions { gap: 0; }
  #stylist-input-home .stylist-fork { margin-top: var(--input-gap); }
}

/* ---- Stage-2 result deck — board «ج» at its exact values (owner review 2026-10-03) ----
   ResultC-Deck / C5 / C2 / Wedding: the deck sits straight on the page (no framed
   panel), the stylist's other picks peek behind the card, every tile is the swap
   button for its piece with the badge in the corner, no captions on the tiles. */
#generation-panel:has(> .generated-result) { min-height: 0; padding: 0; border: none; background: none; display: block; }
.result-counter { margin-inline-start: auto; font-size: 11px; font-weight: 700; color: var(--muted); background: color-mix(in srgb, var(--ink) 6%, var(--paper)); border-radius: var(--radius-pill); padding: 3px 10px; white-space: nowrap; }
.deck { position: relative; padding-top: 20px; }
.deck-under { position: absolute; top: 0; bottom: 24px; left: 30px; right: 30px; border-radius: 24px; background: color-mix(in srgb, var(--ink) 11%, var(--paper)); }
.deck-under-1 { top: 9px; bottom: 15px; left: 15px; right: 15px; background: color-mix(in srgb, var(--ink) 7%, var(--paper)); }
.deck-under-2 { z-index: 0; }
.deck-card { position: relative; background: var(--white); border: none; border-radius: 24px; padding: 10px; box-shadow: 0 14px 30px rgba(33,29,38,.10); touch-action: pan-y; }
/* High-specificity resets: the legacy .outfit-stage/.garment rules (padding,
   centring, 220px min-height, the :has(4) column flip) must not reach the deck. */
.generated-result .outfit-stage.deck-collage { display: grid; gap: 6px; padding: 0; min-height: 0; align-items: stretch; }
.generated-result .outfit-stage.deck-collage.tall { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: 214px 150px; }
.generated-result .outfit-stage.deck-collage.quad,
.generated-result .outfit-stage.deck-collage.quad:has(.garment:nth-child(4)) { grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-rows: 214px 150px; }
.generated-result .outfit-stage.deck-collage.rows,
.generated-result .outfit-stage.deck-collage.rows:has(.garment:nth-child(4)) { grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-rows: 222px 142px; }
.deck-collage .garment.deck-piece { position: relative; overflow: hidden; border: none; border-radius: 14px; padding: 0; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); min-width: 0; min-height: 0; display: block; font: inherit; color: inherit; text-align: start; cursor: pointer; }
.deck-collage div.garment.deck-piece { cursor: default; }
.deck-piece img, .deck-piece .photo-frame, .deck-piece .garment-art { position: absolute; inset: 0; width: 100%; height: 100%; }
.deck-piece img.outfit-item-photo, .deck-piece img { object-fit: cover; max-width: none; border-radius: 0; box-shadow: none; background: none; }
/* A garment the fill would cut short (keepGarmentWhole) is shown whole on the tile's tint. */
img.is-whole[data-keep-whole] { object-fit: contain !important; object-position: 50% 50% !important; }
/* Photo-less art keeps its own proportions in any tile shape — sized off the
   tile's smaller side (container units), centred; the tall tile used to stretch it. */
.deck-collage .garment.deck-piece { container-type: size; }
.deck-piece .garment-art { --ar: .78; border-radius: 0; inset: auto; top: 50%; left: 50%; margin: 0; width: min(62cqw, calc(66cqh * var(--ar))); height: auto; aspect-ratio: var(--ar); transform: translate(-50%, -50%); }
/* Each silhouette at its own native proportions (125×160; shoes 150×90). */
.deck-piece .garment-art.shoes { --ar: 1.67; }
.deck-piece .garment-art.accessory { --ar: 1; }
/* The name stays for screen readers and the outfit-reading hooks — not on the tile. */
.piece-caption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.piece-swap { position: absolute; top: 7px; inset-inline-end: 7px; width: 26px; height: 26px; border-radius: 999px; background: rgba(255,255,255,.92); color: var(--accent); display: grid; place-items: center; box-shadow: 0 2px 6px rgba(33,29,38,.12); pointer-events: none; }
.piece-swap svg { width: 13px; height: 13px; }
.deck-piece:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deck-meta { padding: 12px 6px 2px; }
.deck-meta-top { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.deck-meta-top h2 { flex: 1 1 auto; min-width: 0; max-width: 100%; margin: 0; font-size: 18px; font-weight: 700; overflow-wrap: anywhere; }
.from-closet { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; color: var(--accent); white-space: nowrap; }
/* ♡ on the look (QA round 3, 2026-10-06): keep it without wearing it. */
.deck-meta-tools { flex: none; display: flex; align-items: center; gap: 4px; margin-inline-start: auto; }
.deck-save { position: relative; flex: none; width: 44px; height: 44px; padding: 0; border: none; border-radius: 999px; background: transparent; color: var(--accent); font-size: 17px; line-height: 1; display: grid; place-items: center; cursor: pointer; }
/* The old 34px heart circle keeps its appearance inside a 44px touch target. */
.deck-save::before { content: ""; position: absolute; inset: 5px; border: 1px solid var(--line); border-radius: inherit; background: var(--white); pointer-events: none; }
.result-save-icon { position: relative; }
.deck-save[aria-pressed="true"]::before { border-color: var(--accent); }
.deck-save:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deck-meta .result-reason { margin: 4px 0 0; font-size: 13px; line-height: 1.65; color: color-mix(in srgb, var(--ink) 80%, var(--paper)); }
/* The bodysuit under the look (owner, 2026-10-06): a line of its own — the reason above is clamped. */
.deck-meta .result-layer { margin: 4px 0 0; font-size: 12px; line-height: 1.6; color: var(--muted); }
/* Preserve the familiar circles; equal columns keep wear centered even when labels wrap. */
.deck-actions { max-width: 360px; margin: 14px auto 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; gap: 8px; }
.deck-action { min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 7px; padding-top: 8px; text-align: center; }
.deck-action > span { max-width: 100%; font-size: 13px; line-height: 1.5; font-weight: 600; color: var(--muted); overflow-wrap: anywhere; }
.deck-action-primary { padding-top: 0; }
.deck-action-primary > span { font-size: 13.5px; font-weight: 700; color: var(--accent); }
.circle-button { width: 54px; height: 54px; border-radius: 999px; background: var(--white); border: 1px solid var(--line); color: var(--ink); display: grid; place-items: center; cursor: pointer; }
.circle-button:hover { border-color: var(--sage); }
.circle-button:focus-visible, .generated-result .refine-chip:focus-visible, .chat-entry-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* var(--on-accent), never #fff: the dark theme's accent is a pale pink, and white
   on it was ~2:1 contrast (review finding). */
.circle-primary { width: 70px; height: 70px; background: var(--accent); border: none; color: var(--on-accent); box-shadow: 0 10px 22px rgba(107,24,75,.28); }
.circle-primary:hover { filter: brightness(1.05); }
.circle-primary:disabled { opacity: .6; cursor: default; }
#regenerate-result.circle-button { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
/* The fixed chip row (board): white pills, no divider; «المزيد» muted with ⋯. */
.generated-result .refine-chips { justify-content: center; gap: 6px; margin-top: 12px; padding-top: 0; border-top: none; }
.generated-result .refine-chip { display: inline-flex; align-items: center; justify-content: center; gap: 5px; min-height: 44px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 999px; background: var(--white); color: var(--ink); font-size: 13px; line-height: 1.5; font-weight: 600; }
.generated-result .refine-chip.refine-more { border-style: solid; color: var(--muted); }
.generated-result .refine-chip.reject-entry { border-style: solid; color: var(--muted); }
/* The result top bar (board): «تعديل» as a text link with a chevron, the summary
   centred, the counter at the end — no boxed bar, no pill. */
#stylist-stage-result .stage-topbar { margin-bottom: 0; padding: 8px 0 0; border: none; border-radius: 0; background: none; }
#stylist-stage-result .stage-back-button { min-height: 44px; padding: 4px 8px; border: none; border-radius: 0; background: none; color: var(--ink); font-size: 13px; font-weight: 600; gap: 4px; }
#stylist-stage-result #stylist-summary-text { flex: 1; text-align: center; font-size: 14px; font-weight: 700; color: var(--ink); }
/* The after-the-look chat entry (canvas note n12), restored with its old look. */
.chat-entry-row { display: block; width: 100%; min-height: 48px; margin-top: 18px; padding: 13px 16px; border: 1px dashed var(--line); border-radius: 12px; color: var(--sage-dark); background: var(--surface-soft); font-size: 13px; line-height: 1.6; font-weight: 700; font-family: inherit; cursor: pointer; text-align: start; }
.chat-entry-row:hover { border-color: var(--sage-dark); }

/* ---- The per-slot swap sheet + undo (design «ج», stage 3) ----------------------- */
dialog.swap-sheet { position: fixed; inset: auto 0 0 0; margin: 0 auto; width: 100%; max-width: 560px; border: none; border-radius: 26px 26px 0 0; background: var(--paper); color: var(--ink); padding: 10px 20px calc(26px + env(safe-area-inset-bottom)); box-shadow: 0 -10px 30px rgba(20,14,22,.18); }
dialog.swap-sheet::backdrop { background: rgba(20,14,22,.42); -webkit-backdrop-filter: none; backdrop-filter: none; }
.swap-handle { width: 38px; height: 4px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 16%, var(--paper)); margin: 0 auto 14px; }
.swap-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.swap-head h2 { margin: 0; font-size: 18px; font-weight: 700; }
.swap-head p { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.swap-close { flex: none; width: 32px; height: 32px; border-radius: 999px; border: none; background: color-mix(in srgb, var(--ink) 7%, var(--paper)); color: var(--ink); display: grid; place-items: center; cursor: pointer; }
/* Board ResultC-Swap: the current piece + three alternatives, all in view. */
.swap-cards { margin-top: 14px; display: flex; gap: 6px; }
.swap-card { flex: 1 1 0; min-width: 0; background: var(--white); border: 1px solid var(--line); border-radius: 14px; padding: 6px 6px 8px; display: flex; flex-direction: column; align-items: stretch; gap: 6px; text-align: start; font-family: inherit; cursor: pointer; }
.swap-card.current { border: 2px solid var(--accent); }
.swap-thumb { position: relative; height: 62px; border-radius: 10px; background: var(--surface-soft); overflow: hidden; display: block; }
.swap-thumb img, .swap-thumb .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; max-width: none; border-radius: 0; box-shadow: none; background: none; }
.swap-thumb .garment-art { position: absolute; inset: 0; margin: auto; width: 58%; height: 72%; filter: none; }
.swap-name { font-size: 11.5px; font-weight: 700; line-height: 1.35; color: var(--ink); min-height: 31px; overflow: hidden; }
.swap-tag { align-self: flex-start; white-space: nowrap; font-size: 10px; font-weight: 700; border-radius: 999px; padding: 2px 6px; }
.swap-tag.dir-current { background: var(--accent); color: var(--on-accent); }
/* Board colors: «رسمي أكتر» blue-grey, «نفس المستوى» plum tint, «كاجوال أكتر» sand. */
.swap-tag.dir-up { background: #e9eef3; color: #2f4a63; }
.swap-tag.dir-same { background: var(--accent-soft); color: var(--accent); }
.swap-tag.dir-down { background: color-mix(in srgb, var(--ink) 6%, var(--paper)); color: var(--muted); }
.swap-empty { margin: 10px 2px 0; font-size: 12.5px; color: var(--muted); line-height: 1.6; }
.swap-stylist { margin-top: 14px; width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-line); border-radius: 14px; font-family: inherit; font-size: 14px; font-weight: 700; cursor: pointer; }
.swap-undo-row { margin-top: 10px; display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 12px; color: var(--muted); }
.swap-undo-row span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 55%; }
/* The piece being swapped stays marked behind the dimmed sheet (board ResultC-Swap). */
.deck-piece.swap-target { box-shadow: 0 0 0 2.5px var(--accent); }
.deck-piece.swap-target .piece-swap { background: var(--accent); color: var(--on-accent); }
#undo-swap { background: none; border: none; padding: 2px 4px; font-family: inherit; font-size: 12.5px; font-weight: 700; color: var(--accent); cursor: pointer; }

/* ---- Stage-3 chat — boards Chat1–Chat5 at their exact values (owner review 2026-10-03) ----
   A screen of its own: top bar, the conversation in the flexible middle, the
   composer at the bottom. On phones it takes the whole screen (no app header, no
   tab bar) and follows the visible viewport, so the keyboard never covers the
   composer (n7-4). */
#stylist-stage-chat:not([hidden]) { display: flex; flex-direction: column; height: min(760px, calc(100vh - 150px)); }
.chat-pinned-look[hidden], .chat-intro[hidden], .chat-suggestions[hidden], .chat-quick-pills[hidden] { display: none; }
#stylist-stage-chat .chat-topbar { flex-shrink: 0; margin: 0; padding: 6px 0 8px; border: none; border-bottom: 1px solid var(--line); border-radius: 0; background: none; justify-content: space-between; }
#stylist-stage-chat .chat-topbar .stage-back-button { width: 70px; padding: 4px 0; border: none; border-radius: 0; background: none; color: var(--ink); font-size: 13px; font-weight: 600; gap: 3px; }
.stage-topbar-spacer { width: 70px; }
.chat-identity { display: flex; align-items: center; gap: 8px; }
.chat-identity strong { display: block; font-size: 14.5px; line-height: 1.2; }
.chat-identity small { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--muted); }
.chat-online-dot { width: 6px; height: 6px; border-radius: 999px; background: #3f9a6b; flex: none; }
/* Double-class so the generic .chat-avatar base can never win the cascade back. */
.chat-avatar.chat-avatar-top { width: 30px; height: 30px; border-radius: 999px; background: var(--accent); color: var(--on-accent); display: grid; place-items: center; font-family: Georgia, serif; font-size: 15px; font-weight: 400; flex: none; }
/* The pinned look (from-look entry), and its one-line form while typing (Chat5). */
.chat-pinned-look { flex-shrink: 0; margin: 10px 0 0; width: 100%; display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: var(--white); border: 1px solid var(--line); border-radius: 16px; font-family: inherit; text-align: start; cursor: pointer; color: var(--ink); }
.pinned-thumbs { display: flex; gap: 5px; flex: none; }
.pinned-thumb { position: relative; width: 44px; height: 44px; border-radius: 9px; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); overflow: visible; display: block; }
.pinned-thumb > img, .pinned-thumb > .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; border-radius: 9px; box-shadow: none; background: none; overflow: hidden; }
.pinned-thumb .garment-art { position: absolute; inset: 0; margin: auto; width: 62%; height: 72%; filter: none; }
.pinned-thumb.changed { box-shadow: 0 0 0 2px var(--accent); }
/* A look of more than three pieces shows all of them, a size smaller. */
.pinned-thumbs.many { gap: 4px; }
.pinned-thumbs.many .pinned-thumb { width: 34px; height: 34px; border-radius: 8px; }
.pinned-thumbs.many .pinned-thumb > img, .pinned-thumbs.many .pinned-thumb > .photo-frame { border-radius: 8px; }
.pinned-check { position: absolute; top: -4px; inset-inline-end: -4px; width: 16px; height: 16px; border-radius: 999px; background: var(--accent); color: var(--on-accent); border: 2px solid var(--white); display: grid; place-items: center; }
.pinned-meta { flex: 1; min-width: 0; }
.pinned-meta strong { display: block; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pinned-meta small { display: block; font-size: 11.5px; color: var(--muted); }
.pinned-open { flex: none; display: inline-flex; align-items: center; gap: 3px; font-size: 11.5px; font-weight: 700; color: var(--accent); }
[dir="ltr"] .pinned-open svg, [dir="ltr"] .chat-look-open svg, [dir="ltr"] .chat-change-arrow svg { transform: scaleX(-1); }
.pinned-compact { display: none; font-size: 11px; color: var(--muted); }
#stylist-stage-chat.chat-typing .chat-pinned-look { margin: 0; padding: 6px 2px; gap: 8px; border: none; border-bottom: 1px solid var(--line); border-radius: 0; }
#stylist-stage-chat.chat-typing .pinned-thumbs { gap: 4px; }
#stylist-stage-chat.chat-typing .pinned-thumb { width: 28px; height: 28px; border-radius: 7px; }
#stylist-stage-chat.chat-typing .pinned-meta strong { font-size: 12px; }
#stylist-stage-chat.chat-typing .pinned-sub, #stylist-stage-chat.chat-typing .pinned-open { display: none; }
#stylist-stage-chat.chat-typing .pinned-compact { display: inline; }
#stylist-stage-chat.chat-typing .chat-suggestions, #stylist-stage-chat.chat-typing .chat-quick-pills { display: none; }
/* The conversation: bubbles from the bottom up, the opening centred (Chat1). */
.stylist-chat-card { flex: 1; min-height: 0; display: flex; flex-direction: column; margin: 0; padding: 0; border: none; border-radius: 0; background: none; box-shadow: none; }
.chat-messages { flex: 1; min-height: 0; margin: 0; padding: 12px 2px 4px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; border: none; border-radius: 0; background: none; scroll-behavior: smooth; }
/* Messages gather at the bottom (Chat2–4); the from-scratch opening sits in the
   middle (Chat1). Pseudo spacers, so a hidden first child can't break either. */
.chat-messages::before { content: ""; margin-top: auto; }
/* A drawn scrollbar (desktop) no longer clips her bubbles at the edge (QA round 3). */
@media (min-width: 851px) { .chat-messages { padding-inline: 12px; scrollbar-gutter: stable; } }
.chat-messages::after { content: ""; flex: none; }
.chat-messages:has(#chat-intro:not([hidden]))::after { margin-bottom: auto; }
.chat-intro { display: flex; flex-direction: column; align-items: center; gap: 4px; margin-bottom: 6px; text-align: center; }
.chat-avatar.chat-avatar-big { width: 58px; height: 58px; border-radius: 999px; background: var(--accent); color: var(--on-accent); display: grid; place-items: center; font-family: Georgia, serif; font-size: 29px; font-weight: 400; }
.chat-intro h2 { margin: 6px 0 0; font-size: 18px; font-weight: 700; }
.chat-intro p { margin: 0; font-size: 12.5px; color: var(--muted); }
.chat-message { max-width: 88%; display: flex; align-items: flex-start; gap: 8px; }
.chat-message > div { padding: 9px 12px; border: none; border-radius: 16px 4px 16px 16px; background: color-mix(in srgb, var(--ink) 5%, var(--paper)); color: var(--ink); }
.chat-message.user { align-self: flex-end; max-width: 78%; margin-right: 0; flex-direction: row; }
.chat-message.user > div { color: var(--on-accent); background: var(--accent); border-radius: 4px 16px 16px 16px; }
[dir="ltr"] .chat-message > div { border-radius: 4px 16px 16px 16px; }
[dir="ltr"] .chat-message.user > div { border-radius: 16px 4px 16px 16px; }
.chat-message p { margin: 0; color: inherit; font-size: 13.5px; line-height: 1.65; white-space: pre-wrap; }
.chat-message .sr-only { position: absolute; }
.chat-avatar { width: 26px; height: 26px; display: grid; place-items: center; flex: 0 0 auto; border-radius: 50%; color: var(--on-accent); background: var(--accent); font-family: Georgia, serif; font-size: 13px; font-weight: 400; }
.chat-message.thinking p::after { content: "..."; display: inline-block; width: 18px; overflow: hidden; vertical-align: bottom; animation: typing-dots 1.1s steps(4, end) infinite; }
.chat-outfit-note { display: block; margin-top: 6px; color: var(--muted); font-size: 11px; line-height: 1.6; }
/* The opening cards (starters / the look's questions), 2-up. */
.chat-suggestions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; margin: 0; }
.chat-sug { display: flex; align-items: center; gap: 8px; padding: 7px; background: var(--white); border: 1px solid var(--line); border-radius: 14px; font-family: inherit; font-size: 12.5px; font-weight: 700; color: var(--ink); text-align: start; cursor: pointer; min-width: 0; }
.chat-sug:hover { border-color: var(--sage); }
.sug-art { position: relative; width: 46px; height: 42px; border-radius: 10px; overflow: hidden; background: var(--accent-soft); flex: none; display: grid; place-items: center; color: var(--accent); }
.sug-art svg:not(.sug-glyph svg) { position: absolute; inset: 0; width: 100%; height: 100%; }
.sug-art.sug-glyph svg { position: static; }
.sug-art.sug-piece { background: color-mix(in srgb, var(--ink) 6%, var(--paper)); }
.sug-art.sug-piece img, .sug-art.sug-piece .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; border-radius: 0; box-shadow: none; background: none; }
.sug-art.sug-piece .garment-art { position: absolute; inset: 0; margin: auto; width: 60%; height: 72%; filter: none; }
/* Quick follow-up pills above the composer (Chat2). */
.chat-quick-pills { flex-shrink: 0; display: flex; gap: 6px; padding: 8px 2px 0; overflow-x: auto; scrollbar-width: none; }
.chat-pill { flex-shrink: 0; padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px; background: var(--white); color: var(--ink); font-family: inherit; font-size: 12px; font-weight: 600; cursor: pointer; }
/* The look card (Chat2) and the قبل/بعد card (Chat4) — cards OF the conversation. */
.chat-look-card, .chat-change-card { flex-shrink: 0; background: var(--white); border: 1px solid var(--line); border-radius: 18px; padding: 8px; box-shadow: 0 6px 18px rgba(33,29,38,.06); }
.chat-change-card { padding: 10px; }
.chat-look-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 5px; }
.chat-outfit-piece { position: relative; overflow: hidden; border: none; border-radius: 12px; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); height: 104px; min-width: 0; padding: 0; cursor: pointer; }
.chat-outfit-piece img, .chat-outfit-piece .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; border-radius: 0; box-shadow: none; background: none; }
.chat-outfit-piece .garment-art { position: absolute; inset: 0; margin: auto; width: 60%; height: 68%; filter: none; }
.chat-piece-swap { position: absolute; top: 5px; inset-inline-end: 5px; width: 22px; height: 22px; border-radius: 999px; background: rgba(255,255,255,.92); color: var(--accent); display: grid; place-items: center; pointer-events: none; }
.chat-look-title { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 4px 2px; }
.chat-look-title strong { font-size: 15px; font-weight: 700; }
.chat-look-title span { font-size: 11px; font-weight: 600; color: var(--muted); }
.chat-look-layer { margin: 2px 4px 0; font-size: 11.5px; line-height: 1.6; color: var(--muted); }
.chat-change-row { display: flex; align-items: center; justify-content: center; gap: 10px; }
.chat-change-row + .chat-change-names + .chat-change-row { margin-top: 10px; }
.chat-change-cell { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.chat-change-cell small { font-size: 11px; color: var(--muted); }
.chat-change-cell.after small { color: var(--accent); font-weight: 700; }
.chat-change-thumb { position: relative; width: 92px; height: 66px; border: none; padding: 0; border-radius: 12px; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); overflow: hidden; display: block; }
.chat-change-cell.before .chat-change-thumb { opacity: .5; }
.chat-change-cell.after .chat-change-thumb { box-shadow: 0 0 0 2px var(--accent); cursor: pointer; }
.chat-change-thumb img, .chat-change-thumb .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; border-radius: 0; box-shadow: none; background: none; }
.chat-change-thumb .garment-art { position: absolute; inset: 0; margin: auto; width: 62%; height: 72%; filter: none; }
.chat-change-arrow { color: var(--muted); display: grid; place-items: center; }
.chat-change-names { margin-top: 8px; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--ink); }
.chat-look-actions { display: flex; gap: 6px; padding: 6px 2px 2px; }
.chat-change-card .chat-look-actions { margin-top: 3px; }
.chat-look-open { flex: 1.3; display: inline-flex; align-items: center; justify-content: center; gap: 6px; background: var(--accent); color: var(--on-accent); border: none; border-radius: 12px; padding: 10px; font-family: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer; }
.chat-change-card .chat-look-open { flex: 1.4; }
.chat-look-again { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-line); border-radius: 12px; padding: 9px; font-family: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }
.chat-look-undo { flex: 1; background: var(--white); color: var(--ink); border: 1px solid var(--line); border-radius: 12px; padding: 9px; font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.chat-look-undo:disabled { opacity: .5; cursor: default; }
/* A day-by-day plan (owner's pick, layout «ج — جدول الرحلة»): one compact row per
   day — the day, its note, its pieces' pictures — so a whole week fits on about one
   phone screen; the plum row under it counts the pieces to pack and unfolds them. */
.chat-plan-card, .chat-pieces-card { flex-shrink: 0; background: var(--white); border: 1px solid var(--line); border-radius: 18px; padding: 8px; box-shadow: 0 6px 18px rgba(33,29,38,.06); }
/* A plan an edit replaced folds to one line (QA round 3, 2026-10-06). */
.chat-plan-card.chat-plan-superseded { box-shadow: none; background: transparent; border-style: dashed; padding: 6px 10px; }
.chat-plan-old { margin: 0; font-size: 12px; color: var(--muted); }
.chat-plan-card { display: flex; flex-direction: column; gap: 6px; }
.chat-plan-row { width: 100%; min-height: 64px; display: flex; align-items: center; gap: 8px; padding: 7px 8px; border: 1px solid var(--line); border-radius: 13px; background: color-mix(in srgb, var(--ink) 2%, var(--white)); color: var(--ink); font-family: inherit; text-align: start; cursor: pointer; }
@media (hover: hover) { .chat-plan-row:hover { border-color: var(--accent-line); } }
.chat-plan-when { flex: 0 0 auto; width: 84px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.chat-plan-when strong { font-size: 13px; font-weight: 700; }
.chat-plan-when small { font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-plan-thumbs { flex: 1 1 auto; min-width: 0; display: flex; gap: 4px; }
.chat-plan-thumb { position: relative; display: block; flex: 0 1 50px; min-width: 0; max-width: 50px; aspect-ratio: 1; border-radius: 10px; overflow: hidden; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); }
.chat-plan-thumb img, .chat-plan-thumb .photo-frame, .chat-pieces-art img, .chat-pieces-art .photo-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; border-radius: 0; box-shadow: none; background: none; }
.chat-plan-thumb .garment-art, .chat-pieces-art .garment-art { position: absolute; inset: 0; margin: auto; width: 62%; height: 72%; filter: none; }
.chat-plan-chevron { flex: none; display: grid; place-items: center; color: var(--muted); }
[dir="ltr"] .chat-plan-chevron { transform: scaleX(-1); }
.chat-plan-chevron svg { transition: transform .2s ease; }
.chat-plan-pack { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; border: 1px solid var(--accent-line); border-radius: 13px; background: var(--accent-soft); color: var(--accent); font-family: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }
.chat-plan-pack .chat-plan-chevron { color: inherit; }
.chat-plan-pack[aria-expanded="true"] .chat-plan-chevron svg { transform: rotate(-90deg); }
.chat-plan-pack-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 6px; padding: 2px 2px 4px; }
.chat-plan-pack-list[hidden] { display: none; }
.chat-pack-piece, .chat-pieces-tile { display: flex; flex-direction: column; align-items: stretch; gap: 5px; min-width: 0; padding: 0; border: none; background: none; color: var(--ink); font-family: inherit; text-align: center; cursor: pointer; }
.chat-pack-piece .chat-plan-thumb { flex: none; max-width: none; width: 100%; aspect-ratio: auto; height: 72px; border-radius: 12px; }
.chat-pack-piece small, .chat-pieces-tile small { font-size: 11.5px; font-weight: 600; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Pieces the user asked to see («اعرضهم ليا هنا»), three to a row. */
.chat-pieces-card { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 6px; }
.chat-pieces-art { position: relative; display: block; height: 96px; border-radius: 12px; overflow: hidden; background: color-mix(in srgb, var(--item-tint, var(--ink)) 9%, var(--paper)); }
@media (prefers-reduced-motion: reduce) { .chat-plan-chevron svg { transition: none; } }
/* The composer (Chat1–5): a pill field and a round send button — sand while empty,
   plum once there is text. */
.chat-composer { flex-shrink: 0; margin: 0; padding: 8px 0 4px; display: flex; align-items: center; gap: 8px; }
/* The board's field keeps its plain pill while typing; focus shows as a plum-tinted
   border instead of the global glow + outline. */
#stylist-chat-input:focus, #stylist-chat-input:focus-visible { outline: none; box-shadow: none; border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.chat-composer textarea { flex: 1; min-height: 0; max-height: 120px; margin: 0; padding: 10px 15px; border: 1px solid var(--line); border-radius: 22px; background: var(--white); font-size: 14px; line-height: 1.4; resize: none; overflow-y: auto; }
.chat-send { width: 42px; height: 42px; flex: none; border: none; border-radius: 999px; background: color-mix(in srgb, var(--ink) 16%, var(--paper)); color: #fff; display: grid; place-items: center; cursor: pointer; transition: background .15s; }
.chat-send.has-text { background: var(--accent); color: var(--on-accent); }
.chat-send:disabled { opacity: .6; cursor: default; }
@media (max-width: 850px) {
  /* The conversation takes the whole screen on phones (boards): no app header, no
     tab bar; it follows the VISIBLE viewport so the keyboard sits under the
     composer, never over it. */
  body.chat-stage-open .tabbar, body.chat-stage-open .topbar { display: none; }
  body.chat-stage-open { overflow: hidden; }
  #stylist-stage-chat:not([hidden]) { position: fixed; inset: var(--chat-top, 0px) 0 auto 0; z-index: 25; height: var(--chat-vh, 100dvh); max-width: none; padding: var(--safe-top, 0px) 16px var(--safe-bottom, 0px); background: var(--paper); }
  /* The home indicator is outside the visible viewport while the keyboard is up. */
  #stylist-stage-chat.chat-keyboard-open { padding-bottom: 0; }
  .chat-composer { padding: 8px 0 14px; }
  #stylist-stage-chat.chat-typing .chat-composer { padding-bottom: 8px; }
  /* Edge to edge, as the boards draw them. */
  #stylist-stage-chat .chat-topbar { margin: 0 -16px; padding: 6px 16px 8px; }
  #stylist-stage-chat.chat-typing .chat-pinned-look { width: calc(100% + 32px); margin: 0 -16px; padding: 6px 16px; background: var(--white); }
  /* Phones scroll by touch: no scrollbar drawn as a line beside the bubbles. */
  .chat-messages, .chat-composer textarea, .chat-quick-pills { scrollbar-width: none; }
  .chat-messages::-webkit-scrollbar, .chat-composer textarea::-webkit-scrollbar { display: none; }
}
@media (max-width: 850px) {
  /* The same breakpoint the tab bar itself lives under — 760px left a band of
     large phones where the bar did not yield (review finding). */
  body.chat-stage-open .tabbar { display: none; }
}
/* Back arrows are drawn for RTL; mirror them when the UI runs LTR. */
[dir="ltr"] .stage-back-button > span[aria-hidden="true"] { display: inline-block; transform: scaleX(-1); }
/* The composer's send arrow too (review finding: EN showed "Send ←"). */
[dir="ltr"] .send-arrow { display: inline-block; transform: scaleX(-1); }
/* The greeting + date row the old اليوم landing left behind — now the دولابي
   page's hero (§6.1 leaves the stylist's input screen to the occasion question). */
.stylist-greeting { margin: 2px 0 0; color: var(--ink); font-size: 15px; font-weight: 700; }
/* Stage 2's compact top bar: back («تعديل») + the one-line context summary.
   The summary truncates rather than wraps — a top bar, not a paragraph. */
.stage-topbar { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
.stage-back-button { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; padding: 6px 11px; border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--sage-dark); background: var(--white); font-size: 12px; font-weight: 700; cursor: pointer; }
.stage-back-button:hover { border-color: var(--sage); }
#stylist-summary-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 700; color: var(--sage-dark); }
/* The CTA mid-transition: the generate button swaps for this in-place progress card
   (loading is a state inside the 1→2 transition, not a stage of its own). */
.generate-progress-host { margin-top: 12px; padding: 20px 16px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 18px; background: var(--surface-soft); }
.generate-progress-host[hidden] { display: none; }
.generate-progress-host .orb { width: 64px; height: 64px; margin-bottom: 14px; font-size: 22px; }
/* Stage 2's new-session affordance, full-width under the chat. */
.new-session-row { width: 100%; min-height: 44px; margin-top: 16px; }
/* «طلب خاص؟», the قيّم لوكي tool-entry card, and the time selector are gone from
   stage 1 (§6.1/§6.4): free text is the chat's job, the anchor is its own step
   (.anchor-tile above), and the clock answers the time question itself. */
.form-row { margin-top: 17px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
select, input, textarea { width: 100%; margin-top: 6px; padding: 11px 12px; border: 1px solid var(--line); border-radius: 12px; outline: none; color: var(--ink); background: var(--white); }
select:focus, input:focus, textarea:focus { border-color: var(--sage); box-shadow: 0 0 0 3px rgba(107,24,75,.12); }
.refine-label { margin-top: 17px; }
.refine-label span { color: var(--muted); font-weight: 400; }
.brand-field { margin-top: 17px; display: block; font-size: 12px; font-weight: 700; }
/* `hidden` alone can't hide a .brand-field — the class's own `display:block` wins over
   the UA [hidden] rule. This guard restores it (e.g. the sign-up-only confirm field). */
.brand-field[hidden] { display: none; }
.metadata-details { margin-top: 16px; padding: 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
/* «الحالة والمقاس» (usage_state, Item-Intelligence §24–§25): a fieldset styled like the
   rest of the fold — the browser's default fieldset chrome would read as a foreign
   widget in this form. The favorite checkbox sits beside its label, not above it. */
.usage-state-group { margin-top: 17px; padding: 0; border: 0; }
.usage-state-group legend { padding: 0; font-size: 12px; font-weight: 700; color: var(--sage-dark); }
.usage-state-group .favorite-field { display: flex; align-items: center; gap: 8px; }
.usage-state-group .favorite-field input[type="checkbox"] { width: auto; margin: 0; }
/* §22's six advanced sections share the usage group's quiet fieldset dress — the
   browser's fieldset chrome would read as a foreign widget in this form. Tokens
   only, so RTL and dark come for free. */
.adv-section { margin-top: 17px; padding: 0; border: 0; }
.adv-section legend { padding: 0; font-size: 12px; font-weight: 700; color: var(--sage-dark); }
.adv-section .favorite-field { display: flex; align-items: center; gap: 8px; }
.adv-section .favorite-field input[type="checkbox"] { width: auto; margin: 0; }
.adv-section .field-group-label { margin-top: 12px; }
/* «التنسيق الذكي»: the three linked range selects sit as one row, the climate bands
   and the style strengths as compact two-up grids. */
.form-row-3 { grid-template-columns: 1fr 1fr 1fr; }
.climate-bands, .style-compat { margin-top: 12px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.climate-bands label, .style-compat label { display: block; font-size: 12px; font-weight: 700; }
/* Usage memory (§26): one read-only sentence, never a field. */
.usage-memory { margin: 8px 0 0; color: var(--muted); font-size: 12px; font-weight: 600; }
.usage-memory[hidden] { display: none; }
.metadata-details summary { cursor: pointer; color: var(--sage-dark); font-size: 12px; font-weight: 700; }
.metadata-details[open] summary { margin-bottom: 8px; }
textarea { min-height: 78px; resize: vertical; }
.generate-button { width: 100%; margin-top: 12px; }
.generation-panel { min-height: 580px; padding: 28px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 18px; background: var(--surface-soft); }
.empty-generation { max-width: 310px; text-align: center; }
.orb { width: 100px; height: 100px; margin: 0 auto 22px; display: grid; place-items: center; border: 1px solid rgba(107,24,75,.2); border-radius: 50%; color: var(--sage-dark); background: rgba(255,255,255,.45); font-size: 30px; box-shadow: 0 15px 50px rgba(52,38,74,.1); }
.generated-result { width: 100%; }
.generated-result .outfit-stage { min-height: 310px; }
.generated-result .outfit-stage:has(.garment:nth-child(4)) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.result-top { display: flex; justify-content: space-between; }
.result-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* Home nudge toward the 10-item activation threshold. Full-width tappable card. */
/* One-tap refine chips shown under a generated outfit. */
.refine-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
.refine-chips-label { font-size: var(--fs-label); color: var(--muted); }
.refine-chip { font-size: var(--fs-label); padding: 7px 14px; border-radius: var(--radius-pill); border: 1px solid var(--line); background: var(--surface-soft); color: var(--accent-text); cursor: pointer; transition: background .15s, border-color .15s; }
.refine-chip:hover { background: var(--accent-soft); border-color: var(--accent); }
.refine-chip[hidden] { display: none; }
/* «مش مناسبة» hides behind «المزيد» with the rest: a quiet, borderless entry — the
   learning loop's door, not a competing action. Inherits the chip's pill geometry;
   colours are theme variables, so dark mode needs no extra rule. */
.refine-chip.reject-entry { background: none; border-style: dashed; color: var(--muted); }
.refine-chip.reject-entry:hover { color: var(--accent-text); border-color: var(--muted); background: none; }
.refine-more { color: var(--muted); background: none; border-style: dashed; }
/* Result copy: one context line, a reason clamped to two lines — never an essay. */
.result-context { margin-top: 10px; color: var(--muted); font-size: 12px; font-weight: 600; }
.result-reason { margin: 8px 0 0; color: var(--ink); font-size: 13px; line-height: 1.7; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Server warnings: one quiet amber line each — visible, not shouting, both themes. */
.result-warning { margin: 8px 0 0; padding: 8px 11px; border-radius: 8px; color: #8a5a12; background: rgba(214, 158, 46, .12); font-size: 11.5px; line-height: 1.6; }
html[data-theme="dark"] .result-warning { color: #e2b573; background: rgba(214, 158, 46, .14); }
/* The style-mood gap note (styleGapFeel) and its way to the shop tab — a link, 44px tall to tap. */
.result-style-gap .result-warning { margin-bottom: 0; }
.style-gap-shop { display: block; min-height: 44px; padding: 6px 0; border: 0; background: none; color: var(--accent); font: inherit; font-size: 12px; font-weight: 700; text-align: start; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
/* «جرب كمان»: the stylist's runners-up as small tappable outfit stacks. */
.alt-section { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
.alt-label { display: block; margin-bottom: 8px; color: var(--muted); font-size: var(--fs-label); font-weight: 700; }
.alt-row { display: flex; gap: 10px; }
.alt-outfit { display: flex; gap: 3px; padding: 7px; border: 1px solid var(--line); border-radius: 12px; background: var(--white); cursor: pointer; transition: border-color .15s; }
.alt-outfit:hover { border-color: var(--sage-dark); }
.alt-outfit .photo-frame, .alt-outfit img, .alt-thumb-swatch { width: 42px; height: 54px; border-radius: 6px; object-fit: cover; overflow: hidden; }
.alt-thumb-swatch { display: block; background: var(--c, var(--sand)); }
/* The advanced chat, collapsed under the result by default. */
/* Stage 2's quiet entry row into stage 3 (§6.4) — the same dashed affordance the
   old <details> summary drew, now a full-width button that switches stages instead
   of expanding in place. Theme variables keep it honest in dark mode; text-align
   start keeps it honest in RTL and LTR alike. */
/* Inside stage 3 the card sits directly under the compact top bar — the collapse-era
   28px gap would double the topbar's own margin. */
/* تسوق معي as a page: the old dialog's content wearing a card. */
.shop-page-form { max-width: 560px; padding: 20px; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--white); box-shadow: var(--shadow); }
.loading-orb { animation: breathe 1s ease infinite alternate; }
@keyframes breathe { to { transform: scale(1.12); opacity: .55; } }

/* Generation progress: a real bar + a named step, so "is it working?" is never a question. */
.gen-progress { width: min(280px, 80%); height: 6px; margin: 16px auto 0; border-radius: var(--radius-pill); background: var(--surface-soft); overflow: hidden; }
.gen-progress > span { display: block; height: 100%; width: 0; border-radius: inherit; background: var(--accent); transition: width .4s cubic-bezier(.4,0,.2,1); }
.empty-generation.generating h2 { transition: opacity .2s ease; }
/* «إلغاء» (§14.2): quiet by design — a way out of the wait, not a competing action. */
.gen-cancel { margin: 14px auto 0; min-height: 34px; padding: 0 22px; font-size: 12px; }

/* Wardrobe report (on-demand gap analysis on the analytics page). */
.analytics-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.wardrobe-report { margin: 18px 0 4px; padding: 20px; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--white); box-shadow: var(--shadow); }
.wardrobe-report[hidden] { display: none; }
.report-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.report-head h2 { margin: 4px 0 0; font-size: 20px; }
.report-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 16px 0 4px; }
.report-summary article { padding: 12px; border-radius: var(--radius-md); background: var(--surface-soft); text-align: center; }
.report-summary strong { display: block; font-size: 22px; color: var(--accent-text); font-variant-numeric: tabular-nums; }
.report-summary small { color: var(--muted); font-size: 10px; line-height: 1.4; }
.report-subtitle { margin: 18px 0 8px; font-size: 13px; color: var(--muted); font-weight: 700; }
.report-rows { display: grid; gap: 6px; }
.report-row { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 10px; padding: 10px 12px; border-radius: var(--radius-md); background: var(--surface-soft); font-size: 13px; }
.report-row-count { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.report-row-state { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: var(--radius-pill); }
.report-row.is-ok .report-row-state { color: var(--ok-text); background: rgba(46,158,107,.14); }
.report-row.is-gap .report-row-state { color: var(--danger-text); background: rgba(192,71,63,.12); }
.report-suggestions { margin: 0; padding-inline-start: 18px; display: grid; gap: 7px; }
.report-suggestions li { font-size: 13px; line-height: 1.7; }
.report-note { margin: 14px 0 0; color: var(--muted); font-size: 11px; }
.report-empty { color: var(--muted); font-size: 13px; text-align: center; padding: 10px; }
@media (max-width: 620px) {
  .analytics-actions { width: 100%; }
  .analytics-actions button { flex: 1; }
  .report-summary { grid-template-columns: 1fr; }
}

/* The «حاول تاني» affordance inside the honest AI-unreachable bubble. Colors come from
   the themed .secondary-button base, so light/dark and RTL need nothing extra here. */
.chat-message .chat-retry { margin-top: 10px; padding: 7px 16px; font-size: 12px; }

/* The old pre-redesign thumbnail-strip rules for .chat-outfit-strip /
   .chat-outfit-piece lived here. They are gone: the ONLY producer of that markup
   is appendChatOutfitPreview, whose card is styled by the stage-3 redesign block
   above — these later equal-specificity leftovers were overriding it (review
   finding: bordered 74px tiles, muted-on-dark captions). */
/* Brief highlight when a chat piece is opened in the wardrobe. */
.item-card.is-highlighted { outline: 3px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .gen-progress > span { transition: none; }
  .loading-orb { animation: none; }
}
.chat-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; }
.chat-heading h2 { margin: 4px 0 6px; }
.chat-heading p { max-width: 650px; margin: 0; }
.chat-status { padding: 7px 11px; display: inline-flex; align-items: center; gap: 7px; flex: 0 0 auto; border-radius: var(--radius-pill); color: var(--accent-text); background: var(--accent-soft); font-size: 10px; font-weight: 700; }
.chat-status i { width: 7px; height: 7px; border-radius: 50%; background: #3f7a45; box-shadow: 0 0 0 3px rgba(63,122,69,.14); }
@keyframes typing-dots { from { width: 0; } }
/* The legacy .chat-suggestions pill rules are gone: the redesign's starter CARDS
   (.chat-sug, 2-up grid) own this container now, and the old flex/pill rules at
   this later point in the cascade were collapsing them (review finding). */
.sr-only { width: 1px; height: 1px; position: absolute; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }

.saved-grid { grid-template-columns: repeat(4, 1fr); }
.saved-grid .look-preview { height: 235px; }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; }
.stats-grid article { padding: 20px; border: 1px solid var(--line); border-radius: 12px; background: var(--white); }
.stats-grid span, .stats-grid small { display: block; color: var(--muted); font-size: 11px; }
.stats-grid strong { display: block; margin: 8px 0 5px; font-size: 31px; }
.positive { color: #3f7a45 !important; }
.warning { color: #9a7d2e !important; }
.analytics-grid { margin-top: 18px; display: grid; grid-template-columns: 1.4fr 1fr; gap: 18px; }
.analytics-intelligence-grid { margin-top: 18px; display: grid; grid-template-columns: 1.15fr .85fr; gap: 18px; }
.chart-card { padding: 24px; }
.bar-chart { height: 245px; padding-top: 30px; display: flex; align-items: flex-end; justify-content: space-around; border-bottom: 1px solid var(--line); }
.bar { width: 8%; position: relative; border-radius: var(--radius-sm) 5px 0 0; background: var(--sage); }
.bar span { position: absolute; bottom: -27px; right: 50%; transform: translateX(50%); color: var(--muted); font-size: 10px; }
.donut-wrap { min-height: 240px; display: flex; align-items: center; justify-content: space-around; gap: 20px; }
.donut { width: 150px; height: 150px; position: relative; display: grid; place-items: center; border-radius: 50%; background: conic-gradient(var(--sand) 0 33.33%, var(--sage-dark) 33.33% 66.66%, #6d5a8c 66.66% 91.66%, var(--clay) 91.66%); }
.donut::before { content: ""; width: 92px; height: 92px; position: absolute; border-radius: 50%; background: var(--white); }
.donut span { z-index: 1; font-size: 26px; font-weight: 700; text-align: center; }
.donut small { display: block; color: var(--muted); font-size: 11px; font-weight: 400; }
.legend { display: grid; gap: 12px; }
.legend span { display: grid; grid-template-columns: auto 1fr auto; gap: 8px; align-items: center; color: var(--muted); font-size: 11px; }
.legend i { width: 9px; height: 9px; border-radius: 50%; }
.legend b { color: var(--ink); }
.sand { background: var(--sand); }.dark { background: var(--sage-dark); }.sage { background: #6d5a8c; }.clay { background: var(--clay); }
.gap-list, .memory-summary { margin-top: 18px; display: grid; gap: 9px; }
.gap-item, .memory-item { padding: 12px 13px; display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
.gap-item strong, .gap-item span, .memory-item strong, .memory-item span { display: block; }
.gap-item span, .memory-item span { margin-top: 2px; color: var(--muted); font-size: 10px; line-height: 1.6; }
.gap-item b { min-width: 58px; padding: 6px 8px; border-radius: var(--radius-pill); color: var(--accent-text); background: var(--accent-soft); text-align: center; font-size: 10px; }
.memory-item { grid-template-columns: auto 1fr; }
.memory-item i { width: 30px; height: 30px; display: grid; place-items: center; border-radius: 50%; color: var(--sage-dark); background: var(--accent-soft); font-style: normal; font-weight: 700; }

/* The [hidden] attribute always wins. Any class that sets `display` (grid, flex) outranks
   the browser's own [hidden] rule, and this file had patched that trap one class at a
   time — yet the add-piece card still showed «معرفناش نقرأ القطعة» under every
   SUCCESSFUL analysis (QA, 2026-10-05), with a «جرّب تاني» that spent a paid call, and
   the same leak showed a stale «دي غير محدد؟», an empty dot on «فلاتر» and a hidden
   compare button. One rule for all of them. */
[hidden] { display: none !important; }
/* `color` too, not only the background: a dialog kept the browser's default black text,
   which in the dark theme sat on a near-black panel (1.25:1) — titles, «×» and the
   sign-in labels in 15 dialogs were unreadable (QA, 2026-10-05). */
dialog { width: min(560px, calc(100% - 30px)); padding: 0; border: 0; border-radius: 20px; background: var(--white); color: var(--ink); box-shadow: 0 25px 80px rgba(0,0,0,.22); }
dialog::backdrop { background: rgba(24,18,30,.62); backdrop-filter: blur(3px); }
dialog form { padding: 25px; }
.modal-heading { display: flex; justify-content: space-between; }

/* ---- §11 Add Item menu: three doors, every one of them a photo ------------------- */
.add-menu-dialog { width: min(380px, calc(100% - 30px)); }
.add-menu { padding: 20px; display: grid; gap: 10px; }
.add-menu .modal-heading { align-items: center; margin-bottom: 4px; }
.add-menu .modal-heading h2 { font-size: 18px; }
.add-menu-entry { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 54px; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-soft); color: var(--ink); font-size: 14px; font-weight: 700; text-align: start; cursor: pointer; }
.add-menu-entry svg { flex: 0 0 auto; color: var(--sage-dark); }
.add-menu-entry:hover { border-color: var(--sage-dark); background: var(--accent-soft); }
.add-menu-entry:focus-visible { outline: 2px solid var(--sage-dark); outline-offset: 2px; }
/* The quiet by-hand line under the three doors (owner, 2026-10-23). */
.add-menu-link { display: block; width: 100%; margin-top: 2px; padding: 10px 4px; border: 0; background: none; color: var(--ink-soft); font-size: 13px; text-align: center; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.add-menu-link:hover { color: var(--ink); }

/* «صورة فيها عدة قطع» — the detection review sheet. */
#detect-review { width: min(560px, calc(100vw - 32px)); border: 0; border-radius: var(--radius-lg, 18px); padding: 0; }
.detect-review-sheet { padding: 18px 18px 16px; display: flex; flex-direction: column; gap: 10px; max-height: 82vh; }
.detect-hint { margin: 0; color: var(--ink-soft); font-size: 13px; }
.detect-status { font-size: 13.5px; color: var(--ink-soft); padding: 10px 2px; }
.detect-pieces { display: flex; flex-direction: column; gap: 10px; overflow-y: auto; }
.detect-piece { display: flex; align-items: center; gap: 12px; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-soft); }
.detect-piece.excluded { opacity: .45; }
.detect-piece img { width: 64px; height: 64px; object-fit: contain; border-radius: 10px; background: #fff; flex: 0 0 auto; }
.detect-piece .detect-fields { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.detect-piece input[type="text"] { width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; font: inherit; font-size: 14px; background: #fff; }
.detect-piece .detect-meta { font-size: 12px; color: var(--ink-soft); }
.detect-piece input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--sage-dark); flex: 0 0 auto; }
.detect-actions { display: flex; gap: 10px; justify-content: flex-start; padding-top: 4px; }

/* ---- §14 low-confidence identity question: words, never a number --------------- */
.low-confidence-ask { display: grid; gap: 10px; margin-bottom: 14px; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--accent-soft); }
.lowconf-question { margin: 0; font-size: 15px; font-weight: 700; color: var(--ink); }
.lowconf-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.lowconf-actions button { padding: 8px 20px; min-height: 40px; }

/* ---- §15 multi-item chooser: a question with names, never a silent pick --------- */
.multi-item-choice { display: grid; gap: 10px; margin-bottom: 14px; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--accent-soft); }
.multi-item-choice[hidden] { display: none; }
.multi-item-choice strong { font-size: 15px; color: var(--ink); }
.multi-item-choice p { margin: 0; color: var(--muted); font-size: 13px; }
.multi-item-options { display: flex; gap: 8px; flex-wrap: wrap; }
.multi-item-options[hidden] { display: none; }
.multi-item-option { padding: 10px 18px; min-height: 44px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--ink); font-size: 14px; font-weight: 700; cursor: pointer; }
.multi-item-option:hover { border-color: var(--accent-text); }
.multi-item-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.multi-item-actions button { padding: 8px 20px; min-height: 40px; }

/* ---- §21 add-failure state: one sentence, one plain retry ----------------------- */
.add-failure { display: grid; gap: 10px; margin-bottom: 14px; padding: 14px 16px; border-radius: var(--radius-md); color: #a4483a; background: #f3e2dd; }
.add-failure p { margin: 0; font-size: 13px; font-weight: 700; }
.add-failure .secondary-button { justify-self: start; min-height: 40px; }
html[data-theme="dark"] .add-failure { color: #e69684; background: rgba(185,95,75,.18); }
/* «عندك قطعة شبهها» / «الصورة دي متضافة قبل كده» — said inside the add dialog, in
   the plum family: a question, not an error (QA, 2026-10-05). */
.duplicate-notice { display: grid; gap: 10px; margin: 0 0 14px; padding: 12px 14px; border: 1px solid var(--accent-line); border-radius: var(--radius-md); color: var(--ink); background: var(--accent-soft); font-size: 13px; font-weight: 600; }
.duplicate-notice p { margin: 0; }
.duplicate-notice-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.duplicate-notice-actions .secondary-button { min-height: 40px; }
/* «دي محتاجة حساب» — up front for a guest, on the pages that need one. */
.guest-note { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 14px; padding: 12px 14px; border: 1px solid var(--accent-line); border-radius: var(--radius-md); color: var(--ink); background: var(--accent-soft); font-size: 13px; font-weight: 600; }
.guest-note p { margin: 0; flex: 1 1 200px; }
.guest-note .secondary-button { min-height: 40px; }
/* The shop score says what it measures (QA, 2026-10-05: a bare «٨١٪» next to the verdict). */
.shop-worth { display: grid; justify-items: center; gap: 2px; line-height: 1.1; }
.shop-worth small { font-size: 10px; font-weight: 600; color: var(--muted); white-space: nowrap; }
/* A spent allowance (free limit used → Sartel Plus). The plum family, never the
   error red: nothing broke, and on the web it is an offer. One component on every
   surface — the add card, the bulk dialog, the chat, the result page, review, shop. */
.quota-notice { display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--accent-line); border-radius: var(--radius-md); color: var(--ink); background: var(--accent-soft); }
.quota-notice p { margin: 0; font-size: 13px; line-height: 1.7; }
.quota-notice .quota-notice-main { font-weight: 700; }
.quota-notice .quota-notice-hint { color: var(--muted); font-size: 12px; }
.quota-notice .quota-upgrade { justify-self: start; min-height: 44px; padding: 0 18px; border-radius: 999px; font-size: 13px; font-weight: 700; }
.add-failure.is-allowance,
html[data-theme="dark"] .add-failure.is-allowance { padding: 0; color: var(--ink); background: transparent; }
.add-failure .quota-notice p { font-weight: 400; }
/* The trip plan's cost, said under the stylist's question (subscription quotas). */
.chat-cost-note { margin: 6px 0 0; font-size: 12px; color: var(--muted); }

.analysis-status + .quota-notice,
.bulk-summary + .quota-notice { margin-top: 10px; }
.result-allowance { margin-bottom: 12px; }
.chat-message .quota-notice { margin-top: 10px; padding: 10px 12px; }
.close-button { width: 44px; height: 44px; border: 0; border-radius: 50%; background: var(--paper); font-size: 23px; }
.upload-zone { min-height: 190px; position: relative; overflow: hidden; display: grid; place-items: center; align-content: center; gap: 4px; border: 1px dashed #cfc7d6; border-radius: 12px; background: var(--surface-soft); cursor: pointer; }
.upload-zone:hover { border-color: var(--sage); background: var(--accent-soft); }
.upload-zone input { width: 1px; height: 1px; position: absolute; opacity: 0; pointer-events: none; }
.upload-placeholder { display: grid; place-items: center; gap: 5px; text-align: center; }
.upload-placeholder > span:last-child { color: var(--muted); font-size: 10px; }
.upload-placeholder .upload-tip { max-width: 30ch; color: var(--ink); font-size: 12px; }
.upload-zone.has-image .upload-tip { display: none; }
.upload-icon { color: var(--sage); font-size: 32px; }
.upload-zone.has-image { min-height: 72px; border-style: solid; }
.upload-zone.has-image .upload-icon { font-size: 23px; }
.photo-gallery { margin-top: 12px; display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.photo-gallery[hidden] { display: none; }
.photo-thumb { min-width: 0; position: relative; aspect-ratio: 1; overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
.photo-thumb:first-child { box-shadow: 0 0 0 2px var(--sage); }
.photo-thumb img { width: 100%; height: 100%; display: block; object-fit: cover; }
.photo-thumb small { position: absolute; right: 5px; bottom: 5px; padding: 2px 5px; border-radius: var(--radius-sm); color: white; background: rgba(31,25,38,.75); font-size: 11px; }
.remove-photo { width: 25px; height: 25px; position: absolute; top: 5px; left: 5px; display: grid; place-items: center; border: 0; border-radius: 50%; color: white; background: rgba(158,68,58,.88); font-size: 15px; line-height: 1; }
/* The way back from the server's cutout to the photo the user took. It sits in the
   slot the old in-browser remove-background icon occupied before that feature was
   removed, so a cleaned thumbnail reads as "there is a way back from this". */
.restore-bg-photo { width: 25px; height: 25px; position: absolute; top: 5px; right: 5px; z-index: 2; display: grid; place-items: center; border: 0; border-radius: 50%; color: white; background: rgba(58,88,74,.9); font-size: 13px; line-height: 1; }
.restore-bg-photo .icon { width: 15px; height: 15px; }

/* The camera guide (§9): a quiet sheet — furniture
   the first time, gone forever after. Vars only, so both themes come for free. */
.camera-guide { margin-top: 12px; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-soft); }
.camera-guide[hidden] { display: none; }
.camera-guide strong { display: block; margin-bottom: 6px; font-size: var(--fs-label); }
.camera-guide ul { margin: 0 0 10px; padding-inline-start: 18px; color: var(--muted); font-size: var(--fs-caption); line-height: 1.9; }
.camera-guide button { min-height: 38px; font-size: var(--fs-caption); }

/* Server-side photo prep (§8). The status line borrows .analysis-status wholesale
   (setCleanStatus adds the class) so «بنجهّز القطعة…» breathes exactly like the
   analysis line above it; only the hidden-guard is its own, because the borrowed
   display:flex would otherwise outrank the UA's [hidden]. */
.clean-photo-status[hidden] { display: none !important; }
.clean-photo-status #clean-photo-retake { margin-inline-start: auto; min-height: 32px; padding: 4px 10px; font-size: var(--fs-caption); flex: 0 0 auto; }
.clean-photo-controls { margin-top: 8px; }
.clean-photo-controls[hidden] { display: none; }
/* Deliberately a sentence, not a button: nobody is "in an editor" here. */
.clean-photo-adjust { padding: 4px 2px; border: none; background: none; color: var(--muted); font-size: var(--fs-caption); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.clean-photo-adjust:hover { color: var(--sage-dark); }
/* needs_review from the server's own quality gate: the same sentence, louder. */
.clean-photo-controls.needs-review .clean-photo-adjust { color: #8a6d24; text-decoration-color: currentColor; }
html[data-theme="dark"] .clean-photo-controls.needs-review .clean-photo-adjust { color: #e2b573; }
.clean-photo-actions { margin-top: 8px; display: flex; gap: 8px; }
.clean-photo-actions[hidden] { display: none; }
.clean-photo-actions button { flex: 1; min-height: 38px; font-size: var(--fs-caption); }
.add-more-photos { margin-top: 9px; padding: 7px 11px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--sage-dark); background: var(--white); font-size: 11px; font-weight: 700; }
.analysis-status { margin-top: 12px; padding: 10px 12px; display: flex; align-items: center; gap: 9px; border-radius: 12px; color: var(--muted); background: var(--surface-soft); font-size: 11px; }
.analysis-status.analyzing { color: #635b6b; background: var(--surface-soft); }
.analysis-status.success { color: #2f6b39; background: #e2efe0; }
.analysis-status.warning { color: #8a6d24; background: #f4eedd; }
.analysis-status.error { color: #a4483a; background: #f3e2dd; }
.analysis-dot { width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%; background: currentColor; opacity: .75; }
.analysis-status.analyzing .analysis-dot { animation: breathe .7s ease infinite alternate; }
.bulk-help { margin: 8px 0 18px; color: var(--muted); font-size: 12px; }
.bulk-summary { margin-top: 12px; padding: 10px 12px; border-radius: 8px; color: var(--muted); background: var(--surface-soft); font-size: 11px; }
.bulk-queue { max-height: 280px; margin-top: 12px; overflow: auto; display: grid; gap: 7px; }
.bulk-queue[hidden] { display: none; }
.bulk-row { padding: 9px 10px; display: grid; grid-template-columns: 36px 1fr auto; align-items: center; gap: 9px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
.bulk-row img { width: 36px; height: 36px; object-fit: cover; border-radius: var(--radius-sm); }
.bulk-row strong, .bulk-row small { display: block; }
.bulk-row strong { overflow: hidden; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.bulk-row small { margin-top: 2px; color: var(--muted); font-size: 12px; }
.bulk-row b { color: var(--sage-dark); font-size: 10px; }
.bulk-row.error b { color: #a4483a; }
.bulk-row.success b { color: var(--accent-text); }
/* §31: an analysis that never answered still saves its row — as a draft the user
   should look at, worded amber rather than dressed as either success or failure. */
.bulk-row.review b { color: #a07a2f; }
html[data-theme="dark"] .bulk-row.review b { color: #d9b36a; }
/* §27 Bulk Selection: the pre-run queue is a photo grid — count in the summary,
   each tile removable. */
.bulk-queue.as-grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); max-height: 320px; }
.bulk-tile { position: relative; aspect-ratio: 1; overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); }
.bulk-tile img { width: 100%; height: 100%; display: block; object-fit: cover; }
/* §20: a row's actions (the §15 labels + escape, «جرّبي تاني», «راجعيها») span the
   row under its message. */
.bulk-row-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 6px; }
.bulk-row-actions button { min-height: 36px; padding: 6px 14px; font-size: 12px; }
.bulk-row.choice b { color: var(--accent-text); }
.toast [data-undo-delete] { margin-inline-start: 10px; padding: 4px 9px; border: 1px solid rgba(255,255,255,.55); border-radius: var(--radius-sm); color: white; background: transparent; font-weight: 700; }
.analysis-fields { margin-top: 15px; padding: 12px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface-soft); }
.analysis-fields[hidden] { display: none; }
.analysis-fields span { min-width: 0; }
.analysis-fields .analysis-wide { grid-column: span 2; }
.analysis-fields small, .analysis-fields b { display: block; }
.analysis-fields small { color: var(--muted); font-size: 12px; }
.analysis-fields b { margin-top: 2px; overflow: hidden; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.brand-field > small { margin-top: 5px; display: block; color: var(--muted); font-size: 10px; font-weight: 400; }

/* ---- Add-item dialog: the reviewable item card -------------------------------------
   The dialog has four states — photo / analysing / result / failure (setItemStage in
   src/app.js). The card below is states 3 and 4; .review-skeleton is state 2 and is
   deliberately the SAME shape, so the change reads as the card filling in.
   Built on the documented token scales (docs/handover/05-Design-System.md §§3,4,10):
   the --space, --radius, --fs and --lh scales, and --accent / --accent-soft for focus —
   no fresh magic numbers, and it inherits both themes for free. */
.review-card, .review-skeleton {
  margin-top: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--white);
}
.review-card[hidden], .review-skeleton[hidden] { display: none; }
.review-card-head h3 { margin: 0; color: var(--ink); font-size: var(--fs-h3); line-height: var(--lh-h3); }
.review-card-head p { margin: var(--space-1) 0 0; color: var(--muted); font-size: var(--fs-body-sm); line-height: var(--lh-body-sm); }
/* U03: manual entry starts with the fields. Photo analysis and editing retain
   their existing review layout; this mode is only for a new piece with no photo. */
#add-item-form[data-manual="true"] #upload-zone,
#add-item-form[data-manual="true"] #analysis-status,
#add-item-form[data-manual="true"] .review-card-head h3,
#add-item-form[data-manual="true"] .field-group > .field-group-label,
#add-item-form[data-manual="true"] .quick-confirm > .field-group-label { display: none; }
#add-item-form[data-manual="true"] .review-card { margin-top: 0; padding: 0; border: 0; background: transparent; }
#add-item-form[data-manual="true"] .quick-confirm { margin-top: 0; }
#manual-add-photo { min-height: 44px; margin-top: var(--space-2); }
#manual-add-photo[hidden] { display: none; }

/* One quiet section label instead of a wall of them. */
.field-group { margin-top: var(--space-4); }
.field-group-label {
  display: block; margin-bottom: var(--space-2);
  color: var(--muted); font-size: var(--fs-caption); font-weight: 700;
  letter-spacing: .04em;
}
.review-card .field { display: block; margin-bottom: var(--space-3); font-size: var(--fs-label); font-weight: 700; }
.review-card .field > span { display: block; margin-bottom: var(--space-1); color: var(--muted); font-size: var(--fs-caption); font-weight: 600; }
.review-card .form-row { margin-top: 0; gap: var(--space-3); }
.review-card .form-row .field { margin-bottom: 0; }

/* Filled inputs: 46px targets, no hard border until focus. */
.review-card input, .review-card select, .review-card textarea {
  min-height: 46px; margin-top: 0; padding: var(--space-3);
  border: 1px solid transparent; border-radius: var(--radius-md);
  background: var(--surface-soft); color: var(--ink);
  font-size: var(--fs-body); font-weight: 500;
}
.review-card textarea { min-height: 84px; }
.review-card input:focus, .review-card select:focus, .review-card textarea:focus,
.color-swatch-button:focus-visible {
  border-color: var(--accent); background: var(--white);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.review-card input::placeholder { color: var(--muted); font-weight: 400; }
.review-card .metadata-details { border-radius: var(--radius-md); background: var(--surface-soft); }
.review-card .metadata-details .metadata-details { background: var(--white); }
.review-card .metadata-details summary { min-height: 32px; display: flex; align-items: center; font-size: var(--fs-label); }
/* Optional item groups use the existing palette, with a quiet current-value preview. */
#item-more-details { padding: 0; border: 0; background: transparent; }
#item-more-details > summary { min-height: 44px; width: fit-content; text-decoration: underline; text-underline-offset: 4px; }
.item-details-hint { margin: 0 0 12px; color: var(--muted); font-size: 13px; line-height: 1.7; }
#item-more-details .item-detail-group { margin-top: 10px; border: 1px solid var(--line); border-radius: 12px; background: var(--white); min-width: 0; }
#item-more-details .item-detail-group > summary { display: flex; align-items: center; gap: 14px; min-height: 72px; margin: 0; padding: 14px; list-style: none; }
#item-more-details .item-detail-group > summary::-webkit-details-marker { display: none; }
.item-group-copy { display: grid; gap: 5px; min-width: 0; flex: 1; }
.item-group-title { color: var(--ink); font-size: 14px; line-height: 1.5; font-weight: 700; }
.item-group-value { color: var(--muted); font-size: 12px; line-height: 1.6; font-weight: 400; overflow-wrap: anywhere; }
.item-group-chevron { width: 8px; height: 8px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); flex: 0 0 auto; margin: 0 3px 4px; }
.item-detail-group[open] > summary .item-group-chevron { transform: rotate(225deg); margin-bottom: 0; }
.item-group-body { padding: 0 14px 16px; min-width: 0; }
.item-group-body .adv-section { min-width: 0; }
.item-group-body .adv-section:first-child { margin-top: 0; }
.item-detail-group:not([data-item-group="description"]) .adv-section > legend { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.item-group-body input, .item-group-body select, .item-group-body textarea { min-width: 0; max-width: 100%; min-height: 44px; }
.item-group-body input[type="checkbox"] { min-height: 24px; width: 24px; height: 24px; }
.item-group-body .favorite-field { min-height: 44px; }
.item-group-body .metadata-details > summary { min-height: 44px; }
.item-analysis-details[hidden] { display: none; }
#item-more-details summary:focus-visible { outline: 2px solid var(--sage-dark); outline-offset: 3px; border-radius: 8px; }

/* The read-out keeps two columns on a phone: with the blank rows filtered out the
   values are short, and one column turned it into a tall list under the save button. */
.review-card .analysis-fields { border-radius: var(--radius-md); }
@media (max-width: 420px) {
  .review-card .analysis-fields { grid-template-columns: 1fr 1fr; }
  .review-card .analysis-fields .analysis-wide { grid-column: span 2; }
}

/* The colour field: a swatch that opens the app's own vocabulary grid, not an OS
   colour well that can name nothing. */
.color-swatch-button {
  width: 100%; min-height: 46px; padding: 0 var(--space-3);
  display: flex; align-items: center; gap: var(--space-2);
  border: 1px solid transparent; border-radius: var(--radius-md);
  color: var(--ink); background: var(--surface-soft);
  font: inherit; font-size: var(--fs-body); font-weight: 600; text-align: start;
}
.color-swatch-button i {
  width: 22px; height: 22px; flex: 0 0 auto;
  border: 1px solid rgba(0, 0, 0, .14); border-radius: 50%;
  background: var(--c, var(--sand));
}
.color-swatch-button span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.color-swatch-button:hover { border-color: var(--accent); }

/* ---- The §20 review hero -----------------------------------------------------------
   The large cleaned garment image the review screen leads with, and under it the
   one-line identity «تشينو · زيتوني · قطن/تويل». Vars only: RTL and dark for free. */
.review-hero { margin: var(--space-4) 0 0; }
.review-hero[hidden] { display: none; }
.review-hero img {
  display: block; width: 100%; max-height: 320px; object-fit: contain;
  border-radius: var(--radius-md); background: var(--surface-soft);
}
.review-summary {
  margin: var(--space-2) 0 0; text-align: center;
  color: var(--muted); font-size: var(--fs-body-sm); font-weight: 600;
}
.review-summary[hidden] { display: none; }

/* ---- Quick confirm (UX §10, spec §21) ----------------------------------------------
   Only what changes the garment's identity is offered for a one-tap confirmation —
   the colour (the summary line above carries subtype and fabric). The season chips
   moved behind «تعديل التفاصيل» (§21) but keep the ask-chip grammar (pill, pressed =
   solid accent) so "tap to confirm" reads the same everywhere. Vars only. */
.quick-confirm { margin-top: var(--space-4); }
.quick-confirm-row { display: grid; grid-template-columns: 1fr; gap: var(--space-3); align-items: start; }
.season-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.season-chip {
  min-height: 38px; padding: var(--space-1) var(--space-3);
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  color: var(--muted); background: var(--surface-soft);
  font: inherit; font-size: var(--fs-label); font-weight: 700;
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
.season-chip:hover { border-color: var(--accent); }
.season-chip:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.season-chip[aria-pressed="true"] { border-color: var(--accent); color: var(--on-accent); background: var(--accent); }
@media (prefers-reduced-motion: reduce) { .season-chip { transition: none; } }

/* State 2. Rows mirror the card: eyebrow, title, group label, one field, a 2-up row,
   the collapsed "more data" bar. */
.sk { display: block; border-radius: var(--radius-md); background: var(--surface-soft); position: relative; overflow: hidden; }
.sk-eyebrow { width: 45%; height: 20px; }
.sk-title { width: 70%; height: 16px; margin-top: var(--space-2); }
.sk-group-label { width: 22%; height: 10px; margin-top: var(--space-5); }
.sk-field { height: 46px; margin-top: var(--space-2); }
.sk-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.sk-details { height: 44px; margin-top: var(--space-4); }
.sk::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
  transform: translateX(-100%);
  animation: sk-shimmer 1.5s ease-in-out infinite;
}
html[data-theme="dark"] .sk::after { background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .07), transparent); }
@keyframes sk-shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .sk::after { display: none; } }

/* ---- "Ask, don't guess": one field the photo could not answer -----------------------
   The card exists to be CHECKED, and a field the analysis had no evidence for is the one
   thing checking cannot fix on its own — the user cannot tell a guess from a reading.
   So the guess is drawn as a guess (dashed, unfilled) with one line saying why, and one
   tap turns it into an answer (solid, filled). Ignoring it is always valid: the value is
   already in the form either way, so the save button never waits on this.

   Chips rather than a dropdown because on a phone a <select> is a whole modal for a
   one-second decision, and because a cut is a SHAPE — the silhouettes carry the meaning
   for anyone who could not pick «باجي» out of a list of Arabic transliterations.
   Tokens only: the --space/--radius/--fs scales and --accent/--line/--surface-soft, so
   both themes and both directions come for free. */
.ask-group { margin-top: var(--space-4); }
.ask-group[hidden] { display: none; }
.ask-field + .ask-field { margin-top: var(--space-4); }
.ask-question {
  display: block; margin-bottom: var(--space-1);
  color: var(--ink); font-size: var(--fs-label); line-height: var(--lh-label); font-weight: 700;
}
.ask-note {
  margin: 0 0 var(--space-2);
  color: var(--muted); font-size: var(--fs-caption); line-height: var(--lh-caption);
}
/* Answered: the sentence explained a guess, and there is no guess left to explain. */
.ask-field[data-state="answered"] .ask-note { display: none; }
.ask-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.ask-chip {
  min-height: 44px; padding: var(--space-2) var(--space-3);
  display: inline-flex; align-items: center; gap: var(--space-2);
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  color: var(--muted); background: var(--surface-soft);
  font: inherit; font-size: var(--fs-label); font-weight: 700;
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
/* One viewBox, one fill, one family — the chips read as six views of the same trouser. */
.ask-chip svg { width: 15px; height: 25px; flex: 0 0 auto; fill: currentColor; }
.ask-chip:hover { border-color: var(--accent); }
.ask-chip:focus-visible {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
/* The model's value, preselected — drawn as the guess it is: dashed and unfilled. */
.ask-chip[aria-checked="true"] {
  border-style: dashed; border-color: var(--accent);
  color: var(--accent-text); background: var(--accent-soft);
}
/* One tap, and it is an answer. */
.ask-field[data-state="answered"] .ask-chip[aria-checked="true"] {
  border-style: solid; border-color: var(--accent);
  color: var(--on-accent); background: var(--accent);
}
@media (prefers-reduced-motion: reduce) { .ask-chip { transition: none; } }
.modal-actions { margin-top: 22px; display: flex; justify-content: flex-end; gap: 8px; }
.danger-button { min-height: 44px; padding: 0 19px; border: 1px solid #b04537; border-radius: 12px; color: white; background: #b04537; font-weight: 700; }
.danger-button:hover { background: #963a2e; }
.confirm-dialog { max-width: 430px; text-align: center; }
.confirm-dialog p { margin-bottom: 0; }
.confirm-dialog .modal-actions { justify-content: center; }
.confirm-icon { width: 48px; height: 48px; margin: 0 auto 14px; display: grid; place-items: center; border-radius: 50%; color: #b04537; background: #f3e2dd; font-size: 24px; font-weight: 700; }
.feedback-dialog { max-width: 520px; }
.body-profile-dialog { max-width: 620px; }
.outfit-review-dialog { max-width: 620px; }
.outfit-review-upload { min-height: 250px; }
.outfit-review-upload img { width: 100%; max-height: 430px; object-fit: contain; border-radius: 12px; }
.outfit-review-upload.has-preview { padding: 8px; border-style: solid; }
.outfit-review-upload.has-preview .upload-placeholder { display: none; }
.outfit-review-result { margin-top: 14px; padding: 15px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-soft); }
.outfit-review-result h3 { margin: 0 0 5px; font-size: 20px; }
.outfit-review-result > p { margin: 0 0 12px; color: var(--muted); }
.review-score-line { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 12px; }
.review-score-line b { color: var(--sage-dark); font-size: 24px; }
.review-section { margin-top: 10px; }
.review-section strong { display: block; margin-bottom: 4px; }
.review-section ul { margin: 0; padding-inline-start: 20px; color: var(--muted); }
.review-quick-fix { margin-top: 12px; padding: 10px 12px; border-radius: 12px; background: var(--surface-soft); }

/* Home quick actions: قيّم لوكي + تسوّق معي */
.quick-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 18px 0; }
.quick-action { display: flex; align-items: center; gap: 12px; text-align: start; color: var(--text); padding: 14px 16px; border: 1px solid var(--border); border-radius: 13px; background: var(--white); cursor: pointer; transition: border-color .15s, transform .15s, box-shadow .15s; }
.quick-action:hover { border-color: var(--sage-dark); transform: translateY(-1px); box-shadow: 0 6px 18px rgba(107,24,75,.12); }
.quick-action-icon { font-size: 26px; line-height: 1; color: var(--accent); }
/* Inline SVG icons (replacing functional emoji): inherit colour, size to their
   container, and never shrink in a flex row. */
.icon { width: 1em; height: 1em; display: inline-block; vertical-align: middle; flex: 0 0 auto; }
.quick-action-icon .icon { width: 26px; height: 26px; }
.upload-icon .icon { width: 32px; height: 32px; }
.upload-zone.has-image .upload-icon .icon { width: 23px; height: 23px; }
.quick-action strong { display: block; font-size: 15px; }
.quick-action small { color: var(--muted); font-size: 11px; line-height: 1.5; }
@media (max-width: 600px) { .quick-actions { grid-template-columns: 1fr; } }

/* Styling mode picker */
.styling-mode-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 14px 0; }
.styling-mode-options label { display: flex; align-items: center; gap: 8px; padding: 13px 14px; border: 1px solid var(--border); border-radius: 12px; cursor: pointer; }
/* The global `input { width:100% }` rule (line ~342) makes these radios full-width,
   pushing the text label outside the card. Reset them to their natural size. */
.styling-mode-options input, .styling-hijab-options input { width: auto; margin: 0; padding: 0; flex: 0 0 auto; }
.styling-mode-options label:has(input:checked) { border-color: var(--sage-dark); background: var(--accent-soft); }
.styling-hijab-row { display: flex; flex-direction: column; gap: 9px; margin-bottom: 6px; }
.styling-hijab-row[hidden] { display: none; }
.styling-hijab-label { color: var(--muted); font-size: 12px; font-weight: 700; }
.styling-hijab-options { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.styling-hijab-options label { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 11px 8px; border: 1px solid var(--border); border-radius: 12px; cursor: pointer; font-size: 13px; }
.styling-hijab-options label:has(input:checked) { border-color: var(--sage-dark); background: var(--accent-soft); }
.account-sub-terms { margin: 0; padding: 4px 14px 12px; color: var(--muted); font-size: 11.5px; line-height: 1.7; }
.account-sub-terms a { color: var(--accent-text); }
.legal-links { margin: 12px 0 0; font-size: 11px; color: var(--muted); text-align: center; line-height: 1.7; }
.legal-links a { color: var(--accent-text); }
/* «إبلاغ» under AI output: there when wanted, never louder than the answer. */
.flag-button { display: block; min-height: 24px; margin-top: 6px; padding: 4px 0; border: 0; background: none; color: var(--muted); font-size: 11px; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.chat-message.thinking .flag-button, .chat-message.user .flag-button { display: none; }
.outfit-review-result .flag-button { margin-top: 12px; }
.flag-dialog { min-width: min(340px, 86vw); }
.flag-help { margin-top: 6px; color: var(--muted); font-size: 12.5px; }
.flag-note { margin-top: 12px; }
.flag-note textarea { width: 100%; resize: vertical; }

/* Shopping verdict accent */
.shopping-verdict { padding: 11px 13px; border-radius: 12px; }
.shopping-verdict.buy { background: #e2efe0; }
.shopping-verdict.buy b { color: #3f7a45; }
.shopping-verdict.maybe { background: #f4eedd; }
.shopping-verdict.maybe b { color: #9a7d2e; }
.shopping-verdict.skip { background: #f3e2dd; }
.shopping-verdict.skip b { color: #a4483a; }
/* «تسوق معي» §9.2 — the result reuses the stylist row's thumbnail grammar («جرب
   كمان»), but these stacks are examples to look at, not buttons: same sizing and
   card face, no cursor, no hover. Theme variables carry light/dark; flex follows
   the document direction, so RTL costs nothing extra. */
.shop-compat { margin: 12px 0 2px; font-weight: 600; }
.shop-thumb-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.shop-similar-thumb, .shop-outfit-stack { display: flex; gap: 3px; padding: 7px; border: 1px solid var(--line); border-radius: 12px; background: var(--white); }
.shop-thumb-row .photo-frame, .shop-thumb-row img, .shop-thumb-row .alt-thumb-swatch { width: 42px; height: 54px; border-radius: 6px; object-fit: cover; overflow: hidden; }
.profile-privacy-note { margin: 0 0 15px; padding: 10px 12px; border-radius: 12px; color: var(--muted); background: var(--surface-soft); font-size: 11px; line-height: 1.7; }
.cloud-status { margin: -5px 18px 14px; padding: 7px 9px; border-radius: var(--radius-sm); color: #aaa3b5; background: rgba(255,255,255,.05); font-size: 12px; line-height: 1.5; text-align: center; }
.cloud-status[data-state="online"] { color: #b8dcbb; background: rgba(120,175,120,.16); }
.cloud-status[data-state="syncing"] { color: #cbbde9; }
.cloud-status[data-state="error"] { color: #f0c2b6; background: rgba(180,91,70,.14); }
/* Never wider than the dialog holding it: the browser caps a modal dialog at
   calc(100% - 6px - 2em), which on a 375px phone is 337px — and «100vw - 32px» (343px)
   overflowed it by 6px (QA, 2026-10-05). */
.account-dialog { width: min(520px, calc(100vw - 32px), 100%); }
.account-auth-actions { grid-template-columns: 1fr 1fr; }
/* ---- Signed-in settings page (account dialog) ------------------------------------
   iOS-style grouped settings: profile header, then cards of rows (icon tile + label +
   secondary line + chevron/pill). All functional IDs are unchanged — this is skin. */
.account-session-panel { display: grid; gap: 14px; margin-top: 2px; }
/* display:grid would defeat the [hidden] attribute (same trap as .brand-field) —
   without this, the signed-OUT dialog shows the empty settings cards below the form. */
.account-session-panel[hidden] { display: none; }

/* Signed-in: an iOS-Settings-style sheet — gray page, borderless white cards, and a
   compact top bar (title at the inline-start, ✕ at the inline-end) instead of the
   brand hero, which belongs to the sign-in view only. */
.account-dialog:has(#account-session-panel:not([hidden])) .auth-subtitle,
.account-dialog:has(#account-session-panel:not([hidden])) .auth-brand { display: none; }
.account-dialog:has(#account-session-panel:not([hidden])) .auth-title {
  text-align: start; font-size: 19px; margin: 4px 0 14px; padding-inline-end: 52px;
}
.account-dialog:has(#account-session-panel:not([hidden])) { background: var(--surface-soft); }
#account-modal:has(#account-session-panel:not([hidden])) { background: var(--surface-soft); }
html[data-theme="dark"] .account-dialog:has(#account-session-panel:not([hidden])),
html[data-theme="dark"] #account-modal:has(#account-session-panel:not([hidden])) { background: var(--paper); }
/* The sticky ✕ floats over BOTH the gray sheet and the white cards while the list
   scrolls — its circle must stay visible against each, in each theme. */
.account-dialog:has(#account-session-panel:not([hidden])) .auth-close {
  background: #eae4e6; border: 1px solid var(--line);
  box-shadow: 0 2px 10px rgba(30, 22, 40, .08);
}
html[data-theme="dark"] .account-dialog:has(#account-session-panel:not([hidden])) .auth-close {
  background: #322b3d; border-color: #3f3650; color: var(--ink);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .35);
}
.account-dialog { max-height: 86dvh; overflow-y: auto; }
@media (max-width: 640px) {
  /* Full-screen sheet on phones, like a native settings page. */
  #account-modal:has(#account-session-panel:not([hidden])) {
    width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh;
    margin: 0; border-radius: 0;
  }
  #account-modal:has(#account-session-panel:not([hidden])) .account-dialog {
    width: 100%; max-height: 100dvh;
    /* Respect BOTH safe areas: without the top inset, the title and the sticky ✕
       sit under the iPhone notch/status bar and the ✕ becomes untappable. */
    padding: calc(14px + var(--safe-top, 0px)) 16px
             calc(28px + var(--safe-bottom, 0px));
  }
  #account-modal:has(#account-session-panel:not([hidden])) .auth-close {
    top: var(--safe-top, 0px);
  }
}

.settings-profile-row { padding-block: 15px; gap: 13px; }
.settings-avatar {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--accent), #5d4680);
  color: var(--on-accent); font-size: 21px; font-weight: 700;
}
/* Dark theme: --on-accent flips near-black but the gradient's fixed plum stop
   stays mid-dark → unreadable initial. Use a dark gradient + light text instead. */
html[data-theme="dark"] .settings-avatar {
  background: linear-gradient(140deg, #3a2d52, #5d4680);
  color: #ece9f1;
}
.settings-email { font-size: 16px; font-weight: 700; overflow-wrap: anywhere; }
.settings-private { display: inline-flex; align-items: center; gap: 5px; color: var(--muted); font-size: 11px; line-height: 1.5; }
.settings-private svg { flex: 0 0 auto; }

/* Borderless white cards floating on the gray sheet, iOS-Settings style. */
.settings-group { border: 0; border-radius: 18px; background: var(--white); overflow: hidden; }
.settings-group[hidden] { display: none; }

.settings-row {
  position: relative;
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 13px 16px; min-height: 52px;
  background: none; border: 0; text-align: start; font: inherit;
  color: var(--text); cursor: pointer; text-decoration: none;
  transition: background .15s ease;
}
/* Inset hairline separators (start at the text edge), not full-width borders. */
.settings-row + .settings-row::after,
.settings-row + a.settings-row::after,
a.settings-row + a.settings-row::after {
  content: ""; position: absolute; top: 0; height: 1px;
  inset-inline-start: 16px; inset-inline-end: 0;
  background: var(--line);
}
.settings-row:hover { background: var(--surface-soft); }
/* Rows fill their card and the card clips (overflow:hidden), so the default
   OUTSIDE focus ring would be invisible — draw it inset instead. Covers the
   <summary> row too, which the global button/link focus rule doesn't reach. */
.settings-row:focus-visible { outline: 3px solid rgba(107, 24, 75, .35); outline-offset: -4px; }
html[data-theme="dark"] .settings-row:focus-visible { outline-color: rgba(183, 165, 220, .5); }
.settings-row[hidden] { display: none; }
.settings-row.is-static { cursor: default; }
.settings-row.is-static:hover { background: none; }

.settings-row-main { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.settings-row-main strong { font-size: 15px; font-weight: 500; line-height: 1.5; }
.settings-row-main small { color: var(--muted); font-size: 11px; line-height: 1.6; }
.settings-row-main small:empty { display: none; }

.settings-chevron { flex: 0 0 auto; color: var(--muted); display: grid; place-items: center; }
html[dir="ltr"] .settings-chevron:not(.settings-disclosure) svg { transform: scaleX(-1); }
.settings-disclosure svg { transition: transform .2s ease; }
.account-danger[open] .settings-disclosure svg { transform: rotate(180deg); }

/* Subscription status pill (className is rewritten by app.js — style the base class). */
.account-sub-status { flex: 0 0 auto; font-size: 11px; font-weight: 700; padding: 4px 11px; border-radius: 999px; background: var(--surface-soft); color: var(--muted); }
.account-sub-status.is-paid { background: rgba(46, 158, 107, .14); color: var(--ok-text); }
.account-sub-status:empty { display: none; }
/* Weather opt-in pill: same shape as the subscription pill. «تفعيل» reads as an
   action (accent, like .settings-action); the granted «مفعّل» borrows is-paid's
   green, whose rgba surface already sits right on both light and dark. */
.weather-optin-state { flex: 0 0 auto; font-size: 11px; font-weight: 700; padding: 4px 11px; border-radius: 999px; background: var(--surface-soft); color: var(--accent-text); }
.weather-optin-state.is-on { background: rgba(46, 158, 107, .14); color: var(--ok-text); }
.weather-optin-state:empty { display: none; }
/* Action row: accent-colored text row (iOS style), not a big filled button. */
.settings-action { color: var(--accent-text); }
.settings-action .settings-row-main strong, .settings-action { font-weight: 600; }
.account-sub-cta { width: 100%; min-height: 50px; font-size: 15px; }
.account-sub-cta[hidden] { display: none; }

/* Data management (details): summary is a row; body sits under a divider. */
.account-danger > summary.settings-row { list-style: none; }
.account-danger > summary.settings-row::-webkit-details-marker { display: none; }
.settings-danger-body { padding: 2px 16px 16px; border-top: 1px solid var(--line); }
/* Shown instead of the password field for accounts that sign in with Google. The
   [hidden] guard is not optional: a display rule on the element itself outranks the
   UA [hidden] rule, which is exactly how this panel's sibling once stayed on screen. */
.account-reauth-google { display: grid; gap: 10px; justify-items: start; padding: 8px 0 2px; }
.account-reauth-google[hidden] { display: none; }
.settings-danger-actions { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.settings-danger-actions > button { flex: 1 1 140px; min-height: 44px; }
.account-danger-note { color: var(--muted); font-size: 11px; line-height: 1.7; margin: 10px 0 0; }

/* Sign out: centered red row, iOS-style. */
.settings-signout { justify-content: center; color: #c0473f; font-size: 15px; }
.settings-signout strong { font-weight: 600; }
html[data-theme="dark"] .settings-signout { color: #e08a80; }
/* ---- Auth (sign in / sign up / reset) — focused single-purpose screen ---- */
.account-dialog { position: relative; }
/* Sticky (not absolute): the dialog scrolls now, and the ✕ must stay reachable
   on a phone even when the user is deep in the settings list. margin-inline-start
   pushes it to the inline-end edge; the negative bottom margin gives its row's
   height back so the brand header doesn't shift down. */
.auth-close { position: sticky; top: 0; margin-inline-start: auto; margin-bottom: -44px; display: block; z-index: 3; }
.auth-brand { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 6px 0 20px; }
.auth-logo { border-radius: 12px; display: block; }
.auth-wordmark { font-family: Georgia, "Times New Roman", serif; font-size: 19px; letter-spacing: 3px; font-weight: 600; color: var(--ink); }
.auth-title { margin: 0 0 6px; font-size: 22px; line-height: 1.35; text-align: center; color: var(--ink); }
.auth-subtitle { margin: 0 0 18px; font-size: 13px; line-height: 1.75; text-align: center; color: var(--muted); }
.auth-message { margin: 0 0 14px; font-size: 13px; line-height: 1.7; text-align: center; color: var(--muted); }
.auth-message:empty { display: none; }
.auth-message[data-state="error"] { color: var(--danger-text); }
.auth-message[data-state="success"] { color: var(--ok-text); }
.auth-submit { width: 100%; margin-top: 14px; min-height: 50px; font-size: 15px; }
.auth-submit[disabled] { opacity: .65; }
.auth-forgot { display: block; width: 100%; text-align: center; margin-top: 14px; }
/* setAuthMode() hides this in sign-up mode via the `hidden` attribute, but the
   `display: block` above outranks the UA's [hidden] rule — so it stayed visible.
   Same class of bug as .styling-hijab-row below. A JS property check passes here;
   only a screenshot catches it. */
.auth-forgot[hidden] { display: none; }
.auth-switch { text-align: center; margin: 16px 0 0; font-size: 13px; color: var(--muted); }
.auth-switch .account-link { margin-top: 0; }
.password-field { position: relative; }
.password-toggle { position: absolute; inset-inline-end: 10px; bottom: 9px; display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; padding: 0; border: 0; background: none; color: var(--muted); cursor: pointer; }
.password-toggle:hover { color: var(--ink); }
.account-hint { color: var(--muted); font-size: 12px; margin: 8px 0 0; }
.account-link { display: inline-block; margin-top: 10px; padding: 4px 0; border: 0; background: none; color: var(--accent); font-size: 13px; font-weight: 600; cursor: pointer; text-decoration: underline; }
.account-link:hover { opacity: .8; }
#account-reset-panel .brand-field { margin: 12px 0; }

/* ---- "Continue with Google" ------------------------------------------------
   Google's own pre-approved button (developers.google.com/identity/branding-guidelines):
   their .gsi-material-button asset, their palette, the unmodified four-colour "G".
   Nothing here may be swapped for a Studio token — the colours, the 1px stroke and the
   logo ARE the licensed asset. Only three things are adapted, none of them brand:
     - width, so it lines up with .auth-submit in this dialog (Google sizes the button
       to its container; the logo and its padding are untouched);
     - logical properties, so the icon sits to the RIGHT of the text in Arabic instead
       of being pinned to the physical left;
     - the font stack keeps Google's own 'Roboto', arial, sans-serif fallback chain and
       appends the app's Arabic face, because Roboto has no Arabic glyphs and the label
       is Arabic here. Google Sans is not self-hostable and the page's CSP allows no
       other font host. */
.gsi-material-button {
  -webkit-user-select: none; user-select: none;
  -webkit-appearance: none; appearance: none;
  background-color: #ffffff; background-image: none;
  border: 1px solid #747775; border-radius: 20px;
  box-sizing: border-box; color: #1f1f1f; cursor: pointer;
  font-family: "Roboto", "IBM Plex Sans Arabic", arial, sans-serif;
  font-size: 14px; height: 40px; letter-spacing: .25px;
  outline: none; overflow: hidden; padding: 0 12px; position: relative;
  text-align: center;
  transition: background-color .218s, border-color .218s, box-shadow .218s;
  vertical-align: middle; white-space: nowrap; width: 100%; margin-top: 4px;
}
.gsi-material-button .gsi-material-button-icon {
  height: 20px; min-width: 20px; width: 20px;
  margin-inline-end: 10px;   /* Google's 10px gap after the logo */
}
.gsi-material-button .gsi-material-button-content-wrapper {
  align-items: center; display: flex; flex-direction: row; flex-wrap: nowrap;
  height: 100%; justify-content: center; position: relative; width: 100%;
}
.gsi-material-button .gsi-material-button-contents {
  flex-grow: 0; font-family: inherit; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; vertical-align: top;
}
.gsi-material-button .gsi-material-button-state {
  transition: opacity .218s; inset: 0; opacity: 0; position: absolute;
}
.gsi-material-button:disabled { cursor: default; background-color: #ffffff61; border-color: #1f1f1f1f; }
.gsi-material-button:disabled .gsi-material-button-contents,
.gsi-material-button:disabled .gsi-material-button-icon { opacity: 38%; }
.gsi-material-button:not(:disabled):active .gsi-material-button-state,
.gsi-material-button:not(:disabled):focus .gsi-material-button-state { background-color: #303030; opacity: 12%; }
.gsi-material-button:not(:disabled):hover { box-shadow: 0 1px 2px 0 rgba(60,64,67,.30), 0 1px 3px 1px rgba(60,64,67,.15); }
.gsi-material-button:not(:disabled):hover .gsi-material-button-state { background-color: #303030; opacity: 8%; }
/* Google's dark theme values, not the app's — same asset, other surface. */
html[data-theme="dark"] .gsi-material-button { background-color: #131314; border-color: #8e918f; color: #e3e3e3; }
html[data-theme="dark"] .gsi-material-button:disabled { background-color: #13131461; border-color: #8e918f1f; }
html[data-theme="dark"] .gsi-material-button:not(:disabled):active .gsi-material-button-state,
html[data-theme="dark"] .gsi-material-button:not(:disabled):focus .gsi-material-button-state,
html[data-theme="dark"] .gsi-material-button:not(:disabled):hover .gsi-material-button-state { background-color: #ffffff; }

/* "or" rule between Google and the email form. */
.auth-divider { display: flex; align-items: center; gap: 12px; margin: 18px 0 2px; color: var(--muted); font-size: 12px; }
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* Sign-up password strength meter (advisory) — see cloud-sync updatePasswordStrength. */
.password-strength { margin-top: 10px; display: flex; align-items: center; gap: 10px; }
.password-strength[hidden] { display: none; }
.password-strength-bar { flex: 1 1 auto; height: 5px; border-radius: var(--radius-pill); background: var(--surface-soft); overflow: hidden; }
.password-strength-bar > span { display: block; height: 100%; width: 0; border-radius: inherit; background: var(--muted); transition: width .25s ease, background .25s ease; }
.password-strength-label { flex: 0 0 auto; min-width: 44px; text-align: start; font-size: 11px; font-weight: 700; color: var(--muted); }
.password-strength[data-level="weak"]   > .password-strength-bar > span { background: #c0473f; }
.password-strength[data-level="fair"]   > .password-strength-bar > span { background: #d08a2c; }
.password-strength[data-level="good"]   > .password-strength-bar > span { background: #3a86c8; }
.password-strength[data-level="strong"] > .password-strength-bar > span { background: #2e9e6b; }
.password-strength[data-level="weak"]   > .password-strength-label { color: var(--danger-text); }
.password-strength[data-level="fair"]   > .password-strength-label { color: var(--warn-text); }
.password-strength[data-level="good"]   > .password-strength-label { color: var(--info-text); }
.password-strength[data-level="strong"] > .password-strength-label { color: var(--ok-text); }
@media (prefers-reduced-motion: reduce) { .password-strength-bar > span { transition: none; } }
.body-profile-dialog label > span { color: var(--muted); font-size: 12px; font-weight: 400; }
.anchor-picker-dialog { width: min(760px, calc(100vw - 32px)); max-height: 88vh; padding: 24px; overflow: auto; }
.anchor-picker-dialog > p { margin: -5px 0 16px; color: var(--muted); font-size: 12px; }
.anchor-picker-filters { margin-bottom: 14px; display: flex; gap: 7px; flex-wrap: wrap; }
.anchor-picker-filters button { min-height: 32px; padding: 0 12px; border: 1px solid var(--border); border-radius: 12px; color: var(--muted); background: var(--white); font-size: 10px; font-weight: 700; }
.anchor-picker-filters button.active { border-color: var(--sage-dark); color: var(--on-accent); background: var(--sage-dark); }
.anchor-picker-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.anchor-choice { position: relative; padding: 8px; border: 1px solid var(--border); border-radius: 12px; color: var(--text); background: var(--white); text-align: right; overflow: hidden; }
.anchor-choice.selected { border: 2px solid var(--sage-dark); background: var(--accent-soft); }
.anchor-choice img, .anchor-choice .photo-frame, .anchor-choice .garment-art { width: 100%; height: 110px; border-radius: var(--radius-sm); object-fit: contain; }
.anchor-choice img, .anchor-choice .photo-frame { background: var(--cream); }
.anchor-choice .garment-art { background: var(--item-color); filter: none; }
.anchor-choice strong, .anchor-choice small { display: block; }
.anchor-choice strong { margin-top: 7px; font-size: 11px; }
.anchor-choice small { margin-top: 2px; color: var(--muted); font-size: 12px; }
.anchor-choice .anchor-check { position: absolute; top: 14px; left: 14px; width: 23px; height: 23px; display: grid; place-items: center; border-radius: 50%; color: var(--on-accent); background: var(--sage-dark); font-size: 12px; }
.feedback-options { margin-top: 18px; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.feedback-options label { padding: 10px 11px; display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-soft); font-size: 11px; font-weight: 700; cursor: pointer; }
.feedback-options input { width: auto; margin: 0; }
.toast { position: fixed; z-index: 100; bottom: 25px; left: 25px; padding: 13px 18px; border-radius: 12px; color: white; background: #292331; box-shadow: var(--shadow); opacity: 0; transform: translateY(15px); pointer-events: none; transition: .25s ease; }
/* Only a toast with a button takes taps: a long one stays up for seconds now, and must
   not swallow the taps on what it covers (review of PR 3). */
.toast.show { opacity: 1; transform: translateY(0); pointer-events: none; }
.toast.show:has(button) { pointer-events: auto; }

/* The island (owner, 2026-10-12): background work and what is ready for her, at the top
   of the screen — a small dark pill while work runs, a card when something needs her.
   Dark in both themes; in the dark theme a hairline keeps it off the page. */
:root { --island: #241f2b; --island-2: #322b3a; --island-line: transparent; --on-island: #f6f2f7; --island-muted: #b9afc0; --island-accent: #dca5c7; --on-island-accent: #171221; }
html[data-theme="dark"] { --island: #2b2433; --island-2: #3a3244; --island-line: #4a4152; }
.island { position: fixed; z-index: 120; inset-inline: 0; top: calc(var(--safe-top, env(safe-area-inset-top, 0px)) + 8px); display: flex; justify-content: center; padding: 0 12px; pointer-events: none; }
.island[hidden] { display: none; }
.island-pill, .island-card { pointer-events: auto; color: var(--on-island); background: var(--island); border: 1px solid var(--island-line); box-shadow: 0 10px 30px rgba(20, 14, 28, .28); animation: island-in .22s ease-out; }
.island-pill { min-height: 40px; padding: 0 16px 0 12px; border-radius: 999px; display: inline-flex; align-items: center; gap: 10px; font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer; }
.island-pill small { color: var(--island-muted); font-size: 12.5px; font-weight: 600; }
.island-ring { width: 22px; height: 22px; flex: none; }
.island-ring circle { fill: none; stroke-width: 5; }
.island-ring .island-ring-track { stroke: #4a4152; }
.island-ring .island-ring-done { stroke: var(--island-accent); stroke-linecap: round; transition: stroke-dasharray .3s ease; }
.island-card { width: min(100%, 400px); border-radius: 24px; padding: 12px; display: grid; gap: 10px; }
.island-row { display: flex; align-items: flex-start; gap: 10px; }
.island-text { flex: 1; min-width: 0; padding-top: 2px; }
.island-title { margin: 0; font-size: 14px; font-weight: 800; line-height: 1.45; color: var(--on-island); }
.island-sub { margin: 2px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--island-muted); overflow-wrap: anywhere; }
.island-x { flex: none; width: 28px; height: 28px; padding: 0; border: 0; border-radius: 50%; background: var(--island-2); color: var(--island-muted); font: inherit; font-size: 16px; line-height: 1; cursor: pointer; }
.island-pair { flex: none; display: flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; color: inherit; font: inherit; cursor: zoom-in; }
.island-pair figure { margin: 0; display: grid; gap: 3px; justify-items: center; }
.island-pair img { width: 54px; height: 71px; display: block; border-radius: 11px; object-fit: cover; background: #f4efea; }
.island-pair .is-mine img { opacity: .82; }
.island-pair figcaption { font-size: 10.5px; color: var(--island-muted); }
.island-pair .is-new figcaption { color: var(--island-accent); font-weight: 700; }
.island-arrow { margin-top: -14px; font-size: 15px; color: var(--island-muted); }
html[dir="ltr"] .island-arrow { transform: scaleX(-1); }
.island-actions { display: flex; gap: 8px; }
.island-primary, .island-ghost { flex: 1; min-height: 40px; border: 0; border-radius: 14px; font: inherit; font-size: 13.5px; font-weight: 800; cursor: pointer; }
.island-primary { background: var(--island-accent); color: var(--on-island-accent); }
.island-ghost { background: var(--island-2); color: var(--on-island); font-weight: 700; }
.island-stack { position: relative; width: 70px; height: 50px; flex: none; }
.island-stack img { position: absolute; width: 44px; height: 44px; border: 2px solid var(--island); border-radius: 12px; object-fit: cover; background: #f4efea; }
.island-thumbs { display: flex; gap: 6px; }
.island-thumbs img, .island-thumbs span { width: 40px; height: 40px; border-radius: 11px; object-fit: cover; background: #f4efea; }
.island-thumbs span { display: grid; place-items: center; background: var(--island-2); color: var(--island-muted); font-size: 12.5px; font-weight: 700; }
.island-note { display: flex; align-items: center; gap: 8px; padding: 9px 11px; border-radius: 14px; background: var(--island-2); font-size: 12.5px; }
.island-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--island-accent); }
.island-spinner { width: 18px; height: 18px; flex: none; border: 3px solid #4a4152; border-top-color: var(--island-accent); border-radius: 50%; animation: island-spin .9s linear infinite; }
.island-single-photo { width: 48px; height: 60px; flex: none; border-radius: 11px; object-fit: cover; background: #f4efea; }
.add-background { display: block; margin: 6px auto 0; }
.add-background[hidden] { display: none; }
@keyframes island-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .island-spinner { animation: none; } }
@keyframes island-in { from { opacity: 0; transform: translateY(-8px) scale(.98); } to { opacity: 1; transform: none; } }
/* Updated in place (a bulk run's count): no second entrance. */
.island[data-still] .island-pill, .island[data-still] .island-card { animation: none; }
@media (prefers-reduced-motion: reduce) { .island-pill, .island-card { animation: none; } .island-ring .island-ring-done { transition: none; } }

/* Sync progress card — revealed only while photos actually transfer (see app.js
   syncProgress). Thumbnail of the piece currently moving + a monotonic % + bar. */
.sync-progress {
  position: fixed;
  z-index: 95;
  left: 50%;
  bottom: calc(88px + var(--safe-bottom, 0px));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: min(92vw, 400px);
  padding: 12px 16px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  animation: sync-progress-in .28s ease;
}
.sync-progress[hidden] { display: none; }
@keyframes sync-progress-in {
  from { opacity: 0; transform: translate(-50%, 14px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
.sync-progress-thumb {
  flex: 0 0 auto;
  width: 46px; height: 46px;
  border-radius: var(--radius-md);
  background: var(--surface-soft) center / cover no-repeat;
  border: 1px solid var(--line);
}
.sync-progress-thumb.swap { animation: sync-thumb-swap .38s ease; }
@keyframes sync-thumb-swap {
  from { opacity: .3; transform: scale(.9); }
  to   { opacity: 1; transform: scale(1); }
}
.sync-progress-body { flex: 1 1 auto; min-width: 0; }
.sync-progress-title {
  font-size: var(--fs-body-sm);
  font-weight: 600;
  color: var(--text);
  margin-bottom: 7px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sync-progress-bar {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-soft);
  overflow: hidden;
}
.sync-progress-bar > span {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--accent);
  transition: width .45s cubic-bezier(.4, 0, .2, 1);
}
.sync-progress-pct {
  flex: 0 0 auto;
  min-width: 34px;
  text-align: end;
  font-size: var(--fs-body-sm);
  font-weight: 700;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}
.sync-progress[data-state="done"] .sync-progress-bar > span { background: #2e9e6b; }
.sync-progress[data-state="done"] .sync-progress-pct { color: #2e9e6b; }
.sync-progress[data-state="error"] .sync-progress-bar > span { background: #c0473f; }
.sync-progress[data-state="error"] .sync-progress-pct { color: #c0473f; }
/* A restore (first sign-in on an empty device) opens its card before anything has
   transferred, so the % would read a meaningless 0 — hide it and let the title carry
   the message until the first photo lands. */
.sync-progress[data-mode="restore"][data-state="run"] .sync-progress-pct { visibility: hidden; }
.sync-progress[data-mode="restore"] .sync-progress-title { white-space: normal; }
/* Partial photos need an actionable notice, not a misleading completed meter. */
.sync-progress[data-state="partial"] .sync-progress-thumb,
.sync-progress[data-state="partial"] .sync-progress-pct,
.sync-progress[data-state="partial"] .sync-progress-bar { display: none; }
.sync-progress[data-state="partial"] .sync-progress-title { white-space: normal; margin-bottom: 0; }
/* Failure controls: only ever visible in the error state, where the card stops
   auto-hiding (see syncProgress) because the user is already inside the app. */
.sync-progress-retry {
  flex: 0 0 auto;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--text);
  border-radius: var(--radius-pill);
  padding: 7px 14px;
  font-size: var(--fs-body-sm);
  font-weight: 600;
  cursor: pointer;
}
.sync-progress-retry[hidden] { display: none; }
.sync-progress-close {
  flex: 0 0 auto;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 20px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
}
.sync-progress:not([data-state="error"]) .sync-progress-close { display: none; }
@media (prefers-reduced-motion: reduce) {
  .sync-progress { animation: none; }
  .sync-progress-thumb.swap { animation: none; }
  .sync-progress-bar > span { transition: none; }
}

/* Sync conflict resolution (spec §19/§20). Opened with show(), NOT showModal(), so it
   behaves like the sync-progress card one shelf up: a fixed panel above the app, no
   backdrop, everything behind it still clickable. Logical properties throughout —
   the same rules read correctly in RTL Arabic and LTR English — and every surface is
   a theme variable, so the dark "Atelier" palette applies with no extra rules. */
#sync-conflict-modal[open] {
  position: fixed;
  z-index: 96;               /* one over the sync card it may sit beside */
  /* inset-inline + margin-inline:auto centres in BOTH directions — a translateX(-50%)
     trick would need its sign flipped between RTL and LTR. */
  inset-inline: 0;
  margin-inline: auto;
  inset-block-end: calc(88px + var(--safe-bottom, 0px));
  inset-block-start: auto;
  margin-block: 0;
  width: min(92vw, 460px);
  max-height: min(66dvh, 560px);
  display: flex;
  border: 1px solid var(--line);
  animation: conflict-in .28s ease;
}
@keyframes conflict-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
#sync-conflict-modal .sync-conflict-dialog {
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
  padding: 18px 20px;
}
#sync-conflict-modal .conflict-help { margin: 4px 0 12px; color: var(--muted); font-size: var(--fs-body-sm); }
.sync-conflict-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: grid; gap: 12px; }
.conflict-item { margin: 0; padding: 12px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-soft); }
.conflict-item legend { padding: 0 4px; font-weight: 700; font-size: var(--fs-body-sm); color: var(--text); }
.conflict-options { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.conflict-option {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--white);
  cursor: pointer;
}
.conflict-option:has(input:checked) { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.conflict-option input { margin-block-start: 3px; accent-color: var(--accent); }
.conflict-option-body { display: grid; gap: 5px; min-width: 0; }
.conflict-option-source { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--fs-caption, 12px); font-weight: 700; color: var(--muted); }
.conflict-newest-badge {
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: 11px;
  font-weight: 700;
}
.conflict-option-field { display: grid; gap: 1px; }
.conflict-field-name { font-size: 11px; color: var(--muted); }
.conflict-field-value { font-size: var(--fs-body-sm); font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
/* On narrow phones the two versions stack; the newest stays first in reading order. */
@media (max-width: 420px) {
  .conflict-options { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  #sync-conflict-modal[open] { animation: none; }
}

/* بوابة ملكية الدولاب — the wardrobe ownership handoff dialog. Same tokens as every
   other modal (dark theme rides the variables); the two full-sentence choices stack
   vertically with the safe default (start fresh) on top. */
#wardrobe-handoff-modal { max-width: 470px; }
#wardrobe-handoff-modal .conflict-help { margin: 4px 0 12px; color: var(--muted); font-size: var(--fs-body-sm); }
#wardrobe-handoff-modal .modal-actions { flex-direction: column; align-items: stretch; }

.empty-state { grid-column: 1/-1; padding: 60px; text-align: center; color: var(--muted); }

/* Bottom tab bar — the primary mobile navigation (Studio app shell). Hidden on desktop. */
.tabbar { display: none; }
.tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; padding: 6px 0; border: 0; background: none; color: var(--ink); font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.tab-item svg { width: 23px; height: 23px; }
.tab-item span { font-size: 11px; font-weight: 500; }
.tab-item.active { color: var(--ink); }
.tab-item.active span { font-weight: 700; }
#occasion-grid .occasion:focus-visible, #feel-chips .feel-chip:focus-visible, .tab-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.tab-item.active svg { color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 5px var(--accent-soft); border-radius: 6px; }

@media (max-width: 1100px) {
  .wardrobe-grid, .saved-grid { grid-template-columns: repeat(3, 1fr); }
  /* The stages are a single centred column at every width — nothing to collapse. */
  .generation-panel { min-height: 500px; }
}
@media (max-width: 850px) {
  .sidebar { width: min(82vw, 300px); max-height: 100dvh; overflow-y: auto; z-index: 40; transform: translateX(100%); transition: .25s ease; }
  .sidebar.open { transform: translateX(0); }
  .sidebar-backdrop {
    position: fixed;
    inset: 0;
    z-index: 19;
    border: 0;
    background: rgba(24,18,30,.48);
    backdrop-filter: blur(2px);
  }
  .sidebar-backdrop.show { display: block; }
  .main-content { margin-right: 0; padding-bottom: calc(120px + var(--safe-bottom, 0px)); }
  .toast { bottom: calc(120px + var(--safe-bottom, 0px)); }
  /* A selection confirmation must not cover the action it asks the user to take.
     Dialogs reparent the toast; their notices keep the normal placement. */
  body:has(#stylist-page.active #stylist-stage-input:not([hidden])) > .toast { top: calc(74px + var(--safe-top, 0px)); bottom: auto; }
  .mobile-menu { display: block; margin-left: 12px; }
  .home-grid, .analytics-grid, .analytics-intelligence-grid { grid-template-columns: 1fr; }
  .side-stack { grid-template-columns: 1fr 1fr; }
  .stats-grid { grid-template-columns: 1fr 1fr; }
  /* Tab bar replaces the drawer's nav list on mobile; the drawer keeps account + card. */
  .sidebar .main-nav { display: none; }
  .tabbar {
    position: fixed; inset: auto 12px max(8px, var(--safe-bottom, 0px)); z-index: 30;
    display: flex; justify-content: space-around; align-items: center;
    padding: 5px 4px;
    background: var(--white);
    border: 1px solid var(--line);
    border-radius: 24px;
    box-shadow: 0 4px 24px rgba(30,20,30,.08);
  }
  html[data-theme="dark"] .tabbar { --nav-tint: 72%; }
  /* Keep a solid fallback where background blur is unavailable. */
  @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .tabbar {
      background: color-mix(in srgb, var(--white) var(--nav-tint, 62%), transparent);
      -webkit-backdrop-filter: saturate(1.25) blur(12px);
      backdrop-filter: saturate(1.25) blur(12px);
    }
  }
}

/* iOS Safari auto-zooms (and reflows) the whole page whenever a focused form
   control has a computed font-size < 16px. Force 16px on EVERY touch device —
   any orientation, phones + tablets, and narrow windows — with !important so no
   smaller per-field size (e.g. .item-condition-select at 9px) can re-trigger it.
   Desktop (fine pointer, wide window) keeps its original type scale. */
@media (pointer: coarse), (max-width: 850px) {
  input, select, textarea { font-size: 16px !important; }
  /* §26 touch targets: every small wardrobe control clears ~44px on touch devices.
     Desktop keeps the quieter editorial heights — this is a hit-area rule, not a
     visual redesign, so only min-height moves. */
  .wardrobe-rail .filter,
  .filter-sheet-button,
  .wfilter-swatch,
  .active-filter-summary .clear-filters,
  .item-color,
  .color-option { min-height: 44px; }
}
@media (max-width: 620px) {
  .page { padding: 26px 16px 54px; }
  .topbar {
    min-height: 66px; height: auto;
    padding: var(--safe-top, 0px) 16px 0;
    position: sticky; top: 0; z-index: 12;
  }
  h1 { font-size: 29px; }
  h2 { font-size: 20px; }
  .page-intro, .section-heading { align-items: stretch; flex-direction: column; }
  .page-intro .primary-button, .page-intro .secondary-button { flex: 1; }
  .wardrobe-add-actions { width: 100%; }
  .looks-row, .wardrobe-grid, .saved-grid { grid-template-columns: 1fr 1fr; gap: 12px; }
  .side-stack { grid-template-columns: 1fr; }
  .today-card, .chart-card { padding: 18px; }
  .generation-panel { min-height: 390px; padding: 18px; }
  .outfit-stage { grid-template-columns: repeat(3, minmax(0, 1fr)); min-height: 205px; padding: 14px 0; gap: 6px; }
  .garment { min-width: 0; min-height: 155px; gap: 6px; }
  /* Scoped to the LEGACY stage: the bare selector leaked this shrink into every
     redesign thumbnail (deck tiles, swap/pinned/suggestion/before-after art),
     which size their art themselves (review finding). */
  .outfit-stage:not(.deck-collage) .garment-art { transform: scale(.65); }
  .outfit-item-photo { height: 125px; }
  .garment small { font-size: 10px; text-align: center; line-height: 1.4; }
  .card-actions { flex-wrap: wrap; }
  .card-actions .primary-button, .card-actions .secondary-button { flex: 1; }
  .search-box { min-width: 0; }
  .filters { width: 100%; flex-wrap: nowrap; overflow-x: auto; padding-bottom: 5px; scrollbar-width: thin; }
  .filter { flex: 0 0 auto; min-height: 42px; }
  .occasion-grid { grid-template-columns: 1fr 1fr; }
  .occasion { min-height: 62px; }
  .stats-grid, .form-row { grid-template-columns: 1fr; }
  .donut-wrap { flex-direction: column; }
  .analysis-fields { grid-template-columns: 1fr 1fr; }
  .feedback-options { grid-template-columns: 1fr 1fr; }
  .anchor-picker-grid { grid-template-columns: 1fr 1fr; }
  .stylist-context-tools { grid-template-columns: 1fr; }
  .stylist-context-card { min-height: 58px; }
  .chat-heading { flex-direction: column; }
  .generated-result .outfit-stage:has(.garment:nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .result-top { align-items: flex-start; flex-wrap: wrap; gap: 8px; }
  /* The gap was missing, so the five controls read as one blurred block with odd
     holes. Even 2-up rows, with the two full-width controls spanning both columns. */
  .text-button { min-height: 40px; display: inline-flex; align-items: center; }
  /* EVERY dialog (add item, delete, fit profile, styling mode, anchor picker, look
     review, shopping…) — not just the account sheet. A dialog is centred by the UA, so
     capping its height at the full viewport put its top edge under the status bar on a
     notched phone. Subtracting the inset TWICE keeps the centred box clear of both the
     status bar and the gesture area. */
  dialog {
    max-height: calc(100dvh - 24px - (2 * var(--safe-top, 0px)) - (2 * var(--safe-bottom, 0px)));
    overflow-y: auto; overscroll-behavior: contain;
  }
  dialog form { padding: 19px; }
  .anchor-picker-dialog { width: 100%; max-height: calc(100dvh - 24px - (2 * var(--safe-top, 0px)) - (2 * var(--safe-bottom, 0px))); padding: 19px; }
  .anchor-picker-dialog .modal-actions { position: sticky; bottom: -19px; z-index: 2; margin-inline: -19px; padding: 13px 19px calc(19px + var(--safe-bottom, 0px)); background: linear-gradient(transparent, var(--white) 25%); }
  .anchor-picker-filters { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 4px; }
  .anchor-picker-filters button { min-height: 40px; flex: 0 0 auto; }
  .anchor-choice { min-height: 178px; }
  .anchor-choice img, .anchor-choice .photo-frame, .anchor-choice .garment-art { height: 105px; }
  .modal-actions .primary-button, .modal-actions .secondary-button, .modal-actions .danger-button { min-height: 44px; }
  .photo-gallery { grid-template-columns: repeat(3, 1fr); }
  .toast { right: 12px; left: 12px; text-align: center; }
}
@media (max-width: 520px) {
  .looks-row, .saved-grid { grid-template-columns: 1fr; }
  /* Redesign §7: the wardrobe stays exactly TWO columns on mobile, every width. */
}
@media (max-width: 420px) {
  .today-card { padding: 18px; }
  .feedback-options, .analysis-fields { grid-template-columns: 1fr; }
  .analysis-fields .analysis-wide { grid-column: auto; }
  .weather small { display: none; }
  .anchor-item-button { padding: 11px; }
  .anchor-item-button > span { width: 32px; height: 32px; }
  .anchor-item-button small { font-size: 11px; }
}

/* ===== English / LTR layout overrides ===== */
[dir="ltr"] .sidebar { inset: 0 auto 0 0; }
[dir="ltr"] .main-content { margin-right: 0; margin-left: 250px; }
[dir="ltr"] .nav-item, [dir="ltr"] .profile-chip { text-align: left; }
[dir="ltr"] .nav-item.active { box-shadow: inset 3px 0 var(--accent); }
[dir="ltr"] .weather { margin-right: 0; margin-left: auto; }
@media (max-width: 850px) {
  [dir="ltr"] .main-content { margin-left: 0; }
  [dir="ltr"] .sidebar { transform: translateX(-100%); }
  [dir="ltr"] .sidebar.open { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* Dark theme: elements that hardcode light surfaces/tints bypass the CSS-variable
   flip, so they'd show as bright patches with unreadable text. Remap them here. */
html[data-theme="dark"] .outfit-reason,
html[data-theme="dark"] .item-visual,
html[data-theme="dark"] .generation-panel,
html[data-theme="dark"] .upload-zone,
html[data-theme="dark"] .photo-thumb,
html[data-theme="dark"] .anchor-item-button { background: var(--surface-soft); }
html[data-theme="dark"] .upload-zone { border-color: var(--line); }
html[data-theme="dark"] .upload-zone:hover,
html[data-theme="dark"] .anchor-item-button:hover { background: var(--cream); }
html[data-theme="dark"] .date-badge { background: var(--accent-soft); color: var(--accent-text); }
html[data-theme="dark"] .review-section ul,
html[data-theme="dark"] .styling-hijab-row { color: var(--muted); }
html[data-theme="dark"] .legal-links { color: var(--muted); }
html[data-theme="dark"] .legal-links a { color: var(--accent-text); }

/* Status / verdict tints -> translucent so they blend onto the dark surface */
html[data-theme="dark"] .chat-status { color: var(--accent-text); background: rgba(183,165,220,.16); }
html[data-theme="dark"] .analysis-status.analyzing { color: #b0a9bc; background: rgba(165,155,180,.16); }
html[data-theme="dark"] .analysis-status.success { color: #82cf8b; background: rgba(120,175,120,.16); }
html[data-theme="dark"] .analysis-status.warning { color: #e2b878; background: rgba(185,145,75,.18); }
html[data-theme="dark"] .analysis-status.error,
html[data-theme="dark"] .bulk-row.error b { color: #e69684; background: transparent; }
html[data-theme="dark"] .analysis-status.error { background: rgba(185,95,75,.18); }
html[data-theme="dark"] .review-quick-fix { background: rgba(183,165,220,.12); }
html[data-theme="dark"] .shopping-verdict.buy { background: rgba(120,175,120,.16); }
html[data-theme="dark"] .shopping-verdict.buy b { color: #82cf8b; }
html[data-theme="dark"] .shopping-verdict.maybe { background: rgba(185,145,75,.16); }
html[data-theme="dark"] .shopping-verdict.maybe b { color: #e2b878; }
html[data-theme="dark"] .shopping-verdict.skip { background: rgba(185,95,75,.16); }
html[data-theme="dark"] .shopping-verdict.skip b { color: #e69684; }
html[data-theme="dark"] .confirm-icon { color: #e69684; background: rgba(185,95,75,.18); }
html[data-theme="dark"] .positive { color: #82cf8b !important; }
html[data-theme="dark"] .warning { color: #e2b878 !important; }
html[data-theme="dark"] .exclude-item { color: var(--muted); background: rgba(165,155,180,.12); border-color: var(--line); }
html[data-theme="dark"] .excluded-banner { background: rgba(165,155,180,.12); border-color: var(--line); }
/* Its own block: the selector dangled with a trailing comma and merged into the
   next rule, painting a solid rectangle behind the name (review finding). */
html[data-theme="dark"] .excluded-banner strong { color: var(--ink); }
html[data-theme="dark"] .swap-tag.dir-up { background: #26313d; color: #b9cde0; }

/* Studio dark: neutralise translucent-white fills that would show as bright patches. */
html[data-theme="dark"] .outfit-item-photo { background: var(--surface-soft); }
html[data-theme="dark"] .orb { background: var(--surface-soft); border-color: var(--line); }
html[data-theme="dark"] .item-color { background: rgba(255,255,255,.05); }
html[data-theme="dark"] .item-color-dots i,
html[data-theme="dark"] .color-option i { border-color: rgba(255,255,255,.35); }
html[data-theme="dark"] .color-option { background: rgba(255,255,255,.04); }

/* The post-signup "check your email" panel. It replaces the sign-up form rather than
   sitting above it: once the account exists there is nothing left to submit, and a
   live form with a filled password field reads as unfinished work. */
#account-verify-panel { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
/* PRE-EXISTING BUG, found while screenshotting the Google button: the rule above
   outranks the UA's [hidden] rule, so the "check your email" panel was on screen under
   the sign-in form on EVERY visit — envelope, address line and all. Same trap as
   .brand-field[hidden] and .auth-forgot[hidden] above, and the same reason it survived:
   a JS check of `.hidden` passes (it reads the attribute, not the computed style), so
   only a screenshot catches it. */
#account-verify-panel[hidden] { display: none; }
.verify-icon { width: 52px; height: 52px; display: grid; place-items: center; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent); }
.verify-icon svg { width: 26px; height: 26px; }
.verify-lead { margin: 0; color: var(--muted); font-size: var(--fs-sm); }
.verify-email { margin: 0; font-weight: 700; font-size: var(--fs-md); word-break: break-all; }
.verify-hint { margin: 0; color: var(--muted); font-size: var(--fs-sm); line-height: var(--lh-relaxed); }
#account-verify-panel .auth-submit { width: 100%; margin-top: var(--space-2); }

/* ===== First-run onboarding (spec §5) =====
   Full-screen sequence over the app: below the toast (100) and the sync card (95) —
   both may legitimately speak during onboarding — and irrelevant to <dialog>s, which
   live in the top layer anyway (the account and bulk-add dialogs open above it).
   Colors ride the theme variables, so dark mode needs no extra rules; direction rides
   the document dir, so RTL/LTR need none either. */
.onboarding { position: fixed; inset: 0; z-index: 90; background: var(--paper); overflow-y: auto; }
.onboarding[hidden] { display: none; }
.onboarding-frame { min-height: 100%; width: min(430px, 100%); margin-inline: auto; display: flex; flex-direction: column;
  padding: calc(var(--space-4) + var(--safe-top)) var(--space-5) calc(var(--space-6) + var(--safe-bottom)); }
.onboarding-top { display: flex; align-items: center; justify-content: space-between; min-height: 40px; }
.onboarding-dots { display: flex; gap: var(--space-2); }
.onboarding-dots span { width: 8px; height: 8px; border-radius: 50%; background: var(--line); transition: background .2s ease; }
.onboarding-dots span.active { background: var(--accent); }
.onboarding-skip { border: 0; background: none; color: var(--muted); font-size: var(--fs-body-sm); font-weight: 600;
  padding: var(--space-2) var(--space-3); cursor: pointer; border-radius: var(--radius-pill); }
.onboarding-skip:hover { color: var(--text); background: var(--surface-soft); }
.onboarding-skip[hidden] { display: none; }
/* One decision per screen (§12): art, a heading, at most one sentence, the buttons. */
.onboarding-step { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center;
  gap: var(--space-4); text-align: center; padding-block: var(--space-6); }
.onboarding-step[hidden] { display: none; }
.onboarding-art { color: var(--accent); }
.onboarding-step h2 { margin: 0; font-size: var(--fs-h1); line-height: var(--lh-h1); color: var(--text); }
.onboarding-step p { margin: 0; color: var(--muted); font-size: var(--fs-body); line-height: var(--lh-body); max-width: 34ch; }
.onboarding-step p.onboarding-progress { font-size: var(--fs-display); line-height: var(--lh-display); font-weight: 700; color: var(--text); }
.onboarding-actions { display: flex; flex-direction: column; gap: var(--space-3); width: 100%; max-width: 300px; margin-top: var(--space-4); }
.onboarding-actions .primary-button, .onboarding-actions .secondary-button { width: 100%; }
.item-preparation {
  display: block;
  margin-block-start: 0.25rem;
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1.5;
}
