/* ABOUTME: Main stylesheet defining design tokens, layout, and global styles */

/* ABOUTME: Defines global foundations; layouts load feature stylesheets explicitly */

/*
 * Application-wide styles for Yafa - AI Fitness Tracker
 * Design system based on mockup-10 (Clean Evolution)
 */

/* CSS Variables - Design Tokens from mockup-10 */
:root {
  /* ========== Core Brand Colors ========== */

  /* Sharpened Cream (Jul 2026): same hue, half a stop deeper, so orange holds
     its own as text and accents instead of washing out on the cream. */
  --orange: #E06428;
  --orange-light: #FBE9DA;
  --orange-600: #ca5a24;

  /* Quiet primary (Jul 2026): filled CTAs are a brand-hue wash with an ink
     label and a burnt-orange border - not a solid orange slab with white text.
     Static values first: the native shell supports iOS 16.0, where WebKit has
     neither relative color (16.4+) nor color-mix (16.2+), and an unsupported
     function makes every use invalid (transparent CTAs). The @supports block
     upgrades to brand-derived fills - relative color pins the wash to the
     brand hue at fixed saturation/lightness (plain tints drift salmon), so a
     gym's rebranded --orange carries through. */
  --btn-primary-bg: #F3C7AA;
  --btn-primary-bg-hover: #F2B892;
  --btn-primary-bg-active: #EFAD80;
  --btn-primary-ink: var(--text);
  --btn-primary-border: var(--orange-600);
  --btn-primary-icon: #B65120;

  /* Legacy aliases */
  --yafa-orange: var(--orange);
  --yafa-orange-600: var(--orange-600);

  /* ========== Semantic Colors ========== */
  --green: #34A853;
  --green-light: #E6F4EA;
  --red: #EA4335;
  --red-light: #FCE8E6;
  --yellow: #FBBC04;
  --yellow-light: #FEF7E0;
  --purple: #8b5cf6;
  --purple-light: #f3e8ff;
  --blue: #4285f4;
  --blue-light: #e8f0fe;
  --indigo: #6366f1;
  --indigo-light: #e0e7ff;
  --teal: #14b8a6;
  --teal-light: #ccfbf1;
  --cyan: #06b6d4;
  --cyan-light: #cffafe;
  --amber: #f59e0b;
  --amber-light: #fef3c7;

  /* ========== Surface & Background (Warm Editorial design system) ========== */

  /* Sharpened Cream (Jul 2026): every value half a stop deeper than the Jun
     warm retune. The hues are unchanged - the fix is contrast: sub-text was
     2.8:1 on the cream, hairlines 1.3:1; these land ~3.7:1 and ~1.4:1 with
     the cards visibly lifting off the deeper ground. */
  --bg: #F3EBDD;        /* cream canvas (was #F6F0E7) */
  --surface: #FFFEFB;   /* warm paper card (was #FFFDFA) */
  --border: #D6C4A6;    /* warm rule, firm enough to actually see (was #E0D3BF) */

  /* ========== Typography Colors ========== */
  --text: #251E19;            /* warm ink (was #2A2320) */
  --text-secondary: #544639;  /* warm secondary (was #5D5148) */
  --text-muted: #6E6151;      /* warm muted, meets 4.5:1 AA contrast at caption sizes */

  /* ========== Typography Scale ========== */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;

  /* ========== Font Weights ========== */
  --font-medium: 500;
  --font-semibold: 600;
  --font-bold: 700;

  /* ========== Transitions ========== */
  --transition-fast: 0.15s;
  --transition-base: 0.2s;
  --ease-out: cubic-bezier(0.4, 0, 0.2, 1);

  /* ========== Spacing System (4px base) ========== */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;

  /* ========== Border Radius ========== */
  --radius-sm: 8px;
  --radius-md: 10px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --radius-full: 9999px;

  /* ========== Shadows & Elevation ==========
     The legacy names (--shadow-*, --elev-*) are defined further down as
     aliases onto the warm two-light --e1..e4 ramp. */

  /* ========== Legacy Gray Scale — retuned WARM (Jun 2026) ==========
     Same lightness ramp, warm hue, so the hundreds of var(--gray-N) refs across
     surfaces warm up with the design system instead of clashing cool on cream. */
  --gray-50: #FAF6EF;
  --gray-100: #F3ECE0;
  --gray-200: #E7DCCB;
  --gray-300: #D6C9B6;
  --gray-400: #AEA291;
  --gray-500: #8A7E72;
  --gray-600: #6B5F56;
  --gray-700: #50473F;
  --gray-800: #332B25;
  --gray-900: #221B15;

  /* A floating chip that is always dark-on-light-text - a tooltip, a hover
     popover - regardless of which theme the page under it is wearing. These
     used to reach for --gray-900 because it WAS a fixed near-black in light
     mode, but dark_theme.css inverts the gray ramp (--gray-900 becomes the
     near-white text color there), so any rule still keyed to --gray-900 got a
     cream chip with the white text it was written for - illegible. This token
     is deliberately absent from dark_theme.css so it never flips. */
  --overlay-chip-bg: #221B15;

  /* ========== "Primary" — retuned to the BRAND ORANGE ramp (was cool blue) ==========
     The old design's primary accent was blue; in Warm Editorial the primary IS
     the brand orange, so every var(--primary-N) accent now reads on-brand. */
  --primary-50: #FBE9DA;
  --primary-100: #F8DFCE;
  --primary-200: #F2C2A0;
  --primary-300: #ECA173;
  --primary-400: #E6824C;
  --primary-500: #E06428;
  --primary-600: #CA5A24;
  --primary-700: #9E3A1B;
  --primary-800: #823016;
  --primary-900: #652511;
  --success-50: #f0fdf4;
  --success-100: #dcfce7;
  --success-200: #bbf7d0;
  --success-300: #86efac;
  --success-400: #4ade80;
  --success-500: var(--green);
  --success-600: #16a34a;
  --success-700: #15803d;
  --success-800: #166534;
  --success-900: #14532d;
  --error-50: #fef2f2;
  --error-100: #fee2e2;
  --error-200: #fecaca;
  --error-500: var(--red);
  --error-600: #dc2626;
  --error-700: #b91c1c;
  --warning-500: var(--yellow);
  --warning-600: #d97706;
  --warning-700: #b45309;

  /* ========== Workout Block Type Colors ========== */

  /* Default block header: warm espresso (was cool slate #3d6a8f) — structure stays
     quiet so orange remains the action color; white text ≈ 10:1 on both stops. */
  --block-default-from: #43362C;
  --block-default-to: #322821;
  --block-emom-from: #2a9d8f;
  --block-emom-to: #1a7a6e;
  --block-amrap-from: #c4392a;
  --block-amrap-to: #a82e20;

  /* ===== Apple-native polish (Editorial Native) — Jun 8 2026 ===== */

  /* Native font stacks: true SF Pro on Apple/WKWebView, Manrope as fallback */
  --font-ui: -apple-system, blinkmacsystemfont, "SF Pro Text", "SF Pro", manrope, system-ui, "Segoe UI", roboto, sans-serif;

  /* "Fraunces J" is a one-glyph face (see google-fonts.css): its unicode-range
     covers only U+004A, so it lends the display stack a plain capital J and every
     other character falls through to Fraunces. Fraunces' own J is a swash whose
     tail sweeps out under the word, which reads as a flourish in "Jan"/"Jun"/"Jul". */

  /* Fraunces' f leans far enough right that the font resolves the overlap with a
     ligature, and "fi" comes out as one blob of hood-and-dot that stops reading as
     two letters at display size. There is no alternate f to swap in (Fraunces has
     no ss__ features, and WONK leaves the glyph alone), and borrowing one from
     another family is worse: a donor f overhangs whatever follows it - a letter
     Fraunces still owns - so it lands on "fl", "fo", "fa" and even the word space
     after "off". A ligature cannot fire across two families to absorb that.
     The fix that stays inside one typeface is to turn the ligature off, which
     leaves f and i as themselves with the hood just clearing the dot.
     `font-variant-ligatures` is not part of the font stack and cannot ride on this
     token, so every rule that sets font-family to it pairs the two by hand:

       font-family: var(--font-display);
       font-variant-ligatures: no-common-ligatures;

     New display-face rules should do the same. */
  --font-display: "Fraunces J", "Fraunces", "Iowan Old Style", palatino, georgia, serif;
  --font-mono: ui-monospace, sfmono-regular, "SF Mono", menlo, monaco, monospace;
  --font-sans: var(--font-ui); /* the tab bar already references var(--font-sans) */

  /* Semantic type rhythm */
  --type-eyebrow-size: 11px;
  --type-eyebrow-weight: 700;
  --type-eyebrow-track: 0.07em;

  /* Continuous-feel radius additions (no base-ramp mutation) */
  --radius-card: 32px;
  --radius-2xl: 36px;

  /* Hairline divider (internal rules only) */
  --hairline: color-mix(in srgb, var(--border) 70%, transparent);

  /* One material vocabulary, promoted from the tab bar's proven recipe */
  --material-surface: color-mix(in srgb, var(--surface) 72%, transparent);
  --material-blur: saturate(180%) blur(20px);

  /* Specular top edge — the "lit tile" tell */
  --specular: inset 0 1px 0 rgb(255 255 255 / 60%);

  /* Two-light elevation (ambient contact + soft key spread), warm-ink-tinted (not black).
     e1/e2 are deliberately tight: a big blurry key light on every tile reads
     soft-and-fuzzy; resting surfaces get a crisp contact shadow instead. */
  --e1: 0 1px 1px rgb(42 35 32 / 14%), 0 3px 10px -5px rgb(42 35 32 / 16%);
  --e2: 0 1px 2px rgb(42 35 32 / 14%), 0 8px 18px -8px rgb(42 35 32 / 20%);
  --e3: 0 6px 14px rgb(42 35 32 / 11%), 0 32px 60px -14px rgb(42 35 32 / 44%);
  --e4: 0 12px 28px rgb(42 35 32 / 14%), 0 52px 88px -20px rgb(42 35 32 / 54%);

  /* Alias the legacy shadow names onto the ramp = app-wide depth, zero per-component edits */
  --shadow-sm: var(--e1);
  --shadow: var(--e1);
  --shadow-md: var(--e2);
  --shadow-lg: var(--e3);
  --elev-1: var(--e1);
  --elev-2: var(--e2);

  /* Motion: gentle iOS spring for the press-in (no overshoot); releases pop
     back with a hint of overshoot (--ease-pop) — tactile, never wobbly */
  --ease-spring: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1);
  --transition-press: 0.18s;
  --transition-release: 0.3s;

  /* Warm-editorial aliases + washes — at :root so the shared design-system
     primitives render the warm editorial look on ANY page.
     cream/paper/ink/rule alias the existing semantic tokens (single source); washes are NEW. */
  --cream: var(--bg);            /* #F6F0E7 */
  --paper: var(--surface);       /* #FFFDFA */
  --paper-2: #F9F0E1;
  --ink: var(--text);            /* #251E19 */
  --ink-soft: var(--text-secondary);
  --ink-faint: var(--text-muted);
  --rule: var(--border);
  --accent-ink: #9E3A1B;
  --accent-wash: #F8DFCE;
  --accent-rule: #f3d2bd;
  --sage: #4A6B45;  --sage-wash: #DFE9D8;
  --amber-wash: #F7ECD5;

  /* Yesterday recap tile (gym board): a peachy-cream gradient tile nested on
     --paper. Its own pair, not --award-wash-from/-to - those are a slightly
     different champagne tuned for achievement cards, and reusing them would
     shift this tile's light-mode pixels. */
  --gym-stat-wash-from: #fffaf6;
  --gym-stat-wash-to: #fdf2e9;
  --gym-stat-rule: #f4e2d3;

  /* The excellent-days roll call on the gym board. Its own trio rather than
     --award-wash-from/-to: this card is golden where the award pair is peachy,
     and it has to be TOKENS - hardcoded, the card kept its cream paper under
     .theme-dark while .excellent-days-title's var(--text) flipped to near-
     white, which is the "unreadable wins screen" a member reported: pale ink
     on pale card, the only thing left visible being the faces. */
  --roll-call-wash-from: #fffaf2;
  --roll-call-wash-to: #fdf1e2;
  --roll-call-rule: #f3dcbe;

  /* Daily-score grades. Excellent and Off borrow --sage/--orange and their
     washes; Solid and Steady need their own pair, and it has to be a TOKEN:
     hardcoded here they stayed light under .theme-dark while their neighbours
     flipped, which turned the score strip into a checkerboard of white cells
     on the dark card. */
  --grade-solid: #82A079;  --grade-solid-wash: #EEF3EA;
  --grade-steady: var(--yellow); --grade-steady-wash: #FBF1E0;

  /* #675CA0 measured 4.45:1 on --violet-wash - AA body text needs 4.5:1.
     Nudged a hair darker; --violet-wash and the dark pair are unchanged. */
  --violet: #63589A; --violet-wash: #E3DFF2;
  --blue-wash: #DAE7F0;          /* NEW wash; do NOT touch the cool --blue token */
  --steel: #486E8C;              /* warm-leaning ink partner for --blue-wash */
  --gold: #85671F;   --gold-wash: #EFE0BD; /* Body Metrics identity hue */

  /* Award/celebration palette (achievement cards, streak + PR banners) —
     shared by achievements.css and log_stack.css; peachy champagne, warmer
     and lighter than the accent ramp so a win reads festive, not actionable. */
  --award-wash-from: #FFF6F0;
  --award-wash-to: #FDEEE4;
  --award-rule: #F6D8C4;
  --award-ink: #B56A3F;

  /* Win-emote reaction pill fill: its own pair rather than --award-wash-from,
     which is a slightly different champagne tuned for the card gradient. */
  --award-pill-bg: #fbf7f4;
  --award-pill-bg-hover: #fff1e8;

  /* "Over a ceiling" ink for goal rings. Deliberately NOT --accent-ink: that
     rust is the Workouts category accent, so a ring drawn in it reads as a
     warning on every workout row. */
  --goal-over-ink: #B91C1C;
  --radius-tile: 22px;           /* on-language card radius (NOT --radius-card 32px) */

  /* The .ps-page canvas glow. Two tokens, not one: the fade stop must be the
     SAME hue at zero alpha - `transparent` is rgba(0,0,0,0) and Safari
     interpolates toward black, which grays the middle of the gradient. */
  --page-glow: #F8E4CB;
  --page-glow-fade: rgb(248 228 203 / 0%);
}

/* Brand-derived quiet-primary fills where WebKit supports them (see the static
   fallbacks above): the wash tracks a gym's rebranded --orange. */
@supports (color: hsl(from red h 0% 0%)) {
  :root {
    --btn-primary-bg: hsl(from var(--orange) h 75% 81%);
    --btn-primary-bg-hover: hsl(from var(--orange) h 78% 76%);
    --btn-primary-bg-active: hsl(from var(--orange) h 78% 72%);
  }
}

@supports (color: color-mix(in srgb, red, blue)) {
  :root {
    --btn-primary-icon: color-mix(in srgb, var(--orange-600) 90%, black);
  }
}

/* Reset and base styles */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Pin iOS's text auto-inflation off. WKWebView "boosts" body text when it lays a
   page out at a width that differs from the final rendered one - which is exactly
   what a tapped push notification does: it deep-links straight into a room (e.g. a
   reaction on your message) as the app foregrounds, so the page renders mid-
   transition with every font oversized, and only a relayout - leaving the room and
   coming back - recomputes it at the right size. Fixing the adjustment at 100%
   keeps text at its authored size and never boosts. */
html {
  -webkit-text-size-adjust: 100%; /* stylelint-disable-line property-no-vendor-prefix */
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  background-color: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizelegibility;
}

/* Native shell only: a press-and-hold on the UI should feel native, not web -
   no stray text selection or iOS callout (Copy / Look Up). Desktop web keeps
   normal selection everywhere, so admin/debug text stays copyable. The prefixed
   property is required - iOS WebKit ignores unprefixed user-select here. */
body.native-app {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none; /* stylelint-disable-line property-no-vendor-prefix */
  user-select: none;
}

body.native-app * { -webkit-tap-highlight-color: transparent; }

/* ...but keep selection and the native edit menu where users actually copy or
   edit: message text, form fields, and rich-text editors (the chat composer is
   contenteditable). Restore the callout too - the inherited touch-callout: none
   would otherwise suppress the Copy / Paste / Look Up menu right here. */
body.native-app :is(
  .chatroom-message-content,
  .message-content,
  .message-bubble,
  /* The lightbox is where copying an image happens (see the thumbnail rule
     below). It mounts on <body>, outside every bubble, so it needs its own
     entry here or a long-press on the full-size image gets no Copy menu. */
  .chat-lightbox-image,
  .chatroom-lightbox-image,
  pre,
  code,
  input,
  textarea,
  select,
  [contenteditable="true"]
) {
  -webkit-touch-callout: default;
  -webkit-user-select: text; /* stylelint-disable-line property-no-vendor-prefix */
  user-select: text;
}

/* These chat elements carry their own long-press UI (reactor list, profile
   card), so the native selection/callout must never fire on them - on the
   native shell AND on mobile web, where the body rule above does not apply.
   None hold copyable content, so suppressing them everywhere is safe and keeps
   the gestures working for browser users too.

   Image THUMBNAILS are in the list for a different reason: each is an <img>
   wrapped in an <a href> to the blob, so iOS reads the long-press as a press on
   a link and offers Open Link / Copy Link over a "Zero KB document" preview -
   never a usable Copy of the picture. Copying an image is a lightbox gesture
   instead: tap to expand, then long-press the bare <img> there, which gets the
   real image menu (Copy, Save to Photos, Share). The lightbox classes are in
   the restore list above. */
.chatroom-reaction-btn,
.chatroom-message-avatar,
.chatroom-message-author,
.chatroom-message-image-link,
.chatroom-message-image,
.chat-message-image-link,
.chat-message-image {
  -webkit-touch-callout: none;
  -webkit-user-select: none; /* stylelint-disable-line property-no-vendor-prefix */
  user-select: none;
}

/* Turbo's stream-source elements are non-visual, but as flex items they
   consume a gap slot (e.g. phantom space between nav icons) */
turbo-cable-stream-source {
  display: none;
}

/* Yafa wordmark styling */
.yafa-wordmark {
  font-weight: 800;
  letter-spacing: -0.5px;
}

/* Typography */
h1, h2, h3, h4, h5, h6 {
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
  letter-spacing: -0.02em;
}

h1 {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.022em;
}

h2, h3 { letter-spacing: -0.018em; }

h2 {
  font-size: 1.375rem;
}

/* ===== Apple-native polish globals (Jun 8 2026) ===== */

/* Tabular + SF straight-sided digits on stat/number surfaces (progressive enhancement). */
[data-align="num"],
.editable-field-value,
.timer-display {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "cv01" 1;
}

.card { border-radius: var(--radius-card); box-shadow: var(--specular), var(--e1); }

h3 {
  font-size: 1.125rem;
}

a {
  color: var(--primary-600);
  text-decoration: none;
  transition: color 0.2s;
}

a:hover {
  color: var(--primary-700);
}

/* Unread chat badge: a number = count of @mentions of you. Inline by default so it
   bubbles into rows/pills; the mobile section bar positions its slot on the icon. */
.nav-unread-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--error-500);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1;
  text-align: center;
}

/* Plain dot: unread chat activity with no @mention */
.nav-unread-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--error-500);
}

/* Main content wrapper */
main {
  min-height: calc(100vh - env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
}

/* The chatroom container is position: fixed, so main has no in-flow content.
   The default min-height would still stretch the body to ~100vh and let it
   scroll behind the fixed header and composer; collapse it so nothing scrolls
   behind the shell. */
body:has(.chatroom-container) main {
  min-height: 0;
}

/* Container utilities */
.container {
  width: 100%;
  margin: 0 auto;
  padding: 0 1rem;
}

.container.max-w-6xl {
  max-width: 72rem;
}

/* Card component */
.card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  overflow: hidden;
}

.card-header {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
}

.card-body {
  padding: var(--space-4) var(--space-5);
}

/* Forms */
.form-group {
  margin-bottom: var(--space-4);
}

.form-label {
  display: block;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: var(--space-2);
  font-size: 0.8125rem;
}

.form-input,
.form-textarea,
.form-select {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-family: inherit;
  font-size: 0.9375rem;
  transition: all 0.2s;
  background-color: var(--bg);
}

.form-select {
  appearance: none;
  padding-right: 3rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1.25rem center;
  background-size: 1rem;
  cursor: pointer;
}

.form-input:focus,
.form-textarea:focus,
.form-select:focus {
  outline: none;
  border-color: var(--orange);
  background-color: var(--surface);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--orange) 10%, transparent);
}

.form-input:disabled,
.form-textarea:disabled,
.form-select:disabled {
  background-color: var(--gray-100);
  cursor: not-allowed;
  opacity: 0.7;
}

/* iOS Safari zooms the viewport when a focused control is under 16px */
@media (width <= 640px) {
  .form-input,
  .form-textarea,
  .form-select {
    font-size: 1rem;
  }
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.925rem;
}

thead th {
  background-color: var(--gray-50);
  font-weight: 600;
  text-align: left;
  padding: 0.5rem 0.8rem;
  color: var(--gray-700);
  border-bottom: 1px solid var(--gray-100);
  position: sticky;
  top: 0;
  z-index: 1;
}

th, td {
  padding: 0.5rem 0.8rem;
  border-bottom: 1px solid var(--gray-100);
}

tbody tr:nth-child(even) {
  background: transparent; /* Remove heavy stripes */
}

tbody tr:hover {
  background: var(--gray-50);
}

/* Number alignment and tabular figures */
td[data-align="num"],
[data-align="num"] {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

th[data-align="num"] {
  text-align: right;
}

/* Dim units in tables for better readability */
td .unit {
  opacity: 0.7;
}

/* Alerts and notifications */
.alert {
  padding: 1rem 1.25rem;
  border-radius: var(--radius);
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  border: 1px solid var(--border);
  box-shadow: var(--e1);
}

.alert-success {
  background-color: var(--sage-wash);
  color: var(--sage);
}

.alert-error {
  /* The palette has no dedicated error-red; --accent-ink is already the app's
     deep warm red-brown (used with --accent-wash elsewhere), so reuse that
     pairing instead of the cool web red this used to be. */
  background-color: var(--accent-wash);
  color: var(--accent-ink);
}

.alert-info {
  background-color: var(--gold-wash);
  color: var(--gold);
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.message:last-child {
  margin-bottom: 0;
}

/* Activity item cards */
.activity-item {
  background: var(--paper);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius);
  padding: 1rem;
  margin-bottom: 0.75rem;
  transition: all 0.2s;
}

.activity-item:hover {
  border-color: var(--primary-300);
  box-shadow: var(--shadow-md);
}

@keyframes loading {
  0% {
    background-position: 200% 0;
  }

  100% {
    background-position: -200% 0;
  }
}

/* Utility classes */
.text-center { text-align: center; }

.mt-4 { margin-top: 1rem; }
.mt-6 { margin-top: 1.5rem; }

.mb-8 { margin-bottom: 2rem; }

.py-8 { padding-top: 2rem; padding-bottom: 2rem; }

.flex { display: flex; }

.hidden { display: none; }

/* A tenant brand mark and its dark-room counterpart both ship in the markup
   (shared/_brand_image); this is what picks between them. The theme is a class
   on <html> resolved in the browser and changeable after render, so the choice
   has to be made in CSS - a server-picked src would be stale the moment the
   member switched rooms. Explicit `inline` rather than a revert: these are
   plain images, and every rule that styles one sets only box metrics. */
.brand-img-dark { display: none; }
.theme-dark .brand-img-light { display: none; }
.theme-dark .brand-img-dark { display: inline; }

/* Responsive */
@media (width <= 640px) {
  h1 { font-size: 2rem; }
  h2 { font-size: 1.5rem; }
  h3 { font-size: 1.25rem; }
}

/* Message Styles (used in daily dashboard) */

.message.own-message {
  align-items: flex-end;
}

.message.other-message {
  align-items: flex-start;
}

.message-bubble {
  max-width: 90%;
  padding: 0.625rem 0.875rem;
  border-radius: 1rem;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.45;
}

/* The user speaks on plain paper; the companion speaks in its own color.
   The user's bubble sits on --surface, which flips dark in dark mode, so its
   text tracks --text rather than a hardcoded ink. Salvy's bubble stays a
   light peach wash in both themes (see below), so its ink can stay fixed. */
.own-message .message-bubble {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  border-bottom-right-radius: 0.25rem;
}

/* Salvy's bubble: a wash of the user's chosen orb color (--salvy-custom,
   seeded on the messages container; brand orange when no pick). Static
   brand wash first for pre-16.2 WebKit without color-mix. Background stays a
   light peach in both themes, so the dark ink here is intentionally fixed. */
.other-message .message-bubble {
  background: #F5D0B0;
  color: #1C1511;
  border-bottom-left-radius: 0.25rem;
}

@supports (color: color-mix(in srgb, red, blue)) {
  .other-message .message-bubble {
    background: color-mix(in oklch, var(--orange) 40%, white);
  }
}

.message-bubble p {
  margin: 0 0 0.75rem;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

.message-bubble--markdown p {
  white-space: normal;
}

.message-bubble p:last-child {
  margin-bottom: 0;
}

/* Markdown styling for chat messages */
.message-bubble h1,
.message-bubble h2,
.message-bubble h3,
.message-bubble h4,
.message-bubble h5,
.message-bubble h6 {
  margin: 1rem 0 0.5rem;
  line-height: 1.3;
}

.message-bubble h1 { font-size: 1.25rem; }
.message-bubble h2 { font-size: 1.125rem; }
.message-bubble h3 { font-size: 1rem; }
.message-bubble h4 { font-size: 0.9375rem; }
.message-bubble h5 { font-size: 0.875rem; }
.message-bubble h6 { font-size: 0.875rem; }

/* First heading shouldn't have top margin */
.message-bubble h1:first-child,
.message-bubble h2:first-child,
.message-bubble h3:first-child,
.message-bubble h4:first-child,
.message-bubble h5:first-child,
.message-bubble h6:first-child {
  margin-top: 0;
}

/* Lists in messages */
.message-bubble ul,
.message-bubble ol {
  margin: 0.5rem 0 0.75rem;
  padding-left: 1.5rem;
}

.message-bubble ul:last-child,
.message-bubble ol:last-child {
  margin-bottom: 0;
}

.message-bubble li {
  margin: 0.25rem 0;
  line-height: 1.5;
}

.message-bubble li:first-child {
  margin-top: 0;
}

.message-bubble li:last-child {
  margin-bottom: 0;
}

/* Nested lists */
.message-bubble ul ul,
.message-bubble ol ol,
.message-bubble ul ol,
.message-bubble ol ul {
  margin: 0.25rem 0;
}

/* Strong emphasis */
.message-bubble strong {
  font-weight: 600;
}

/* Code blocks */
.message-bubble code {
  background: rgb(0 0 0 / 5%);
  padding: 0.125rem 0.25rem;
  border-radius: 3px;
  font-family: 'SF Mono', Monaco, 'Courier New', monospace;
  font-size: 0.875em;
}

.message-bubble pre {
  background: rgb(0 0 0 / 5%);
  padding: 0.75rem;
  border-radius: 6px;
  overflow-x: auto;
  margin: 0.5rem 0 0.75rem;
}

.message-bubble pre code {
  background: none;
  padding: 0;
}

/* Blockquotes */
.message-bubble blockquote {
  border-left: 3px solid rgb(0 0 0 / 10%);
  margin: 0.5rem 0 0.75rem;
  padding-left: 1rem;
  font-style: italic;
  color: rgb(0 0 0 / 70%);
}

/* Horizontal rules */
.message-bubble hr {
  border: none;
  border-top: 1px solid rgb(0 0 0 / 10%);
  margin: 1rem 0;
}

/* Tables in messages */
.message-bubble table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.5rem 0 0.75rem;
  font-size: 0.875rem;
}

.message-bubble th,
.message-bubble td {
  padding: 0.5rem;
  border: 1px solid rgb(0 0 0 / 10%);
  text-align: left;
}

.message-bubble th {
  background: rgb(0 0 0 / 5%);
  font-weight: 600;
}

.message-bubble.streaming p {
  color: #453931;
  font-style: italic;
}

.own-message .message-time {
  text-align: right;
}

/* Loading animation */
.message #loading {
  max-width: 90%;
}

/* Compact line under an assistant bubble listing actions the AI completed */
.action-summary {
  max-width: 90%;
  margin-top: 4px;
  font-size: 0.75rem;
  color: var(--text-muted);
}

.action-summary::before {
  content: "\2713  ";
  color: var(--success-600);
  font-weight: 700;
}

/* A refused turn's footer: the way back (Retry), and - for admins only - what
   the provider actually said. Sits under the bubble in the same quiet register
   as the action summary, because a failure should read as a hiccup to recover
   from, not as an alarm. */
.chat-error-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  max-width: 90%;
  margin-top: 6px;
}

.chat-retry-form {
  display: inline;
}

.chat-retry-button {
  padding: 4px 12px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--surface);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}

.chat-retry-button:hover {
  border-color: var(--orange);
  color: var(--orange);
}

.chat-retry-button:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 2px;
}

.chat-error-details {
  font-size: 0.7rem;
  color: var(--text-muted);
}

.chat-error-details summary {
  cursor: pointer;
}

.chat-error-details code {
  display: block;
  margin-top: 4px;
  overflow-wrap: anywhere;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* =====================================================
   In-chat log receipt - what the turn's logging DID.
   Reads like a till receipt, not a card: the quiet proof that "had eggs and
   toast" moved a goal, shown where the user actually is (the chat), because
   the dashboard's rings filling under a full-screen panel is a payoff nobody
   sees. Data is persisted per-message (ChatLogReceipt), so history shows the
   at-log-time state. */

/* A grid with subgrid rows, not per-row flex: every row draws its bar on the
   SAME track - a bar whose width depended on its own row's text would make
   84% of calories draw shorter than 60% of protein. Rows carry only the
   label, the tappable bar and the turn's delta - the exact figures live in
   the goal-detail popup, all frozen at the moment of logging. */
.log-receipt {
  display: grid;
  grid-template-columns: max-content minmax(3rem, 1fr) max-content;
  column-gap: 8px;
  max-width: 90%;
  margin-top: 4px;
  padding: 8px 10px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--surface);
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* The old action-summary line becomes the receipt's header - same register,
   same check, it just stops being the whole story. */
.log-receipt-head {
  grid-column: 1 / -1;
  margin-bottom: 6px;
  font-weight: 600;
}

.log-receipt-head::before {
  content: "\2713  ";
  color: var(--success-600);
  font-weight: 700;
}

/* Each row is one link: label, bar and delta together are the tap target,
   opening the goal-detail sheet in the universal modal. Deliberately compact
   rather than 44px-padded - the receipt reads as a tight till receipt, and
   the detail sheet is a bonus, not a primary control. */
.log-receipt-row {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: center;
  min-height: 30px;
  text-decoration: none;
  color: inherit;
  border-radius: 6px;
}

html:not([data-input-mode="pointer"]) .log-receipt-row:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 1px;
}

.log-receipt-label {
  color: var(--ink-soft);
  font-weight: 600;
}

.log-receipt-bar {
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--paper-2);
  overflow: hidden;
}

.log-receipt-bar-fill {
  display: block;
  height: 100%;
  border-radius: 2px;
}

/* The macro strip's judgment, verbatim: busting a ceiling (fat, calories) is
   warning ink; clearing a floor (protein, fiber, sleep) reads positive - never
   the same red as an overage that actually is one. */
.log-receipt-bar-fill--over {
  background: var(--goal-over-ink);
}

.log-receipt-bar-fill--cleared {
  background: var(--green);
}

.log-receipt-delta {
  justify-self: end;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.log-receipt-delta--cleared {
  color: var(--green);
  font-weight: 600;
}

/* One calm line, no exclamation marks: closing a goal is stated, not shouted. */
.log-receipt-closed {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 0 2px;
  color: var(--success-600);
  font-weight: 600;
}

.log-receipt-check {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
}

/* Live arrival only (broadcast passes arrived: true); history renders still. */
@keyframes receipt-settle {
  from {
    opacity: 0;
    transform: translateY(4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.log-receipt--arrived {
  animation: receipt-settle 0.45s ease both;
}

/* The check draws itself a beat after the receipt settles - the one flourish. */
.log-receipt--arrived .log-receipt-check path {
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  animation: receipt-check-draw 0.3s ease-out 0.3s forwards;
}

@keyframes receipt-check-draw {
  to {
    stroke-dashoffset: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .log-receipt--arrived,
  .log-receipt--arrived .log-receipt-check path {
    animation: none;
  }

  .log-receipt--arrived .log-receipt-check path {
    stroke-dashoffset: 0;
  }
}

/* Mutations Display Styles */
.mutations {
  max-width: 90%;
  margin-top: 0.5rem;
  font-size: 0.875rem;
}

/* =====================================================
   Dropdown action menus (shared primitive)
   Wrapper .dropdown is the positioning context wired to dropdown_controller;
   .dropdown-menu is the floating container, .dropdown-menu-item its rows.
   ===================================================== */

.dropdown {
  position: relative;
}

.dropdown-menu {
  display: none;
  position: absolute;
  right: 0;
  top: 100%;
  margin-top: 4px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  box-shadow: var(--specular), var(--e3);
  min-width: 180px;
  padding: 4px;
  z-index: 100;
  animation: menu-in 0.14s var(--ease-out);
}

/* Opens above the toggle when dropdown_controller detects clipping below */
.dropdown-menu--up {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: 4px;
  animation-name: menu-in-up;
}

@keyframes menu-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes menu-in-up {
  from {
    opacity: 0;
    transform: translateY(4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .dropdown-menu {
    animation: none;
  }
}

.dropdown-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 11px;
  background: none;
  border: 0;
  border-radius: 10px;
  text-align: left;
  cursor: pointer;
  font-size: 14px;
  font-weight: 550;
  font-family: inherit;
  color: var(--text);
  text-decoration: none;
  transition: background var(--transition-fast);
}

.dropdown-menu-item:hover {
  background: var(--gray-100);
}

.dropdown-menu-item:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: -2px;
}

/* Two ways to be unavailable, one look. [disabled] is rendered that way by the
   server; [aria-disabled] is a menu locked while one of its own actions is in
   flight, which stays focusable and keyboard-reachable so it can announce
   itself rather than vanishing from the rotation. */
.dropdown-menu-item[disabled],
.dropdown-menu-item[aria-disabled="true"] {
  opacity: 0.4;
  cursor: default;
}

.dropdown-menu-item[disabled]:hover,
.dropdown-menu-item[aria-disabled="true"]:hover {
  background: none;
}

.dropdown-menu-item svg {
  flex-shrink: 0;
  color: var(--text-muted);
}

.dropdown-menu-item--danger,
.dropdown-menu-item--danger svg {
  color: var(--error-500);
}

.dropdown-menu-item--danger:hover {
  background: var(--error-50);
}

.dropdown-menu-divider {
  height: 1px;
  background: var(--hairline);
  margin: 4px 8px;
}

/* button_to wraps its button in a form; keep the form out of menu layout */
.dropdown-menu-form {
  display: contents;
}

/* Round kebab toggle for action menus */
.dropdown-kebab {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--rule);
  color: var(--ink-soft);
  font-size: 14px;
  cursor: pointer;
}

.dropdown-kebab:hover {
  background: var(--paper-2);
}

.dropdown-kebab:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 2px;
}

/* Library template browser (Add From Library modal) */
.library-folders {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.library-folder {
  border: 1px solid var(--gray-200);
  border-radius: 10px;
}

.library-folder-summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.75rem;
  cursor: pointer;
  list-style: none;
}

.library-folder-summary svg {
  flex-shrink: 0;
}

.library-folder-name {
  flex: 1;
  font-weight: 600;
}

.library-folder-count {
  font-size: 0.8rem;
  color: var(--gray-500);
}

.library-template-list {
  display: flex;
  flex-direction: column;
  padding: 0 0.5rem 0.5rem;
}

.library-template-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.625rem 0.75rem;
  background: none;
  border: 0;
  border-radius: 8px;
  text-align: left;
  cursor: pointer;
  font-size: 0.875rem;
  font-family: inherit;
  color: var(--text);
  transition: background var(--transition-fast);
}

.library-template-btn:hover,
.library-template-btn:focus-visible {
  background: var(--gray-50);
}

.library-template-btn:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: -2px;
}

.library-template-btn svg {
  flex-shrink: 0;
  color: var(--text-muted);
}

.library-template-name {
  flex: 1;
}

@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.8; transform: scale(1.1); }
}

/* Badge container for count + suggestion indicator */
.badge-container {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* Chat messages scroll shadow */

.chat-scroll-shadow-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 20px;
  background: linear-gradient(to bottom, rgb(0 0 0 / 10%), transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
  z-index: 10;
}

.chat-scroll-shadow-bottom {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 20px;
  background: linear-gradient(to top, rgb(0 0 0 / 10%), transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
  z-index: 10;
}

.chat-scroll-shadow-top.visible,
.chat-scroll-shadow-bottom.visible {
  opacity: 1;
}

/* Divider */
.divider {
  position: relative;
  margin: 1.5rem 0;
  text-align: center;
}

.divider::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  background-color: var(--gray-300);
}

.divider span {
  position: relative;
  background-color: var(--paper);
  padding: 0 1rem;
  color: var(--gray-500);
  font-size: 0.875rem;
}

/* Devise error messages */
.error-alert {
  background-color: var(--error-100);
  border: 1px solid var(--error-200);
  color: var(--error-700);
  padding: 1rem;
  border-radius: 0.5rem;
  margin-bottom: 1.5rem;
}

.error-content {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.error-icon {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  margin-top: 0.125rem;
  color: var(--error-600);
}

.error-messages {
  flex: 1;
}

.error-message {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 500;
}

.error-message + .error-message {
  margin-top: 0.25rem;
}

/* Fix Rails field_with_errors wrapper */
.field_with_errors {
  display: contents;
}

.field_with_errors input,
.field_with_errors textarea,
.field_with_errors select {
  border-color: var(--error-500);
}

.field_with_errors input:focus,
.field_with_errors textarea:focus,
.field_with_errors select:focus {
  border-color: var(--error-500);
  box-shadow: 0 0 0 3px rgb(239 68 68 / 10%);
}

/* Portal Overlay System */
#overlay-root {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
}

/* Portaled Tooltip Styles */
.tooltip-portal {
  position: fixed;
  max-width: 160px;
  background: var(--overlay-chip-bg);
  color: white;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  font-size: 0.75rem;
  line-height: 1.2;
  box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
  pointer-events: none;
  transform: translate(-50%, -100%);
  white-space: normal;
  overflow-wrap: break-word;
  text-align: center;
}

.tooltip-portal::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-top-color: var(--overlay-chip-bg);
}

/* Flipped tooltip when at top of viewport */
.tooltip-bottom {
  transform: translate(-50%, 0);
}

.tooltip-bottom::before {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: var(--overlay-chip-bg);
}

/* Applied count span styles */
.applied-count {
  font-size: 0.75rem !important;
  margin-left: 0.5rem !important;
}

/* Utility Classes for JavaScript */
.hidden {
  display: none !important;
}

.visible {
  opacity: 1 !important;
}

.invisible {
  opacity: 0 !important;
}

.opacity-50 {
  opacity: 0.5 !important;
}

.inline-flex {
  display: inline-flex !important;
}

.block {
  display: block !important;
}

.inline-block {
  display: inline-block !important;
}

.date-nav {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  justify-content: center;
}

.date-btn {
  width: 40px;
  height: 40px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 1rem;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
}

.date-btn:hover {
  background: var(--bg);
  color: var(--text);
  border-color: var(--gray-400);
}

.date-content {
  flex: 1;
  text-align: center;
}

.date-main {
  font-size: 1.125rem;
  font-weight: 700;
}

.date-chip {
  display: inline-block;
  background: var(--orange-light);
  color: var(--orange);
  font-size: 0.6875rem;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 6px;
  margin-top: 4px;
  text-transform: uppercase;
}

/* Activity List */
.activity-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.activity-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--bg);
  border-radius: var(--radius);
  position: relative;
  transition: all 0.2s;
}

.activity-item:hover {
  background: var(--gray-100);
}

.activity-icon {
  width: 40px;
  height: 40px;
  background: var(--surface);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.125rem;
  flex-shrink: 0;
}

.activity-content {
  flex: 1;
  min-width: 0;
}

.activity-title {
  font-weight: 600;
  font-size: 0.875rem;
}

.activity-meta {
  display: flex;
  gap: var(--space-3);
  font-size: 0.75rem;
  color: var(--text-secondary);
  margin-top: 2px;
}

.activity-meta strong {
  color: var(--text);
}

/* Meal Groups */
.meal-group {
  margin-bottom: var(--space-4);
}

.meal-group:last-child {
  margin-bottom: 0;
}

.meal-header {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: var(--space-2);
  padding-left: 4px;
}

.fab {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-lg);
  border: none;
  font-size: 1.375rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
}

/* ===== Apple-native polish: app-wide depth + material (Jun 8 2026) ===== */

/* Most depth is free via the token alias; these add the specular top-edge to
   surfaces that read as lifted tiles, and float the popovers. */
.activity-item { box-shadow: var(--specular), var(--e1); }
.activity-item:hover { box-shadow: var(--specular), var(--e2); }
