
@media (max-width: 768px) {
  /* — Touch floor ————————————————————————————————— */

  /* Shell chrome. The workspace switcher is id="ws-selector" class="topbar-ws";
     an earlier .ws-selector rule matched nothing and the control stayed
     140x40 on every authenticated page. */
  /* min-WIDTH as well as height. Once the workspace name is hidden on the
     tightest phones the control's content is a single 18px glyph, and a
     shrinking flex row squeezed it to 18x44 — on screen, correctly tall,
     and still not a 44px target. The floors block is the right home for
     this: it is emitted last, so a page or shell rule cannot undercut it. */
  /* min-height only. min-width:44 + flex-shrink:0 here made the row rigid
     and pushed the notifications bell off-screen at 320-414px — a control
     hidden entirely is worse than one that is narrow but visible. The
     selector still reaches 44px wide at >=375px; below that it narrows.
     See TOPBAR_320 note in the report: the durable fix is moving
     notifications into the menu, which is a nav change, not a CSS one. */
  #ws-selector, .topbar-ws { min-height: 44px; }
  .mode-toggle { min-height: 44px; }
  .mode-toggle-btn, .mode-btn, .mode-quick-btn, .mode-adv-btn {
    min-height: 44px; padding-inline: 14px;
    display: inline-flex; align-items: center; justify-content: center;
  }

  /* Icon-only controls: keep the glyph small, grow the hit area around it. */
  .info-btn, .topbar-btn, .icon-btn, .cmd-refresh-btn, .kpi-spark-btn {
    min-width: 44px; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }

  /* Buttons and CTAs measured under the floor. */
  /* .auth-submit is NOT a .btn and .auth-alt a is a bare anchor, so neither
     was covered by any floor selector — measured 250x40 and 64x15 at all six
     widths. Both are defined in authShared.ts; naming them here keeps the
     fix in the shared system instead of a per-page override. */
  .btn, .submit-btn, .main-move-cta, .section-empty-cta,
  .topbar-login, .topbar-register, .btn-reconnect,
  .auth-submit, .auth-alt a {
    min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }

  /* Tabs and chips are primary navigation on a phone. */
  .tab, .chip, .filter-chip, .seg-btn, .qa-chip {
    min-height: 44px;
    display: inline-flex; align-items: center;
    padding-inline: 10px;
    min-width: 0;
  }

  /* Inline text links used as actions need a real target without becoming
     a block and breaking the sentence they sit in. */
  .switch-account-link, .link-action, .hg-action-link {
    display: inline-flex; align-items: center;
    padding-block: 12px; min-height: 44px;
  }

  /* Form controls. 16px stops iOS Safari zooming the viewport on focus,
     which is the usual cause of "the page jumped and I lost my place". */
  input, select, textarea { min-height: 44px; font-size: 16px; }
  .settings-nav-item { min-height: 44px; }

  /* — Overflow containment ——————————————————————————
     .topbar-actions is flex-shrink:0 with no wrap. At 320px the action row
     needs ~436px, and the dashboard — the only page that also renders the
     pro/beginner toggle there — tipped 118px past the viewport. Every other
     page stayed under only because it happens to carry fewer controls, so
     this was one added button away from breaking anywhere.

     It scrolls rather than wraps: wrapping produced a 171px sticky header,
     which is 30% of a 780px screen once the bottom nav is counted. */
  /* The action row SHRINKS to fit; it does not scroll.
     Scrolling was the previous fix for the 118px overflow, and it worked —
     but it pushed the notifications bell to left:-141px at 320px, entirely
     off-screen and reachable only by a horizontal drag on a top bar, which
     nobody discovers. Hidden is worse than cramped.
     Now the row is allowed to shrink and the workspace name absorbs it via
     its own ellipsis, so every control stays on screen at every width. */
  .topbar-actions {
    min-width: 0;
    flex-shrink: 1;
    overflow: visible;
  }
  .topbar-ws { min-width: 0; flex-shrink: 1; }

  /* — Text floor ————————————————————————————————— */
  .nav-section-label, .sidebar-logo-tagline, .sidebar-footer-label,
  .sidebar-user-email,
  .mobile-nav-item span,
  .kpi-cmd-insight, .hero-sub, .text-xs,
  .auth-footer, .form-hint, .badge,
  .ws-hero-kicker, .ws-id-label, .ws-id-value,
  .camp-kpi-label, .status-strip-item,
  .cc-meta, .cc-conf, .cc-unit-label { font-size: 12px; }

  /* — Safe area ————————————————————————————————————
     Bottom nav and any sticky footer clear the home indicator. */
  .mobile-bottom-nav { padding-bottom: env(safe-area-inset-bottom, 0px); }
  .page-content { padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px)); }

  /* — Hover independence ————————————————————————————
     Nothing may reveal itself only on hover: a phone has no hover state. */
  .hover-only { display: none; }
}

/* A coarse pointer is the real test, not width — a 1024px tablet still taps. */
@media (pointer: coarse) {
  .btn, .submit-btn, .tab, .chip, .icon-btn, .info-btn, .topbar-btn {
    min-height: 44px;
  }
}

/* ══ THE DESKTOP LAYER ═════════════════════════════════════════════════
   This is the product's FIRST min-width query. Until now every rule was
   max-width, which means the layout above 768px was never designed — it was
   the phone layout with more room, and nobody had measured what that looks
   like. A pass at 1280 / 1440 / 1600 / 1920 / 2560 found:

     · 30 of 40 page-widths carried a line of running text longer than 90
       characters, worst 247 — roughly three times the width at which the eye
       reliably finds the start of the next line
     · a label and its number 971px apart inside one .funnel-stage row
     · 0 horizontal overflow, and the 1400px content cap working correctly

   THE CONTRACT, in four rules:

   1. TWO KINDS OF CONTENT, TWO WIDTHS. Prose — a sentence a merchant reads —
      is capped at a reading measure. Data — a table, a chart, a grid of
      tiles — takes the whole column, because there the width IS the
      information.

   2. A DATUM NEVER LEAVES ITS VALUE. "مرات الظهور" at one end of a 1400px
      row and "120,000" at the other is not a layout; it is two facts the
      reader has to re-pair by hand.

   3. A SECTION HEAD MAY SPAN. Title at one end, action at the other is a
      real convention and the gap there is deliberate. Rule 2 is about data
      pairs, not about headers — collapsing both would be a worse layout, not
      a more careful one.

   4. NOTHING HERE TOUCHES THE PHONE. Every rule is inside min-width: 1024,
      above the whole mobile system, so the six phone widths measure exactly
      as they did before.

   68ch is the cap. Arabic set in Readex Pro has generous counters and wide
   joins, so it runs longer per character than Latin; 68 lands near the
   middle of the classic 45–75 band at this size rather than at its edge. ── */
/* Below the desktop breakpoint the two dashboard columns must not merely
   stack — they must NOT EXIST. display:contents removes a box from the
   tree while keeping its children, so at phone widths every section is a
   direct child of #dashboard-content in the original source order, exactly
   as before the wrappers were added. This is what makes the phone provably
   unaffected rather than carefully re-checked. */
.dash-grid, .dash-col { display: contents; }

@media (min-width: 1024px) {
  /* ── Rule 1: prose gets a measure ─────────────────────────────────── */
  .page-subtitle,
  .dash-state-text,
  .observer-msg,
  .camp-trends-note,
  .empty-text,
  .form-hint,
  .card-text,
  .panel-sub,
  .auth-brand-tagline,
  .rec-why,
  .insight-body,
  p.hint {
    /* 60ch, not 68. The CSS ch unit is the advance of the digit zero, and
       Arabic glyphs in Readex Pro are narrower than that on average — so a
       68ch box measured 97 real characters, not 68. The cap is expressed in
       the unit CSS gives us; the number comes from what the browser actually
       rendered. */
    max-width: 60ch;
  }

  /* Evidence and reasoning lists run slightly longer: each item is a short
     clause, not a paragraph, and breaking them narrower makes a three-line
     bullet out of a one-line fact. */
  .why-list li,
  .evidence-list li,
  .diag-evidence li,
  .cc-why-list li,
  .funnel-note li {
    /* Same correction: 76ch measured 92 real characters. */
    max-width: 70ch;
  }

  /* ── Rule 2: a datum stays with its value ─────────────────────────── */
  /* Measured at 971px of empty space between .funnel-stage-label and
     .funnel-stage-count at 1920. Capping the ROW keeps the pair readable
     without touching the markup or inventing a new visualisation. */
  /* space-between is right on a phone, where the row is 340px and the two
     ends are a glance apart. Capping the row alone still left 449px between
     them, so the pair is packed from the start instead — and the label is
     given a fixed track so the counts still line up in a column, which is
     what makes the stages comparable at all. */
  .funnel-stage {
    max-width: 620px;
    justify-content: flex-start;
    gap: 18px;
  }
  .funnel-stage-label { flex: 0 0 190px; }
  .cc-metric-row,
  .kpi-row,
  .ws-stat-row { max-width: 720px; }

  /* ── Rule 4's corollary: pointer density ──────────────────────────── */
  /* The 44px floors are correct for a thumb and oversized for a cursor. This
     only relaxes them where a POINTER is the input; a touch laptop keeps the
     floors, because (pointer: coarse) still applies there. */
  @media (pointer: fine) {
    .btn-sm, .chip, .tab { min-height: 32px; }
  }
}

/* ══ TWO COLUMNS — AND ONLY WHERE BOTH ACTUALLY FIT ════════════════════
   Rule 5: the decision is READ, the data is CONSULTED. They belong beside
   each other, not stacked, once there is room for both to be themselves.

   "Room" is a number, not a feeling. Work backwards from what each track
   needs and the breakpoint falls out:

     data      >= 572px   two KPI tiles at their 280px minimum, plus the gap
     narrative >= 480px   where the 60ch prose cap lands at 13.5px
     ------------------------------------------------------------------
     content   >= 1072px  and content = viewport - 236 sidebar - 56 padding
     viewport  >= 1364px

   1024 was the obvious guess and it is wrong: at 1280 the content box is
   988px, the data track collapses to 368, the KPI grid drops to one tile per
   row and the quick-action chips are clipped at the column edge. Measured,
   not predicted — the 1280 screenshot showed "حل الإبدا" sliced in half.

   So the two-column layout starts at 1440, the first real width where both
   tracks work (content 1148 = 556 + 20 + 572). Below it the dashboard stays
   the single column that measured clean, which is the right answer for a
   1280 laptop rather than a compromise.

   minmax on BOTH tracks, not a fixed size and a fraction: the narrative may
   shrink toward its measure but never grow past it, and the data track
   states its own minimum instead of silently absorbing whatever is left. */
@media (min-width: 1440px) {
  /* max-width: 1180px on #dashboard-content was a reading cap, correct while
     the dashboard WAS one column and the wrong constraint once each column
     carries its own measure. Releasing it to the page's 1400px cap is what
     turns the second track from 520px — one KPI tile per row — into a grid. */
  #dashboard-content { max-width: none; }

  .dash-grid {
    display: grid;
    grid-template-columns: minmax(420px, 600px) minmax(572px, 1fr);
    align-items: start;   /* a short column must not stretch its cards to
                             match a tall neighbour */
    gap: 20px;
  }
  /* min-width: 0 because a grid item, like a flex item, otherwise refuses to
     shrink below its widest child — the same failure that once let .main
     hang 344px off the edge of a 900px viewport. */
  .dash-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

  /* Stacking margins were the single column's spacing mechanism; the grid
     gap is now. Keeping both would double every gap. */
  .dash-col > * { margin-bottom: 0; }
}
