@telepath-computer/television 0.1.84 → 0.1.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -48407,7 +48407,7 @@ function registerRoutes(app, store, options) {
48407
48407
  handleStoreError(res, error48, "Failed to read artifact content");
48408
48408
  }
48409
48409
  });
48410
- app.get("/artifacts/:id/content/*", ...auth, (req, res) => {
48410
+ app.get("/artifacts/:id/content/*", (req, res) => {
48411
48411
  const artifact = store.getArtifact(req.params.id);
48412
48412
  if (!artifact) {
48413
48413
  sendError(res, HTTP_NOT_FOUND, `Artifact not found: ${req.params.id}`);
@@ -50093,18 +50093,10 @@ function findCardIDInNode(node, artifactID) {
50093
50093
  var import_meta = {};
50094
50094
  var DAEMON_NAME = "com.television.server";
50095
50095
  var MAX_PORT = 65535;
50096
- var HELP_POINTER = "Load/read the installed `television` skill. If the skill is not installed, the bundled content is reachable via `tv skills show` \u2014 no arguments lists the relative paths and their descriptions; passing a relative path prints that file. Key relative paths (arguments to `tv skills show`): `SKILL.md` for the mental model and the artifact-vs-chat decision; `cli-capabilities.md` for commands, focus, and screen placement; `artifact-workflow.md` for artifact lifecycle work; `html-house-style.md` for HTML artifact authoring; `artifact-types/<kind>.md` for kind-specific authoring.";
50096
+ var HELP_POINTER = "Television guidance is split across bundled skills. For screens, lifecycle work, and the `tv` CLI, read the `television` skill. For artifact authoring, use `tv skills install` or `tv skills show`, then let the matching `artifact-*` skill guide the output.";
50097
50097
  var CLIDirectiveError = class extends Error {
50098
50098
  name = "CLIDirectiveError";
50099
50099
  };
50100
- var CLISilentExitError = class extends Error {
50101
- name = "CLISilentExitError";
50102
- silentExitCode;
50103
- constructor(silentExitCode = 1) {
50104
- super("");
50105
- this.silentExitCode = silentExitCode;
50106
- }
50107
- };
50108
50100
  function writeJSON(output, value) {
50109
50101
  output.write(`${JSON.stringify(value)}
50110
50102
  `);
@@ -50131,8 +50123,8 @@ function resolveVercelSkillsInstallerBin() {
50131
50123
  return localRequire.resolve("skills/bin/cli.mjs");
50132
50124
  }
50133
50125
  function readCLIVersion() {
50134
- if ("0.1.84".length > 0) {
50135
- return "0.1.84";
50126
+ if ("0.1.86".length > 0) {
50127
+ return "0.1.86";
50136
50128
  }
50137
50129
  const devPackageJsonPath = import_node_path7.default.join(getDevPackageDir(), "package.json");
50138
50130
  if (!(0, import_node_fs4.existsSync)(devPackageJsonPath)) {
@@ -50140,123 +50132,80 @@ function readCLIVersion() {
50140
50132
  }
50141
50133
  return JSON.parse((0, import_node_fs4.readFileSync)(devPackageJsonPath, "utf8")).version;
50142
50134
  }
50143
- function listKnownArtifactTypeDocs() {
50144
- if ('["artifact-types/calendar.md","artifact-types/table.md"]'.length > 0) {
50145
- return JSON.parse('["artifact-types/calendar.md","artifact-types/table.md"]');
50146
- }
50147
- const televisionSkillsWorkspaceDir = import_node_path7.default.resolve(getDevPackageDir(), "../skills");
50148
- if (!(0, import_node_fs4.existsSync)(televisionSkillsWorkspaceDir)) {
50149
- return [];
50150
- }
50151
- return (0, import_node_fs4.readdirSync)(televisionSkillsWorkspaceDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && /^artifact-/.test(entry.name)).map((entry) => entry.name.slice("artifact-".length)).sort((a, b) => a.localeCompare(b)).map((slug) => `artifact-types/${slug}.md`);
50152
- }
50153
- function formatArtifactTypeDocsList() {
50154
- const docs = listKnownArtifactTypeDocs();
50155
- return docs.length > 0 ? docs.map((doc) => ` - ${doc}`).join("\n") : " - artifact-types/<name>.md";
50135
+ var FRONTMATTER_DELIMITER = "---\n";
50136
+ var FRONTMATTER_DELIMITER_LENGTH = FRONTMATTER_DELIMITER.length;
50137
+ function splitFrontmatter(text) {
50138
+ if (!text.startsWith(FRONTMATTER_DELIMITER)) {
50139
+ return { frontmatter: {}, body: text };
50140
+ }
50141
+ const closing = text.indexOf("\n---", FRONTMATTER_DELIMITER_LENGTH);
50142
+ if (closing === -1) {
50143
+ return { frontmatter: {}, body: text };
50144
+ }
50145
+ const block = text.slice(FRONTMATTER_DELIMITER_LENGTH, closing);
50146
+ const after = text.slice(closing + FRONTMATTER_DELIMITER_LENGTH);
50147
+ const body = after.startsWith("\n") ? after.slice(1) : after;
50148
+ const frontmatter = {};
50149
+ for (const rawLine of block.split("\n")) {
50150
+ const line = rawLine.trim();
50151
+ if (line === "" || line.startsWith("#")) continue;
50152
+ const colon = line.indexOf(":");
50153
+ if (colon === -1) continue;
50154
+ const key = line.slice(0, colon).trim();
50155
+ let value = line.slice(colon + 1).trim();
50156
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
50157
+ value = value.slice(1, -1);
50158
+ }
50159
+ frontmatter[key] = value;
50160
+ }
50161
+ return { frontmatter, body };
50162
+ }
50163
+ function readBundledSkill(skillRoot) {
50164
+ const skillMarkdownPath = import_node_path7.default.join(skillRoot, "SKILL.md");
50165
+ if (!(0, import_node_fs4.existsSync)(skillMarkdownPath)) {
50166
+ throw new Error(`Bundled skill is missing SKILL.md at ${skillMarkdownPath}.`);
50167
+ }
50168
+ const markdown = (0, import_node_fs4.readFileSync)(skillMarkdownPath, "utf8");
50169
+ const { frontmatter } = splitFrontmatter(markdown);
50170
+ const name = frontmatter.name?.trim();
50171
+ const description = frontmatter.description?.trim();
50172
+ if (!name || !description) {
50173
+ throw new Error(`Bundled skill has invalid frontmatter at ${skillMarkdownPath}.`);
50174
+ }
50175
+ return { name, description, markdown, root: skillRoot };
50176
+ }
50177
+ function listBundledSkills(collectionRoot) {
50178
+ return (0, import_node_fs4.readdirSync)(collectionRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readBundledSkill(import_node_path7.default.join(collectionRoot, entry.name))).sort((a, b) => a.name.localeCompare(b.name));
50179
+ }
50180
+ function resolveBundledSkill(collectionRoot, skillName) {
50181
+ const skillRoot = import_node_path7.default.join(collectionRoot, skillName);
50182
+ if (!(0, import_node_fs4.existsSync)(skillRoot)) {
50183
+ throw createDirectiveError(`tv skills show could not find bundled skill \`${skillName}\`.`);
50184
+ }
50185
+ return readBundledSkill(skillRoot);
50156
50186
  }
50157
50187
  function buildAgentHelpNote() {
50158
50188
  return [
50159
50189
  "",
50160
50190
  "Agent workflow note:",
50161
- " Load/read the installed `television` skill before Television work.",
50162
- " If the skill is not installed, the bundled content is reachable via the CLI:",
50163
- " tv skills show lists relative paths and descriptions",
50164
- " tv skills show <relative-path> prints one file",
50165
- " Key relative paths (arguments to `tv skills show`):",
50166
- " SKILL.md \u2014 mental model and artifact-vs-chat decision",
50167
- " cli-capabilities.md \u2014 commands, focus, screen placement",
50168
- " artifact-workflow.md \u2014 artifact lifecycle",
50169
- " html-house-style.md \u2014 HTML artifact authoring",
50170
- " Known artifact-type relative paths:",
50171
- formatArtifactTypeDocsList()
50191
+ " Television guidance is split across bundled skills.",
50192
+ " For screens, lifecycle work, and the `tv` CLI, read `television`.",
50193
+ " For artifact authoring, install or inspect the bundled skills with `tv skills install` or `tv skills show`.",
50194
+ " Then use the matching `artifact-*` skill, such as `artifact-calendar` or `artifact-table`."
50172
50195
  ].join("\n");
50173
50196
  }
50174
50197
  function buildArtifactWorkflowHelpNote(includeHTMLNote) {
50175
50198
  const lines = [
50176
50199
  "",
50177
50200
  "Agent note:",
50178
- " If you are an agent doing artifact lifecycle work, load/read the `television` skill \u2014 in particular `artifact-workflow.md`.",
50179
- " If the skill is not installed, read it with `tv skills show artifact-workflow.md`."
50201
+ " For Television lifecycle work, read `television`."
50180
50202
  ];
50181
50203
  if (includeHTMLNote) {
50182
- lines.push(
50183
- " If you are authoring an HTML artifact, also read `html-house-style.md` (`tv skills show html-house-style.md`)."
50184
- );
50185
- lines.push(" Known artifact-type relative paths (arguments to `tv skills show`):");
50186
- lines.push(formatArtifactTypeDocsList());
50204
+ lines.push(" For artifact authoring, install or inspect the bundled skills with `tv skills install` or `tv skills show`.");
50205
+ lines.push(" Then use the matching `artifact-*` skill, such as `artifact-calendar` or `artifact-table`.");
50187
50206
  }
50188
50207
  return lines.join("\n");
50189
50208
  }
50190
- function getBundledTelevisionSkillRoot(bundledTelevisionSkillsCollectionRoot) {
50191
- return import_node_path7.default.join(bundledTelevisionSkillsCollectionRoot, "television");
50192
- }
50193
- function readSkillManifest(skillRoot) {
50194
- const empty = { version: void 0, descriptions: /* @__PURE__ */ new Map() };
50195
- const manifestPath = import_node_path7.default.join(skillRoot, ".skill-manifest.json");
50196
- if (!(0, import_node_fs4.existsSync)(manifestPath)) return empty;
50197
- try {
50198
- const raw = (0, import_node_fs4.readFileSync)(manifestPath, "utf8");
50199
- const parsed = JSON.parse(raw);
50200
- if (typeof parsed !== "object" || parsed === null) return empty;
50201
- const root = parsed;
50202
- const version2 = typeof root.version === "string" ? root.version : void 0;
50203
- const files = Array.isArray(root.files) ? root.files : [];
50204
- const entries = [];
50205
- for (const entry of files) {
50206
- if (typeof entry === "object" && entry !== null && typeof entry.path === "string" && typeof entry.description === "string") {
50207
- entries.push([entry.path, entry.description]);
50208
- }
50209
- }
50210
- return { version: version2, descriptions: new Map(entries) };
50211
- } catch {
50212
- return empty;
50213
- }
50214
- }
50215
- function listSkillFiles(skillRoot, prefix = "") {
50216
- const entries = (0, import_node_fs4.readdirSync)(skillRoot, { withFileTypes: true }).filter((entry) => !entry.name.startsWith(".")).sort((a, b) => a.name.localeCompare(b.name));
50217
- const files = [];
50218
- for (const entry of entries) {
50219
- const relativePath = prefix === "" ? entry.name : import_node_path7.default.posix.join(prefix, entry.name);
50220
- const absolutePath = import_node_path7.default.join(skillRoot, entry.name);
50221
- if (entry.isDirectory()) {
50222
- files.push(...listSkillFiles(absolutePath, relativePath));
50223
- continue;
50224
- }
50225
- files.push(relativePath);
50226
- }
50227
- return files;
50228
- }
50229
- function resolveSkillFilePath(skillRoot, relativePath) {
50230
- const normalized = import_node_path7.default.posix.normalize(relativePath);
50231
- if (normalized.startsWith("../") || normalized === ".." || import_node_path7.default.isAbsolute(relativePath)) {
50232
- return { kind: "invalid-path" };
50233
- }
50234
- const resolved = import_node_path7.default.join(skillRoot, normalized);
50235
- const relativeResolved = import_node_path7.default.relative(skillRoot, resolved);
50236
- if (relativeResolved.startsWith("..") || import_node_path7.default.isAbsolute(relativeResolved)) {
50237
- return { kind: "invalid-path" };
50238
- }
50239
- if (!(0, import_node_fs4.existsSync)(resolved)) {
50240
- return { kind: "not-found" };
50241
- }
50242
- return { kind: "ok", absolutePath: resolved };
50243
- }
50244
- function writeSkillListing(stdout, skillRoot) {
50245
- const manifest = readSkillManifest(skillRoot);
50246
- if (manifest.version !== void 0) {
50247
- writeLine(stdout, `Television skill content version: ${manifest.version}`);
50248
- writeLine(stdout, "");
50249
- }
50250
- writeLine(stdout, "Relative paths inside the bundled `television` skill:");
50251
- writeLine(stdout, "");
50252
- for (const file2 of listSkillFiles(skillRoot)) {
50253
- const description = manifest.descriptions.get(file2);
50254
- writeLine(stdout, description ? `${file2} \u2014 ${description}` : file2);
50255
- }
50256
- writeLine(stdout, "");
50257
- writeLine(stdout, `Television skill root: ${skillRoot}`);
50258
- writeLine(stdout, "To read one file directly: tv skills show <relative-path>");
50259
- }
50260
50209
  function commandNameFromArgv(argv) {
50261
50210
  const commandName = argv.find((value) => !value.startsWith("-"));
50262
50211
  return commandName ?? "tv";
@@ -50317,7 +50266,7 @@ function resolveBundledSkillsRoot() {
50317
50266
  if (builtPath && (0, import_node_fs4.existsSync)(builtPath)) {
50318
50267
  return builtPath;
50319
50268
  }
50320
- const devPath = import_node_path7.default.resolve(getDevPackageDir(), "../skills/dist/skills");
50269
+ const devPath = import_node_path7.default.resolve(getDevPackageDir(), "../skills/dist");
50321
50270
  return (0, import_node_fs4.existsSync)(devPath) ? devPath : void 0;
50322
50271
  }
50323
50272
  function isInTempDirectory(inputPath) {
@@ -50777,11 +50726,11 @@ If you wish to display temporary content to the user, use an internal artifact i
50777
50726
  const result = await client.viewer.focus(focusInput);
50778
50727
  writeLine(env.stdout, `Focused artifact ${result.artifactID} on screen ${result.screenID}.`);
50779
50728
  });
50780
- const skillsCommand = program2.command("skills").description("Install the bundled Television skill").addHelpText("after", [
50729
+ const skillsCommand = program2.command("skills").description("Manage the bundled Television skills").addHelpText("after", [
50781
50730
  "",
50782
- "This command group manages the bundled `television` skill.",
50783
- "`tv skills install` installs or reinstalls it globally through the `skills` package.",
50784
- "`tv skills show` lists bundled skill files or prints one directly, which is useful for agents that need the content without running the interactive installer."
50731
+ "This command group manages the bundled Television skill collection.",
50732
+ "`tv skills install` installs or reinstalls every bundled Television skill globally through the `skills` package.",
50733
+ "`tv skills show` lists each bundled skill or prints one SKILL.md directly, which is useful for agents that need the content without running the interactive installer."
50785
50734
  ].join("\n"));
50786
50735
  skillsCommand.command("path").description("Print the bundled Television skills collection root").action(() => {
50787
50736
  const bundledTelevisionSkillsCollectionRoot = env.resolveBundledSkillsRoot();
@@ -50790,36 +50739,36 @@ If you wish to display temporary content to the user, use an internal artifact i
50790
50739
  }
50791
50740
  writeLine(env.stdout, bundledTelevisionSkillsCollectionRoot);
50792
50741
  });
50793
- skillsCommand.command("install").description("Install or reinstall the bundled Television skill globally").allowUnknownOption(true).action(async function() {
50742
+ skillsCommand.command("install").description("Install or reinstall all bundled Television skills globally").allowUnknownOption(true).action(async function() {
50794
50743
  const bundledTelevisionSkillsCollectionRoot = env.resolveBundledSkillsRoot();
50795
50744
  if (!bundledTelevisionSkillsCollectionRoot) {
50796
50745
  throw new Error("Could not resolve the bundled Television skills root.");
50797
50746
  }
50798
50747
  await env.runSkillsInstaller(["add", bundledTelevisionSkillsCollectionRoot, "--global"]);
50799
50748
  });
50800
- skillsCommand.command("show").description("List bundled Television skill files or print one by relative path").argument("[path]", "Relative path within the television skill root").action((relativePath) => {
50749
+ skillsCommand.command("show").description("List bundled Television skills or print one SKILL.md by name").argument("[skill]", "Bundled skill name").action((skillName) => {
50801
50750
  const bundledTelevisionSkillsCollectionRoot = env.resolveBundledSkillsRoot();
50802
50751
  if (!bundledTelevisionSkillsCollectionRoot) {
50803
50752
  throw new Error("Could not resolve the bundled Television skills root.");
50804
50753
  }
50805
- const skillRoot = getBundledTelevisionSkillRoot(bundledTelevisionSkillsCollectionRoot);
50806
- if (!(0, import_node_fs4.existsSync)(skillRoot)) {
50807
- throw new Error(`Could not resolve the bundled television skill root at ${skillRoot}.`);
50808
- }
50809
- if (relativePath === void 0) {
50810
- writeSkillListing(env.stdout, skillRoot);
50754
+ if (skillName === void 0) {
50755
+ const bundledSkills = listBundledSkills(bundledTelevisionSkillsCollectionRoot);
50756
+ bundledSkills.forEach((skill2, index) => {
50757
+ writeLine(env.stdout, `${skill2.name} \u2014 ${skill2.description}`);
50758
+ writeLine(env.stdout, ` ${skill2.root}`);
50759
+ if (index < bundledSkills.length - 1) {
50760
+ writeLine(env.stdout, "");
50761
+ }
50762
+ });
50811
50763
  return;
50812
50764
  }
50813
- const result = resolveSkillFilePath(skillRoot, relativePath);
50814
- if (result.kind === "ok") {
50815
- env.stdout.write((0, import_node_fs4.readFileSync)(result.absolutePath, "utf8"));
50816
- return;
50765
+ const skill = resolveBundledSkill(bundledTelevisionSkillsCollectionRoot, skillName);
50766
+ writeLine(env.stdout, `Path: ${skill.root}`);
50767
+ writeLine(env.stdout, "---");
50768
+ env.stdout.write(skill.markdown);
50769
+ if (!skill.markdown.endsWith("\n")) {
50770
+ writeLine(env.stdout, "");
50817
50771
  }
50818
- const preamble = result.kind === "invalid-path" ? `tv skills show: "${relativePath}" is not a relative path inside the bundled television skill.` : `tv skills show: no bundled Television skill file at "${relativePath}".`;
50819
- writeLine(env.stdout, preamble);
50820
- writeLine(env.stdout, "");
50821
- writeSkillListing(env.stdout, skillRoot);
50822
- throw new CLISilentExitError(1);
50823
50772
  });
50824
50773
  program2.command("stop").description("Stop the Television system service").action(async () => {
50825
50774
  const daemon = env.createDaemon();
@@ -50862,9 +50811,6 @@ async function runCLI(argv, environment = {}) {
50862
50811
  await program2.parseAsync(argv, { from: "user" });
50863
50812
  return 0;
50864
50813
  } catch (error48) {
50865
- if (error48 instanceof CLISilentExitError) {
50866
- return error48.silentExitCode;
50867
- }
50868
50814
  if (error48 instanceof Error && "exitCode" in error48) {
50869
50815
  const commanderError = error48;
50870
50816
  if (commanderError.exitCode === 0) return 0;
@@ -1,29 +1,37 @@
1
1
  ---
2
- description: Authoring conventions for the calendar artifact kind.
2
+ name: artifact-calendar
3
+ description: Author self-contained HTML calendar artifacts using the bundled calendar-week elements and copied calendar assets.
3
4
  ---
4
5
 
5
6
  # Authoring a calendar week
6
7
 
8
+ Before authoring the artifact, read `house-style.md` in this skill folder.
9
+
7
10
  A working-week calendar with a generated header strip, all-day band, time axis,
8
11
  and timed event grid. The agent only authors a single `<calendar-week>` plus
9
12
  flat sibling `<calendar-event>` children. The component renders the rest.
10
13
 
11
14
  ## Required assets
12
15
 
13
- Every calendar artifact must load both the canonical stylesheet and the
14
- calendar element bundle:
16
+ Every calendar artifact must be self-contained. Read `calendar.css` and
17
+ `calendar.js` from this skill folder and carry them into the artifact output
18
+ instead of referencing `/skills/artifact-calendar/...` URLs.
19
+
20
+ For a Television internal artifact bundle, copy both files into the artifact's
21
+ `public/` directory and reference them relatively:
15
22
 
16
23
  ```html
17
24
  <link rel="stylesheet" href="/canonical/v1/styles.css" />
18
- <link rel="stylesheet" href="/skills/artifact-calendar/calendar.css" />
19
- <script type="module" src="/skills/artifact-calendar/calendar.js"></script>
25
+ <link rel="stylesheet" href="./calendar.css" />
26
+ <script type="module" src="./calendar.js"></script>
20
27
  ```
21
28
 
22
- `/skills/artifact-calendar/calendar.js` and
23
- `/skills/artifact-calendar/calendar.css` are the built skill-local assets
24
- served by artifactory from the package's `dist/` output. They register the
25
- custom elements and provide the calendar-specific chrome styling. Do not
26
- inline or reimplement those elements yourself.
29
+ For a standalone single-file HTML artifact, inline the contents of
30
+ `calendar.css` and `calendar.js` directly into `<style>` and
31
+ `<script type="module">` tags so the output stays self-contained.
32
+
33
+ `calendar.js` registers the custom elements. `calendar.css` provides the
34
+ calendar-specific chrome styling. Do not reimplement those elements yourself.
27
35
 
28
36
  ## Markup contract
29
37
 
@@ -119,8 +127,8 @@ Those are internal chrome and CSS targets created by `<calendar-week>`.
119
127
  <meta name="viewport" content="width=device-width, initial-scale=1" />
120
128
  <title>Team Week</title>
121
129
  <link rel="stylesheet" href="/canonical/v1/styles.css" />
122
- <link rel="stylesheet" href="/skills/artifact-calendar/calendar.css" />
123
- <script type="module" src="/skills/artifact-calendar/calendar.js"></script>
130
+ <link rel="stylesheet" href="./calendar.css" />
131
+ <script type="module" src="./calendar.js"></script>
124
132
  <style>
125
133
  html, body { margin: 0; min-height: 100vh; }
126
134
  calendar-week { height: 100vh; }
@@ -0,0 +1 @@
1
+ calendar-event{display:contents}calendar-event .event-block{pointer-events:none;z-index:2}calendar-event .event-block-inner{background:var(--event-bg-timed, var(--neutral-100));border-left:3px solid var(--event-border-color, var(--neutral-300));border-radius:4px;box-shadow:inset 0 0 0 .5px var(--neutral-200)}calendar-grid calendar-event .event-block{grid-column:calc(var(--day-index) + 1);grid-row:1 / -1;position:relative;z-index:0}calendar-grid calendar-event .event-block-inner{position:absolute;top:calc(var(--y-start) * 100%);height:calc((var(--y-end) - var(--y-start)) * 100%);left:calc(2px + var(--cascade-depth, 0) * 6px);right:2px;padding:var(--space-4) var(--space-8);overflow:hidden;pointer-events:auto;z-index:calc(1 + var(--cascade-depth, 0))}calendar-allday calendar-event .event-block{grid-column:calc(var(--day-start) + 1) / span var(--day-span);grid-row:var(--lane-index);padding:2px}calendar-allday calendar-event .event-block-inner{background:var(--event-bg-all-day, var(--event-bg-timed, var(--neutral-100)));border-left:var( --event-all-day-border, 3px solid var(--event-border-color, var(--neutral-300)) );padding:1px var(--space-8);display:flex;align-items:center;pointer-events:auto}calendar-event[color=red]{--event-bg-timed: var(--red-100);--event-bg-all-day: var(--red-200);--event-border-color: var(--red-500);--event-all-day-border: none}calendar-event[color=orange]{--event-bg-timed: var(--orange-100);--event-bg-all-day: var(--orange-200);--event-border-color: var(--orange-500);--event-all-day-border: none}calendar-event[color=yellow]{--event-bg-timed: var(--yellow-100);--event-bg-all-day: var(--yellow-200);--event-border-color: var(--yellow-500);--event-all-day-border: none}calendar-event[color=green]{--event-bg-timed: var(--green-100);--event-bg-all-day: var(--green-200);--event-border-color: var(--green-500);--event-all-day-border: none}calendar-event[color=blue]{--event-bg-timed: var(--blue-100);--event-bg-all-day: var(--blue-200);--event-border-color: var(--blue-500);--event-all-day-border: none}calendar-event[color=purple]{--event-bg-timed: var(--purple-100);--event-bg-all-day: var(--purple-200);--event-border-color: var(--purple-500);--event-all-day-border: none}calendar-event h3{margin:0;font-size:var(--text-sm);font-weight:600;color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}calendar-time-axis{display:contents}calendar-time-axis .hour-label{grid-column:time-left / days-start;grid-row-start:calc(var(--hour-index) + 1);align-self:start;padding:var(--space-2) var(--space-8);font-size:round(calc(var(--text-sm) / var(--text-scale)),1px);color:var(--color-text-muted);text-align:right;white-space:nowrap;transform:translateY(-50%)}calendar-time-axis .hour-label[data-hour="0"]{visibility:hidden;width:0;height:0;padding:0;overflow:hidden}calendar-week{display:grid;grid-template-columns:[time-left] auto [days-start] repeat(var(--day-count, 0),minmax(0,1fr)) [days-end];grid-template-rows:[headers] auto [allday] auto [hours-start] repeat(var(--hour-count, 0),minmax(var(--hour-min-height, 4rem),1fr)) [hours-end];width:100%;height:100%;overflow:auto;background:var(--color-surface);font-family:inherit;color:var(--color-text)}calendar-week>calendar-headers,calendar-week>calendar-allday,calendar-week>calendar-grid{display:grid;grid-column:1 / -1;grid-template-columns:subgrid;min-width:0}calendar-week>calendar-headers{grid-row:headers / allday;position:sticky;top:0;z-index:3;background:var(--color-surface);border-top:.5px solid var(--color-border);border-bottom:1px solid var(--color-border)}calendar-headers>calendar-day{grid-column:calc(var(--day-index) + 1);display:flex;align-items:baseline;gap:var(--space-2);padding:var(--space-12);font-size:var(--text-sm);border-left:.5px solid var(--color-border-muted)}calendar-headers>calendar-day:last-of-type{border-right:.5px solid var(--color-border-muted)}calendar-headers>calendar-day .weekday{text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-muted)}calendar-headers>calendar-day .date-num{color:var(--color-text)}calendar-week>calendar-allday{grid-row:allday / hours-start;grid-template-rows:repeat(var(--allday-lane-count, 1),auto);position:sticky;top:var(--headers-height, 0px);z-index:2;border-bottom:1px solid var(--color-border);background:var(--color-surface)}calendar-allday>calendar-cell{grid-column:calc(var(--day-index) + 1);grid-row:1;border-left:.5px solid var(--color-border-muted)}calendar-allday>calendar-cell:last-of-type{border-right:.5px solid var(--color-border-muted)}calendar-week>calendar-grid{grid-row:hours-start / hours-end;grid-template-rows:subgrid;position:relative}calendar-grid>calendar-column{grid-column:calc(var(--day-index) + 1);grid-row:1 / -1;border-left:.5px solid var(--color-border-muted);background-image:repeating-linear-gradient(to bottom,transparent 0,transparent calc(100% / var(--hour-count) - .5px),var(--color-border-muted) calc(100% / var(--hour-count) - .5px),var(--color-border-muted) calc(100% / var(--hour-count)))}calendar-grid>calendar-column:last-of-type{border-right:.5px solid var(--color-border-muted)}calendar-grid>.start-hour-marker{grid-column:2;grid-row-start:calc(var(--start-hour) + 1);width:0;height:0}calendar-grid>.now-line-faint,calendar-grid>.now-line{grid-row:1 / -1;position:relative;pointer-events:none;z-index:1}calendar-grid>.now-line-faint{grid-column:2 / -1}calendar-grid>.now-line{grid-column:calc(var(--day-index) + 1)}calendar-grid>.now-line-faint:before,calendar-grid>.now-line:before{content:"";position:absolute;left:0;right:0;top:calc(var(--y-fraction) * 100%);height:1px;transform:translateY(-.5px)}calendar-grid>.now-line-faint:before{background:#e7202240}calendar-grid>.now-line:before{background:#e72022}calendar-grid>.now-line:after{content:"";position:absolute;left:0;top:calc(var(--y-fraction) * 100%);width:.5rem;height:.5rem;border-radius:50%;background:#e72022;transform:translate(-50%,-50%)}