commit 8eddfee34bf65183a1cfc557b424c2be1ee9e7e2 Author: Alex Date: Mon Mar 23 22:54:38 2026 +0000 Initial commit: Weedops WordPress theme Includes front-page, strain archive/single templates, header/footer, functions.php with custom post types, and base styles. diff --git a/archive-strain.php b/archive-strain.php new file mode 100644 index 0000000..777dce0 --- /dev/null +++ b/archive-strain.php @@ -0,0 +1,307 @@ + + +
+ +
+ + +
+

Strain Catalog

+

Browse our curated database of cannabis strains. Filter by type, potency, and effects.

+
+ + +
+ + + + +
+ + +
+ found_posts; + ?> + + strain found + +
+ + + + +
+ + + + + + + + + +
+ + +
+ 'โ† Previous', + 'next_text' => 'Next โ†’', + 'before_page_number' => 'Page ', + ] ); + ?> +
+ + + +
+ ๐Ÿ” +

No strains found

+

Check back soon โ€” we're always adding to the catalog.

+
+ + + +
+ +
+ + + + + + diff --git a/assets/img/hero-cannabis.jpg b/assets/img/hero-cannabis.jpg new file mode 100644 index 0000000..facfab3 Binary files /dev/null and b/assets/img/hero-cannabis.jpg differ diff --git a/footer.php b/footer.php new file mode 100644 index 0000000..85323e3 --- /dev/null +++ b/footer.php @@ -0,0 +1,91 @@ + + + + + + + + + + diff --git a/front-page.php b/front-page.php new file mode 100644 index 0000000..d6edc4f --- /dev/null +++ b/front-page.php @@ -0,0 +1,153 @@ + + + + + + + + + +
+
+ +
+
+

+

+ +

+
+ +
+ +
+
🌿
+

+ +

+

+ +

+
+ +
+
📋
+

+ +

+

+ +

+
+ +
+
📦
+

+ +

+

+ +

+
+ +
+
+ + + 'wo_strain', + 'posts_per_page' => 6, + 'orderby' => 'date', + 'order' => 'DESC', + ] ); + + if ( $strains->have_posts() ) : + ?> +
+
+

+ + + +
+ +
+ have_posts() ) : $strains->the_post(); ?> + + +
+
+ + + __( 'Primary Navigation', 'weedops' ), + 'footer' => __( 'Footer Navigation', 'weedops' ), + 'account' => __( 'Account Menu', 'weedops' ), + ] ); +} +add_action( 'after_setup_theme', 'weedops_setup' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Scripts & Styles +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_enqueue_assets(): void { + // Google Fonts โ€” Inter + wp_enqueue_style( + 'weedops-fonts', + 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap', + [], + null + ); + + // Main stylesheet + wp_enqueue_style( + 'weedops-style', + get_stylesheet_uri(), + [ 'weedops-fonts' ], + WEEDOPS_VERSION + ); + + // Main JS bundle + wp_enqueue_script( + 'weedops-main', + WEEDOPS_URI . '/assets/js/main.js', + [], + WEEDOPS_VERSION, + true + ); + + // Pass data to JS + wp_localize_script( 'weedops-main', 'WeedopsData', [ + 'ajaxUrl' => admin_url( 'admin-ajax.php' ), + 'restUrl' => esc_url_raw( rest_url( 'weedops/v1/' ) ), + 'nonce' => wp_create_nonce( 'wp_rest' ), + 'siteUrl' => get_site_url(), + 'isLoggedIn'=> is_user_logged_in(), + ] ); +} +add_action( 'wp_enqueue_scripts', 'weedops_enqueue_assets' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Custom Post Types, Taxonomies & Meta Fields +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +// Post types, taxonomies, and meta field registration live in their own file. +require_once WEEDOPS_DIR . '/inc/custom-post-types.php'; + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Widget Areas +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_register_sidebars(): void { + $sidebars = [ + [ 'id' => 'sidebar-main', 'name' => __( 'Main Sidebar', 'weedops' ) ], + [ 'id' => 'sidebar-catalog', 'name' => __( 'Catalog Sidebar', 'weedops' ) ], + [ 'id' => 'footer-col-1', 'name' => __( 'Footer Column 1', 'weedops' ) ], + [ 'id' => 'footer-col-2', 'name' => __( 'Footer Column 2', 'weedops' ) ], + [ 'id' => 'footer-col-3', 'name' => __( 'Footer Column 3', 'weedops' ) ], + ]; + + foreach ( $sidebars as $s ) { + register_sidebar( [ + 'id' => $s['id'], + 'name' => $s['name'], + 'before_widget' => '
', + 'after_widget' => '
', + 'before_title' => '

', + 'after_title' => '

', + ] ); + } +} +add_action( 'widgets_init', 'weedops_register_sidebars' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Helper Functions +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +/** + * Render a strain type badge. + * + * @param string $type indica | sativa | hybrid | cbd + * @param bool $echo Echo or return. + */ +function weedops_strain_badge( string $type, bool $echo = true ): string { + $label = ucfirst( $type ); + $class = 'wo-badge wo-badge--' . sanitize_html_class( strtolower( $type ) ); + $html = sprintf( '%s', esc_attr( $class ), esc_html( $label ) ); + if ( $echo ) echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + return $html; +} + +/** + * Return formatted THC/CBD string for a strain. + * + * @param int $post_id + */ +function weedops_get_cannabinoid_str( int $post_id ): string { + $thc = get_post_meta( $post_id, 'wo_thc_percent', true ); + $cbd = get_post_meta( $post_id, 'wo_cbd_percent', true ); + $parts = []; + if ( $thc !== '' ) $parts[] = 'THC ' . number_format( (float) $thc, 1 ) . '%'; + if ( $cbd !== '' ) $parts[] = 'CBD ' . number_format( (float) $cbd, 1 ) . '%'; + return implode( ' ยท ', $parts ); +} + +/** + * Check if a product has a valid COA (lab test certificate). + */ +function weedops_has_valid_coa( int $post_id ): bool { + $coa = get_post_meta( $post_id, 'wo_coa_url', true ); + $tested = get_post_meta( $post_id, 'wo_lab_tested', true ); + return ! empty( $coa ) && (bool) $tested; +} + +/** + * Age-gate: returns true if the user has confirmed they are 21+. + * Stored in a session cookie. + */ +function weedops_age_verified(): bool { + return ! empty( $_COOKIE['wo_age_verified'] ); +} + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Age Verification AJAX Handler +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_ajax_age_verify(): void { + check_ajax_referer( 'wo_age_verify', 'nonce' ); + setcookie( 'wo_age_verified', '1', time() + ( 30 * DAY_IN_SECONDS ), COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true ); + wp_send_json_success( [ 'verified' => true ] ); +} +add_action( 'wp_ajax_nopriv_wo_age_verify', 'weedops_ajax_age_verify' ); +add_action( 'wp_ajax_wo_age_verify', 'weedops_ajax_age_verify' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Title Tag +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_document_title_parts( array $parts ): array { + $parts['tagline'] = get_bloginfo( 'description' ); + return $parts; +} +add_filter( 'document_title_parts', 'weedops_document_title_parts' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Excerpt length +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +add_filter( 'excerpt_length', fn() => 30 ); +add_filter( 'excerpt_more', fn() => '…' ); diff --git a/header.php b/header.php new file mode 100644 index 0000000..51ddea2 --- /dev/null +++ b/header.php @@ -0,0 +1,91 @@ + +> + + + + + + + + +> + + + + +
+ +
+ + + + +'; + echo '
  • ' . esc_html__( 'Home', 'weedops' ) . '
  • '; + echo '
  • ' . esc_html__( 'Strains', 'weedops' ) . '
  • '; + echo '
  • ' . esc_html__( 'Products', 'weedops' ) . '
  • '; + echo '
  • ' . esc_html__( 'Dispensaries', 'weedops' ) . '
  • '; + echo ''; +} +?> + +
    +
    diff --git a/inc/custom-post-types.php b/inc/custom-post-types.php new file mode 100644 index 0000000..2f8846e --- /dev/null +++ b/inc/custom-post-types.php @@ -0,0 +1,391 @@ + __( 'Strains', 'weedops' ), + 'labels' => [ + 'name' => __( 'Strains', 'weedops' ), + 'singular_name' => __( 'Strain', 'weedops' ), + 'add_new' => __( 'Add New', 'weedops' ), + 'add_new_item' => __( 'Add New Strain', 'weedops' ), + 'edit_item' => __( 'Edit Strain', 'weedops' ), + 'new_item' => __( 'New Strain', 'weedops' ), + 'view_item' => __( 'View Strain', 'weedops' ), + 'search_items' => __( 'Search Strains', 'weedops' ), + 'not_found' => __( 'No strains found', 'weedops' ), + 'not_found_in_trash' => __( 'No strains in trash', 'weedops' ), + 'menu_name' => __( 'Strains', 'weedops' ), + ], + 'public' => true, + 'show_ui' => true, + 'show_in_menu' => true, + 'show_in_rest' => true, + 'rest_base' => 'strains', + 'menu_icon' => 'dashicons-palmtree', + 'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ], + 'has_archive' => true, + 'rewrite' => [ 'slug' => 'strains', 'with_front' => false ], + 'capability_type' => 'post', + 'map_meta_cap' => true, + ] ); + + // โ”€โ”€ Cannabis Products โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_post_type( 'wo_product', [ + 'label' => __( 'Cannabis Products', 'weedops' ), + 'labels' => [ + 'name' => __( 'Cannabis Products', 'weedops' ), + 'singular_name' => __( 'Cannabis Product', 'weedops' ), + 'add_new_item' => __( 'Add New Product', 'weedops' ), + 'edit_item' => __( 'Edit Product', 'weedops' ), + 'not_found' => __( 'No products found', 'weedops' ), + ], + 'public' => true, + 'show_in_rest' => true, + 'rest_base' => 'cannabis-products', + 'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ], + 'menu_icon' => 'dashicons-archive', + 'has_archive' => true, + 'rewrite' => [ 'slug' => 'products', 'with_front' => false ], + 'capability_type' => 'post', + ] ); + + // โ”€โ”€ Compliance Records โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_post_type( 'wo_compliance', [ + 'label' => __( 'Compliance Records', 'weedops' ), + 'labels' => [ + 'name' => __( 'Compliance Records', 'weedops' ), + 'singular_name' => __( 'Compliance Record', 'weedops' ), + 'add_new_item' => __( 'Add Record', 'weedops' ), + ], + 'public' => false, + 'show_ui' => true, + 'show_in_menu' => true, + 'show_in_rest' => true, + 'rest_base' => 'compliance', + 'supports' => [ 'title', 'custom-fields' ], + 'menu_icon' => 'dashicons-shield', + 'capability_type' => 'post', + ] ); + + // โ”€โ”€ Dispensaries / Locations โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_post_type( 'wo_dispensary', [ + 'label' => __( 'Dispensaries', 'weedops' ), + 'public' => true, + 'show_in_rest' => true, + 'rest_base' => 'dispensaries', + 'supports' => [ 'title', 'editor', 'thumbnail', 'custom-fields' ], + 'menu_icon' => 'dashicons-location-alt', + 'has_archive' => true, + 'rewrite' => [ 'slug' => 'dispensaries', 'with_front' => false ], + ] ); +} +add_action( 'init', 'weedops_register_post_types' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Taxonomies +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_register_taxonomies(): void { + + // โ”€โ”€ Strain Type: indica / sativa / hybrid / cbd โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_taxonomy( 'wo_strain_type', [ 'wo_strain', 'wo_product' ], [ + 'label' => __( 'Strain Type', 'weedops' ), + 'labels' => [ + 'name' => __( 'Strain Types', 'weedops' ), + 'singular_name' => __( 'Strain Type', 'weedops' ), + 'add_new_item' => __( 'Add Strain Type', 'weedops' ), + 'search_items' => __( 'Search Types', 'weedops' ), + ], + 'hierarchical' => true, + 'show_in_rest' => true, + 'rest_base' => 'strain-types', + 'rewrite' => [ 'slug' => 'strain-type' ], + 'show_admin_column' => true, + ] ); + + // โ”€โ”€ Effects (relaxed, euphoric, creative, โ€ฆ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_taxonomy( 'wo_effect', [ 'wo_strain', 'wo_product' ], [ + 'label' => __( 'Effects', 'weedops' ), + 'labels' => [ + 'name' => __( 'Effects', 'weedops' ), + 'singular_name' => __( 'Effect', 'weedops' ), + 'add_new_item' => __( 'Add Effect', 'weedops' ), + ], + 'hierarchical' => false, + 'show_in_rest' => true, + 'rest_base' => 'effects', + 'rewrite' => [ 'slug' => 'effect' ], + 'show_admin_column' => true, + ] ); + + // โ”€โ”€ Terpenes โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_taxonomy( 'wo_terpene', [ 'wo_strain', 'wo_product' ], [ + 'label' => __( 'Terpenes', 'weedops' ), + 'hierarchical' => false, + 'show_in_rest' => true, + 'rest_base' => 'terpenes', + 'rewrite' => [ 'slug' => 'terpene' ], + ] ); + + // โ”€โ”€ Product Category (flower / concentrate / edible / topical / โ€ฆ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_taxonomy( 'wo_product_cat', [ 'wo_product' ], [ + 'label' => __( 'Product Category', 'weedops' ), + 'hierarchical' => true, + 'show_in_rest' => true, + 'rest_base' => 'product-categories', + 'rewrite' => [ 'slug' => 'product-category' ], + ] ); + + // โ”€โ”€ Compliance Status โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + register_taxonomy( 'wo_compliance_status', [ 'wo_compliance', 'wo_product' ], [ + 'label' => __( 'Compliance Status', 'weedops' ), + 'hierarchical' => true, + 'show_in_rest' => true, + 'public' => false, + 'show_ui' => true, + ] ); +} +add_action( 'init', 'weedops_register_taxonomies' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Meta Field Registration (REST API + Gutenberg) +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_register_meta_fields(): void { + + // Strain meta + $strain_meta = [ + 'wo_thc_percent' => [ 'type' => 'number', 'label' => 'THC %', 'sanitize' => 'floatval' ], + 'wo_cbd_percent' => [ 'type' => 'number', 'label' => 'CBD %', 'sanitize' => 'floatval' ], + 'wo_genetics' => [ 'type' => 'string', 'label' => 'Genetics / Lineage', 'sanitize' => 'sanitize_text_field' ], + 'wo_flowering_time' => [ 'type' => 'integer', 'label' => 'Flowering Time (days)', 'sanitize' => 'absint' ], + 'wo_yield_indoor' => [ 'type' => 'string', 'label' => 'Indoor Yield', 'sanitize' => 'sanitize_text_field' ], + 'wo_yield_outdoor' => [ 'type' => 'string', 'label' => 'Outdoor Yield', 'sanitize' => 'sanitize_text_field' ], + 'wo_difficulty' => [ 'type' => 'string', 'label' => 'Grow Difficulty', 'sanitize' => 'sanitize_text_field' ], + ]; + + foreach ( $strain_meta as $key => $config ) { + register_post_meta( 'wo_strain', $key, [ + 'type' => $config['type'], + 'single' => true, + 'show_in_rest' => true, + 'description' => $config['label'], + 'sanitize_callback' => $config['sanitize'], + 'auth_callback' => fn() => current_user_can( 'edit_posts' ), + ] ); + } + + // Product meta + $product_meta = [ + 'wo_sku' => [ 'type' => 'string', 'label' => 'SKU / License #', 'sanitize' => 'sanitize_text_field' ], + 'wo_batch_id' => [ 'type' => 'string', 'label' => 'Batch ID', 'sanitize' => 'sanitize_text_field' ], + 'wo_lab_tested' => [ 'type' => 'boolean', 'label' => 'Lab Tested', 'sanitize' => 'rest_sanitize_boolean' ], + 'wo_coa_url' => [ 'type' => 'string', 'label' => 'COA (Certificate of Analysis) URL','sanitize' => 'esc_url_raw' ], + 'wo_price_gram' => [ 'type' => 'number', 'label' => 'Price per Gram', 'sanitize' => 'floatval' ], + 'wo_inventory_qty' => [ 'type' => 'integer', 'label' => 'Inventory Qty (g)', 'sanitize' => 'absint' ], + 'wo_origin_state' => [ 'type' => 'string', 'label' => 'Origin State', 'sanitize' => 'sanitize_text_field' ], + 'wo_license_no' => [ 'type' => 'string', 'label' => 'Producer License #', 'sanitize' => 'sanitize_text_field' ], + ]; + + foreach ( $product_meta as $key => $config ) { + register_post_meta( 'wo_product', $key, [ + 'type' => $config['type'], + 'single' => true, + 'show_in_rest' => true, + 'description' => $config['label'], + 'sanitize_callback' => $config['sanitize'], + 'auth_callback' => fn() => current_user_can( 'edit_posts' ), + ] ); + } +} +add_action( 'init', 'weedops_register_meta_fields' ); + +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Admin Meta Box โ€” Strain Details +// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +function weedops_add_strain_meta_box(): void { + add_meta_box( + 'wo_strain_details', + __( 'Strain Details', 'weedops' ), + 'weedops_render_strain_meta_box', + 'wo_strain', + 'normal', + 'high' + ); +} +add_action( 'add_meta_boxes', 'weedops_add_strain_meta_box' ); + +function weedops_render_strain_meta_box( WP_Post $post ): void { + wp_nonce_field( 'wo_save_strain_details', 'wo_strain_nonce' ); + + $thc = get_post_meta( $post->ID, 'wo_thc_percent', true ); + $cbd = get_post_meta( $post->ID, 'wo_cbd_percent', true ); + $genetics = get_post_meta( $post->ID, 'wo_genetics', true ); + $difficulty = get_post_meta( $post->ID, 'wo_difficulty', true ); + + // Strain type from taxonomy + $strain_types = get_the_terms( $post->ID, 'wo_strain_type' ); + $current_type = ( $strain_types && ! is_wp_error( $strain_types ) ) + ? $strain_types[0]->slug + : ''; + + // Effects from taxonomy + $effects_terms = get_terms( [ 'taxonomy' => 'wo_effect', 'hide_empty' => false ] ); + $assigned_effects = wp_get_post_terms( $post->ID, 'wo_effect', [ 'fields' => 'ids' ] ); + + ?> + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +
    + + +
    + + +
    + +
    + + + +
    +
    + + $type_slug ] ); + $term_id = is_wp_error( $inserted ) ? 0 : $inserted['term_id']; + } else { + $term_id = $term->term_id; + } + if ( $term_id ) { + wp_set_post_terms( $post_id, [ $term_id ], 'wo_strain_type' ); + } + } else { + wp_set_post_terms( $post_id, [], 'wo_strain_type' ); + } + } + + // Effects โ€” array of term IDs + $effect_ids = isset( $_POST['wo_effect_terms'] ) + ? array_map( 'absint', (array) $_POST['wo_effect_terms'] ) + : []; + wp_set_post_terms( $post_id, $effect_ids, 'wo_effect' ); +} +add_action( 'save_post_wo_strain', 'weedops_save_strain_meta' ); diff --git a/index.php b/index.php new file mode 100644 index 0000000..989abc8 --- /dev/null +++ b/index.php @@ -0,0 +1,144 @@ + + + +
    +

    +
    + + + + +
    + + +
    > + + + + + + +
    + slug ); + } + } + } elseif ( 'wo_product' === $post_type ) { + $cats = get_the_terms( get_the_ID(), 'wo_product_cat' ); + if ( $cats && ! is_wp_error( $cats ) ) { + echo ''; + echo esc_html( $cats[0]->name ); + echo ''; + } + } else { + echo ''; + echo esc_html( get_the_category_list( ', ' ) ); + echo ''; + } + ?> +
    + +

    + +

    + + + + + +

    + +

    + + + +
    + +
    + + + +
    + + +
    + + + + + + + +
    + +

    +

    + +

    +
    + +
    +
    + + + +
    +
    + + + + + +
    + + +
    > + +
    +
    + + 'strain-hero__img' ] ); ?> + +
    +
    + ๐ŸŒฟ + Product Image Coming Soon +
    +
    + +
    + +
    + + +

    + +
    + + + +
    + THC + % +
    +
    +
    +
    + + + +
    + CBD + % +
    +
    +
    +
    + +
    + + +
    +

    Effects

    +
    + + + +
    +
    + +
    +
    + + +
    +

    About This Strain

    +
    + +
    +
    + + +
    +

    โš ๏ธ For use only by adults 21+. Keep out of reach of children. This product has not been evaluated by the FDA.

    +
    + + + +
    + + +
    + + + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..d84883b --- /dev/null +++ b/style.css @@ -0,0 +1,393 @@ +/* +Theme Name: Weedops +Theme URI: https://weedops.site +Author: Weedops Dev Team +Author URI: https://weedops.site +Description: Cannabis industry product management and compliance platform theme. Built for dispensaries, growers, and cannabis brands. +Version: 1.0.0 +Requires at least: 6.0 +Tested up to: 6.7 +Requires PHP: 8.0 +License: Proprietary +License URI: https://weedops.site/license +Text Domain: weedops +Tags: cannabis, dispensary, woocommerce, compliance, inventory +*/ + +/* ============================================================ + WEEDOPS THEME โ€” Cannabis Industry Platform + Brand: Deep green (#1a3d2b), Gold (#c8a951), Off-white (#f5f0e8) + ============================================================ */ + +:root { + --wo-green-dark: #1a3d2b; + --wo-green-mid: #2e6b47; + --wo-green-light: #4a9e68; + --wo-gold: #c8a951; + --wo-gold-light: #e2c97a; + --wo-cream: #f5f0e8; + --wo-white: #ffffff; + --wo-text-dark: #1c1c1c; + --wo-text-muted: #666666; + --wo-border: #d4cfc6; + --wo-error: #c0392b; + --wo-success: #27ae60; + + --wo-font-sans: 'Inter', 'Helvetica Neue', Arial, sans-serif; + --wo-font-serif: 'Georgia', 'Times New Roman', serif; + --wo-font-mono: 'JetBrains Mono', 'Courier New', monospace; + + --wo-radius: 6px; + --wo-radius-lg: 12px; + --wo-shadow: 0 2px 8px rgba(0,0,0,0.12); + --wo-shadow-lg: 0 8px 32px rgba(0,0,0,0.18); + --wo-transition: 0.2s ease; +} + +/* โ”€โ”€ Reset โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +html { font-size: 16px; scroll-behavior: smooth; } + +body { + font-family: var(--wo-font-sans); + color: var(--wo-text-dark); + background-color: var(--wo-cream); + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +/* โ”€โ”€ Typography โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +h1, h2, h3, h4, h5, h6 { + font-weight: 700; + line-height: 1.25; + color: var(--wo-green-dark); +} + +h1 { font-size: clamp(1.8rem, 4vw, 2.8rem); } +h2 { font-size: clamp(1.4rem, 3vw, 2.1rem); } +h3 { font-size: clamp(1.1rem, 2.5vw, 1.5rem); } +h4 { font-size: 1.15rem; } + +p { margin-bottom: 1rem; } + +a { color: var(--wo-green-mid); text-decoration: none; transition: color var(--wo-transition); } +a:hover { color: var(--wo-gold); } + +/* โ”€โ”€ Layout โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-container { + width: 100%; + max-width: 1280px; + margin: 0 auto; + padding: 0 1.5rem; +} + +.wo-main { + min-height: calc(100vh - 80px - 160px); + padding: 2.5rem 0; +} + +.wo-grid { + display: grid; + gap: 1.5rem; +} + +.wo-grid--2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } +.wo-grid--3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } +.wo-grid--4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); } + +/* โ”€โ”€ Header โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-header { + background-color: var(--wo-green-dark); + border-bottom: 3px solid var(--wo-gold); + position: sticky; + top: 0; + z-index: 100; + box-shadow: var(--wo-shadow); +} + +.wo-header__inner { + display: flex; + align-items: center; + justify-content: space-between; + height: 70px; +} + +.wo-logo { + display: flex; + align-items: center; + gap: 0.6rem; + color: var(--wo-white); + font-size: 1.4rem; + font-weight: 800; + letter-spacing: -0.02em; +} + +.wo-logo span { color: var(--wo-gold); } +.wo-logo:hover { color: var(--wo-gold-light); } + +/* โ”€โ”€ Navigation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-nav ul { + display: flex; + align-items: center; + gap: 0.25rem; + list-style: none; +} + +.wo-nav a { + color: rgba(255,255,255,0.85); + padding: 0.5rem 0.9rem; + border-radius: var(--wo-radius); + font-size: 0.9rem; + font-weight: 500; + transition: background var(--wo-transition), color var(--wo-transition); +} + +.wo-nav a:hover, +.wo-nav .current-menu-item > a { + background: rgba(200,169,81,0.2); + color: var(--wo-gold-light); +} + +/* โ”€โ”€ Buttons โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-btn { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.6rem 1.2rem; + border-radius: var(--wo-radius); + font-size: 0.9rem; + font-weight: 600; + border: 2px solid transparent; + cursor: pointer; + transition: all var(--wo-transition); + text-decoration: none; + line-height: 1; +} + +.wo-btn--primary { + background: var(--wo-gold); + color: var(--wo-green-dark); + border-color: var(--wo-gold); +} +.wo-btn--primary:hover { + background: var(--wo-gold-light); + border-color: var(--wo-gold-light); + color: var(--wo-green-dark); +} + +.wo-btn--outline { + background: transparent; + color: var(--wo-green-dark); + border-color: var(--wo-green-mid); +} +.wo-btn--outline:hover { + background: var(--wo-green-dark); + color: var(--wo-white); +} + +/* โ”€โ”€ Cards โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-card { + background: var(--wo-white); + border-radius: var(--wo-radius-lg); + border: 1px solid var(--wo-border); + padding: 1.5rem; + box-shadow: var(--wo-shadow); + transition: box-shadow var(--wo-transition), transform var(--wo-transition); +} + +.wo-card:hover { + box-shadow: var(--wo-shadow-lg); + transform: translateY(-2px); +} + +/* โ”€โ”€ Strain / Product badges โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-badge { + display: inline-flex; + align-items: center; + padding: 0.2rem 0.6rem; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.wo-badge--indica { background: #3d1a5e; color: #e8ccff; } +.wo-badge--sativa { background: #1a3d1a; color: #ccffcc; } +.wo-badge--hybrid { background: #3d2e1a; color: #ffe0b2; } +.wo-badge--cbd { background: #1a2e3d; color: #b3d9ff; } + +/* โ”€โ”€ Compliance tags โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-compliance-tag { + display: inline-flex; + align-items: center; + gap: 0.3rem; + padding: 0.25rem 0.7rem; + border-radius: var(--wo-radius); + font-size: 0.78rem; + font-weight: 600; + border: 1px solid currentColor; +} + +.wo-compliance-tag--ok { color: var(--wo-success); } +.wo-compliance-tag--warning { color: var(--wo-gold); } +.wo-compliance-tag--fail { color: var(--wo-error); } + +/* โ”€โ”€ Footer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-footer { + background: var(--wo-green-dark); + color: rgba(255,255,255,0.7); + padding: 2.5rem 0 1.5rem; + margin-top: auto; +} + +.wo-footer__grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 2rem; + margin-bottom: 2rem; +} + +.wo-footer__brand .wo-logo { font-size: 1.2rem; margin-bottom: 0.75rem; } +.wo-footer p { font-size: 0.85rem; line-height: 1.7; } + +.wo-footer h4 { + color: var(--wo-gold); + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-bottom: 0.75rem; +} + +.wo-footer ul { list-style: none; } +.wo-footer ul li { margin-bottom: 0.4rem; } +.wo-footer ul a { color: rgba(255,255,255,0.65); font-size: 0.875rem; } +.wo-footer ul a:hover { color: var(--wo-gold-light); } + +.wo-footer__bottom { + border-top: 1px solid rgba(255,255,255,0.12); + padding-top: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.8rem; + flex-wrap: wrap; + gap: 0.5rem; +} + +/* โ”€โ”€ Age-gate / Compliance notice โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-age-notice { + background: var(--wo-green-dark); + color: var(--wo-cream); + text-align: center; + padding: 0.5rem 1rem; + font-size: 0.8rem; + border-bottom: 1px solid var(--wo-gold); +} + +/* โ”€โ”€ Hero (Photography Style) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-hero { + position: relative; + min-height: 85vh; + display: flex; + align-items: center; + justify-content: center; + background: + url('assets/img/hero-cannabis.jpg') + center center / cover + no-repeat; + overflow: hidden; +} + +.wo-hero__overlay { + position: absolute; + inset: 0; + background: linear-gradient( + 160deg, + rgba(26, 61, 43, 0.88) 0%, + rgba(26, 61, 43, 0.55) 50%, + rgba(0, 0, 0, 0.40) 100% + ); + z-index: 1; +} + +.wo-hero__content { + position: relative; + z-index: 2; + max-width: 720px; + padding: 3rem 2rem; + text-align: center; +} + +.wo-hero__eyebrow { + display: inline-block; + font-size: 0.78rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.18em; + color: var(--wo-gold); + margin-bottom: 1.25rem; + padding: 0.35rem 1rem; + border: 1px solid rgba(200, 169, 81, 0.4); + border-radius: 999px; +} + +.wo-hero__title { + font-size: clamp(2rem, 5vw, 3.4rem); + font-weight: 800; + line-height: 1.12; + color: var(--wo-white); + margin-bottom: 1.25rem; + letter-spacing: -0.02em; +} + +.wo-hero__subtitle { + font-size: clamp(1rem, 2vw, 1.2rem); + color: rgba(255, 255, 255, 0.85); + line-height: 1.7; + margin-bottom: 2rem; +} + +.wo-hero__actions { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; +} + +.wo-btn--lg { + padding: 0.85rem 1.8rem; + font-size: 1rem; +} + +.wo-btn--ghost { + background: transparent; + color: var(--wo-white); + border-color: rgba(255, 255, 255, 0.5); +} +.wo-btn--ghost:hover { + background: rgba(255, 255, 255, 0.12); + border-color: var(--wo-white); + color: var(--wo-white); +} + +/* โ”€โ”€ Sections โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-section { padding: 1rem 0; } + +/* โ”€โ”€ Utilities โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.wo-text-center { text-align: center; } +.wo-text-muted { color: var(--wo-text-muted); } +.wo-mt-1 { margin-top: 0.5rem; } +.wo-mt-2 { margin-top: 1rem; } +.wo-mt-3 { margin-top: 1.5rem; } +.wo-mb-2 { margin-bottom: 1rem; } +.wo-mb-3 { margin-bottom: 1.5rem; } +.wo-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); } + +/* โ”€โ”€ Responsive โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +@media (max-width: 768px) { + .wo-header__inner { height: 60px; } + .wo-nav { display: none; } /* mobile nav handled by JS toggle */ + .wo-footer__bottom { flex-direction: column; text-align: center; } +}