/* ============================================================================
   Design tokens — the single source of truth.

   Nothing else in the stylesheet writes a raw colour, size, or font. If a value
   appears twice in app.css, it belongs here instead.

   The palette is champagne gold on a graded near-black. Gold is an accent, not
   a theme: it marks the one thing that matters in a view (the primary action,
   the top recommendation, the active tab) and nothing else. Used everywhere it
   would read as decoration and stop meaning anything.
   ========================================================================= */

:root {
  /* --- Type ---------------------------------------------------------------
     Naskh for headings gives the page an editorial, typographically Arabic
     voice. Plex Sans Arabic carries the body: it has real Arabic drawing
     rather than a Latin face with Arabic bolted on, and both families were
     designed alongside a Latin companion, so mixed text sits on one baseline. */
  /* The Latin face comes FIRST, and that order is the whole point.

     Font fallback is resolved per glyph, and the first family in the stack
     that has a glyph wins it. Noto Naskh Arabic ships Latin as well as Arabic,
     so listing it first handed it every Latin character too — verified with
     Chrome's own platform-font reporting, which showed one family rasterising
     the entire heading. Its Latin is a serviceable Times-like serif that
     nobody chose, and on an English heading it is the whole line.

     Newsreader first takes the Latin; it has no Arabic, so Arabic falls
     straight through to Naskh. Georgia is the fallback rather than Times,
     because Georgia was drawn for screens. */
  --font-display: 'Newsreader', 'Noto Naskh Arabic', Georgia, serif;
  --font-body: 'IBM Plex Sans Arabic', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', monospace;

  /* A small scale, deliberately. Every extra step is another chance for two
     things that should match to differ by 1px. */
  --text-xs: 0.75rem; /* 12 — labels, metadata */
  --text-sm: 0.8125rem; /* 13 — secondary text */
  --text-base: 0.9375rem; /* 15 — body */
  --text-md: 1.0625rem; /* 17 — lead paragraph */
  --text-lg: 1.375rem; /* 22 — section heading */
  --text-xl: 1.875rem; /* 30 — page heading */
  --text-2xl: 2.5rem; /* 40 — hero */

  --leading-tight: 1.25;
  --leading-snug: 1.5;
  --leading-body: 1.85; /* Arabic needs more room than Latin to stay readable */

  --weight-medium: 500;
  --weight-semibold: 600;

  /* --- Space --------------------------------------------------------------
     A 4px base. Named by size rather than by use, so one scale serves padding,
     gaps and margins alike. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;

  /* --- Shape --------------------------------------------------------------
     Restrained on purpose. Heavily rounded corners on every surface is the
     single most recognisable tell of a generated interface. */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-pill: 999px;

  --border-width: 1px;

  /* --- Layout ------------------------------------------------------------ */
  --width-content: 46rem; /* Reading column: roughly 70 Arabic characters */
  --width-wide: 72rem; /* Header and the category grid */
  --header-height: 3.5rem;
  /* Shared by every small control in the header and composer, so they line up
     on one row. Nudging one of them alone is how a header goes crooked. */
  --control-height: 2.25rem;

  /* --- Motion -------------------------------------------------------------
     Two jobs, two curves.

     --ease is for state: hover, focus, press. It starts fast and settles, so a
     control feels answerable the instant you touch it. Anything past 200ms on
     a hover reads as sluggish.

     --ease-entrance is for arrival: a section appearing, a message landing. It
     decelerates hard, which is what makes something read as having travelled
     rather than having been switched on. Entrances get longer durations
     because they only happen once and you are meant to notice them.

     Nothing here loops. Motion that repeats forever stops being information
     and becomes noise, and it is the surest tell of a template. */
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-entrance: cubic-bezier(0.16, 1, 0.3, 1);

  --duration-instant: 70ms; /* press — must land inside the tap itself */
  --duration-fast: 120ms; /* colour change */
  --duration-base: 200ms; /* hover, focus */
  --duration-slow: 420ms; /* entrance */
  --duration-panel: 260ms; /* dialogs and sheets */

  /* Gap between neighbours in a staggered entrance. Small: the point is that
     the eye reads the group as arriving in order, not as a queue. */
  --stagger: 55ms;

  /* Distance a surface travels on entrance. One value, so everything on the
     page arrives from the same place. */
  --rise: 12px;

  /* --- Texture ------------------------------------------------------------
     Fractal noise, desaturated to pure luminance so the texture it produces is
     even rather than blotchy, and stitched so the 160px tile repeats without a
     visible seam. Used as a mask; see body::before in app.css. */
  --grain-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");

  --sidebar-width: 17rem;
  /* The same drawer with its labels dropped: wide enough for a 20px icon and a
     44px touch target, narrow enough that the reading column keeps its measure
     beside it. */
  --rail-width: 4.25rem;

  /* Four layers, and the order between them is load-bearing.
     The drawer starts below the header and the scrim dims only what the drawer
     covers, so the header stays lit and clickable while the drawer is open —
     otherwise the hamburger that opened it could not close it, and neither the
     theme nor the language control could be reached.
     The composer sits under the scrim on purpose: it is part of what the
     drawer is covering, so it dims and stops responding with the rest. */
  --z-dock: 10;
  --z-scrim: 20;
  --z-header: 25;
  --z-sidebar: 30;

  /* How much of the viewport the on-screen keyboard is covering. Set by
     app.js from the visual viewport; zero everywhere without one. */
  --keyboard-inset: 0px;
}

/* ============================================================================
   Themes.

   Every colour is declared once, with both values side by side, using
   light-dark(). Which half applies is decided by the used `color-scheme`, so
   the three tiny rules below are the entire theming mechanism.

   The alternative — a full palette in a [data-theme='light'] block and the
   same palette again in a prefers-color-scheme fallback — means writing every
   colour twice and keeping two copies in sync by hand. They drift.
   ========================================================================= */

:root {
  /* Dark unless something below says otherwise. */
  color-scheme: dark;

  /* Backgrounds. Three stops rather than a flat fill, so the page darkens
     toward the top and the header separates without needing a border. */
  --bg-top: light-dark(#fbfaf7, #060608);
  --bg-mid: light-dark(#f6f4ef, #0b0b0e);
  --bg-bottom: light-dark(#f2f0e9, #121216);

  /* Surfaces. Light mode is warm off-white rather than pure white, so it stays
     in the same family as the dark palette instead of reading as a different
     product. */
  --surface: light-dark(#ffffff, #191920);
  --surface-raised: light-dark(#ffffff, #22222b);
  --surface-sunken: light-dark(#eeece4, #050507);

  /* Two weights, for two jobs. --border separates surfaces that are already
     distinguishable by fill, so it can stay quiet. --border-strong outlines
     controls — the composer, the palette — where the boundary is the only
     thing telling you where the control is, so it must clear the 3:1 that
     WCAG requires for a UI boundary. It was below 2:1 until a test said so. */
  --border: light-dark(#e3e0d7, #2a2a31);
  --border-strong: light-dark(#8f8b81, #6b6b78);

  /* Text. Every one of these clears 4.5:1 against the surface it sits on in
     both themes — including --text-faint, which is the easy one to get wrong
     because it is only ever used at 12px. */
  --text: light-dark(#1a1a1e, #ededf0);
  --text-muted: light-dark(#63636d, #9b9ba5);
  --text-faint: light-dark(#6c6c76, #8e8e99);

  /* Gold darkens sharply in light mode: champagne on white lands near 1.5:1,
     far below readable. Same accent, different luminance. */
  --gold: light-dark(#8a6a2f, #e3c88c);
  --gold-deep: light-dark(#6e5424, #c4a55f);
  /* Gold at low alpha over near-black is not pale gold — it is olive mud.
     rgba(227,200,140,0.32) over the card fill renders #58503f, a dark khaki,
     and that colour was carrying the composer focus edge, the card hover
     border and the top-pick ring. Mixing toward the surface instead of fading
     toward it keeps the hue and only moves the lightness. */
  --gold-dim: light-dark(#f0e6cd, color-mix(in oklab, var(--gold) 16%, var(--surface)));
  --gold-edge: light-dark(#c2a45f, color-mix(in oklab, var(--gold) 55%, var(--surface)));
  /* Alpha is right for a glow, where the blur is the point and the hue is not. */
  --gold-glow: light-dark(rgba(138, 106, 47, 0.18), rgba(227, 200, 140, 0.22));

  /* Text sitting on a gold fill, which inverts with the accent. */
  --on-gold: light-dark(#fffdf7, #17140d);

  --danger: light-dark(#a8452f, #e08b7a);
  --success: light-dark(#2f6b45, #8fc9a0);

  /* Dimmer behind a modal. A token because it is a colour, and a raw one in
     app.css would be the only colour in the app with no theme and no test. */
  --scrim: light-dark(rgba(60, 50, 30, 0.32), rgba(0, 0, 0, 0.55));

  /* A one-pixel highlight along the top edge of a raised surface. This is the
     whole trick behind a surface reading as a physical object rather than a
     coloured rectangle: real materials catch light on their upper edge. */
  --edge-highlight: light-dark(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.1));

  /* Grain. Barely perceptible on its own — the point is that a flat digital
     fill has no texture at all, and the eye reads that as cheap.

     Expressed as a colour, not an opacity, and deliberately so: light-dark()
     is defined to return a <color>, so `opacity: light-dark(0.02, 0.035)` is
     an invalid declaration. It was silently dropped, the layer fell back to
     opacity 1, and full-strength noise covered the entire page — which is
     what made the site look like grey static. Carrying the strength in the
     alpha channel keeps one token per theme and keeps it valid.

     Light mode darkens, dark mode lightens: grain should read as texture in
     the surface, and a surface is textured by shadow on white and by
     highlight on black. */
  --grain: light-dark(rgba(40, 34, 20, 0.16), rgba(255, 252, 245, 0.14));

  --shadow-overlay: 0 16px 48px light-dark(rgba(60, 50, 30, 0.16), rgba(0, 0, 0, 0.55));
  /* Depth, in two parts, because the two themes get it from opposite places.

     On a near-black ground a black shadow is invisible — there is nothing left
     to darken — so depth in the dark comes from light: a bright rim along the
     top edge, drawn as an inset so it follows the border radius. On white the
     rim is nearly invisible and the cast shadow does the work.

     Both are applied together everywhere; each is inert in the theme that does
     not need it. They are two tokens rather than one because light-dark()
     returns a colour, so a whole shadow cannot go inside it — only the colour
     within one can. */
  --shadow-raised: 0 1px 2px light-dark(rgba(60, 50, 30, 0.06), rgba(0, 0, 0, 0.5));
  --rim: inset 0 1px 0 var(--edge-highlight);
}

/* An explicit choice always wins. */
:root[data-theme='light'] {
  color-scheme: light;
}

:root[data-theme='dark'] {
  color-scheme: dark;
}

/* No prefers-color-scheme fallback, deliberately.

   Gold on graded black is this product's identity, not a theme it happens to
   ship in. Following the system meant a visitor on a light-preference machine
   met a beige page that looked like a different site. Light mode stays one
   click away in the header, and the choice is remembered. */
