/* Self-hosted, latin subset only.
   Google Fonts delivered these through an @import, which is the slowest way
   to load a face: the browser fetches and parses a stylesheet before it even
   learns the font URLs. Declared here instead — same origin, no third party
   on the critical path, and the two hot faces are preloaded from the HTML. */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/font/inter-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/font/inter-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/font/inter-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/font/inter-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/font/jetbrains-mono-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/font/jetbrains-mono-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/font/jetbrains-mono-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* ==========================================================================
   Omarchy homepage — visual system

   The palette is Tokyo Night. That is not a preference: it is the theme
   `install/user/theme.sh` seeds for every new Omarchy user, so the page wears
   the system's own default instead of inventing a brand beside it. Values are
   lifted verbatim from `themes/tokyo-night/colors.toml` and mapped onto
   surface roles here. No rule below this block may introduce a colour literal.
   ========================================================================== */

:root {
  /* 13px root compresses every rem-based length at once. The type scale is
     locked in px precisely so it does NOT ride along — a 13px root silently
     drags a rem scale down to 9-10px captions, which is how dense layouts end
     up unreadable. Spacing shrinks; type does not. */
  font-size: 13px;

  --radius: 0.375rem;
  --radius-sm: 0.25rem;

  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --t-xs: 11px;
  --t-sm: 12px;
  --t-base: 13px;
  --t-lg: 15px;
  --t-xl: 17px;
  --t-2xl: 20px;
  --t-3xl: 24px;
  --t-display: clamp(36px, 6.6vw, 76px);
  --t-display-sm: clamp(22px, 3.4vw, 34px);

  --measure: 1120px;
  --gutter: clamp(20px, 4vw, 40px);

  color-scheme: dark;

  /* Sampled from omarchy.org itself, not derived. The live site paints its
     page with the palette's `background` (#1a1b26 covers 55% of the homepage)
     and accents with `accent` (#7aa2f7 — the news ribbon, every button
     border). An earlier draft used `darker_background` as the ground, which is
     a defensible reading of the TOML and simply not the colour the brand is. */
  --ground: #1a1b26;        /* background        — the site's own page colour */
  --surface: #24283b;       /* lighter_background — cards lift from the ground */
  --raised: #292e42;        /* selection          — hover */
  --line: #292e42;          /* selection */
  --line-strong: #414868;   /* muted */

  --text: #c0caf5;          /* bright_foreground — 10.6:1 on ground */
  --text-2: #a9b1d6;        /* foreground        —  8.1:1 on ground */

  /* Not the palette's dark_foreground (#565f89): it fails 3:1 on every surface
     here. Mixed 28% toward the palette's own foreground it clears 3:1 on all
     three (3.86 / 3.29 / 3.03) while keeping the hue the theme intended. */
  --text-3: #6d769f;

  --accent: #7aa2f7;        /* accent — 6.8:1 on ground; the ribbon blue */
  --accent-ink: #000000;    /* label on filled accent — 8.3:1 */

  /* The wordmark's colour on omarchy.org, sampled from the workstations page. */
  /* The official brand colour: the only value in omarchy.org's wordmark and
     logo files. Also Tokyo Night's green, so palette and brand agree. */
  --brand: #9ece6a;         /* 9.4:1 on ground, 12.0:1 with black */

  --red: #f7768e;
  --yellow: #e0af68;
  --green: #9ece6a;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: var(--t-base);
  line-height: 1.55;
  /* Inter sets a touch wide at small sizes; the negative track is what makes
     13px body read as deliberate rather than defaulted. */
  letter-spacing: -0.006em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 {
  margin: 0;
  color: var(--text);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

p { margin: 0; }

/* figure carries a browser default of `margin: 1em 40px`. Every gallery cell is
   a figure, so that 40px was eating both sides of each image — the grid looked
   like small pictures adrift in wide gutters rather than a gallery. */
figure, blockquote { margin: 0; }

a { color: var(--text); text-decoration: none; text-underline-offset: 3px; }
a:hover { text-decoration: underline; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

code, kbd, pre { font-family: var(--font-mono); }

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: clamp(44px, 5.5vw, 72px);
  border-top: 1px solid var(--line);
}

/* Section label: the small mono eyebrow heading each band, tracked wide and
   uppercased so it reads as a system label rather than as copy. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 26px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.eyebrow::after { content: ''; flex: 1; height: 1px; background: var(--line); }

/* The page makes one claim and spends five beats proving it. Numbering them is
   what separates an argument from a pile of sections: a reader landing
   mid-page can see they are inside a sequence. */
.eyebrow .beat {
  padding: 2px 7px;
  background: var(--accent);
  color: var(--accent-ink);
  letter-spacing: 0.08em;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 60;
  padding: 10px 14px;
  background: var(--accent);
  color: var(--accent-ink);
}

.skip:focus { left: 0; }

/* ==========================================================================
   Announcement ribbon

   Omarchy's brand colour, dark text. This is not a pick from the theme: the
   official wordmark and logo at omarchy.org/brand/ contain exactly one colour,
   #9ece6a, in both the SVGs and the 4096px PNG. It happens to be Tokyo Night's
   green, which is why the palette and the brand agree.

   omarchy.org runs this strip in accent blue, but that blue already carries
   every button and link here — a news bar in the same colour competes with the
   thing it should be leading people towards. The brand colour reads as notice
   rather than action, and leaves the accent to the CTA.

   It was --surface before, the same value as the bar directly beneath it, so
   the two read as one slab of chrome. Three distinct layers now.
   ========================================================================== */

.ribbon {
  display: block;
  padding: 8px var(--gutter);
  background: var(--brand);
  color: #000;
  font-size: var(--t-sm);
  text-align: center;
}

.ribbon:hover { text-decoration: none; filter: brightness(1.07); }
.ribbon b { color: #000; font-weight: 600; }

/* On the accent the tag cannot also be the accent; a knocked-out chip keeps the
   label reading as a label. */
.ribbon .tag {
  margin-right: 9px;
  padding: 1px 6px;
  background: rgb(0 0 0 / 0.24);
  color: #000;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ribbon .go { color: #000; opacity: 0.6; }

/* ==========================================================================
   Top bar — the shell's own bar

   Composition is taken from config/omarchy/shell.json, not invented: the menu
   launcher and workspaces sit left, the clock is the centre anchor, and a tray
   cluster sits right. That file also formats the clock as `dddd HH:mm`, which
   is why it reads "Saturday 21:05" rather than a bare time.

   The tray holds links, not indicators. The real one shows bluetooth, network,
   audio and battery; a web page drawing those would be inventing a machine
   state it cannot see.
   ========================================================================== */

.bar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 34px;
  padding-inline: 10px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
}

.bar-side { display: flex; align-items: center; gap: 4px; }
.bar-tray { justify-content: flex-end; }
.bar-center { display: flex; justify-content: center; }

/* Every bar item is the same square hit target, the way the shell's own
   BarIconButton is. */
/* Direct children only. The panel lives inside .bar-tray so it can be
   positioned against it, and a descendant selector here turned every link row
   inside the panel into a 26px icon box. */
.bar-launch,
.bar-tray > a,
.tray-btn {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}

.bar-launch:hover, .bar-tray > a:hover, .tray-btn:hover { background: var(--raised); color: var(--text); }
.bar-tray > a.is-accent { color: var(--accent); }

.bar-launch svg { width: 12px; height: auto; fill: var(--brand); }
.bar-launch:hover svg { fill: var(--brand); }
.bar-tray > a svg, .tray-btn svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.tray-btn { -webkit-appearance: none; appearance: none; }

.bar-pips { display: flex; align-items: center; gap: 4px; margin-left: 6px; }

.pip {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  background: var(--line-strong);
  cursor: pointer;
}

.pip:hover { background: var(--text-3); }
.pip.is-active { width: 16px; background: var(--accent); }

.bar-clock { color: var(--text-2); font-variant-numeric: tabular-nums; letter-spacing: 0.02em; white-space: nowrap; }

@media (max-width: 560px) {
  /* The centre anchor wins the space it needs; the pips go first. */
  .bar-pips { display: none; }
}

/* ==========================================================================
   Hero — deliberately bare

   Mark, claim, one sentence, one door. Everything that used to sit here (a
   version chip, a credits row, a terminal mock, a second button) was competing
   with the only two things a first-time visitor needs: what this is, and how
   to get it.
   ========================================================================== */

.hero { padding-block: clamp(56px, 10vw, 112px) clamp(44px, 7vw, 88px); text-align: center; }

/* The block is exactly 80 columns, so its size comes from the column it sits
   in, not the viewport. A monospace advance is 0.6em, so 80 glyphs occupy
   48 × font-size; anything wider clips the final letter — which is what a
   vw-based size did, slicing the Y at exactly 1440px. */
.ascii-wrap { container-type: inline-size; max-width: 680px; margin-inline: auto; }

.ascii {
  margin: 0 0 34px;
  color: var(--brand);
  font-family: var(--font-mono);
  font-size: min(10px, 1.95cqw);
  line-height: 1.06;
  white-space: pre;
}

@media (max-width: 620px) {
  /* Below this the mark is smaller than legibility, and a mark you cannot read
     is worse than no mark. The h1 carries the name from here down. */
  .ascii-wrap { display: none; }
}

.hero h1 {
  max-width: 17ch;
  margin-inline: auto;
  font-size: var(--t-display);
  letter-spacing: -0.038em;
  line-height: 0.96;
}

.hero h1 em {
  display: block;
  margin-top: 20px;
  color: var(--accent);
  font-family: var(--font-mono);
  font-style: normal;
  font-size: 0.36em;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.hero-lede {
  max-width: 52ch;
  margin-top: 30px;
  color: var(--text-2);
  font-size: var(--t-xl);
  line-height: 1.5;
}

.hero-cta { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 34px; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding-inline: 20px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: var(--t-lg);
  font-weight: 500;
  letter-spacing: -0.01em;
  cursor: pointer;
}

.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost { border-color: var(--line-strong); background: transparent; color: var(--text); }
.btn-ghost:hover { background: var(--raised); }

/* ==========================================================================
   Numbers
   ========================================================================== */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: clamp(20px, 4vw, 40px);
}

.stat dt { color: var(--text-3); font-family: var(--font-mono); font-size: var(--t-xs); letter-spacing: 0.1em; text-transform: uppercase; }

.stat dd {
  margin: 8px 0 0;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: clamp(30px, 4.4vw, 44px);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.04em;
  line-height: 1;
}

.stat p { margin-top: 8px; color: var(--text-3); font-size: var(--t-sm); }
.stat code { color: var(--accent); }

/* ==========================================================================
   Video showcase

   Facade pattern: thumbnail plus play button, iframe injected on click.
   Embedding five players eagerly would pull several hundred kilobytes of
   third-party script and set cookies on every visitor who never presses play.
   ========================================================================== */

/* Five videos into three columns leaves a hole. Giving the project's own
   introduction a double-width cell fills both rows exactly (2+1, then 3) and
   ranks them while it is at it. */
.videos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }

@media (max-width: 940px) { .videos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .videos { grid-template-columns: minmax(0, 1fr); } }

/* Same tile as .shot: fill the cell, caption over the image, no frame. The
   caption used to be a bordered bar below the thumbnail, which made the video
   grid a row of cards sitting under a gallery — two languages for one job. */
.video {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
}

.video-thumb { display: block; position: absolute; inset: 0; overflow: hidden; }

.video-thumb img, .video-thumb iframe {
  display: block; width: 100%; height: 100%; border: 0; object-fit: cover;
  transition: transform 400ms ease;
}

.video:hover .video-thumb img { transform: scale(1.03); }

.video-play { position: absolute; inset: 0; display: grid; place-items: center; }

.video-play span {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  padding-left: 3px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 15px;
  /* The thumbnail is a third-party image in unknown colours; a ring in the
     page ground keeps the button legible over any of them. */
  box-shadow: 0 0 0 3px var(--ground);
}

.video-meta {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 34px 12px 10px;
  /* These thumbnails are bright at the bottom as often as not — a channel name
     landing on a white wordmark needs more than a polite scrim. */
  background: linear-gradient(to top, rgb(0 0 0 / 0.92), rgb(0 0 0 / 0.62) 42%, transparent);
  pointer-events: none;
}

.video-meta b { display: block; color: #fff; font-size: var(--t-base); font-weight: 500; line-height: 1.35; }
.video-meta span { display: block; margin-top: 3px; color: rgb(255 255 255 / 0.78); font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; }

/* Once a player is injected the tile must stop pretending to be a thumbnail. */
.video.is-playing .video-meta, .video.is-playing .video-play { display: none; }

/* ==========================================================================
   Community, patron, close, footer
   ========================================================================== */

/* Six links, three columns: two full rows rather than the 4+2 auto-fit gave. */
.links { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }

@media (max-width: 860px) { .links { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .links { grid-template-columns: minmax(0, 1fr); } }

.link-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 15px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: var(--t-lg);
  font-weight: 500;
}

.link-card:hover { border-color: var(--accent); text-decoration: none; }
.link-card span { color: var(--text-3); font-family: var(--font-mono); font-size: var(--t-xs); }

.patron {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: clamp(24px, 4vw, 36px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.patron h2 { font-size: var(--t-display-sm); }
.patron p { max-width: 52ch; margin-top: 10px; color: var(--text-3); font-size: var(--t-lg); }
.patron p a { color: var(--accent); font-family: var(--font-mono); font-size: var(--t-base); }

.close { padding-block: clamp(64px, 10vw, 120px); border-top: 1px solid var(--line); text-align: center; }
.close h2 { margin-inline: auto; max-width: 16ch; font-size: var(--t-display); letter-spacing: -0.038em; line-height: 1; }
.close h2 span { display: block; color: var(--accent); }
.close p { margin: 24px auto 0; max-width: 54ch; color: var(--text-3); font-size: var(--t-xl); }
.close .hero-cta { justify-content: center; }

.foot { padding-block: 40px 60px; border-top: 1px solid var(--line); color: var(--text-3); font-size: var(--t-sm); }

.foot-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin-bottom: 26px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
}

.foot-nav a { color: var(--text-3); }
.foot-nav a:hover { color: var(--text); }

.foot-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px; }
.foot a { color: var(--text-2); }
.foot-legal { margin-top: 18px; max-width: 74ch; font-size: var(--t-xs); line-height: 1.6; }

/* ==========================================================================
   The Omarchy menu

   The page's navigation is the desktop's menu. On a real Omarchy machine
   Super+Space opens this over everything: icon column, label column,
   type-to-filter, submenus that push and pop. Reproducing it is not
   decoration — it is the interaction that defines using this system, and it
   moves a reader through the argument faster than a nav bar would.

   Square corners on purpose: the shell ships `cornerRadius: 0`, mirroring
   Hyprland's rounding. This is the one surface here that does not take
   --radius, because the thing it quotes does not either.
   ========================================================================== */

dialog.omenu {
  width: min(560px, calc(100vw - 24px));
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 0;
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-mono);
}

dialog.omenu::backdrop { background: rgb(0 0 0 / 0.5); }

.omenu-head { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-bottom: 1px solid var(--line); }

.omenu-crumb { color: var(--text-3); font-size: var(--t-xs); letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap; }
.omenu-crumb b { color: var(--accent); font-weight: 500; }

/* A real input, not a fake one: people type into this immediately. */
.omenu-input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--text); font: inherit; font-size: var(--t-base); outline: 0; }
.omenu-input::placeholder { color: var(--text-3); }

.omenu-list { max-height: min(52vh, 420px); margin: 0; padding: 5px; overflow-y: auto; list-style: none; }

.omenu-row {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 8px 9px;
  border: 0;
  background: transparent;
  color: var(--text-2);
  font: inherit;
  font-size: var(--t-base);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

/* One cursor, driven by keyboard and mouse alike — the shell's "hover-cursor"
   state, where hovering and arrowing land in the same place instead of
   fighting over two separate highlights. */
.omenu-row.is-cursor { background: var(--accent); color: var(--accent-ink); }
.omenu-row.is-cursor .omenu-desc, .omenu-row.is-cursor .omenu-sub { color: var(--accent-ink); opacity: 0.7; }

.omenu-icon { display: grid; place-items: center; width: 17px; flex: none; color: var(--accent); }
.omenu-row.is-cursor .omenu-icon { color: var(--accent-ink); }
.omenu-icon svg { display: block; width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.6; }

.omenu-label { flex: 1; min-width: 0; }
.omenu-desc { display: block; margin-top: 1px; color: var(--text-3); font-size: var(--t-xs); }
.omenu-sub { flex: none; color: var(--text-3); font-size: var(--t-xs); }

.omenu-empty { padding: 16px 12px; color: var(--text-3); font-size: var(--t-sm); }

.omenu-foot { display: flex; gap: 16px; padding: 8px 14px; border-top: 1px solid var(--line); color: var(--text-3); font-size: 10px; }
.omenu-foot b { color: var(--text-2); font-weight: 500; }

/* ==========================================================================
   The invitation

   The one band on the page that is not information. Omarchy's whole texture is
   that everything lives behind a single keystroke, and no paragraph conveys
   that as well as making the reader press it. So: a large key, centred in a
   lot of empty space, and nothing else competing for the eye.
   ========================================================================== */

.invite { padding-block: clamp(68px, 10vw, 124px); border-top: 1px solid var(--line); text-align: center; }

.invite p {
  margin-bottom: 30px;
  color: var(--text-2);
  font-size: var(--t-display-sm);
  font-weight: 600;
  letter-spacing: -0.028em;
}

.invite-key {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 16px 26px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--t-xl);
  letter-spacing: 0.02em;
  cursor: pointer;
}

.invite-key:hover { border-color: var(--accent); color: var(--accent); }

.invite-key i {
  display: block;
  width: 7px;
  height: 7px;
  background: var(--accent);
  font-style: normal;
}

.invite small { display: block; margin-top: 22px; color: var(--text-3); font-family: var(--font-mono); font-size: var(--t-xs); }

/* Visually hidden, still announced — the pips are icons with no text. */
.sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   Pull quote

   DHH's own sentence about why this system exists, verbatim and attributed.
   No quotation marks, no rule, no card — his own properties (once.com, the
   HEY blog, dhh.dk) carry text on bare ground with nothing around it, and a
   decorated quote would be the first thing on this page he didn't write that
   sounded like it wasn't written by him.
   ========================================================================== */

.quote { padding-block: clamp(64px, 9vw, 112px); border-top: 1px solid var(--line); }

.quote { text-align: center; }

.quote blockquote {
  margin: 0 auto;
  max-width: 22ch;
  color: var(--text);
  font-size: clamp(26px, 4.4vw, 52px);
  font-weight: 600;
  letter-spacing: -0.032em;
  line-height: 1.08;
}

.quote blockquote em { color: var(--accent); font-style: normal; }

.quote figcaption {
  margin-top: 26px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.06em;
}

.quote figcaption a { color: var(--text-3); }
.quote figcaption a:hover { color: var(--text-2); }

/* ==========================================================================
   Pill grid

   omarchy.org navigates with rows of bordered, icon-led pills, centred and
   balanced. Keeping that is the point — it is the site's existing order, and
   the complaint about the old draft was that it had none. Rows are laid out so
   each one fills completely; a widowed pill on its own line is what breaks the
   symmetry, not the pill itself.
   ========================================================================== */

/* Ten links, and flex-wrap packed them 7 + 3 because the labels are different
   lengths — the same ragged last row the galleries were fixed for. A grid of
   five equal columns gives 5 + 5 regardless of how long WORKSTATIONS is. */
.pills {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
  max-width: 860px;
  margin-inline: auto;
}

@media (max-width: 760px) { .pills { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.pill-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.pill-link:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.pill-link svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7; }

/* ==========================================================================
   Galleries

   The argument this page could not make in prose: 77 desks and 200 desktops
   that people actually built. Uniform cells, one aspect ratio, cover-cropped —
   the source pages stack these at their native heights, which reads as a pile
   rather than a collection. Same size for every entry says they belong to the
   same thing.
   ========================================================================== */

/* Nine tiles, one of them four times the size of the rest.
 *
 * A grid of twelve identical squares is orderly and dull; the eye has nowhere
 * to land first. One double tile gives the grid a subject without giving up
 * the discipline — and the counts are chosen so it never costs a hole, which
 * is what made the earlier asymmetric attempt look broken rather than composed:
 *
 *   4 columns → 1 double (4 cells) + 8 singles = 12 cells = 3 full rows
 *   3 columns → the same 12 cells = 4 full rows
 *   2 columns → the same 12 cells = 6 full rows
 *
 * `dense` is what backfills the gaps beside the double tile as it flows.
 */
.gallery {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-flow: dense;
  gap: 6px;
}

.gallery .is-feature { grid-column: span 2; grid-row: span 2; }

@media (max-width: 1000px) { .gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 720px)  { .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* On the narrowest layout a double tile is most of the screen; let it be a
   plain cell so the grid stays a grid. */
@media (max-width: 480px) {
  .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gallery .is-feature { grid-column: span 2; grid-row: span 1; }
}

/* The feature tile earns a larger caption. */
.gallery .is-feature figcaption { padding: 22px 14px 11px; font-size: var(--t-xs); }

.shot {
  position: relative;
  display: block;
  /* Same ratio as the video tiles below, so the two grids read as one family. */
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}

.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Photographs of other people's rooms carry every colour there is. Holding
     them a little back keeps the grid reading as one surface until hover. */
  filter: saturate(0.92) brightness(0.94);
  transition: filter 180ms ease, transform 400ms ease;
}

.shot:hover img { filter: none; transform: scale(1.03); }

.shot figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 16px 10px 7px;
  background: linear-gradient(to top, rgb(0 0 0 / 0.85), rgb(0 0 0 / 0.4) 55%, transparent);
  color: #fff;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Section head: a label on the left, the way out on the right. */
.gal-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}

.gal-head h2 { font-size: var(--t-2xl); letter-spacing: -0.02em; }

.gal-head a {
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The sixth cell of the video grid: where the other five came from. */
.more-card {
  display: grid;
  place-content: center;
  gap: 8px;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  text-align: center;
}

.more-card:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.more-card b { display: block; font-size: var(--t-2xl); font-weight: 700; letter-spacing: -0.03em; }

/* ==========================================================================
   Brand marks

   A logo is read before a word is. The footer said "Cloudflare" and
   "37signals" in body text, which is the weakest possible way to carry a
   credential — the marks are recognised instantly and take less room.
   ========================================================================== */

.mark { display: inline-flex; align-items: center; gap: 7px; color: var(--text-2); }
.mark:hover { color: var(--text); text-decoration: none; }
.mark svg { width: 15px; height: 15px; fill: currentColor; flex: none; }

/* ==========================================================================
   Patrons

   The single largest omission of the previous draft. omarchy.org has nine
   founding patrons at a million dollars each — the founders of Shopify,
   Stripe, Dell, Block, Cloudflare, 37signals and Dropbox — and the homepage
   linked to them in a nav row without showing one face. This is the strongest
   trust signal the project has, and it is a row of photographs.
   ========================================================================== */

/* Ten founding patrons, so the column count has to divide ten or the last row
   is a stub. Five and two do; four and three do not, which is why the usual
   4/3/2 ladder is skipped here. */
.patrons {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(10px, 1.6vw, 20px) 10px;
}

@media (max-width: 560px) { .patrons { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.patron-card { display: block; text-align: center; color: inherit; }
.patron-card:hover { text-decoration: none; }

.patron-card img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: 50%;
  filter: grayscale(1) contrast(0.95);
  transition: filter 200ms ease;
}

.patron-card:hover img { filter: none; }

.patron-card b { display: block; margin-top: 9px; color: var(--text-2); font-size: var(--t-xs); font-weight: 500; }
.patron-card span { display: block; color: var(--text-3); font-family: var(--font-mono); font-size: 10px; }
.patron-card:hover b { color: var(--text); }

/* Funded-project marks: the three logos omarchy.org itself publishes. */
/* These three are drawn for dark backgrounds already — gradients, a brand
   green, a white mark. Greyscaling them at 60% opacity did not make them
   restrained, it made them invisible; at 26px they read as smudges. Shown at
   size, in their own colours, held back only slightly. */
.sponsors { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: clamp(36px, 7vw, 80px); }
.sponsors img { height: 40px; width: auto; opacity: 0.85; transition: opacity 200ms ease, transform 200ms ease; }
.sponsors a:hover img { opacity: 1; transform: translateY(-2px); }

.sponsors-label {
  margin: 0 0 24px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  text-align: center;
  text-transform: uppercase;
}

.foot-marks { display: flex; align-items: center; gap: 20px; }
.foot-marks .mark b { color: var(--text-2); font-weight: 600; letter-spacing: -0.01em; }
.foot-marks .mark:hover b { color: var(--text); }

/* Published on a URL that is not omarchy.org, wearing Omarchy's name, logo and
   palette — so it has to say it is not the real site. It does not have to
   shout: a boxed callout with an accent rule was louder than the footer it sat
   in, which is the wrong emphasis for a line nobody is looking for. Same size
   as the legal text around it, just carried at full strength. */
.foot-note { color: var(--text-2); }
.foot-note a { color: var(--accent); }

/* ==========================================================================
   Bar panels

   On a real machine each tray icon drops a panel: Super+Ctrl+A is audio,
   +W network, +B bluetooth, +D display, +P power. Section labels, ordering and
   titles below are taken from shell/plugins/panels/, not invented.

   What they are NOT is a readout of the visitor's machine. A web page cannot
   see anyone's battery or wifi, and drawing a plausible one would be a lie
   dressed as a feature. Each panel says what it is in its own footer, and the
   values are the shipped defaults rather than anything measured.
   ========================================================================== */

.opanel {
  position: absolute;
  top: calc(100% + 5px);   /* Style.gapsOut is 5 in the shell */
  right: 8px;
  z-index: 50;
  width: 268px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  /* Square, like every surface the shell draws: cornerRadius is 0. */
  border-radius: 0;
}

.opanel[hidden] { display: none; }

.opanel-title {
  padding: 11px 13px 9px;
  border-bottom: 1px solid var(--line);
  color: var(--text);
  font-size: var(--t-base);
  font-weight: 500;
}

.opanel-body { padding: 5px 0 7px; }

.opanel h4 {
  margin: 10px 13px 6px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.opanel-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 13px;
  color: var(--text-2);
}

.opanel-row.is-on { color: var(--text); }
.opanel-row b { font-weight: 500; }
.opanel-row span { color: var(--text-3); }

.opanel-row .dot {
  width: 6px; height: 6px; flex: none;
  background: var(--brand);
  margin-right: 7px;
}

.opanel-row .grow { flex: 1; display: flex; align-items: center; min-width: 0; }

/* The shell's PanelSlider: a filled track, no thumb ornament. */
.opanel-slider { padding: 4px 13px 8px; }
.opanel-track { height: 5px; background: var(--raised); }
.opanel-fill { height: 100%; background: var(--accent); }

.opanel-foot {
  padding: 8px 13px;
  border-top: 1px solid var(--line);
  color: var(--text-3);
  font-size: 10px;
  line-height: 1.5;
}

.opanel-foot kbd {
  padding: 1px 4px;
  border: 1px solid var(--line-strong);
  color: var(--text-2);
  font-size: 9px;
}

.bar { position: sticky; }
.bar-tray { position: relative; }
.bar-tray > a.is-open, .tray-btn.is-open { background: var(--raised); color: var(--text); }

@media (max-width: 560px) { .opanel { width: min(268px, calc(100vw - 16px)); } }

/* A panel that cannot read something says so here rather than showing a
   number it made up. */
.opanel-none { padding: 10px 13px; color: var(--text-3); line-height: 1.5; }

.opanel-act { padding: 4px 13px 8px; }

.opanel-act button {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-2);
  font: inherit;
  font-size: var(--t-xs);
  cursor: pointer;
}

.opanel-act button:hover { border-color: var(--accent); color: var(--accent); }

/* Rows that navigate are links; they must not look different from rows that
   only state a value. */
a.opanel-row { text-decoration: none; }
a.opanel-row:hover { background: var(--raised); color: var(--text); }
a.opanel-row:hover span { color: var(--text); }

.opanel-pre {
  margin: 2px 13px 6px;
  padding: 8px 9px;
  background: var(--ground);
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-all;
}

/* ==========================================================================
   Meetup screen

   A full-bleed overlay in the shell's idiom — the register Omarchy uses when a
   surface takes the whole screen rather than dropping from the bar. Square,
   one hairline frame, mono labels, an accent cursor on the numbering.

   Its content is real: the nine rules are the ones omarchy.org publishes for
   running your own meetup, unedited. That page is otherwise a wall of prose
   with no events on it, which is exactly the kind of thing a homepage should
   surface rather than link away to.
   ========================================================================== */

dialog.screen {
  width: min(860px, calc(100vw - 28px));
  max-width: none;
  max-height: calc(100vh - 40px);
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 0;
  background: var(--surface);
  color: var(--text-2);
  overflow: hidden;
}

dialog.screen::backdrop { background: rgb(0 0 0 / 0.72); }

.screen-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  padding: 20px 22px 16px;
  border-bottom: 1px solid var(--line);
}

.screen-head h2 { font-size: var(--t-2xl); letter-spacing: -0.02em; }

.screen-head p {
  margin-top: 5px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.02em;
}

/* Nine rules, so three columns — not two. Two left the ninth alone on a row of
   its own with an empty cell beside it, the same ragged last row the galleries
   were fixed for. Three divides nine exactly; one does too. */
.screen-body {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 26px;
  padding: 6px 22px 18px;
  overflow-y: auto;
  max-height: min(64vh, 560px);
}

@media (max-width: 860px) { .screen-body { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 18px; } }
@media (max-width: 700px) { .screen-body { grid-template-columns: minmax(0, 1fr); } }

.rule { display: flex; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--line); }

/* The last row in each column has nothing under it, so its rule would hang. */
/* The bottom row of each column has nothing under it, so its rule would hang
   in space. Three columns means the last three items are that row. */
.rule:nth-last-child(-n+3) { border-bottom: 0; }
@media (max-width: 700px) {
  .rule:nth-last-child(-n+3) { border-bottom: 1px solid var(--line); }
  .rule:last-child { border-bottom: 0; }
}

.rule i {
  flex: none;
  width: 20px;
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-style: normal;
  padding-top: 2px;
}

.rule b { display: block; color: var(--text); font-size: var(--t-sm); font-weight: 600; line-height: 1.35; }
.rule span { display: block; margin-top: 4px; color: var(--text-3); font-size: var(--t-xs); line-height: 1.55; }

.screen-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 22px;
  border-top: 1px solid var(--line);
  background: var(--ground);
}

.screen-foot p { color: var(--text-3); font-family: var(--font-mono); font-size: var(--t-xs); }
.screen-foot kbd { padding: 1px 5px; border: 1px solid var(--line-strong); color: var(--text-2); font-size: 10px; }

/* One card in the row opens a screen instead of navigating; it must not look
   like a different kind of thing because of it. */
/* One item in each row opens a screen instead of navigating. A <button> gets
   the browser's own font and chrome, so it has to be told to match its
   neighbours exactly — otherwise the odd one out is the interactive one. */
button.pill-link { font: inherit; font-family: var(--font-mono); background: transparent; cursor: pointer; }
