/* ── Design tokens ── */
    :root {
      --glass-bg:         rgba(0,0,0,.32);
      --glass-border:     rgba(255,255,255,.09);
      --glass-blur:       blur(16px) saturate(140%);
      --dock-bg:          rgba(155,155,158,.09);
      --dock-blur:        blur(14px) saturate(160%);
      --dock-border:      rgba(255,255,255,.07);
      --dock-shadow:      0 2px 10px rgba(0,0,0,.20),
                          inset 0 0 0 1px rgba(255,255,255,.06),
                          inset 1px 1px 0 rgba(255,255,255,.12),
                          inset -1px -1px 0 rgba(0,0,0,.10);
      --icon-inset-shadow: inset 1px 1px 0 rgba(255,255,255,.18),
                           inset -1px -1px 0 rgba(0,0,0,.14);
      --icon-sheen:       linear-gradient(135deg,rgba(255,255,255,.10) 0%,transparent 60%);
      --label-color:      rgba(255,255,255,.90);
      --label-shadow:     0 1px 4px rgba(0,0,0,.70);
      --bounce-spring:    cubic-bezier(.34,1.56,.64,1);
      --page-ease:        cubic-bezier(.77,0,.175,1);
      /* The page behind the wallpaper, and the boot veil over the unstyled
         first paint. */
      /* Darker than the system greys: it sits behind the wallpaper. */
      --bg-base:          #0d1117;
      /* The opaque card preset a widget can ask for by name. */
      --card-dark:        var(--sy-gray6);
      --badge-red:        var(--danger);
      --badge-blue:       var(--sy-blue);
    }

    /* ── Root ── */
    html {
      width:100vw; height:100vh; height:100dvh; overflow:hidden;
      background: var(--bg-color, var(--bg-base));
      font-family:var(--font-ui);
      -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
    }
    /* background, position and z-index come from tokens.css. */
    body { width:100vw; height:100vh; height:100dvh; overflow:hidden; }
    /* ── Boot loading veil — fades out once boot() finishes ── */
    body::after {
      content:''; position:fixed; inset:0; z-index:9999;
      background:var(--bg-base); pointer-events:none;
      transition:opacity .4s ease;
    }
    body.ready::after { opacity:0; }

    /* ── Page strip ── */
    #pages {
      position:fixed; inset:0; z-index:10;
      display:flex;
      transition:transform .44s var(--page-ease);
    }
    .page {
      flex:0 0 100vw; width:100vw; height:100vh; height:100dvh;
      display:flex;
      flex-direction:column;
      align-items:center;
      justify-content:start;
      overflow:hidden;
      /* Top clears the controls bar, bottom clears the dock. The fluid
         horizontal padding keeps .grid inside the content box on a
         narrow-wide viewport. */
      padding:clamp(44px,4vh,70px) clamp(16px,4vw,270px) clamp(110px,10vh,160px);
    }
    /* ── Desktop grid scale ──
       Six columns at every width. The grid, the gaps and the tile height are
       one proportional system derived from the viewport, so six columns stay
       square on a tablet. Above the design width the system stops: each min()
       is capped at its design value, so a large screen gets the same sizes a
       desktop has always had.

       The design width is 1041px, which over six columns and a 25px gap gives a
       152.67px column, the width the 152px tile height and every value in
       WIDGET_HEIGHTS were drawn against. Each ratio below is that value over
       1041.

       dashboard.js reads --tile-h and --row-gap back to paginate. Changing a
       ratio here without changing DESIGN_TILE there breaks the page breaks. */
    :root {
      --grid-avail:calc(100vw - 88px);
      --grid-w:min(1041px, var(--grid-avail));
      --col-gap:min(25px, calc(var(--grid-avail) * 0.024015));
      --row-gap:min(30px, calc(var(--grid-avail) * 0.028818));
      --tile-h:min(152px, calc(var(--grid-avail) * 0.146013));
    }
    /* Measured by dashboard.js. An element resolves these to pixels; reading the
       custom properties themselves returns their unresolved text. */
    .gm-probe {
      position:absolute; visibility:hidden; pointer-events:none;
      width:0; height:var(--tile-h);
    }
    .gm-probe > i { display:block; height:var(--row-gap); }
    .grid {
      display:grid; grid-template-columns:repeat(6,1fr);
      column-gap:var(--col-gap); row-gap:var(--row-gap);
      width:var(--grid-w); align-items:start;
    }
    .c1 { grid-column:span 1 }
    .c2 { grid-column:span 2 }
    .r2 { grid-row:span 2 }
    .r3 { grid-row:span 3 }

    /* ── Widget card ── */
    .wc {
      display:flex;
      align-items:stretch;
    }
    .widget {
      position:relative;
      width:100%; border-radius:28px; overflow:hidden;
      border:1px solid var(--glass-border); background:var(--glass-bg);
      -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
    }
    .widget iframe { display:block; border:0; width:100% }

    /* The mobile home screen builds its own card element with the same glass
       material. Its sizing stays inline. */
    .mob-widget-card {
      border:1px solid var(--glass-border); background:var(--glass-bg);
      -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
    }

    /* ── Card backgrounds ──
       A widget picks one of these by name in its manifest, so no widget is named
       here. A widget that paints its own interior declares nothing and keeps the
       default glass behind it. */
    .widget[data-card="dark"],
    .mob-widget-card[data-card="dark"] {
      background: var(--card-dark);
      -webkit-backdrop-filter: none; backdrop-filter: none;
    }
    .widget[data-card="light"],
    .mob-widget-card[data-card="light"] {
      background: var(--bg-primary-light); border-color: rgba(0,0,0,.12);
      -webkit-backdrop-filter: none; backdrop-filter: none;
    }
    .widget[data-card="translucent"],
    .mob-widget-card[data-card="translucent"] {
      background: rgba(0,0,0,.25);
      -webkit-backdrop-filter: blur(22px) saturate(140%);
              backdrop-filter: blur(22px) saturate(140%);
    }
    .icon {
      height:var(--tile-h,152px);
      display:flex;
      flex-direction:column;
      align-items:center;
      justify-content:center;
      text-decoration:none; cursor:pointer; grid-column:span 1;
      -webkit-tap-highlight-color:transparent;
    }

    /* ── Icon wrap (grid + dock share structure, differ in size via inline style) ── */
    .iwrap, .dwrap {
      position:relative;
      display:flex;
      align-items:center;
      justify-content:center;
      flex-shrink:0; overflow:visible;
      transition:transform .18s var(--bounce-spring);
    }
    .iwrap { border-radius:16px }
    .dwrap { border-radius:15px }

    /* Inset shadow bevel — applied via ::before so it doesn't clip children */
    .iwrap::before, .dwrap::before {
      content:''; position:absolute; inset:0; border-radius:inherit;
      background:inherit; z-index:0;
      box-shadow:var(--icon-inset-shadow);
    }
    /* Gloss sheen */
    .iwrap::after, .dwrap::after {
      content:''; position:absolute; inset:0; border-radius:inherit;
      background:var(--icon-sheen);
      pointer-events:none; z-index:2;
    }
    .iwrap img, .dwrap img { object-fit:contain; position:relative; z-index:3 }
    .iwrap .fb, .dwrap .fb,
    .dyn-mob-icon .fb, .dyn-dock-icon .fb { position:relative; z-index:3; font-weight:600; color:rgba(255,255,255,.85) }

    /* Hover lift */
    .icon:hover .iwrap,
    .folder-icon-link:hover .iwrap {
      transform:scale(1.10) translateY(-4px);
    }
    .di:hover .dwrap {
      transform:scale(1.15) translateY(-8px);
    }

    /* ── Icon label ── */
    .ilabel {
      font-size:var(--fs-footnote);line-height:var(--lh-footnote);letter-spacing:var(--tr-footnote); font-weight:500; color:var(--label-color);
      text-align:center; text-shadow:var(--label-shadow); margin-top:6px;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    }

    /* ── Badge — reference size, scaled by --sc (desktop overrides below) ── */
    .badge {
      position:absolute;
      top:calc(-7px * var(--sc,1)); right:calc(-7px * var(--sc,1));
      min-width:calc(24px * var(--sc,1)); height:calc(24px * var(--sc,1));
      border-radius:50px; padding:0 calc(6px * var(--sc,1));
      display:none;
      align-items:center;
      justify-content:center;
      font-size:calc(var(--fs-footnote) * var(--sc,1));letter-spacing:var(--tr-footnote); font-weight:800; color:var(--label-primary); line-height:1;
      z-index:20; pointer-events:none;
      /* Pins the badge to its own compositing layer. WebKit otherwise
         promotes and demotes it as its classes change, and the clipped
         corners rasterise torn. */
      transform:translateZ(0);
    }
    .badge.on  { display:flex }
    .badge.red  { background:var(--badge-red) }
    .badge.blue { background:var(--badge-blue) }
    .badge.green { background:var(--success) }
    .badge.stale { opacity:.55; outline:1.5px dashed rgba(255,255,255,.92); outline-offset:1px }
    /* Desktop: restore compact badge size */
    body:not(.is-mob) .badge {
      top:-7px; right:-7px;
      min-width:20px; height:20px; padding:0 5px;
      font-size:var(--fs-caption-2);line-height:var(--lh-caption-2);letter-spacing:var(--tr-caption-2); font-weight:700;
    }

    /* ── Top-right controls ── */
    #ctrls {
      position:fixed; top:10px; right:max(44px,calc((100vw - 1160px)/2));
      z-index:200; display:flex; gap:6px;
    }
    .ctrl {
      width:34px; height:34px; border-radius:9px; border:0; cursor:pointer;
      background:rgba(255,255,255,.10); color:rgba(255,255,255,.62); font-size:var(--fs-callout);line-height:var(--lh-callout);letter-spacing:var(--tr-callout);
      display:flex;
      align-items:center;
      justify-content:center;
      transition:background .15s,color .15s;
      text-decoration:none;
      -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
    }
    .ctrl:hover { background:rgba(255,255,255,.18); color:rgba(255,255,255,.90) }

    /* ── Page dots ── */
    #dots {
      position:fixed; bottom:160px; left:50%; /* desktop only — mobile overrides bottom inline */
      transform:translateX(-50%);
      display:flex; gap:10px; z-index:500;
      background:rgba(255,255,255,.28);
      -webkit-backdrop-filter:blur(12px) saturate(140%); backdrop-filter:blur(12px) saturate(140%);
      border-radius:24px; padding:10px 18px;
      align-items:center;
    }
    .dot {
      width:8px; height:8px; border-radius:50%; background:rgba(255,255,255,.50);
      transition:background .2s,transform .2s,width .25s,opacity .25s;
      cursor:pointer; flex-shrink:0;
      /* A dot is a <button>, so Tab reaches it and Enter and Space work. */
      padding:0; border:0; -webkit-appearance:none; appearance:none;
    }
    .dot.on { background:var(--control-knob); transform:scale(1.25) }

    /* ── Search pill — mobile only ── */
    #mob-search-pill {
      position:fixed; left:50%; z-index:500;
      transform:translateX(-50%);
      display:none; /* shown by buildMobile */
      align-items:center;
      justify-content:center;
      background:rgba(60,60,67,.72);
      -webkit-backdrop-filter:blur(20px) saturate(160%); backdrop-filter:blur(20px) saturate(160%);
      border-radius:calc(17px * var(--sc,1));  /* half of pillH = capsule ends */
      border:0.5px solid rgba(255,255,255,.10);
      cursor:pointer;
      -webkit-tap-highlight-color:transparent;
      overflow:hidden;
      transition:width .25s cubic-bezier(.4,0,.2,1);
    }
    /* Search content — shown when idle */
    #mob-search-pill .msp-search {
      display:flex;
      align-items:center;
      justify-content:center;
      gap:calc(5px * var(--sc,1));
      position:absolute; inset:0;
      transition:opacity .18s ease;
      pointer-events:none;
    }
    #mob-search-pill .msp-icon {
      font-size:calc(var(--fs-footnote) * var(--sc,1));letter-spacing:var(--tr-footnote); color:rgba(255,255,255,.60); line-height:1;
      font-style:normal;
    }
    #mob-search-pill .msp-label {
      font-size:calc(var(--fs-subheadline) * var(--sc,1));line-height:var(--lh-subheadline);letter-spacing:var(--tr-subheadline); font-weight:400; color:rgba(255,255,255,.80);
      white-space:nowrap; 
    }
    /* Dots row — shown when paging */
    #mob-search-pill .msp-dots {
      display:flex;
      align-items:center;
      justify-content:center;
      gap:calc(5px * var(--sc,1));
      position:absolute; inset:0;
      opacity:0;
      transition:opacity .18s ease;
      pointer-events:none;
    }
    /* Pill dots — must match JS _pdotSz/_pdotGap, which size the paging pill */
    #mob-search-pill .msp-dot {
      width:calc(8px * var(--sc,1)); height:calc(8px * var(--sc,1)); border-radius:50%;
      background:rgba(255,255,255,.38); flex-shrink:0;
      transition:background .18s,transform .18s;
    }
    #mob-search-pill .msp-dot.on { background:rgba(255,255,255,.90); transform:scale(1.2) }
    /* State transitions */
    #mob-search-pill.paging .msp-search { opacity:0; pointer-events:none }
    #mob-search-pill.paging .msp-dots   { opacity:1; pointer-events:auto }

    /* ── Dock ── */
    #dock {
      position:fixed; bottom:12px; left:50%;
      transform:translateX(-50%);
      z-index:400;
      display:flex;
      align-items:center;
      gap:15px; padding:22px;
      background:var(--dock-bg);
      -webkit-backdrop-filter:var(--dock-blur); backdrop-filter:var(--dock-blur);
      border:1px solid var(--dock-border); border-radius:45px;
      box-shadow:var(--dock-shadow);
    }
    .mdock {
      position:fixed; left:50%;
      transform:translateX(-50%);
      z-index:400;
      display:flex;
      align-items:center;
      justify-content:space-around;
      background:var(--dock-bg);
      -webkit-backdrop-filter:var(--dock-blur); backdrop-filter:var(--dock-blur);
      border:1px solid var(--dock-border);
      box-shadow:var(--dock-shadow);
    }
    .di {
      display:flex;
      align-items:center;
      justify-content:center;
      cursor:pointer; text-decoration:none;
      -webkit-tap-highlight-color:transparent;
    }

    /* ── Spotlight overlay — shared base ── */
    #spot {
      position:fixed; inset:0; z-index:1000;
      display:none; opacity:0;
      transition:opacity .2s ease;
    }
    #spot.on  { display:flex;
                flex-direction:column; }
    #spot.vis { opacity:1 }

    /* ── Spotlight — mobile layout (default, overridden for desktop below) ── */
    #spot {
      background:rgba(0,0,0,.52);
      -webkit-backdrop-filter:blur(40px) saturate(180%) brightness(.76);
      backdrop-filter:blur(40px) saturate(180%) brightness(.76);
      align-items:stretch;
      justify-content:flex-end;
      padding-bottom:0; box-sizing:border-box;
    }
    /* Results fill from below X button to sbox */
    body.is-mob #spot #sres {
      flex:1 1 0;
      overflow-y:auto; 
      padding:170px 0 4px; /* 120px (X top) + 40px (X height) + 10px gap */
      min-height:0;
    }
    /* Search bar pinned to bottom on mobile */
    body.is-mob #spot #sbox {
      flex-shrink:0;
      padding:10px 16px 12px; box-sizing:border-box;
    }
    /* ✕ close button, mobile only */
    #spot-cancel-mob {
      /* inset-inline-end, not right. The end of the line is the left in
         Persian. */
      display:none; position:fixed; top:120px; inset-inline-end:16px; z-index:1002;
    }
    body.is-mob #spot.on #spot-cancel-mob { display:block; }
    #spot-cancel-mob-btn {
      width:40px; height:40px; border-radius:50%;
      background:rgba(118,118,128,.50);
      border:0; outline:0; cursor:pointer;
      -webkit-tap-highlight-color:transparent;
      display:flex;
      align-items:center;
      justify-content:center;
      position:relative;
    }
    #spot-cancel-mob-btn::after { content:''; position:absolute; inset:-7px; }

    /* ── Spotlight — desktop overrides ── */
    body:not(.is-mob) #spot {
      background:rgba(0,0,0,.45);
      -webkit-backdrop-filter:blur(20px) saturate(160%);
      backdrop-filter:blur(20px) saturate(160%);
      align-items:center;
      justify-content:flex-start;
      flex-direction:column;
      padding-top:max(env(safe-area-inset-top),80px);
      box-sizing:border-box;
    }
    /* Search bar as a floating card at the top */
    body:not(.is-mob) #sbox {
      width:min(680px,92vw);
      background:rgba(28,28,32,.92);
      border:1px solid rgba(255,255,255,.14); border-radius:18px;
      box-shadow:0 20px 60px rgba(0,0,0,.60); overflow:hidden;
      flex-shrink:0; padding:0; order:-1;
    }
    /* Results as a separate card below the search bar */
    body:not(.is-mob) #sres {
      width:min(680px,92vw);
      max-height:60vh; overflow-y:auto; 
      padding:6px 0; margin-top:8px; flex:none; min-height:0;
      background:rgba(28,28,32,.92);
      border:1px solid rgba(255,255,255,.14); border-radius:18px;
      box-shadow:0 20px 60px rgba(0,0,0,.40);
    }
    body:not(.is-mob) #sres:empty { display:none; }
    body:not(.is-mob) #spot-cancel { display:flex; }

    /* ── Search bar ── */
    .spot-bar {
      display:flex;
      align-items:center;
      gap:10px; padding:14px 18px;
      border-bottom:1px solid rgba(255,255,255,.08);
    }
    body.is-mob #spot .spot-bar {
      background:rgba(118,118,128,.30);
      border-radius:50px; border-bottom:none;
      padding:22px 22px; gap:14px;
    }
    .spot-icon {
      color:rgba(255,255,255,.45); flex-shrink:0;
      display:flex;
      align-items:center;
      pointer-events:none;
    }
    #sin {
      flex:1; background:transparent; border:0; outline:none;
      font-size:var(--fs-callout);line-height:var(--lh-callout);letter-spacing:var(--tr-callout); color:rgba(255,255,255,.92);
      font-family:inherit; caret-color:var(--accent);
      -webkit-appearance:none; appearance:none;
      min-height:26px; padding:0; margin:0; width:100%;
    }
    /* Mobile only — larger input text to match the bigger search bar */
    body.is-mob #spot #sin { font-size:var(--fs-title-2);line-height:var(--lh-title-2);letter-spacing:var(--tr-title-2); }
    #sin::placeholder { color:rgba(255,255,255,.38); }
    #spot #sin::placeholder { color:rgba(235,235,245,.38); }
    #spot-cancel {
      display:none; flex-shrink:0; background:transparent; border:0;
      outline:0; cursor:pointer; -webkit-tap-highlight-color:transparent;
      font-size:var(--fs-body);line-height:var(--lh-body);letter-spacing:var(--tr-body); color:rgba(255,255,255,.55); font-weight:400;
      padding:0 4px; white-space:nowrap;
      align-items:center;
      justify-content:center;
    }

    /* ── Mobile result rows — only apply on mobile ── */
    body.is-mob #sres .sr { padding:calc(10px * var(--sc,1)) calc(14px * var(--sc,1)); gap:calc(12px * var(--sc,1)); }
    body.is-mob #sres .sr + .sr { border-top:0.5px solid rgba(255,255,255,.10); }
    body.is-mob #sres .sr-section { display:none; }
    body.is-mob #sres .srn { font-size:calc(var(--fs-body) * var(--sc,1));line-height:var(--lh-body);letter-spacing:var(--tr-body); font-weight:500; }
    body.is-mob #sres .srh { display:none; }
    body.is-mob #sres .sra { display:none; }
    body.is-mob #sres .sri { width:calc(44px * var(--sc,1)); height:calc(44px * var(--sc,1)); border-radius:calc(10px * var(--sc,1)); }
    /* !important: beats the equally-important #sres .sri img rule below. */
    body.is-mob #sres .sri img, body.is-mob #sres .sri .sri-img { width:calc(30px * var(--sc,1)) !important; height:calc(30px * var(--sc,1)) !important; }

    /* ── Spotlight result rows ── */
    .sr-section {
      font-size:var(--fs-footnote);line-height:var(--lh-footnote); font-weight:600; color:rgba(255,255,255,.42);
      padding:10px 16px 4px; letter-spacing:0.04em; text-transform:uppercase;
      border-bottom:0.5px solid rgba(255,255,255,.08);
    }
    .sr {
      display:flex;
      align-items:center;
      gap:14px; padding:12px 16px; cursor:pointer; text-decoration:none;
      transition:background .12s;
    }
    .sr:hover, .sr:active, .sr.sel { background:rgba(255,255,255,.07) }
    .sri {
      width:44px; height:44px; border-radius:12px;
      display:flex;
      align-items:center;
      justify-content:center;
      flex-shrink:0; overflow:hidden;
    }
    .sri img, .sri .sri-img { width:28px; height:28px; object-fit:contain }
    #sres .sri img, #sres .sri .sri-img { width:34px !important; height:34px !important; }
    .srn { font-size:var(--fs-body);line-height:var(--lh-body);letter-spacing:var(--tr-body); font-weight:400; color:rgba(255,255,255,.92) }
    .srh {
      font-size:var(--fs-footnote);line-height:var(--lh-footnote);letter-spacing:var(--tr-footnote); color:rgba(255,255,255,.38); margin-top:1px;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    }
    .sra { margin-inline-start:auto; color:rgba(255,255,255,.25); font-size:var(--fs-footnote);line-height:var(--lh-footnote);letter-spacing:var(--tr-footnote)}

    /* ── Mobile safe area ──
       The platform reports an inset after the first paint and again after a rotation.
       These stay in CSS so the browser keeps them current. Nothing reads them
       into JavaScript. */
    body.is-mob {
      --sa-top:    max(env(safe-area-inset-top), calc(18px * var(--sc,1)));
      --sa-bottom: max(env(safe-area-inset-bottom), calc(8px * var(--sc,1)));
    }
    /* Sized by the insets, and observed. A change to either fires the layout
       rebuild. */
    .sa-probe {
      position:fixed; top:0; left:0; width:1px; visibility:hidden; pointer-events:none;
      height:calc(env(safe-area-inset-top) + env(safe-area-inset-bottom));
    }
    .mob-page {
      flex:0 0 100vw; width:100vw; height:var(--pgh,100dvh); overflow:hidden;
      padding:var(--sa-top) var(--sm,18px) calc(var(--sa-bottom) + var(--dh,108px) + var(--dz,52px));
    }
    /* The box the layout measures. */
    .mob-grid {
      width:100%; height:100%;
      display:grid;
      grid-template-columns:repeat(4,1fr); grid-template-rows:repeat(6,1fr);
      gap:var(--gap);
      justify-content:center; align-content:start;
    }
    .mob-cell { display:flex; align-items:center; justify-content:center; min-width:0; min-height:0; }

    /* ── Folder overlay — mobile ── */
    .folder-overlay-mobile {
      position:fixed; inset:0; z-index:800;
      -webkit-backdrop-filter:blur(22px) brightness(.72);
      backdrop-filter:blur(22px) brightness(.72);
      background:rgba(0,0,0,.18);
    }
    .folder-title-mobile {
      font-weight:700; color:var(--label-primary);
      text-align:start; line-height:1.05;
      text-shadow:0 1px 6px rgba(0,0,0,.45);
      -webkit-user-select:none; user-select:none;
    }
    /* Reference: frosted glass, very low opacity dark tint, visible blur of background */
    .folder-box-mobile {
      background:rgba(200,200,210,.18);
      border:0.5px solid rgba(255,255,255,.22);
      -webkit-backdrop-filter:blur(80px) saturate(180%) brightness(1.40);
      backdrop-filter:blur(80px) saturate(180%) brightness(1.40);
    }
    .folder-dots {
      display:flex; justify-content:center; align-items:center;
      flex-shrink:0;
    }
    .folder-dot {
      border-radius:50%; cursor:pointer; flex-shrink:0;
      background:rgba(255,255,255,.35);
      transition:background .2s,transform .2s;
    }
    .folder-dot.on { background:var(--control-knob); transform:scale(1.25) }

    /* ── Folder overlay — desktop ── */
    .folder-overlay {
      position:fixed; inset:0; z-index:800;
      display:flex;
      align-items:center;
      justify-content:center;
      background:rgba(0,0,0,.45);
      -webkit-backdrop-filter:blur(24px); backdrop-filter:blur(24px);
    }
    .folder-outer {
      display:flex; flex-direction:column; align-items:center;
      gap:16px; max-width:600px; width:90vw;
    }
    .folder-title-desktop {
      font-size:var(--fs-title-2);line-height:var(--lh-title-2);letter-spacing:var(--tr-title-2); font-weight:600; color:rgba(255,255,255,.95);
      text-shadow:0 1px 8px rgba(0,0,0,.6); text-align:center;
    }
    .folder-box-desktop {
      background:rgba(30,34,52,.88); border-radius:28px; padding:28px 32px 24px;
      border:1px solid rgba(255,255,255,.16); width:100%;
      box-shadow:0 32px 80px rgba(0,0,0,.65),0 0 0 0.5px rgba(255,255,255,.08);
      -webkit-backdrop-filter:blur(40px) saturate(160%);
      backdrop-filter:blur(40px) saturate(160%);
    }
    .folder-icon-link {
      display:flex; flex-direction:column;
      align-items:center; justify-content:center;
      text-decoration:none; cursor:pointer;
      -webkit-tap-highlight-color:transparent;
    }

    /* ── Folder icon grid (thumbnail on main homescreen page) ── */
    .folder-icon-grid {
      position:absolute; inset:0; border-radius:16px;
      background:rgba(100,110,140,.30);
      display:grid; grid-template-columns:repeat(3,1fr); grid-template-rows:repeat(3,1fr);
      gap:3px; padding:10px; overflow:hidden;
      -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
      box-shadow:var(--icon-inset-shadow);
    }
    .folder-icon-grid-sheen {
      position:absolute; inset:0; border-radius:16px;
      pointer-events:none; z-index:2;
      background:var(--icon-sheen);
    }
    .folder-mini-cell {
      display:flex; align-items:center; justify-content:center; z-index:1;
      min-width:0; min-height:0;
    }
    .folder-mini-bg {
      width:100%; height:100%; border-radius:28%;
      display:flex; align-items:center; justify-content:center;
      overflow:hidden; box-shadow:inset 0 0 0 0.5px rgba(255,255,255,.15);
    }
    .folder-mini-img { width:72%; height:72%; object-fit:contain }
    .folder-mini-fb  { font-size:50%; font-weight:700; color:rgba(255,255,255,.85) }

    /* Dynamic layout classes — pixel values set via CSS custom properties from JS */
    .dyn-box        { position:relative; flex-shrink:0; }
    .dyn-sz         { width:var(--sz); height:var(--sz); }
    .dyn-folder-box { position:relative; width:var(--iw); height:var(--iw); flex-shrink:0; }
    .dyn-grid       { display:grid; grid-template-columns:repeat(6,var(--iw)); gap:24px; justify-content:center; }
    .dyn-mob-btn    { flex:1; height:var(--rh); background:none; border:none; padding:0; display:flex; flex-direction:column; align-items:center; justify-content:center; cursor:pointer; flex-shrink:0; -webkit-tap-highlight-color:transparent; -webkit-appearance:none; }
    .dyn-mob-icon   { display:flex; flex-direction:column; align-items:center; justify-content:center; width:var(--cw); height:var(--rh); cursor:pointer; text-decoration:none; flex-shrink:0; -webkit-tap-highlight-color:transparent; }
    .dyn-mob-label  { font-weight:500; color:rgba(255,255,255,.88); text-align:center; margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-shadow:0 1px 3px rgba(0,0,0,.65); font-size:var(--lfs); width:var(--lw); }
    .dyn-fold-label { font-weight:500; color:rgba(255,255,255,.90); text-align:center; margin-top:3px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-shadow:0 1px 3px rgba(0,0,0,.70); font-size:var(--lfs); width:var(--lw); }
    .dyn-fold-wrap  { position:absolute; inset:0; pointer-events:none; border-radius:var(--br); background:rgba(120,130,160,.35); display:grid; grid-template-columns:repeat(3,1fr); grid-template-rows:repeat(3,1fr); gap:var(--gap); padding:var(--pad); overflow:hidden; -webkit-backdrop-filter:blur(7px); backdrop-filter:blur(7px); box-shadow:inset 1px 1px 0 rgba(255,255,255,.22),inset -1px -1px 0 rgba(0,0,0,.12); }
    .dyn-fold-cell  { display:flex; align-items:center; justify-content:center; z-index:1; pointer-events:none; min-width:0; min-height:0; }
    .dyn-fold-sheen { position:absolute; inset:0; pointer-events:none; z-index:2; border-radius:inherit; background:linear-gradient(135deg,rgba(255,255,255,.12) 0%,transparent 55%); }
    .dyn-clip       { overflow:hidden; flex-shrink:0; width:var(--gw); height:var(--gh); }
    .dyn-strip      { display:flex; height:var(--gh); will-change:transform; transition:transform .3s cubic-bezier(.4,0,.2,1); }
    .dyn-page-grid  { flex-shrink:0; display:grid; gap:var(--gap); justify-content:center; align-content:start; width:var(--gw); height:var(--gh); padding:var(--ovh,0); overflow:hidden; grid-template-columns:repeat(3,var(--fiw)); grid-template-rows:repeat(3,var(--fiw)); }
    .dyn-dot        { border-radius:50%; cursor:pointer; flex-shrink:0; width:var(--dsz); height:var(--dsz); }
    .dyn-dots-row   { display:flex; justify-content:center; align-items:center; flex-shrink:0; width:100%; }
    /* WebKit paints its own focus ring on a script-focused anchor. Only
       :focus-visible is styled below. */
    .folder-overlay-mobile:focus, .dyn-fold-anchor:focus,
    .folder-overlay:focus, .folder-icon-link:focus { outline:none; }
    .dyn-fold-anchor { display:flex; flex-direction:column; align-items:center; gap:4px; text-decoration:none; -webkit-tap-highlight-color:transparent; }
    .dyn-fold-inner-label { font-weight:400; color:rgba(255,255,255,.90); text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-shadow:0 1px 3px rgba(0,0,0,.6); font-size:var(--lfs); width:var(--fiw); }
    .dyn-title-mob  { position:absolute; pointer-events:none; font-size:var(--tfs); }
    .dyn-box-mob    { position:absolute; display:flex; flex-direction:column; align-items:center; left:var(--left); width:var(--bw); height:var(--bh); top:var(--top); border-radius:var(--br); padding:var(--pt) var(--ph) var(--pb); }
    .dyn-dock-icon  { display:flex; align-items:center; justify-content:center; flex:1; height:100%; cursor:pointer; text-decoration:none; -webkit-tap-highlight-color:transparent; overflow:visible; position:relative; }

/* Strip backdrop-filter blur for anyone who asks for reduced motion or
   transparency. */
/* The general rules for both preferences live in tokens.css. What remains here
   is only what the dashboard defines. */

/* Reduced transparency → drop blur/material (legibility), keep motion as-is */
@media (prefers-reduced-transparency: reduce) {
  :root { --glass-blur: none; --dock-blur: none; }
}

/* Reduced motion: neutralize slides, springs, and lift transforms. */
@media (prefers-reduced-motion: reduce) {
  #pages { transition: none !important; }
  .icon:hover .iwrap, .folder-icon-link:hover .iwrap, .di:hover .dwrap,
  .dot.on { transform: none !important; }
}

/* API error screen — no inline styles, CSP-safe */
.api-error-screen {
  position: fixed; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  color: rgba(255,255,255,.7); font-family: inherit; gap: 16px; z-index: 10000;
}
.api-error-title { font-size:var(--fs-body);line-height:var(--lh-body);letter-spacing:var(--tr-body); font-weight: 500; margin: 0; }
.api-error-sub   { font-size:var(--fs-footnote);line-height:var(--lh-footnote);letter-spacing:var(--tr-footnote); color: rgba(255,255,255,.4); margin: 0; }
.api-error-btn   {
  margin-top: 8px; padding: 10px 24px; border-radius: 20px;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.18);
  color: var(--label-primary); font-size:var(--fs-subheadline);line-height:var(--lh-subheadline);letter-spacing:var(--tr-subheadline); cursor: pointer; font-family: inherit;
}

/* ── Accessibility layer (added in Phase 3) ── */

/* Screen-reader-only utility (used by the search results live region) */
.visually-hidden {
  position:absolute !important; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* Visible keyboard focus for all interactive elements. */
a:focus-visible, button:focus-visible, [role="button"]:focus-visible,
.icon:focus-visible, .di:focus-visible, .ctrl:focus-visible, .sr:focus-visible,
.dot:focus-visible, .dyn-mob-icon:focus-visible, .dyn-mob-btn:focus-visible,
.dyn-dock-icon:focus-visible, .dyn-fold-anchor:focus-visible,
.folder-icon-link:focus-visible {
  outline:2px solid var(--accent); outline-offset:3px; border-radius:8px;
}
#sin:focus-visible { outline:none; }
.spot-bar:focus-within { outline:2px solid var(--accent); outline-offset:2px; }

/* Larger tap/click area for page dots without changing their visual size */
.dot { position:relative; }
.dot::after { content:''; position:absolute; inset:-11px; }

/* 44px is the minimum tap target, and a dot is 8px of it. */
@media (pointer:coarse) {
  .ctrl { width:44px; height:44px; }
  .dot::after { inset:-18px; }
}

/* Increased-contrast mode. */
@media (prefers-contrast: more) {
  :root {
    --glass-bg:      rgba(0,0,0,.62);
    --glass-border:  rgba(255,255,255,.30);
    --dock-bg:       rgba(40,40,44,.55);
    --dock-border:   rgba(255,255,255,.30);
    --label-color:   var(--label-primary);
    --label-shadow:  0 1px 4px rgba(0,0,0,.95);
  }
  .ilabel, .dyn-mob-label, .dyn-fold-label, .dyn-fold-inner-label { color:var(--label-primary); }
  .ctrl { color:var(--label-primary); background:rgba(255,255,255,.22); }
  .srn  { color:var(--label-primary); }
  .srh, .sr-section { color:rgba(235,235,245,.85); }
  .widget, .mob-widget-card { border-color:rgba(255,255,255,.35); }
  /* A translucent card cannot honour a contrast request and stay translucent. */
  .widget[data-card="translucent"], .mob-widget-card[data-card="translucent"] { background:rgba(0,0,0,.62); }
  .widget[data-card="light"], .mob-widget-card[data-card="light"] { border-color:rgba(0,0,0,.45); }
  .dot { background:rgba(255,255,255,.75); }
  .badge { box-shadow:0 0 0 1.5px rgba(0,0,0,.85); }
}

/* Do not add `container-type:size` here. It applies size containment and
   collapses the desktop .widget, which has no explicit height, to 0. */

.setup-prompt {
  position: fixed; inset: 0; z-index: 10001;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.5);
  -webkit-backdrop-filter: blur(20px) saturate(140%); backdrop-filter: blur(20px) saturate(140%);
  font-family: inherit; padding: 24px;
}
.setup-card {
  width: 100%; max-width: 360px; display: flex; flex-direction: column; gap: 12px;
  padding: 24px; border-radius: 20px;
  background: rgba(40,40,44,.7); border: 1px solid rgba(255,255,255,.14);
  -webkit-backdrop-filter: blur(24px) saturate(140%); backdrop-filter: blur(24px) saturate(140%);
  color: var(--label-primary);
}
.setup-title { font-size:var(--fs-body);line-height:var(--lh-body);letter-spacing:var(--tr-body); font-weight: 600; margin: 0; }
.setup-sub   { font-size:var(--fs-footnote);letter-spacing:var(--tr-footnote); line-height: 1.4; color: rgba(255,255,255,.55); margin: 0; }
.setup-pw {
  width: 100%; box-sizing: border-box; padding: 11px 14px; border-radius: 12px;
  background: rgba(0,0,0,.25); border: 1px solid rgba(255,255,255,.16);
  color: var(--label-primary); font-size:var(--fs-subheadline);line-height:var(--lh-subheadline);letter-spacing:var(--tr-subheadline); font-family: inherit; outline: none;
}
.setup-pw:focus { border-color: var(--accent); }
.setup-field { position: relative; display: flex; align-items: center; }
.setup-field .setup-pw { padding-inline-end: 44px; }
.setup-reveal {
  position: absolute; inset-inline-end: 6px; display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border: none; border-radius: 8px;
  background: none; color: rgba(255,255,255,.55); cursor: pointer;
}
.setup-reveal:hover { color: rgba(255,255,255,.9); }
.setup-reveal[aria-pressed="true"] { color: var(--accent); }
.setup-bars { display: flex; gap: 4px; }
.setup-bars .pwbar { flex: 1; height: 4px; border-radius: 2px; background: rgba(255,255,255,.1); transition: background .15s; }
.setup-hint { font-size:var(--fs-caption-1);line-height:var(--lh-caption-1);letter-spacing:var(--tr-caption-1); min-height: 14px; color: rgba(255,255,255,.5); }
.setup-err  { display: none; font-size:var(--fs-footnote);line-height:var(--lh-footnote);letter-spacing:var(--tr-footnote); color: var(--danger); }
.setup-btns { display: flex; gap: 10px; margin-top: 4px; }
.setup-btn {
  flex: 1; padding: 10px; border-radius: 14px; font-size:var(--fs-subheadline);line-height:var(--lh-subheadline);letter-spacing:var(--tr-subheadline); cursor: pointer; font-family: inherit;
  border: 1px solid rgba(255,255,255,.18);
}
.setup-btn-skip { background: rgba(255,255,255,.1); color: rgba(255,255,255,.85); }
.setup-btn-set  { background: var(--accent); border-color: var(--accent); color: var(--label-primary); }
.setup-btn-set:disabled { opacity: .4; cursor: default; }

/* ── RTL ──
   The grid and dock are symmetric, and flexbox rows reverse on their own. What
   remains uses logical properties, so it follows the text direction without an
   override: `text-align: start` is left in English and right in Persian, and
   `inset-inline-end` is the end of the line rather than a fixed side.

   The override block that used to be here listed the cases someone had noticed,
   which is a list that can only ever be incomplete: any new rule with
   `margin-left` in it needed a matching entry, and forgetting meant Persian
   quietly looked wrong. Logical properties remove the need for the list. */
