/*
IC SHIP PASS — generated by icpass.py from the map. edit the CODE; rerun to refresh this.

══════════════════════════════════════════════════════════════════════
 PAGE 0 — TABLE OF CONTENTS  (goldfish pointers)
 jump by SEARCHING the anchor phrase — line numbers drift, names don't.
══════════════════════════════════════════════════════════════════════
  bevel — repetition: one definition, used ..... search: "bevel — repetition: one"
  btn — physical object, has mass. can you ..... search: "btn — physical object,"
  ♿ the a11y layer (ACCESSIBILITY.md pass ...... search: "♿ the a11y layer"
  PERMISSION TIER ICONS — png in the fantasy ... search: "PERMISSION TIER ICONS"
  THE TIER BUTTON IS A HEAD BUTTON, SO IT ...... search: "THE TIER BUTTON IS A"
══════════════════════════════════════════════════════════════════════

 FOR AI
 ───────
   **OWNS** — the structural tokens (spacing, type scale, hit targets, radii) and the global
   **accessibility layer (focus rings, keyboard mode, reduced motion). Every skin file imports
   **these tokens as CSS variables. The file exports no JavaScript names; it is pure structure.
   
   **TOUCH HERE**
   - change the invisible grid (spacing) → `:root` L5–11
   - change type scale (font sizes) → `:root` L13–22
   - change hit target size (button/tile minimum) → `:root` L29–31, then `body.chunky` L148–154
   - for the accessibility override
   - change focus ring color or style → `:focus-visible` L90–94, `.a11y-popped` L123–126,
   - `.tb-kbd.lit` L128–132, `.card.kbd-grab` L140–144
   - change button appearance (shadow, radius, active state) → `.btn` L73–84
   - change skip-link position or timing → `.skip-link` L97–104
   - change reduced-motion behavior → `@media (prefers-reduced-motion: reduce)` L108–115
   - change tier button (permission icons) size or padding → `.oz-perm-btn, .ab-esp` L238–249
   
   **TRAPS**
   - `--hit: 44px` (L30) is the palsy rule floor; lowering it breaks accessibility. `body.chunky`
   - (L148) overrides it to 60px — both must stay in sync with the design intent.
   - `.oz-perm-btn` and `.ab-esp` (L238) share one rule block; changes to one affect the other.
   - They are intentionally paired.
   - `--head-icon-h` (L247) is referenced but not defined in this file — it lives in a skin file.
   - Renaming it here orphans every skin.
   - The focus ring color `#57e0c8` appears as a fallback in five places (L91, L100, L119, L124,
   - L130, L141, L159, L160, L162, L168). Changing one without the others creates visual
   - inconsistency.
   - `z-index: 100000` (L158) and `z-index: 100001` (L167) are stacked intentionally (keymap
   - below onboard). Do not reorder.
   - `outline-offset: 2px` (L92, L120, L142) and `outline-offset: 3px` (L125) are deliberate —
   - the dashed ring pops further. Do not unify them.
   
   **DO NOT**
   - rename `.btn`, `.bevel`, `.skip-link`, `.a11y-popped`, `.oz-perm-btn`, `.ab-esp`, or any
   - `--` token without auditing every skin file and every JavaScript reference.
   - move the `:root` block (L5–40) — it must load before any rule that uses its variables.
   - add color values here; colors belong in skin files only. This file has no `--bg`, `--text`,
   - `--btn`, `--bevel-light`, `--bevel-dark`, `--btn-sh`, `--focus-ring` definitions — they are
   - injected by the skin.
   - change the `#zoom-root` flex structure (L50) without understanding zoom.js and how it scales
   - iframes.
   - add new global animations or transitions without checking `@media (prefers-reduced-motion:
   - reduce)` (L108–115) — they must be curbed there too.
   - move or rename the chunky mode rules (L146–155) — they override `--hit` and must stay
   - grouped.
   
   
   
   ---

END IC SHIP PASS
*/

/* base.css — structure tokens. no color lives here. (skin owns color.)
   build phase: lean. full folio header at ship.
   tokens = law. change here, everything updates. */

:root {
  /* spacing — the invisible grid (alignment + placement) */
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 40px;

  /* type — large print is the baseline, not a setting (pharma grade).
     (Sum 2026-07-13) T-SHIRT SCALE — tokenize every font to one of these. XL is the workhorse (everything the user
     reads/clicks); HUGE is the rare shout (titles). We basically never use HUGE in this app — reach for XL. */
  --fs-xl:     20px;   /* the standard big-print size — the floor for any text the user READS or CLICKS */
  --fs-huge:   28px;   /* only when something truly needs to shout (titles) — rarely */
  --fs-chrome: 18px;
  --fs-label:  var(--fs-xl);
  --fs-body:   var(--fs-xl);   /* (Sum 2026-07-13) was 28px (huge) — that "huge" was leaking into the linter + suggestor; body text is XL */
  --fs-title:  var(--fs-huge);
  --fs-ui:     var(--fs-xl);

  /* radii */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 16px;

  /* hit targets — palsy rule: never below 30px. topbar runs roomier. */
  --hit: 44px;
  --topbar-h: 56px;

  /* topbar tiles — ONE tile size. every launcher (nav · deck · suite) is --hit square,
     its icon --tb-icon. change here → every tile in the bar updates. (2026-07-09) */
  --tb-icon:     30px;   /* the rendered PNG / css icon inside a tile */
  --tb-emoji-fs: 26px;   /* the emoji-icon glyph size (matches the PNG optical weight) */
  --tb-icon-sub: 26px;   /* the same, one notch down, for the subbar drawer pills */

  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; overflow: hidden; }   /* page never scrolls. cards do. */

/* the zoom STAGE — holds the whole app (topbar · subbar · desk). EAT ME/DRINK ME scales THIS with a
   transform (zoom.js), NOT body.zoom — CSS zoom on an ancestor mis-sizes descendant iframes, letterboxing
   preview/ban/monaco in white. transform scales them as one layer, so they fill at any zoom. zoom.js sets
   width/height to 100/z so scaling by z lands the stage exactly on the viewport. */
#zoom-root { display: flex; flex-direction: column; width: 100vw; height: 100vh; overflow: hidden; transform-origin: 0 0; flex-shrink: 0; }   /* flex-shrink:0 — as a body flex-child, a 100/z-vh stage (z<1) must NOT shrink back to 100vh, or scale(z) renders it short → gap at the bottom */

body {
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  font-size: var(--fs-body);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* ── bevel — repetition: one definition, used everywhere. ───────────
   the offsets are structure (here). the colors are skin (there). */

.bevel {
  box-shadow:
    inset 1px 1px 0 var(--bevel-light),
    inset -1px -1px 0 var(--bevel-dark);
}

/* ── btn — physical object, has mass. can you pick it up? ───────────── */

.btn {
  background: var(--btn);
  color: var(--text);
  border: none;
  border-radius: var(--r-md);
  box-shadow: 0 3px 0 var(--btn-sh);
  min-height: var(--hit);
  font: inherit;
  cursor: pointer;
}

.btn:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--btn-sh); }

/* ── ♿ the a11y layer (ACCESSIBILITY.md pass 1+6, 2026-07-14) — tokens + three global rules ── */

/* the focus ring — one ring, everywhere, only for keyboard/switch travel (:focus-visible skips mouse
   clicks). high-contrast teal on the dark skins; the outline sits OUTSIDE so it never squeezes layout. */
:focus-visible {
  outline: 3px solid var(--focus-ring, #57e0c8);
  outline-offset: 2px;
  border-radius: 4px;
}

/* the skip link — invisible until a keyboard lands on it, then a clear banner to jump the chrome */
.skip-link {
  position: fixed; top: -100px; left: 12px; z-index: 99999;
  padding: 10px 18px; border-radius: var(--r-md);
  background: var(--focus-ring, #57e0c8); color: #08211c;
  font-size: var(--fs-ui); font-weight: 700; text-decoration: none;
  transition: top .12s;
}
.skip-link:focus { top: 12px; }

/* reduced motion — the OS setting wins: curb every animation/transition (no flashing, no loops).
   near-zero (not zero) so animationend/transitionend events still fire and JS state machines finish. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ⌨ FOCUS MODE (Sum 2026-07-14) — keyboard travel made VISIBLE. body.kbd-mode set by OZ_KBD (a11y.js). */
body.kbd-mode :focus {
  outline: 3px solid var(--focus-ring, #57e0c8) !important;
  outline-offset: 2px;
}
/* the pop-out flash — Esc lands you HERE: a dashed ring on the surface you popped to, 1.6s */
.a11y-popped {
  outline: 3px dashed var(--focus-ring, #57e0c8) !important;
  outline-offset: 3px;
}
/* the ⌨ topbar toggle, lit while focus mode is on */
.tb-kbd.lit {
  background: rgba(87, 224, 200, .22);
  box-shadow: inset 0 0 0 2px var(--focus-ring, #57e0c8);
  border-radius: 8px;
}

/* ⌖ focus mode — cartography's "you are here" (Sum: the dashed circle was just noise). big + bold;
   ON wears the same collar-red .active as deck/drawer (topbar.css), glyph warms to match. */
.tb-youarehere { font-size: 30px; line-height: 1; font-weight: 700; }
.tb-kbd.active .tb-youarehere { color: var(--accent, #d33); text-shadow: 0 0 8px var(--accent, #d33); }

/* ⌨ a KBD-GRABBED card/bot visibly lifts off the desk (hold G on its head · arrows dock · release) */
.card.kbd-grab, .agent-bar.kbd-grab {
  outline: 3px solid var(--focus-ring, #57e0c8);
  outline-offset: 2px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .55);
}

/* ▮ CHUNKY MODE (Sum 2026-07-14) — fatter TARGETS, same layout scale. tokens are law: bump --hit +
   the grabbable chrome. zoom (eat/drink me) scales the world; chunky just makes it easier to HIT. */
body.chunky { --hit: 60px; }
body.chunky .tb-btn { min-width: 52px; min-height: 48px; }
body.chunky .mc-pit-btn { min-width: 48px; min-height: 44px; }
body.chunky .mc-wing-grip-h { height: 34px; }
body.chunky .mc-wing-grip-v { width: 34px; }
body.chunky .mc-tool-split:not(.wide) > .mc-split, body.chunky .mc-fix:not(.wide) .mc-fix-body > .mc-split, body.chunky .mc-sq-main:not(.wide) > .mc-split { height: 34px; }
body.chunky .mc-tool-split.wide > .mc-split, body.chunky .mc-fix.wide .mc-fix-body > .mc-split, body.chunky .mc-sq-main.wide > .mc-split { width: 34px; }
.tb-chunky-glyph { font-size: 26px; line-height: 1; }

/* ? THE KEY MAP — big type, one card, the whole travel language */
#oz-keymap { position: fixed; inset: 0; z-index: 100000; background: rgba(8, 10, 14, .72); display: flex; align-items: center; justify-content: center; cursor: pointer; }
.oz-keymap-box { background: #16181d; color: #eef1f5; border: 2px solid var(--focus-ring, #57e0c8); border-radius: 14px; padding: 26px 34px; max-width: 560px; font-size: var(--fs-ui, 20px); line-height: 1.5; box-shadow: 0 18px 50px rgba(0,0,0,.6); }
.oz-keymap-box h2 { margin: 0 0 12px; font-size: 26px; color: var(--focus-ring, #57e0c8); }
.oz-keymap-box dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 18px; margin: 0; }
.oz-keymap-box dt { font-weight: 800; color: var(--focus-ring, #57e0c8); white-space: nowrap; }
.oz-keymap-box dd { margin: 0; }
.oz-keymap-box p { margin: 14px 0 0; opacity: 1; color: #9aa3ad; font-size: 16px; }

/* 🚪 THE PER-BODY DOOR (onboard.js) — big type, big toggles; itself accessible (it must be) */
#oz-onboard { position: fixed; inset: 0; z-index: 100001; background: rgba(8, 10, 14, .78); display: flex; align-items: center; justify-content: center; }
.oz-ob-box { background: #16181d; color: #eef1f5; border: 2px solid var(--focus-ring, #57e0c8); border-radius: 16px; padding: 30px 36px; max-width: 620px; width: min(92vw, 620px); box-shadow: 0 20px 60px rgba(0,0,0,.65); }
.oz-ob-box h2 { margin: 0 0 8px; font-size: 30px; }
.oz-ob-box p { margin: 0 0 18px; font-size: 18px; color: #b9c1ca; line-height: 1.45; }
.oz-ob-rows { display: flex; flex-direction: column; gap: 10px; }
.oz-ob-row { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left; background: #23262d; color: #eef1f5; border: 2px solid #3a3f47; border-radius: 12px; padding: 12px 18px; min-height: var(--hit, 44px); cursor: pointer; font: inherit; }
.oz-ob-row:hover { border-color: #5a626c; }
.oz-ob-row.on { background: #0e3a33; border-color: var(--focus-ring, #57e0c8); box-shadow: inset 0 0 0 1px var(--focus-ring, #57e0c8); }
.oz-ob-big { font-size: 22px; font-weight: 800; }
.oz-ob-small { font-size: 16px; color: #aeb7c0; }
.oz-ob-row.on .oz-ob-small { color: #cde8e2; }
.oz-ob-done { margin-top: 18px; width: 100%; min-height: 54px; font-size: 22px; font-weight: 800; background: #1d7a3e; color: #fff; border: 0; border-radius: 12px; box-shadow: 0 4px 0 #14582c; cursor: pointer; }
.oz-ob-done:active { transform: translateY(2px); box-shadow: 0 2px 0 #14582c; }

/* airy letters — the dyslexia-friendly spacing mode (letterforms breathe; big type is already law) */
body.dyslexia-air { letter-spacing: .035em; word-spacing: .1em; }
body.dyslexia-air p, body.dyslexia-air .mc-tool-msg, body.dyslexia-air .msg { line-height: 1.7; }

/* PEAK SAAS — the last row: a washing-machine GLYPH + a dial-on-NORMAL GLYPH (CSS-drawn, monochrome,
   currentColor), then "Peak SaaS Skin" set in ACTUAL fine print. the row is the joke. */
.oz-ob-box { max-height: 88vh; overflow-y: auto; }
.oz-ob-saas { flex-direction: row; align-items: center; gap: 12px; }
.oz-ob-saas-glyphs { display: inline-flex; gap: 8px; align-items: center; }
.ob-washer { display: inline-block; width: 22px; height: 26px; border: 2px solid currentColor; border-radius: 5px; position: relative; }
.ob-washer::before { content: ''; position: absolute; top: 2px; left: 2px; right: 2px; height: 3px; border: 1px solid currentColor; border-radius: 1px; }   /* the control panel strip */
.ob-washer::after { content: ''; position: absolute; top: 8px; left: 3px; right: 3px; bottom: 3px; border: 2px solid currentColor; border-radius: 50%; }   /* the porthole door */
.ob-dial-wrap { display: inline-flex; flex-direction: column; align-items: center; gap: 1px; }
.ob-dial-lbl { font-size: 13px; font-weight: 800; letter-spacing: .06em; line-height: 1; }
.ob-dial { display: inline-block; width: 18px; height: 18px; border: 2px solid currentColor; border-radius: 50%; position: relative; }
.ob-dial::after { content: ''; position: absolute; top: 1px; left: 50%; width: 2px; height: 6px; margin-left: -1px; background: currentColor; }
.oz-ob-fineprint { font-size: 13px; letter-spacing: .02em; color: #9aa3ad; }
.oz-ob-saas.on .oz-ob-fineprint { color: #cde8e2; }

/* 🔤 the glyph CHIP — what a png button wears on the clean skins: its glyph twin or its own name */
.gl-chip { display: inline-flex; align-items: center; justify-content: center; font-size: 17px; font-weight: 700; line-height: 1; min-width: 20px; padding: 1px 3px; letter-spacing: .01em; }
button .gl-chip, a .gl-chip { pointer-events: none; }

/* 🖼 an emoji's PNG twin, swapped in-place by the icon bean (fantasy skins) — sits like a character */
.em-ico { height: 1.2em; width: auto; vertical-align: -0.2em; display: inline-block; }

/* the DRAWN bubbles (clean tier) — speech = pointed tail, thought = dot trail; currentColor line art */
.gl-drawn { display: inline-block; position: relative; vertical-align: -0.08em; }
.gl-speech { width: 0.95em; height: 0.72em; border: 0.11em solid currentColor; border-radius: 0.3em; }
.gl-speech::after { content: ''; position: absolute; left: 0.1em; bottom: -0.32em; border: 0.14em solid transparent; border-top-color: currentColor; }
.gl-think { width: 0.95em; height: 0.72em; border: 0.11em solid currentColor; border-radius: 50%; }
.gl-think::after { content: ''; position: absolute; left: -0.02em; bottom: -0.34em; width: 0.14em; height: 0.14em; border-radius: 50%; background: currentColor; box-shadow: 0.2em 0.14em 0 -0.02em currentColor; }

/* ── PERMISSION TIER ICONS — png in the fantasy skins, drawn in the clean ones. (Sum 2026-07-30.)
      "png for oz and unicorn, draw or code, svg or css for clin and corp. just no emoji ever,
      every png gets a drawn version." Both ship; the tier picks. Nothing is deleted this time. ── */
.oz-perm-ico .oz-perm-png { width: 20px; height: 20px; object-fit: contain; display: block; }
.oz-perm-ico .oz-perm-svg { display: none; }
.oz-perm-ico .oz-perm-svg svg { width: 20px; height: 20px; display: block; }
html[data-tier="clean"] .oz-perm-ico .oz-perm-png { display: none; }
html[data-tier="clean"] .oz-perm-ico .oz-perm-svg { display: block; }
/* the ask-rows sit above a bot's ceiling — dim the ROW, never the text (IC: opacity on text is banned) */
.oz-perm-opt.oz-perm-ask { filter: saturate(.45) brightness(.8); }
.oz-perm-ico.oz-perm-dim { filter: grayscale(.4); }
/* the ESP toggle — png in oz/unicorn, the drawn svg in clinical/corporate. Both states in both media. */
.ab-esp .ab-esp-svg { display: none; }
html[data-tier="clean"] .ab-esp .ab-esp-png { display: none; }
html[data-tier="clean"] .ab-esp .ab-esp-svg { display: block; }

/* ── THE TIER BUTTON IS A HEAD BUTTON, SO IT WEARS HEAD SIZES (Sum 2026-07-30: "it's the weird button
      shape it's making them way too tiny. they should be as big as the gear and the collar").
      He is right and the cause is structural: .ab-gear carries `background: none; border: 0; padding: 2px`
      — no seat at all, so its icon runs the full --head-icon-h. The tier control was a PILL with padding
      and a border, so the same 40px slot had to fit a border, two paddings AND the picture. The picture
      lost. Drop the pill; keep only as much seat as the dark photographic icons need to have a ground
      (that part of the last fix was right — object on object reads as nothing).
      TOKENS ARE LAW: --head-icon-h, never a number, so this tracks every skin and every zoom step. ── */
.oz-perm-btn, .ab-esp {
  background: #d8d5cf; border: 0; border-radius: 10px;
  padding: 2px; line-height: 0;
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.oz-perm-btn:hover, .ab-esp:hover { background: #eceae5; filter: none; }
.oz-perm-btn .oz-perm-png,
.oz-perm-btn .oz-perm-svg svg,
.ab-esp .ab-esp-png,
.ab-esp .ab-esp-svg svg { width: var(--head-icon-h); height: var(--head-icon-h); display: block; object-fit: contain; }
.oz-perm-btn .oz-perm-ico { filter: none; opacity: 1; display: block; line-height: 0; }
.ab-esp.on { background: #16201a; }        /* lit = the screen goes dark and the phosphor carries it */

/* the MENU rows keep their own smaller icon — the row already gives them a ground, and 40px there
   would make the dropdown a poster instead of a list. */
.oz-perm-menu .oz-perm-ico .oz-perm-png,
.oz-perm-menu .oz-perm-ico .oz-perm-svg svg { width: 22px; height: 22px; }

/* clinical + corporate keep their own ground — don't paint a grey tile onto a clean skin */
html[data-tier="clean"] .oz-perm-btn,
html[data-tier="clean"] .ab-esp { background: transparent; }

