/*
Theme Name: Sulli Blog
Theme URI: https://blog.sulli.one
Author: sulli.one
Description: بلاگ سولی — قالب فارسی و راست‌چین. A Persian-first block theme: conventional blog structure, sulli brand colours and typeface.
Version: 2.0.0
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: sulli-blog
Tags: blog, rtl-language-support, block-styles, full-site-editing
*/

/*
 * ─────────────────────────────────────────────────────────────────────────────
 * THE GATE (.claude/skills/sulli-design)
 * ─────────────────────────────────────────────────────────────────────────────
 *
 * NOTE FIRST — a deliberate departure, on the owner's instruction (2026-08-31).
 * Version 1 of this theme applied the Instrument concept to the blog: a dark
 * ground, the seam cut across the masthead, and the index as a ledger of
 * hairline rows. It was rejected: "it has to be blog-specific and have
 * completely standard element sizes and placement." So the concept does not
 * cross over, and this file is built to blog convention instead. What still
 * carries the brand is listed under 5.
 *
 * 1. WHAT IS THE VISUAL CONCEPT?
 *    A quiet reading surface. Light ground, one column, generous measure. Every
 *    element sits where a reader already expects it — image, then category and
 *    date, then title, then excerpt, one post per row — so nothing has to be
 *    learned before the writing can be read.
 *
 * 2. WHAT MAKES IT DIFFERENT FROM A TYPICAL BLOG?
 *    Honestly: structurally, very little, and that is the requirement. What is
 *    not typical is the restraint — no sidebar, no share widgets, no related-
 *    posts grid, no author box, no cookie bar, no newsletter interstitial. One
 *    column of writing with room around it.
 *
 * 3. THE THREE STRONGEST DECISIONS
 *    a. Persian first, not Persian retrofitted: Estedad throughout, RTL by
 *       logical properties only, Jalali dates, and a 1.9 line-height — Persian
 *       needs materially more leading than Latin at the same size.
 *    b. The featured image leads each entry at full column width, 16:9, so the
 *       index is scannable by picture as well as by headline.
 *    c. Contrast is checked, not assumed. Every text colour here is a measured
 *       ratio against the ground; the smallest one a reader has to read
 *       (--text-faint, used for dates) is 5.12:1.
 *
 * 4. BANNED AI-DEFAULT PATTERNS DELIBERATELY AVOIDED
 *    - No centred hero with a pill badge and two buttons.
 *    - No gradient text on any headline.
 *    - No glassmorphism: `backdrop-filter` appears nowhere in this file.
 *    - No 3-column icon + bold title + grey text grid. No bento grid.
 *    - No testimonial cards with circular avatars — avatars are off entirely,
 *      and are also a gravatar.com request that fails on Iranian networks.
 *    - No fade-up-on-scroll; the only transitions are on hover states.
 *    - No emoji as icons.
 *    - Not Inter/Poppins/Manrope on a default grey ramp: Estedad, on greys
 *      mixed from the brandbook's own #1E1224 and #2A2456. WordPress's palette,
 *      gradients, duotones, shadow presets and default font sizes are all
 *      switched off in theme.json.
 *
 * 5. HOW IT REINFORCES THE BRAND
 *    Through material rather than layout: the brandbook typeface, the brandbook
 *    blue as the single accent, greys derived from the brandbook's own dark
 *    anchors rather than from a stock neutral ramp, the two digit systems
 *    (D14b), and the same refusal to decorate. It reads as the same company in
 *    a different room — which is what a blog next to a trading product should
 *    do.
 *
 * ─────────────────────────────────────────────────────────────────────────────
 *
 * Fonts are declared in theme.json (settings.typography.fontFamilies.fontFace),
 * which is what makes WordPress serve them from this theme's own directory.
 * No Google Fonts, no CDN — Iran's network runs SNI whitelisting, so a CDN
 * asset is a page that fails to render, not one that loads slowly.
 */

/* Read off theme.json's presets rather than restated, so a style variation
   swaps the palette and everything below follows. */
:root {
	--ground: var(--wp--preset--color--ground);
	--surface: var(--wp--preset--color--surface);
	--hairline: var(--wp--preset--color--hairline);
	--hairline-strong: var(--wp--preset--color--hairline-strong);
	--text: var(--wp--preset--color--text);
	--text-dim: var(--wp--preset--color--text-dim);
	--text-faint: var(--wp--preset--color--text-faint);
	--accent: var(--wp--preset--color--accent);
	--accent-strong: var(--wp--preset--color--accent-strong);
	--accent-soft: var(--wp--preset--color--accent-soft);

	--radius: 10px;
	--radius-sm: 6px;
	--ease: cubic-bezier(0.16, 0.84, 0.30, 1);
	--dur: 140ms;
}

/*
 * `clip`, not `hidden`. `overflow-x: hidden` makes the element a scroll
 * container, which silently breaks `position: sticky` for everything inside it.
 */
html {
	overflow-x: clip;
	-webkit-text-size-adjust: 100%;
}

body {
	overflow-x: clip;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
	text-wrap: balance;
}

p {
	text-wrap: pretty;
}

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

::selection {
	background: var(--accent-soft);
	color: var(--accent-strong);
}

img,
video,
iframe {
	max-width: 100%;
}

/* A page with one short paragraph must not leave its footer mid-viewport. */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: 100svh;
}

.wp-site-blocks > main {
	flex-grow: 1;
}

/* ── Header ────────────────────────────────────────────────────────────────*/

.site-header {
	border-block-end: 1px solid var(--hairline);
	padding-block: 1.15rem;
	margin-block-end: var(--wp--preset--spacing--50);
}

.site-header .wp-block-site-title {
	margin: 0;
	font-size: 1.375rem;
	font-weight: 700;
}

.site-header .wp-block-site-title a {
	color: var(--text);
	text-decoration: none;
}

.site-header .wp-block-site-title a:hover {
	color: var(--accent);
}

.site-header .wp-block-navigation {
	font-size: var(--wp--preset--font-size--small);
}

.site-header .wp-block-navigation a {
	color: var(--text-dim);
	text-decoration: none;
}

.site-header .wp-block-navigation a:hover {
	color: var(--accent);
}

/* ── The post list ─────────────────────────────────────────────────────────
 *
 * One post per row: featured image, then category, title, date, excerpt.
 * Stacked, full column width, in the order a reader expects to meet them.
 */
.post-list ul.wp-block-post-template {
	margin: 0;
	padding: 0;
	list-style: none;
	display: block;
}

.post-list li.wp-block-post {
	margin: 0 0 var(--wp--preset--spacing--50);
	padding-block-end: var(--wp--preset--spacing--50);
	border-block-end: 1px solid var(--hairline);
}

.post-list li.wp-block-post:last-child {
	margin-block-end: 0;
	padding-block-end: 0;
	border-block-end: 0;
}

.post-list .wp-block-post-featured-image {
	margin: 0 0 var(--wp--preset--spacing--30);
}

.post-list .wp-block-post-title {
	margin: 0 0 0.6rem;
	font-size: var(--wp--preset--font-size--h2);
	line-height: 1.5;
	font-weight: 700;
}

.post-list .wp-block-post-title a {
	color: var(--text);
	text-decoration: none;
	transition: color var(--dur) var(--ease);
}

.post-list .wp-block-post-title a:hover {
	color: var(--accent);
}

.post-list .wp-block-post-excerpt {
	margin: 0;
	color: var(--text-dim);
}

.post-list .wp-block-post-excerpt__more-text {
	margin-block-start: 0.75rem;
	font-size: var(--wp--preset--font-size--small);
}

/* The meta row: category tag, then date. */
.entry-meta {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	flex-wrap: wrap;
	margin-block-end: 0.75rem;
	font-size: var(--wp--preset--font-size--small);
	color: var(--text-faint);
}

.entry-meta .wp-block-post-date,
.entry-meta .wp-block-post-terms {
	margin: 0;
}

.entry-meta .wp-block-post-date {
	color: var(--text-faint);
}

/* Category tags. Standard blog furniture, kept quiet: a soft tint of the brand
   blue rather than a saturated chip. */
.wp-block-post-terms a {
	display: inline-block;
	background: var(--accent-soft);
	color: var(--accent-strong);
	padding: 0.2rem 0.65rem;
	border-radius: 999px;
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 600;
	text-decoration: none;
	transition: background var(--dur) var(--ease);
}

.wp-block-post-terms a:hover {
	background: var(--hairline);
	text-decoration: none;
}

.wp-block-post-terms .wp-block-post-terms__separator {
	display: none;
}

/* ── Featured images ───────────────────────────────────────────────────────
 *
 * Fixed 16:9 with `object-fit: cover`, so a picture of any shape is cropped to
 * fit rather than squashed — squashing is the specific way a featured image
 * looks broken, and it is what happens by default.
 */
.wp-block-post-featured-image img {
	display: block;
	width: 100%;
	height: auto;
	object-fit: cover;
	border-radius: var(--radius);
	background: var(--surface);
}

.post-list .wp-block-post-featured-image a img {
	transition: opacity var(--dur) var(--ease);
}

.post-list .wp-block-post-featured-image a:hover img {
	opacity: 0.9;
}

/* ── A single post ─────────────────────────────────────────────────────────*/

.entry-header {
	margin-block-end: var(--wp--preset--spacing--40);
}

.entry-header .wp-block-post-title {
	margin: 0.75rem 0 0;
}

.single-post .wp-block-post-featured-image {
	margin-block-end: var(--wp--preset--spacing--40);
}

.entry-content > * + * {
	margin-block-start: 1.6em;
}

.entry-content :is(h2, h3, h4) {
	margin-block-start: 2.2em;
	margin-block-end: 0.7em;
}

.entry-content a {
	color: var(--accent);
	text-decoration: underline;
	text-underline-offset: 0.25em;
	text-decoration-thickness: 1px;
	text-decoration-color: color-mix(in oklab, var(--accent) 40%, transparent);
	transition: text-decoration-color var(--dur) var(--ease);
}

.entry-content a:hover {
	text-decoration-color: currentColor;
}

.entry-content :is(ul, ol) {
	padding-inline-start: 1.35em;
}

.entry-content li + li {
	margin-block-start: 0.4em;
}

.entry-content blockquote {
	margin-inline: 0;
	padding: 0.25rem 1.25rem;
	border-inline-start: 3px solid var(--accent);
	color: var(--text-dim);
}

.entry-content blockquote p:first-child {
	margin-block-start: 0;
}

.entry-content img {
	border-radius: var(--radius);
}

.entry-content figcaption {
	margin-block-start: 0.6rem;
	color: var(--text-faint);
	font-size: var(--wp--preset--font-size--small);
	text-align: center;
}

/*
 * Code is left-to-right, and this is the one place a BLOCK may carry
 * `direction: ltr`. The rule that dir=ltr belongs on an inline span protects
 * VALUES sitting inside Persian prose; a code listing is a left-to-right
 * document in its own right, and inheriting RTL right-aligns every line so the
 * indentation runs backwards.
 */
.entry-content pre {
	direction: ltr;
	text-align: left;
	overflow-x: auto;
}

.entry-content :is(pre, code, kbd, samp) {
	font-family: var(--wp--preset--font-family--num);
}

.entry-content :not(pre) > code {
	background: var(--surface);
	border: 1px solid var(--hairline);
	border-radius: var(--radius-sm);
	padding: 0.1em 0.4em;
	font-size: 0.9em;
	direction: ltr;
	unicode-bidi: isolate;
}

/* Wide content scrolls inside itself; the page never scrolls sideways. */
.entry-content .wp-block-table {
	overflow-x: auto;
}

.entry-content table {
	border-collapse: collapse;
	width: 100%;
	font-size: var(--wp--preset--font-size--small);
}

.entry-content :is(th, td) {
	border: 1px solid var(--hairline);
	padding: 0.6rem 0.85rem;
	text-align: start;
}

.entry-content th {
	background: var(--surface);
	font-weight: 700;
}

/* Footer of a post: tags, then previous/next. */
.entry-footer {
	margin-block-start: var(--wp--preset--spacing--50);
	padding-block-start: var(--wp--preset--spacing--30);
	border-block-start: 1px solid var(--hairline);
}

.post-nav {
	display: flex;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
	flex-wrap: wrap;
	margin-block-start: var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--small);
}

.post-nav .wp-block-post-navigation-link {
	margin: 0;
}

/* ── Numbers ───────────────────────────────────────────────────────────────
 *
 * D14(b): Persian digits (۱۲۳) in prose, Latin digits (123) for every price,
 * size, leverage and percentage — because Latin is what the reader sees on the
 * exchange itself. Dates are prose and are converted in PHP; a figure typed
 * into a post is not, and gets this class.
 *
 * `display: inline` matters. Putting dir=ltr on a block or a <td> makes its
 * text-align follow its own direction, and the value jumps to the left edge of
 * the page or into the neighbouring column.
 */
.numeric {
	display: inline;
	font-family: var(--wp--preset--font-family--num);
	font-variant-numeric: tabular-nums;
	font-feature-settings: 'tnum' 1, 'zero' 1;
	letter-spacing: -0.01em;
	direction: ltr;
	unicode-bidi: isolate;
}

/* ── Pagination, search, comments ──────────────────────────────────────────*/

.wp-block-query-pagination {
	margin-block-start: var(--wp--preset--spacing--50);
	padding-block-start: var(--wp--preset--spacing--30);
	border-block-start: 1px solid var(--hairline);
	font-size: var(--wp--preset--font-size--small);
	gap: 0.75rem;
}

.wp-block-query-pagination-numbers {
	display: flex;
	gap: 0.5rem;
}

.wp-block-query-pagination .page-numbers {
	padding: 0.3rem 0.6rem;
	border-radius: var(--radius-sm);
	text-decoration: none;
}

.wp-block-query-pagination .page-numbers.current {
	background: var(--accent-soft);
	color: var(--accent-strong);
	font-weight: 700;
}

.wp-block-search__input {
	background: var(--ground);
	border: 1px solid var(--hairline-strong);
	border-radius: var(--radius-sm);
	color: var(--text);
	padding: 0.6rem 0.85rem;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--body);
}

.wp-block-search__button {
	border-radius: var(--radius-sm);
}

.wp-block-comments {
	margin-block-start: var(--wp--preset--spacing--50);
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--hairline);
}

.wp-block-comment-template li {
	padding-block: var(--wp--preset--spacing--30);
	border-block-end: 1px solid var(--hairline);
	list-style: none;
}

/* ── Footer ────────────────────────────────────────────────────────────────*/

.site-footer {
	margin-block-start: var(--wp--preset--spacing--60);
	padding-block: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--hairline);
	color: var(--text-dim);
	font-size: var(--wp--preset--font-size--small);
}

.site-footer a {
	color: var(--text-dim);
	text-decoration: none;
}

.site-footer a:hover {
	color: var(--accent);
	text-decoration: underline;
}

/* ── Small screens ─────────────────────────────────────────────────────────
 *
 * Most of this audience reads on a phone on a metered connection, so this is
 * the layout that matters.
 */
@media (max-width: 640px) {
	/*
	 * WordPress's own root-padding variables — the supported way to do this.
	 * 1.5rem a side costs 48px of a 375px screen, and Persian at a readable
	 * size needs some of it back.
	 */
	body {
		--wp--style--root--padding-left: 1.15rem;
		--wp--style--root--padding-right: 1.15rem;
	}

	.site-header {
		margin-block-end: var(--wp--preset--spacing--40);
	}

	.post-list li.wp-block-post {
		margin-block-end: var(--wp--preset--spacing--40);
		padding-block-end: var(--wp--preset--spacing--40);
	}

	.site-footer {
		margin-block-start: var(--wp--preset--spacing--50);
	}

	/* Thumb-sized targets on everything anyone actually taps. */
	.post-list .wp-block-post-title a,
	.wp-block-query-pagination a,
	.site-header .wp-block-navigation a {
		display: inline-block;
		padding-block: 0.2rem;
	}
}

/*
 * Motion only ever explains a state change. When the reader has asked for less
 * of it there is nothing here worth keeping.
 */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}
