/* ═══════════════════════════════════════════════════════════
   mahfuzmaruf.me — DESIGN TOKENS
   The single source of truth for colour, type, spacing, shape and
   motion. Load this before style.css. Nothing here describes a
   component; if a value is used twice, it belongs in this file.

   The system rests on φ (1.618):
     · layout columns are φ-family ratios
     · display type steps by √φ (1.272)
     · spacing is Fibonacci, whose neighbours are φ apart
   Live reference: design-system.html
   ═══════════════════════════════════════════════════════════ */

:root {

  /* ══ RATIOS ═══════════════════════════════════════════════ */

  --phi:      1.618;   /* golden ratio                          */
  --phi-2:    2.618;   /* φ²                                    */
  --phi-half: 1.272;   /* √φ — type step, card aspect           */

  /* Main panel's grid track against the rail's 1fr.
     3fr → rail 25%.  φ³ 4.236fr → 19.1%
                      φ² 2.618fr → 27.6%  (the original Figma)
                      φ  1.618fr → 38.2%  (classic golden section)
     Must carry the `fr` unit: a bare number is invalid in
     grid-template-columns and silently drops the declaration. */
  --col-main: 3fr;


  /* ══ TYPE ═════════════════════════════════════════════════
     Two faces carry the whole system, both Helvetica:
       · display  — Helvetica 700, tight line-heights, for headlines
       · text     — Helvetica 400 / 500, for body, buttons, labels
     Sentence case only, never letter-spaced. Weights are 400/500/700
     only — no 300, no 600. Every size below is a fixed px step with a
     paired line-height (the Uber scale).

     Helvetica is a local face, not a webfont — macOS/iOS ship
     Helvetica Neue, Windows falls back to Arial (metrically
     compatible), then the system UI face. Nothing is downloaded, so
     the scale renders identically at every screen size. */

  --font-sans:  'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif;
  --font-badge: 'Helvetica Neue', Helvetica, Arial, sans-serif;   /* numerals in badges */

  /* Weights — the only three the system uses. */
  --fw-regular: 400;
  --fw-medium:  500;
  --fw-bold:    700;

  /* ── The scale (size / line-height) ──
     Named by role, not by number, so intent is legible at the callsite.
     Display steps drop one level on the phone (see the ≤720 query). */

  /* Display — Helvetica 700 */
  --fs-display-xxl: 52px;   --lh-display-xxl: 64px;   /* hero headline        */
  --fs-display-xl:  36px;   --lh-display-xl:  44px;   /* section headlines    */
  --fs-display-lg:  32px;   --lh-display-lg:  40px;   /* promo-card headlines */
  --fs-display-md:  24px;   --lh-display-md:  32px;   /* card titles          */
  --fs-display-sm:  20px;   --lh-display-sm:  28px;   /* sub-card headings    */

  /* Text — Helvetica 400 / 500 */
  --fs-body-lg:  18px;   --lh-body-lg:  24px;   /* lead paragraphs, big buttons */
  --fs-body-md:  16px;   --lh-body-md:  24px;   /* default body; 20 when strong  */
  --fs-body-sm:  14px;   --lh-body-sm:  20px;   /* captions, metadata, chips     */
  --fs-caption:  12px;   --lh-caption:  20px;   /* fine print, footnotes         */

  /* ── Legacy aliases ──
     The component CSS was written against these names; pointing each at
     a scale step migrates the whole site to the new system in one place.
     Prefer the scale tokens above for any new rule. */
  --fs-hero:  var(--fs-display-xxl);   /* 52 */
  --fs-lead:  var(--fs-display-xl);    /* 36 */
  --fs-title: var(--fs-display-md);    /* 24 */
  --fs-body:  var(--fs-body-lg);       /* 18 */
  --fs-sm:    var(--fs-body-md);       /* 16 */
  --fs-nav:   var(--fs-body-sm);       /* 14 */
  --fs-micro: var(--fs-caption);       /* 12 */

  /* Off-scale one-offs the user set by eye. Kept as named tokens so no
     component hardcodes a size, but deliberately listed apart from the
     scale above — don't reach for these in new rules. */
  --fs-hint: 15px;   /* the rail's resting "Click on … " line */

  /* The header brand is its own face, not the site's Helvetica — Cal
     Sans, loaded (weight 400, its only weight) via Fontshare in every
     page's <head>. Isolated here rather than folded into --font-sans
     so the rest of the type scale stays on the system face.
     (Replaced General Sans/600/23/30 with Cal Sans/400/45/58, 2026-07-26.) */
  --font-nav-title: 'Cal Sans', sans-serif;
  --fs-nav-title:    20px;
  --lh-nav-title:    26px;
  --fw-nav-title:    600;
  /* The mark sits on the wordmark's baseline and rises to exactly the
     cap height of the M, so both are expressed in em and track any
     change to --fs-nav-title. 0.72em is the measured cap ratio. */
  --brand-mark-h:    0.72em;
  --brand-gap:       0.2em;

  /* The bar-chart mark beside the brand name — same blue family as
     the map pins/accent but its own literal value, taken from the
     Figma export rather than derived from --accent. */
  --brand-mark: #1877ff;

  --lh-tight: 1.25;     /* headlines — matches the display px ratios */
  --lh-snug:  1.45;     /* UI text, bubbles     */
  --lh-prose: 1.6;      /* long-form paragraphs */

  /* Display type shrinks with its container once too narrow to hold
     the cap. 1cqi = 1% of the container's inline size, so these need
     an ancestor with `container-type: inline-size`. */
  /* The hero headline is capped at 35px rather than the --fs-hero step:
     the coefficient is raised to 9cqi so the cap is what binds on a
     full-width rail, and the rail still shrinks the headline below
     ~389px wide. Only .hero-title reads this — 404's h1 keeps
     --fs-hero. */
  --fs-hero-cap:    35px;
  --fs-hero-fluid:  min(var(--fs-hero-cap), 9cqi);
  --fs-lead-fluid:  min(var(--fs-lead),   7.5cqi);
  --fs-title-fluid: min(var(--fs-title),    7cqi);


  /* ══ SPACING — Fibonacci; neighbours are φ apart ══════════ */

  --s1:  8px;
  --s2: 13px;
  --s3: 21px;
  --s4: 34px;
  --s5: 55px;
  --s6: 89px;

  --gutter: var(--s4);   /* page edge inset */


  /* ══ BUBBLES ══════════════════════════════════════════════
     Anything with a tail (border-radius x x 0 x) is a bubble.
     Bubbles read as a chat thread: each hugs the side it was sent
     from and never spans its column, so the opposite side stays
     open. Padding is tighter than a section's — the fill colour
     does the separating, not the inset. */

  --pad-section: var(--s3);              /* 21 — section shells   */
  /* Bubble inset scales with the column instead of sitting at a fixed
     px, which looked starved on a wide desktop bubble and right on a
     narrow one.

     Both run from one Fibonacci step to the next — 13→34 and 21→55 —
     over a column of 322px (a 13" laptop rail) to 600px (a desktop
     one), then hold. Consecutive Fibonacci steps are φ apart, so the
     horizontal:vertical ratio stays ≈1.62 the whole way.

     1cqi = 1% of .chat's width, so .chat carries container-type. */
  --pad-bubble-block:  clamp(var(--s2), calc(7.55cqi - 11.3px), var(--s4));
  --pad-bubble-inline: clamp(var(--s3), calc(12.23cqi - 18.4px), var(--s5));
  --pad-bubble: var(--pad-bubble-block) var(--pad-bubble-inline);
  --bubble-max:  75%;                    /* of column; rest open  */
  --bubble-gap:  20px;                   /* a bubble standing alone */

  /* ── Chat thread ──
     Messages stack from the bottom, newest last, the way a thread
     reads. The area takes the rail's slack and no more: once the
     thread is taller than that it scrolls rather than pushing the
     section below it off screen. So the maximum is not a number —
     it is whatever height is left, which keeps the layout stable at
     every viewport. */
  --chat-gap:   var(--s2);   /* between consecutive bubbles */
  --chat-fade:  var(--s4);   /* top fade, so a cut message reads as cut */

  /* Thread colour. Deliberately not --accent: the bubbles are a
     running commentary beside the maps, and at accent strength a
     column of them out-shouts the cards they describe. Grey lets the
     accent keep meaning "this is interactive". */
  --chat-bubble:     #ebebeb;
  --chat-bubble-ink: #666869;

  /* Flashed on a bubble the user asks for a second time. A tint of
     the accent rather than the accent itself — it has to read as
     "here it is again", not as a new, louder message. */
  --chat-bubble-recall:     #dce8fd;
  --chat-bubble-recall-ink: #2f4b7a;
  /* Much longer than the site's other durations on purpose — this one
     is not a UI response, it is a highlight the eye has to follow
     back to a bubble that may be off-screen. */
  --dur-recall: 1.8s;


  /* ══ COLOUR ═══════════════════════════════════════════════ */

  --bg:       #f8fafd;              /* page / rail                */
  --surface:  #ffffff;              /* panels, cards, bubbles     */
  --screen:   #f6f6f6;              /* map + media placeholder    */
  --ink:      #000000;
  --ink-mute: rgba(0, 0, 0, .55);
  --accent:   #3477f2;              /* the only brand colour      */
  --dot:      #393333;
  --danger:   #ff3b30;              /* badge counts only          */
  --hairline: rgba(0, 0, 0, .08);   /* dividers                   */

  /* Dock resting (unselected) state. The active tile takes --accent;
     everything else recedes to grey so the current page reads at a
     glance. Two greys because a glyph at label weight looks heavier
     than text — the icon sits a shade lighter to match. */
  --dock-idle-icon:  #afafaf;
  --dock-idle-label: #6b6b6b;

  /* ── Icon rail ──
     The launch rail's own palette. Its blue is a step deeper than
     --accent (#3477f2) because the chip tint sits behind it and a
     lighter blue would not hold contrast on it; the tint is that same
     blue at ~5%, kept as a literal so the chip stays exactly the
     specified colour rather than drifting with --accent. */
  --rail-ink:      #8a93a2;   /* idle glyph + label      */
  --rail-hover:    #f3f5f8;   /* idle item, hovered      */
  --rail-chip:     #eef3ff;   /* active item's chip      */
  --rail-chip-ink: #2563eb;   /* active glyph + label    */
  --rail-border:   #e6e9ef;   /* the pill's 1px outline  */

  /* ── Skills — chip cards ──
     A near neighbour of the icon rail's palette above, but specified
     as its own values rather than reused — close enough to feel like
     one family, not close enough to collapse without drifting off
     the given hexes. */
  --chipcard-border: #eceef2;   /* card outline          */
  --chipcard-label:  #9aa2af;   /* category label ink    */
  --chipcard-name:   #0b1220;   /* tool name ink         */
  --chip-bg:         #f4f6f9;   /* skill chip fill       */
  --chip-ink:        #5b6472;   /* skill chip ink        */

  /* Flag bars — colour abstractions, not flag artwork */
  --flag-bd-green: #006a4e;
  --flag-bd-red:   #f42a41;
  --flag-de-black: #000000;
  --flag-de-red:   #dd0000;
  --flag-de-gold:  #ffce00;


  /* ══ SHAPE ════════════════════════════════════════════════ */

  --radius:      16px;   /* main panel        */
  --radius-rail: 14px;   /* icon rail pill    */
  --radius-sm:    8px;   /* cards, buttons    */
  --radius-xs:    4px;   /* images            */
  --radius-bubble: 25px 25px 0 25px;   /* tail bottom-right */


  /* ══ ELEVATION ════════════════════════════════════════════ */

  --shadow-sm:   0 1px 3px rgba(11, 27, 58, .14);
  --shadow-md:   0 1px 5px rgba(11, 27, 58, .45);   /* map markers */
  --shadow-lift: 0 4px 12px rgba(0, 0, 0, .07);     /* hover       */
  /* Resting lift for the map cards. Softer and lower than --shadow-lift
     so the nav bar floating inside a card still reads as the higher of
     the two. */
  --shadow-card: 0 2px 8px rgba(11, 27, 58, .06);


  /* ══ MOTION ═══════════════════════════════════════════════
     Every animated property should use these. Anything decorative
     must be disabled under prefers-reduced-motion. */

  --dur-fast: .18s;
  --dur-mid:  .38s;
  --dur-slow: .42s;
  --ease:        ease;
  --ease-out:    cubic-bezier(.22, .9, .3, 1);
  --ease-spring: cubic-bezier(.34, 1.3, .64, 1);


  /* ══ LAYOUT CONSTANTS ═════════════════════════════════════ */

  --header-h: 81px;

  /* Everything stacked above and below a card screen, measured:
     body frame 13+13 + header 81 + main padding 34/21 + caption 104 +
     rail 48 + the rail's 21 top margin = 335. Subtracted from the
     viewport for the card's height budget. RE-MEASURE whenever the
     caption, rail, main padding or the body's frame changes: too low
     and the page gains a scrollbar, too high and the cards sit
     smaller than they need to. (The icon rail gave 50px back over the
     labelled dock; the panel-with-header shell then spent 26 of it on
     the frame — 359 → 309 → 335.) */
  --card-chrome: 335px;

  /* Card shape and size, taken from the Figma frame (1710×876): the card
     is 416×470 — wider and shorter than the old √φ portrait, which is why
     it reads lighter than the taller 401 card did. --card-aspect is w/h,
     used for both `aspect-ratio` and the height-fit guard. --card-w is the
     desktop width cap; on shorter screens the height guard shrinks it. */
  --card-aspect: 0.885;   /* 416 / 470 */
  --card-w: 416px;
  /* The one standard gutter between the two cards, at every screen
     size — a Fibonacci step up from the tile gap so the pair reads as
     two cards, not one split panel. */
  --card-gap: var(--s4);


  /* ══ PHONE ════════════════════════════════════════════════
     The mobile layout was drawn against a 390pt frame and specified in
     its own round px, not derived from the φ scale the desktop runs
     on. Those numbers live here rather than in the ≤720 media query so
     that query stays as free of literals as every other rule.

     The ≤720 block re-points the semantic tokens (--bg, --ink,
     --accent, --gutter …) at these, so no component rule has to know
     which layout it is in.

     #2563eb, #8a93a2, #e6e9ef and #eef3ff are already in this file as
     the icon rail's palette — the phone reuses those names rather than
     restating the same hexes. */

  /* The phone page is white — the same white as the navbar card, so
     the bar reads as part of the page rather than as a panel floating
     on a grey one. Its 1px --chipcard-border is what still separates
     it, and every other white surface here (map card, icon rail, the
     stories sheet) carries a border or a shadow for the same reason.
     Desktop keeps its grey --bg; only ≤720 reads this. */
  --phone-bg:    var(--surface);   /* page */
  --phone-ink:   #0b1220;   /* near-black, not pure black  */
  --phone-meta:  #6b7280;   /* header links, card dates    */

  /* The map card's own fill: a very shallow vertical gradient rather
     than the desktop's flat --screen, so the pins and the floating tab
     bar have something to sit on while the tiles load. */
  --phone-screen-top:    #fbfcfe;
  --phone-screen-bottom: #eef1f6;

  /* Inter carries the phone layout. Spelled out in full rather than
     built on --font-sans, because the ≤720 query points --font-sans at
     this — referring back would be circular. */
  --font-ui: 'Inter', 'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif;

  /* The navbar's own palette. #eceef2 and #f4f6f9 are already here as
     the skills chip-cards' border and fill, so the bar reuses those. */
  --phone-divider: #f0f2f6;   /* rule above the open menu   */
  --phone-row-ink: #374151;   /* an inactive menu row       */
  --phone-chevron: #c7cdd6;   /* its chevron, a shade paler */

  --phone-gutter:      20px;   /* one side inset, everywhere        */
  --phone-bar-gap:     12px;   /* navbar's lift off the top edge    */
  --phone-bar-pad-y:   13px;   /* the collapsed bar                 */
  --phone-bar-pad-x:   18px;
  --phone-brand-gap:    9px;   /* mark → wordmark                   */
  --phone-burger:      38px;   /* the toggle's square               */
  --phone-burger-bar:  17px;   /* one of its three rules            */
  --phone-burger-rule:  2px;
  --phone-burger-gap:   4px;
  --phone-menu-pad:     8px;   /* the open menu's container         */
  --phone-row-pad:  14px 12px; /* one menu row                      */
  --phone-card-h:     300px;   /* map card                          */
  --phone-card-inset:  12px;   /* tab bar's inset inside the card   */
  --phone-seg-pad:      6px;   /* tab bar's + icon rail's padding   */
  --phone-attrib-lift: 58px;   /* keeps OSM credit above the tab bar */
  --phone-pin:         38px;   /* map marker (see js/maps.js)       */
  --phone-flag-w:     130px;
  --phone-flag-h:       6px;
  --phone-hint-dot:     8px;
  --phone-dock-gap:    10px;   /* pill → chat button                */
  --phone-dock-bottom: 26px;   /* dock's lift off the bottom edge   */
  --phone-dock-space:  78px;   /* the page's runway under the dock  */
  --phone-chat-btn:    52px;

  --fs-brand-phone:   15px;
  --fs-hero-phone:    30px;
  --fs-row:           15px;   /* menu row label                */
  --fs-nav-phone:     13px;   /* icon-rail label               */
  --fs-seg:           12px;   /* tab-bar label                 */
  --fs-caption-phone: 13px;   /* the "Tap ●…" line             */

  /* The mark is set flat here rather than at the desktop's cap-height
     ratio: at 15px the cap is only ~10.6px and the drawn mark reads as
     14px tall against it. */
  --brand-mark-phone: 14px;

  --radius-card:   18px;   /* map card           */
  --radius-seg:    14px;   /* tab bar            */
  --radius-dock:   16px;   /* pill + chat button */
  --radius-navbar: 16px;   /* the collapsed bar  */
  --radius-burger: 11px;   /* its toggle         */
  --radius-row:    10px;   /* one menu row       */

  /* Slower than --dur-mid: the bar is growing, not just recolouring,
     and the eye has to follow the edge down. */
  --dur-menu: .28s;
}
