/* ═════════════════════════════════════════════════════════════
   MIRROR DESIGN TOKENS — MWU ADDITIVE LAYER
   Mirror Web UX/UI Reconstruction, pilot 1 (Customer Profile)
   2026-08-31.  See docs/mirror-web-ux-rebuild-2026-08-31/

   ── WHY THIS FILE EXISTS SEPARATELY ──────────────────────────
   `mirror-tokens.css` is the single source of truth and remains
   so. It is also SHA-256 PINNED by
     tests/Feature/Portal/S5CustomerAppIconsTest.php:311
       'assets/tokens/mirror-tokens.css'
         => '92f6c90bb2da1345d62f502cbe6ffd6f5e4669853a4d0b6e252fc115472e61ff'
   so editing it fails a live test. This layer therefore EXTENDS
   that file's vocabulary — same `--mirror-*` naming, same
   SOURCE/ADAPTATION commentary discipline — as a second file
   loaded immediately after it.

   ⛔ THIS FILE ONLY ADDS. It redefines NOTHING that
   `mirror-tokens.css` already declares. If you find yourself
   wanting to override a value here, you are re-creating the
   layering defect this programme exists to end — read
   docs/mirror-web-ux-rebuild-2026-08-31/02-…§3 first.

   ── DIRECTION OF TRUTH ───────────────────────────────────────
   The Flutter customer app is the product/UX source of truth:
     Flutter-user-app/mirror_user-master/lib/app/
   Every [SOURCE] value below is traced to a Flutter declaration
   with file:line. Every [ADAPTATION] states why the web needed
   something the app does not have.

   Consolidation into `mirror-tokens.css` is DEFERRED and is an
   owner-ruled action, because it requires moving the SHA pin.
   See 05-integration-plan.md §4.3.
   ═════════════════════════════════════════════════════════════ */

:root {

    /* ═══════════════════════════════════════════════════════
       APP-DERIVED — traced to the Flutter theme
       ═══════════════════════════════════════════════════════ */

    /* ── Lines ───────────────────────────────────────────────
       settings_view.dart:185-187 — the hub row separator.
       A DISTINCT literal: NOT gray2Color (#E5E5E5), which this
       layer already carries as --mirror-line-soft.
       ──────────────────────────────────────────────────────── */
    --mirror-hairline:            #F4F4F5;

    /* ── Radii the profile surfaces need ─────────────────────
       settings_view.dart:44   the white sheet's top curve
                               BorderRadius.vertical(top: 28)
       language_changer.dart:98  bottom-sheet top curve, 20
       bottom_bar.dart:61        ClipRRect 24.bRadius
       ──────────────────────────────────────────────────────── */
    --mirror-radius-sheet:        28px;
    --mirror-radius-sheet-sm:     20px;
    --mirror-radius-nav:          24px;

    /* ── Accent colours: DELIBERATELY NOT DECLARED ───────────
       constants.dart:27,28,31,32 define buttonColor #CBA329,
       bgColor #FFD861, maleColor #59C1F2, femaleColor #F576AB.
       None is painted by the profile surfaces, so none is added
       here. Two reasons, both learned during this build:

       1. `--mirror-gold` ALREADY EXISTS in mirror-tokens.css:235
          as #D4A574 — a LEGACY web value, not the app's. Adding
          the app's #CBA329 under the same name would have been
          the exact layering defect this programme exists to end,
          just relocated into a new file.
          (test_the_additive_token_layer_redefines_nothing caught
          this before it shipped.)
       2. A token nothing uses is clutter that the next author
          must still evaluate. The screen that needs one adds it,
          with its own evidence, at that point.

       ⛔ If you need the app's gold, do NOT redefine
       `--mirror-gold`. Reconciling it with the legacy value is an
       owner decision, like every other legacy/app collision in
       mirror-tokens.css's LEGACY section.
       ──────────────────────────────────────────────────────── */

    /* ── Identity header ─────────────────────────────────────
       user_info_section.dart:16-30
         SvgWidget(bg_pattern.svg, color: Colors.black.withOpacity(0.3))
       :50-58  the avatar: circle, 2px WHITE ring drawn OUTSIDE
               the box (BorderSide.strokeAlignOutside) — which is
               why the web uses box-shadow, not border.
       :48-49  height = width = mqSize.height * 0.07
               ≈ 59px on an 844-tall phone.
       ──────────────────────────────────────────────────────── */
    --mirror-header-overlay:      rgba(0, 0, 0, .30);
    --mirror-avatar-ring:         2px;
    --mirror-avatar-hub:          60px;

    /* Pattern tile — ⚠️ REGISTERED ADAPTATION.
       The source asset assets/svgs/bg_pattern.svg is 11,517,075
       bytes: a traced 3x7 grid of one 133x124 motif in a 400x800
       viewBox. It cannot ship. The ONE motif was extracted from
       the REAL asset by rendering it and cropping the grid cell
       at (61.5312, 0.0702948) at exactly 133x124 — so the
       artwork IS the product's own pattern, not a substitute.
       The PNG is 266x248 (2x, for HiDPI) and is DISPLAYED at
       133x124 so the app's apparent scale is preserved.
       BoxFit.cover becomes background-repeat because fixed
       400x800 art cannot cover a 1440px header without gross
       upscaling. See 05-integration-plan.md §11.2. */
    --mirror-pattern-tile:        133px 124px;

    /* ── Toast — flashbar_helper.dart:19-49 ──────────────────
       SnackBar, backgroundColor Colors.black87, floating, 3 s,
       leading icon check_circle/error/info in green/red/blue.
       These are Flutter FRAMEWORK Material constants the app
       uses directly, not values this project chose.
       ──────────────────────────────────────────────────────── */
    --mirror-toast-bg:            rgba(0, 0, 0, .87);   /* :44 Colors.black87 */
    --mirror-toast-fg:            #FFFFFF;
    --mirror-toast-success:       #4CAF50;              /* :31 Colors.green M500 */
    --mirror-toast-error:         #F44336;              /* :25 Colors.red   M500 */
    --mirror-toast-info:          #2196F3;              /* :28 Colors.blue  M500 */

    /* ── Interaction ─────────────────────────────────────────
       bouncing_widgets.dart — BounceIt wraps every tappable
       surface in the app and scales it down on press.
       ──────────────────────────────────────────────────────── */
    --mirror-tap-scale:           .96;


    /* ═══════════════════════════════════════════════════════
       WEB ADAPTATIONS — no Flutter counterpart.
       Each states the reason it cannot be [SOURCE].
       ═══════════════════════════════════════════════════════ */

    /* Flutter's hint colour (constants.dart:13 gray1Color #979797)
       on the field fill (#F5F5F5) measures 2.67:1 and FAILS
       WCAG AA (4.5:1). #6E6E6E measures 4.54:1 on the same fill.

       ⛔ --mirror-hint is NOT redefined. It stays exactly as
       `mirror-tokens.css` declares it and remains correct for
       DECORATION — chevrons, rules, aria-hidden glyphs. This
       token is for hints and labels that CARRY MEANING.
       Owner ruling: `04-decision-record.md` D-10. */
    --mirror-hint-strong:         #6E6E6E;

    /* Flutter draws NO focus indicator on inputs — every border
       is BorderSide.none in all four states
       (custom_text_form_field.dart:152-176). A pointer/keyboard
       medium requires one (WCAG 2.4.7).
       Brand-coloured, NOT arbitrary: the app's own focus
       behaviour IS "recolour to brand" — :130-135 recolours the
       prefix SVG to Constants.mainColor on focus. */
    --mirror-focus-ring:          0 0 0 3px rgba(var(--mirror-brand-rgb), .30);

    /* The VALUE is [SOURCE] — bottom_bar.dart:46-53 declares
       exactly this shadow. It is listed as an adaptation because
       the LIVE MainBottomBar (:60-125) never applies it; only
       the commented-out earlier class did. The web reinstates it
       so a fixed bar separates from scrolling content. */
    --mirror-nav-shadow:          0 -10px 31px rgba(0, 0, 0, .09);

    /* Overlay elevation. These two screens draw NO shadows at
       all — Constants.blackAndWhiteShadow is defined but
       commented out at every use site
       (input_decoration_theme.dart:32,
        custom_text_form_field.dart:174) and both app bars set
       elevation: 0. A modal floating over a scrim needs one. */
    --mirror-overlay-shadow:      0 24px 70px rgba(43, 22, 35, .22);

    /* The app is portrait-LOCKED (main.dart:12
       setPreferredOrientations([portraitUp])), so it has no
       opinion about wide viewports. A measure cap is required or
       a three-field form stretches across 1920px.
       640 ≈ 1.5x the app's own 428 design frame
       (my_app.dart:16 designSize: Size(428, 926)). */
    --mirror-content-max:         640px;

    /* Desktop master–detail rail. Owner ruling B-3, 2026-08-31:
       "use the Master–Detail design exactly as established in the
       approved prototype." No Flutter counterpart — see above. */
    --mirror-rail-width:          360px;

    /* WCAG 2.5.8 / platform minimum. The app's own smallest
       targets on these screens are the 48px back button
       (custom_appbar.dart:206) and ~52px rows, but the gear is a
       bare 24px SvgWidget with no padding
       (user_info_section.dart:71-79). */
    --mirror-hit-min:             44px;

    /* ── The Mirror wordmark, as a MASK ──────────────────────
       [SOURCE] loading_widgets.dart:6-8,53-73 —
         LogoLoadingWidget({this.size = 72})
         SizedBox(72 x 72) > SvgWidget(Assets.svgsLogo,
           color: Constants.mainColor, fit: BoxFit.contain)
           .animate(repeat).shimmer(2s, easeOut, Colors.white,
                                    angle: 100)
       This is the indicator the app shows while a profile save
       is in flight (profile_view.dart:139-142), and it is what
       the approved prototype renders for the Saving state.

       ⛔ NO NEW ASSET. The wordmark is ALREADY in the web tree
       at assets/site/images/logo/mirror_logo.svg, and it is
       already byte-identical to the app's assets/svgs/logo.svg
       (sha256 762a225c…, pinned by S5CustomerAppIconsTest:51).
       ⛔ And it is deliberately NOT copied to
       assets/account/svgs/logo.svg — that exact path is a
       standing prohibition (S5CustomerAppIconsTest::
       test_no_neosans_font_and_no_hipno_demo_asset_entered_the_repo).
       ──────────────────────────────────────────────────────── */
    --mirror-logo-mark:           url('/assets/site/images/logo/mirror_logo.svg');

    /* ── The customer shell's bottom bar ─────────────────────
       [SOURCE] bottom_bar.dart — the app's MainBottomBar is a
       fixed bar the content never sits under.
       ⚠️ The VALUE is the web shell's own: layouts/customer/
       nav.blade.php:138 declares `height: 72px` for the spacer
       that reserves the bar's room. It is named here because a
       SECOND element now has to clear that bar — the success
       toast (see mirror-profile.css §5.5) — and two hard-coded
       72s in two files is how drift starts.
       ⛔ nav.blade.php stays the source; this token follows it.
       ──────────────────────────────────────────────────────── */
    --mirror-nav-h:               72px;

    /* Web-idiomatic transition for the small state changes
       (label lift, hover, press). The app uses flutter_animate
       defaults; its one explicit duration on these screens is
       image_selector.dart:52 `duration: 300ms` for the focused
       menu, which the overlay timing below matches. */
    --mirror-motion:              180ms cubic-bezier(.2, 0, .2, 1);
    --mirror-motion-sheet:        300ms cubic-bezier(.2, 0, .2, 1);

    /* ── Typography ──────────────────────────────────────────
       ⛔ NeoSans is NOT declared here. OQ-3 was VERIFIED on
       2026-08-31 and the answer is that the project holds no
       licence permitting web @font-face serving: the font's own
       embedded licence (TTF name ID 13, Linotype GmbH) states
       "you may not copy or distribute this font software", and
       two repo guards enforce the prohibition
       (S5CustomerAppIconsTest::test_no_neosans_font_…,
        CwaS8SearchIdentityTest::test_p3_…).
       See 04-decision-record.md §OQ-3-VERIFICATION.

       ⚠️ FUP-3, found at runtime 2026-08-31: portal.css declares
       `html, body { font-family }` TWICE — rule index 2 asks for
       Sora, rule index 204 asks for Inter, and the LATER WINS.
       So the customer body face is Inter and the Sora
       declaration is dead. The profile surface therefore
       DECLARES its own stack rather than inheriting an accident.
       Sora leads it so that when FUP-3 is fixed this surface
       already honours the intent; Inter follows so nothing
       visibly changes on release; the Arabic faces are named
       explicitly because NEITHER Sora NOR Inter has Arabic
       coverage — today Arabic falls to an undeclared OS default.
       Licence-free, and not a NeoSans substitute. */
    --mirror-font-profile:
        'Sora', Inter, 'Segoe UI', Tahoma,
        'Noto Naskh Arabic', 'Geeza Pro', 'Arabic Typesetting',
        ui-sans-serif, system-ui, sans-serif;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MWU SCREEN 3 — SEARCH  ·  2026-09-01
   Owner ruling Q-2 (STOP 3): the Search tokens live HERE, additively.

   ⛔ ADDITIVE ONLY. Not one token above is redefined — this block declares
      eleven NEW `--mirror-csearch-*` names and nothing else. `mirror-tokens.css`
      is SHA-256 pinned by S5CustomerAppIconsTest and is not touched.

   Every value is traced to Flutter source, cited inline. Consumed only by
   public/assets/search/mirror-csearch.css, which is the sole owner of the
   `mirror-csearch-*` class namespace (ruling Q-1).
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
    /* The gender/type chip, service_card.dart:198-211 tinted by
       service.dart:10-12 — THREE arms, not two. */
    /* ⛔ The names CwaS8 A6 already pins are KEPT. `unisex` resolves through
       the EXISTING --mirror-hint (#979797, the same gray1Color) rather than
       minting a third literal — the rule A6 states in its own docblock. */
    --mirror-csearch-type-woman:  #F576AB;   /* constants.dart:33 femaleColor */
    --mirror-csearch-type-man:    #59C1F2;   /* constants.dart:32 maleColor   */
    --mirror-csearch-type-unisex: var(--mirror-hint);   /* :13 gray1Color */

    /* search_input.dart:62 — `fillColor: Constants.lightGrayColor`, and the
       same fill the app's dropdown fields use (drop_down_search_config.dart:63). */
    --mirror-csearch-field-fill:      #F5F5F5;   /* constants.dart:17 lightGrayColor */

    /* salon_card.dart:6-11 · freelancer_card.dart:4-9 — ONE shadow, declared
       identically on both cards: rgba(0,0,0,.09), offset 0/10, blur 31, spread 3. */
    /* ⛔ The token KEEPS the name CwaS8 A4 pins (`--mirror-csearch-shadow`) and
       its exact value. What changes is WHERE it is applied — see the sheet. */
    --mirror-csearch-shadow:          0 10px 31px 3px rgba(0, 0, 0, .09);

    /* salon_card.dart:30 (card) and :40 (its image). */
    --mirror-csearch-salon-radius:    24px;
    --mirror-csearch-salon-img-radius:16px;

    /* freelancer_card.dart:25 */
    --mirror-csearch-tile-radius:     12px;

    /* service_card.dart:100 — Material(SquircleBorder(radius: 60)) on the
       ~86px thumbnail. ⚠️ APPROXIMATION, registered in
       04-owner-rulings-and-decision-record.md §4: CSS has no true squircle, and
       30% reads as neither a circle nor a 12px rectangle — the perceptual
       distinction that matters. To be measured at Phase 8. */
    --mirror-csearch-squircle:        30%;

    /* drop_down_search_config.dart:25-27 — the anchored menu meets its field, so
       only the BOTTOM corners are rounded. */
    --mirror-csearch-menu-radius:     0 0 8px 8px;
    /* :19-22 — elevation 4, shadowColor black @ 50%. */
    --mirror-csearch-menu-shadow:     0 4px 14px rgba(0, 0, 0, .28);

    /* ⛔ NO Search-owned red. filiter_bottom_sheet.dart:75 and :126 both use
       Flutter's `Colors.red`, which the token layer ALREADY carries exactly as
       --mirror-app-red (#F44336). An earlier draft of this block minted
       #D32F2F, which is a DIFFERENT colour — caught by CwaS9's S9-6 guard,
       which pins the existing token by name. Additive means adding what is
       missing, not duplicating what is not. */

    /* service_card.dart:22-24 — `shortestSide * 0.22`, i.e. 85.8 on the app's
       own 390 viewport.
       ⛔ A PIXEL FLOOR, NOT `vmin`. `vmin` IS shortestSide, so it ports exactly
          on a portrait-locked phone and catastrophically on a desktop: at
          1920x855 the superseded `28vmin` token computes to 239.4px, and the
          shipped card measured 240.5 (02 §2.2). The unit was the defect.
       ⛔ And it is a MINIMUM, not a fixed height — owner ruling OQ-S15. */
    --mirror-csearch-row-min:         85.8px;
}

/* ===========================================================================
   MWU SCREEN 6 - PROVIDER SERVICE FORM  .  2026-09-03
   Owner ruling (STOP 2, decision 3): the Screen 6 tokens live HERE, additively.

   /!\ ADDITIVE ONLY. Seven NEW `--mirror-psvf-*` names; nothing above is
       redefined (MwuProfileSurfaceIsolationTest::test_the_additive_token_layer
       _redefines_nothing proves it). mirror-tokens.css stays SHA-pinned and
       untouched, and this file's own <link> buster on master-provider
       (`mwu-phome-20260903a`) does NOT move - the rule that guard states is
       that the token layer's link keeps the key it was introduced with.

   Consumed only by public/assets/provider-service-form/mirror-psvf.css.
   Every value is traced to the Flutter source and to the frozen prototype
   (provider-service-form-en.html sha256 f670a86d...).
   =========================================================================== */
:root {
    /* custom_text_form_field.dart:158 - EdgeInsets.symmetric(vertical: 16, horizontal: 12) */
    --mirror-psvf-field-pad:      16px 12px;

    /* image_selector_section.dart:19-21 - width * 0.50 at the app's 428 design
       frame. A PIXEL value, never 50vw: Screen 3's viewport-fraction token
       computed 239px on desktop where the app draws ~86. */
    --mirror-psvf-image-size:     214px;

    /* image_selector.dart:55 blurSize: 5.0 */
    --mirror-psvf-menu-blur:      5px;

    /* image_selector.dart:53 menuWidth: .5.sw -> 50% of the 428 frame */
    --mirror-psvf-menu-w:         214px;

    /* image_selector.dart:57 menuItemExtent: 50.r */
    --mirror-psvf-menu-item-h:    50px;

    /* all four FinalCustomDropdown call sites - maxHeight: 300
       (subcatgeory_select.dart:133,:175 . city_select.dart:133,:178) */
    --mirror-psvf-dropdown-max-h: 300px;

    /* submit_button.dart:61 height: 48.h - and LoadingWidget is 48x48, which is
       why the ring replaces the button in place rather than sitting inside it. */
    --mirror-psvf-submit-h:       48px;
}
