/* Synfonos design tokens — "Odak".
 *
 * Source of truth order (docs/design/TEMA.md and docs/design/tokens.json are DERIVED,
 * the canvas is AUTHORITATIVE):
 *   1. synfonos-desktop-audio-design/project/*.dc.html   <- wins
 *   2. docs/design/tokens.json                          <- derived, loses every time
 *
 * Where a token below differs from tokens.json the canvas line that overruled it is
 * cited inline. Two blocks exist in NO token file at all — the ring gradient timings
 * and the device palette's slots 4..8 — and both are recorded here rather than
 * re-derived somewhere else.
 *
 * FONTS ARE NOT DEFINED HERE. `fonts/fonts.css` owns --font-display / --font-ui /
 * --font-mono and must be linked BEFORE this file. Having two definitions of a font
 * stack is how a build ends up shipping Arial; there is exactly one.
 */

:root {
  --ground: #f4f2ee;
  --raised: #fffefb;
  --sunken: #eeebe4;
  --line: #e8e5df;
  /* 23 Sep 2026 (owner) · the chosen option of a segment (app.css, "2.d the segment"):
   * a surface one step LIGHTER than the sunken track it sits in, in both themes. Light
   * reads that off `--raised`; dark cannot, because there `--raised` (#17171b) is darker
   * than `--sunken` (#212127) and a pill darker than its track reads as unselected — the
   * owner's dark screenshots. The dark block points it at `--line`, the one existing
   * surface-grey above `--sunken`. */
  --seg-pill: var(--raised);

  /* The page behind the artboard. WB:16 sets the document ground to #EEEBE4 while the
   * artboard itself (WB:39) is #F4F2EE — two different greys, not one. */
  --page: #eeebe4;

  --ink-1: #14161a;
  --ink-2: #5c5a55;
  --ink-3: #64625c; /* M-18: was #a29e95, 2.03:1 */
  --ink-4: #c0bcb3;

  /* Inverted ink, used on filled controls. DUR:232 (filled button rest),
   * DUR:433 (the "seçili" badge). */
  --ink-on-fill: #fbfaf8;

  /* 23 Sep 2026 (owner) · THE TWO STEPS A FILLED CONTROL TAKES UNDER THE POINTER.
   *
   * A filled control is `--ink-1` ground with `--ink-on-fill` text. Its hover and its
   * pressed step used to be written as the LITERALS #000000 and #2e2c35 in seven places
   * (settings.css's `.pillbtn.is-primary`, app.css's `.btn[aria-pressed]`,
   * `.outbanner-link`, `.fwbanner-allow`, `.pairask-allow`, chrome.css's `.wcup-go`,
   * update.css's `.up-btn`). A literal cannot follow a theme: in dark, `--ink-on-fill` is
   * #14161a and the hover ground was #000000, so "Güncellemeleri denetle" went
   * black-on-black at 1.09:1 the moment the pointer touched it — the owner's own report.
   *
   * These two are the SAME MOVE in both themes rather than the same colour: one step
   * further along the ink axis away from the text sitting on them. Light goes darker
   * (#000000, which is what the canvas draws and what `app.css:440`'s pressed Sustur
   * already used); dark goes lighter, because in dark the resting fill is already near
   * white. `contrast.controls.test.mjs` holds both at 4.5:1 in both themes. */
  --fill-hover: #000000;
  --fill-active: #2e2c35;

  /* 23 Sep 2026 (owner) · THE LINK INK, which is not the accent.
   *
   * `.doclink` (Ayarlar → Tanılama) drew its text in `--dev-1`, the accent, and the
   * accent is a colour picked to be SEEN on a device chip, not to be READ as 12.5px
   * text: #2a78d6 is 3.71:1 on `--sunken` and 3.95:1 on `--ground`, both under this
   * product's own 4.5:1 floor (docs/design/TEMA.md:26). The accent keeps its job on
   * chips, rings and the focus outline — a ring is a shape and has its own 3:1 floor —
   * and text that happens to be a link now has an ink of its own, one step darker in
   * light and one step lighter in dark, clearing 4.5:1 on all four surfaces in both. */
  --link: #2569bd;

  /* Device colours — the identity set, NOT the ring's material sweep.
   *
   * Slots 1..3 are drawn on the Ana ekran itself (WB:734-736).
   *
   * SLOTS 4..8 ARE D-7'S SET AND NOT THE ONE THIS FILE SHIPPED BEFORE
   * (docs/KARAR-BEKLEYENLER.md, "D-7 · Cihaz paleti"). Three candidate sets existed and
   * none corroborated another: tokens.json's #eda100 #e87ba4 #008300 #4a3aa7 #e34948,
   * which appear in no canvas at all; the Windows Paneller set #7a5ad8 #c64b9b #1b9fb0
   * #5f9b2e #64707f, which this file used to carry with PAN:151-155 beside it; and
   * `Synfonos - Ayarlar tam.dc.html:836-848`, the five below. The decision picked the
   * third for a reason neither of the others can meet: **every one of these five is
   * also a stop on the ring's own conic sweep** (docs/design/HALKA-KARARLARI.md), so a
   * device's chip and the band it sits on are the same colour rather than two palettes
   * meeting at one pixel. The other two sets are absent from the sweep entirely.
   *
   * The PAN citation was not wrong about what PAN draws — it is overruled, and the
   * canvas-beats-tokens.json rule at the head of this file is unchanged. What decided
   * this was a canvas too; it was a different one, and the ring is what broke the tie.
   *
   * A device does not own a colour; a SLOT does. The engine decides which device lands
   * in which slot, and the slot hands out both this colour and its ring angle.
   * There is no ninth (tokens.json rules[0]). */
  --dev-1: #2a78d6; /* Mavi       PAN:148 */
  --dev-2: #eb6834; /* Turuncu    PAN:149 */
  --dev-3: #1baf7a; /* Yeşil      PAN:150 */
  --dev-4: #219fa6; /* Camgöbeği  AYAR:836-848, ring stop 92° */
  --dev-5: #2a8fcb; /* Mavi ton   AYAR:836-848 */
  --dev-6: #6b95d2; /* Lavanta    AYAR:836-848 */
  --dev-7: #8fbcae; /* Adaçayı    AYAR:836-848 */
  --dev-8: #cfcbc2; /* Kum        AYAR:836-848 */

  /* M-18 (Windows quality audit, 15 Sep 2026) · TEXT roles reach 4.5:1 on --ground,
   * --raised, --sunken and --page, at rest and under --hover-wash, in both themes
   * (tokens.contrast.test.mjs). --warning and --serious stay the fill/border hues; the
   * text drawn in those roles uses --warning-text / --serious-text. */
  --good: #087308; /* was #0ca30c, 2.55:1 */
  --warning: #fab219;
  --warning-text: #815c0d;
  /* The warning pill's fill. Both warn pills on the Ana ekran are this exact rgba over
   * a 1px --warning border (WB:104 card, WB:149 footer). */
  --warn-fill: rgba(250, 178, 25, 0.16);
  --warn-fill-hover: rgba(250, 178, 25, 0.26);  /* DUR:254 */
  --warn-fill-active: rgba(250, 178, 25, 0.34); /* DUR:256 */
  /* --serious IS RESTORED (W-03, 2026-09-05). It was deleted here (see the archived
   * reasoning this replaces: "exists in tokens.json and in no canvas") on the premise
   * that the Ana ekran/panel canvases never tint latency text with it — true, and still
   * the rule for latency. But `Synfonos - Durumlar ve bilesenler.dc.html`'s notification
   * card ("BİLDİRİM / UYARI KARTI · DÖRT DURUM", DUR:490-493) uses exactly this hex at
   * 20% for its third of four severity fills ("İş laptopu menzil dışında · sessize
   * alındı"), and the state/error card table (docs/design/odak-plan/states.md §2, cards
   * #3 "Cihaz menzil dışına çıktı" and #7 "Ekran kilitlendiğinde ses durdu") cites the
   * same hex for the "ciddi" pill. A token absent from every consumer earned deletion;
   * a token two consumers already draw does not. --serious-fill is the companion
   * `rgba()` DUR:490 actually paints, on the same pattern --warn-fill already set: a
   * severity token pairs with its own translucent fill rather than every caller
   * recomputing the alpha. This is the ONE token this file restores — the other four
   * severity tiers below (good/warning/critical) predate this edit unchanged. */
  --serious: #ec835a;
  --serious-text: #925138;
  --serious-fill: rgba(236, 131, 90, 0.2); /* DUR:490 */
  --critical: #b83030; /* error borders and error TEXT only — never latency. DUR:441. M-18: was #d03b3b, 3.66:1; now docs/design/tokens.json light.critical */

  /* The unselected-tab/segment/rail-item hover wash. Three sites (app.css's .tab and
   * .segment>button, settings.css's .railitem) each carried their own hand-picked rgba
   * literal here, tuned to their own light-theme background — and none of the three had
   * a dark-theme counterpart, so dark mode got the light literal verbatim: a near-white
   * flash with washed-out text on every hover. One token, overridden per theme below,
   * replaces all three. */
  --hover-wash: rgba(20, 22, 26, 0.05);

  /* One alias, kept because JS that predates fonts.css still asks for --font-num.
   * The stack itself lives in fonts/fonts.css and only there. */
  --font-num: var(--font-mono);

  /* There is no single display size. The canvas runs one face (Bricolage Grotesque,
   * weight 300, tracking -0.045em) at four sizes chosen per context:
   *   76 hub master (WB:84) · 56 card level (WB:111) · 46 node card (NODE:40)
   *   · 26 dark-theme mini (DUR:613)
   * tokens.json's single 66px matched none of them. */
  --size-display-hub: 76px;
  --size-display-card: 56px;
  --size-display-node: 46px;
  --size-display-mini: 26px;
  --display-weight: 300;
  --display-tracking: -0.045em;

  /* The wordmark is Instrument Sans 15/600/-0.01em (WB:44). There is no 20px text
   * anywhere on the Ana ekran. */
  --size-title: 15px;
  --size-body: 14px;
  --size-sub: 12.5px;
  --size-label: 11px;      /* WB:83, ls 0.09em; section labels use 11px / ls 0.08em */

  --r-sm: 8px;
  --r-md: 12px;   /* list rows, handoff row (DUR:392, WB:130) */
  --r-lg: 16px;   /* channel cards (DUR:423) */
  --r-xl: 22px;   /* the Ana ekran card and the node card (WB:93, NODE:10) */
  --r-pill: 999px;

  --space: 4px;
  --touch: 44px;

  --elev-card: 0 1px 2px rgba(20, 22, 26, 0.05);
  --elev-pop: 0 2px 6px rgba(20, 22, 26, 0.1), 0 22px 48px -22px rgba(20, 22, 26, 0.34);
  --elev-drag: 0 4px 12px rgba(20, 22, 26, 0.18), 0 26px 56px -24px rgba(20, 22, 26, 0.45);

  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --dur-level: 80ms;
  --dur-enter: 160ms;
  --dur-exit: 220ms;

  /* ===== THE MOTION LANGUAGE — Kapı 8 rule 8 ================================
   *
   * The owner, 6 Sep 09:20: *"her sayfayi guzelce animasyonlarla donatiyorsun dimi? …
   * baktığım kadarıyla çok yavandı."* The gate's answer is one easing family and one
   * duration ruler for the WHOLE product: fast 120 / medium 240 / slow 400, ease-out on
   * the way in, ease-in on the way out, and a spring reserved for the one thing that has
   * mass. Every animated property under `apps/desktop-tauri/ui` reads one of the names
   * below and nothing else — `motion.test.mjs` fails on a raw millisecond value inside a
   * `transition` and on a `cubic-bezier()` written anywhere but THIS file.
   *
   * WHY THE FOUR OLDER NAMES ABOVE SURVIVE. `--dur-enter`/`--dur-exit` are TEMA rule 7's
   * own 160/220 pair and are what every hover and fill transition already in this tree
   * reads; `--dur-level` is the meter's smoothing and `--ease` is the canvas's curve.
   * Renaming them would be a diff across nine stylesheets with no visible change at the
   * end of it. They are the same ruler at finer resolution, and the reduced-motion block
   * at the foot of this file zeroes them alongside the three new ones — which is the one
   * property that has to hold for all seven at once.
   *
   * WHY THE SPRING IS PANELS-ONLY. An overshoot reads as mass. A panel weighs something:
   * it is a 420px slab arriving from off-screen, so it lands with one. A number, a pill
   * or a crossfade does not, and giving them the same curve makes a screen feel loose.
   * `--ease-spring` therefore has exactly one consumer (`.panel`'s open transition in
   * app.css) and the source scan is not what keeps it that way; this paragraph is. */
  --dur-fast: 120ms;   /* press, hover, focus — anything under the finger */
  --dur-med: 240ms;    /* something arriving or leaving: panel, pane, step, toast, number */
  --dur-slow: 400ms;   /* the page itself: a theme swap */

  /* ease-out: quick off the mark, settles at the end. Everything ARRIVING.
   * ease-in: leaves slowly, then goes. Everything LEAVING.
   *
   * THESE TWO ARE THE ANDROID SHELL'S CURVES, TO THE DIGIT. `Motion.kt`'s enter/exit pair
   * (`docs/design/odak-plan/ANDROID-MOTION.md`) is `cubic-bezier(0,0,.2,1)` and
   * `cubic-bezier(.4,0,1,1)`, chosen there first and copied here rather than re-derived —
   * a phone and a desktop running the same product must not decelerate differently, and
   * "one easing family" is meaningless if it stops at the platform boundary. The three
   * durations below the pair (120/240/400) are already identical across both shells. */
  --ease-enter: cubic-bezier(0, 0, 0.2, 1);
  --ease-exit: cubic-bezier(0.4, 0, 1, 1);
  /* Overshoots and settles. Panels only — see above. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* The two rhythms a list arrives on. A group of rows staggers 30 ms apart; the four
   * pairing digits are 40, because four glyphs inside 120 ms read as one event and the
   * whole point of that one is that you can count them as they land. */
  --stagger-step: 30ms;
  --stagger-digit: 40ms;

  /* Press and hover as numbers, rather than as literals repeated in nine stylesheets.
   * `--panel-scale` is the panel's own arrival scale (0.98 -> 1) and sits here beside
   * them because reduced motion has to be able to flatten all three in one place. */
  --press-scale: 0.97;
  --hover-lift: -2px;
  --panel-scale: 0.98;

  /* The ring's selection machine. NOT in tokens.json or TEMA.md — measured off the
   * canvas JS (break 240 / rotate 560 / join 320, WB:818/821/826). */
  --dur-ring-break: 240ms;
  --dur-ring-rotate: 560ms;
  --dur-ring-join: 320ms;

  --icon-stroke: 1.7px;

  /* Focus. DUR:598 states the rule in words: a 2px visible ring on every focusable,
   * focus order following screen order. The Ana ekran uses offset 2px throughout
   * (WB:48, 72, 112, 120, 140); the component sheet's 3px is the out-of-context value.
   * The ring chips are the one exception and carry ink, not accent — see app.css. */
  --focus: var(--dev-1);
  --focus-offset: 2px;
}

/* ===== reduced motion — the whole ruler collapses to zero ==================
 *
 * ONE BLOCK, NOT NINE. Six stylesheets in this directory carry their own
 * `* { transition: none !important }` under this query; they are all still there and all
 * still correct. But a blanket `!important` only reaches CSS. It cannot tell `ring.js` to
 * stop turning, it cannot tell `motion.js`'s `tweenNumber` to land on the final digit
 * instead of counting up to it, and it cannot tell `flip()` not to measure. Zeroing the
 * TOKENS does all three, because both halves read the same names: CSS resolves
 * `var(--dur-med)` to `0ms`, and `motion.js` reads the same custom properties off the
 * computed root style and gets the same zero.
 *
 * `--press-scale` and `--hover-lift` go to their identity values rather than being
 * dropped: a control still has to answer a press, and a colour change over `0ms` IS an
 * answer. The gate's words are *"geçişler anında, halka durur"* — instant, not absent.
 *
 * THE RING'S OWN STOP IS NOT HERE AND CANNOT BE: `EvoRing.paint` pins its clock to zero
 * in JavaScript (`this.reduced ? 0 : t`). What is new is where that boolean comes from —
 * `motion.js`'s `reducedMotion()`, one MediaQueryList for the whole front end, which the
 * ring now SUBSCRIBES to as well, so a person who turns the setting on mid-session gets a
 * ring that stops now rather than one that stops on the next launch. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0ms;
    --dur-med: 0ms;
    --dur-slow: 0ms;
    --dur-level: 0ms;
    --dur-enter: 0ms;
    --dur-exit: 0ms;
    --dur-ring-break: 0ms;
    --dur-ring-rotate: 0ms;
    --dur-ring-join: 0ms;
    --stagger-step: 0ms;
    --stagger-digit: 0ms;
    --press-scale: 1;
    --hover-lift: 0px;
    --panel-scale: 1;
  }
}

:root[data-theme='dark'] {
  --ground: #0c0c0e;
  --raised: #17171b;
  --sunken: #212127;
  --line: #2e2c35;
  --seg-pill: var(--line);
  --page: #08080a;

  --ink-1: #fbfaf8;
  --ink-2: #a5a2ab;
  --ink-3: #9d9ba2; /* M-18: was #79767f, 2.84:1 */
  --ink-4: #57545e;
  --ink-on-fill: #14161a;
  /* The dark halves of the two filled-control steps defined in the light block. Rest is
   * `--ink-1` #fbfaf8 here, so hover goes to true white and the pressed step to a grey
   * that is still far lighter than the #14161a text standing on it. */
  --fill-hover: #ffffff;
  --fill-active: #d8d5cf;
  /* The dark half of the link ink: lighter than the accent, not darker. */
  --link: #5a9df0;

  /* M-18 · the dark halves of the text roles (the light values fail on these grounds). */
  --good: #35b335;
  --warning-text: #fab219;
  --serious-text: #ec835a;
  --critical: #e18181;

  /* Dark-theme half of the hover wash defined above --font-num in the light block: a
   * light-ink tint rather than the light theme's dark-ink one, so hover lightens a dark
   * surface instead of darkening it (and instead of the flat near-white literal this
   * replaces, which read as a bright flash against #17171b/#212127). */
  --hover-wash: rgba(251, 250, 248, 0.08);

  --dev-1: #3987e5;
  --dev-2: #d95926;
  --dev-3: #199e70;
  /* Slots 4..8 have NO dark step anywhere, and that survived D-7 unchanged.
   * tokens.json had five; they were dark steps of five colours no canvas draws, and
   * they died with their light halves. The five that replaced those light halves have
   * no dark canvas either. Deriving new ones would be a design decision, not a port —
   * the light values are inherited until a dark canvas says otherwise. */

  /* The dark node-graph grid. Present in the dark canvas, absent from every token
   * file. Recorded here so it stops being a magic number. */
  --grid-dark: #2a2830;

  --elev-card: 0 1px 2px rgba(0, 0, 0, 0.5);
  --elev-pop: 0 2px 6px rgba(0, 0, 0, 0.55), 0 22px 48px -22px rgba(0, 0, 0, 0.8);
  --elev-drag: 0 4px 12px rgba(0, 0, 0, 0.6), 0 26px 56px -24px rgba(0, 0, 0, 0.85);
}
