'#0B0B0C', 't' => '#1F4B5E', 'r' => '#D40000'];
const GATE_DOTS = [
[34, 86, 3.4, 'k'],
[64, 86, 3.8, 'r'],
[24, 86, 3.8, 'k'],
[74, 86, 3.4, 'k'],
[14, 86, 3.4, 'k'],
[84, 86, 3.8, 't'],
[34, 76, 3.4, 'k'],
[64, 76, 3.4, 'k'],
[24, 76, 3.4, 't'],
[74, 76, 3.8, 'k'],
[14, 76, 3.8, 'k'],
[84, 76, 3.4, 'k'],
[34, 66, 3.4, 't'],
[64, 66, 3.8, 'k'],
[24, 66, 3.8, 'k'],
[74, 66, 3.4, 'k'],
[14, 66, 3.4, 'k'],
[84, 66, 3.8, 'r'],
[34, 56, 3.8, 'k'],
[64, 56, 3.4, 'k'],
[24, 56, 3.4, 'k'],
[74, 56, 3.8, 't'],
[14, 56, 3.8, 'k'],
[84, 56, 3.4, 'k'],
[34, 46, 3.4, 'k'],
[64, 46, 3.8, 'k'],
[24, 46, 3.8, 'k'],
[74, 46, 3.4, 'k'],
[14, 46, 3.4, 't'],
[84, 46, 3.8, 'k'],
[44, 36, 3.8, 't'],
[54, 36, 3.8, 'k'],
[34, 36, 3.4, 'k'],
[64, 36, 3.4, 'k'],
[24, 36, 3.8, 'r'],
[74, 36, 3.8, 'k'],
[14, 36, 3.4, 'k'],
[84, 36, 3.4, 'k'],
[44, 26, 3.4, 'k'],
[54, 26, 3.8, 'k'],
[34, 26, 3.8, 'k'],
[64, 26, 3.4, 't'],
[24, 26, 3.4, 'k'],
[74, 26, 3.8, 'k'],
[14, 26, 3.8, 'k'],
[84, 26, 3.4, 'k'],
[44, 16, 3.8, 'k'],
[54, 16, 3.4, 'k'],
[34, 16, 3.8, 't'],
[64, 16, 3.8, 'k'],
[24, 16, 3.4, 'k'],
[74, 16, 3.4, 'r']
];
/** The simplified 5 by 5 gate, for anything drawn below 32 px (the brand pack's mark-small). */
const GATE_SMALL = [[32, 14, 6.5, 't'], [50, 14, 6.5, 'k'], [68, 14, 6.5, 'k'], [14, 32, 6.5, 'k'], [32, 32, 6.5, 'k'], [50, 32, 6.5, 'k'], [68, 32, 6.5, 'k'], [86, 32, 6.5, 'k'], [14, 50, 6.5, 't'], [32, 50, 6.5, 'k'], [68, 50, 6.5, 'k'], [86, 50, 6.5, 'k'], [14, 68, 6.5, 'k'], [32, 68, 6.5, 'k'], [68, 68, 6.5, 't'], [86, 68, 6.5, 'k'], [14, 86, 6.5, 'k'], [32, 86, 6.5, 'k'], [68, 86, 6.5, 'k'], [86, 86, 6.5, 'k'], [50, 78, 9, 'r']];
function gatecraft_mark_small(string $variant = 'color', string $class = 'gc-mark-sm'): string
{
$rev = $variant === 'reversed';
$out = '';
}
/** The admin always looks like Gatecraft: these replace the organiser's colour inside the admin. Front-end branding is in Settings. */
/** The Gatecraft lockup: the mark and the wordmark. */
function gatecraft_lockup(bool $dark = false, string $href = '/admin'): string
{
return '' . gatecraft_mark($dark ? 'reversed' : 'color', 'brand-gc-mark')
. '';
}
/** Where Gatecraft lives on the web, for the "Powered by" link. Empty: the line is shown without a link. */
defined('GATECRAFT_HOME_URL') || define('GATECRAFT_HOME_URL', '');
/**
* The gate as inline SVG.
* level how much of the gate is filled, in dots (0 to 52, fractions allowed). Whole dots are drawn at full strength in
* fill order; the next dot is filled from the bottom by the fraction (by area); the rest are faint outlines.
* 52 = the full mark.
* guest draw the red guest in the doorway
* ring index of the dot to ring (a guest's own place on their ticket), or null
* variant color (light backgrounds) or reversed (dark backgrounds)
*/
function gate_svg(float $level = 52, bool $guest = true, ?int $ring = null, string $variant = 'color', string $label = 'Gatecraft', string $class = 'gc-gate'): string
{
static $uid = 0;
$rev = $variant === 'reversed';
$n = count(GATE_DOTS);
$level = max(0.0, min((float)$n, $level));
$whole = (int)floor($level + 1e-9);
$frac = $level - $whole;
$out = '';
}
/** Height, as a share of the diameter, of the bottom slice of a circle that holds $share of its area. */
function gate_fill_height(float $share): float
{
$lo = 0.0; $hi = 1.0;
for ($k = 0; $k < 30; $k++) {
$m = ($lo + $hi) / 2;
$d = 1 - 2 * $m; // distance of the cut line from the centre, as a share of the radius
$area = (acos($d) - $d * sqrt(1 - $d * $d)) / M_PI;
if ($area < $share) $lo = $m; else $hi = $m;
}
return ($lo + $hi) / 2;
}
/** The Gatecraft mark, drawn from the same data. */
function gatecraft_mark(string $variant = 'color', string $class = 'gc-mark'): string
{
return gate_svg(count(GATE_DOTS), true, null, $variant, 'Gatecraft', $class);
}
/** Total places for an event: the places in its active ticket categories, capped by the event's or the venue's capacity. Null when there are none. */
function event_places(array $ev): ?int
{
$sum = (int)qv('SELECT COALESCE(SUM(capacity), 0) FROM {ticket_categories} WHERE event_id = ? AND is_active = 1 AND capacity > 0', [(int)$ev['id']]);
$cap = event_cap($ev);
$places = $cap !== null && $sum > 0 ? min($cap, $sum) : ($cap ?? $sum);
return $places > 0 ? $places : null;
}
/** The living gate of an event: places, places taken, dots filled and whether the doors are open. Null when the event has no limit. */
function event_gate(array $ev, ?array $held = null): ?array
{
$places = event_places($ev);
if (!$places) return null;
$taken = min($places, ($held ?? held_counts((int)$ev['id']))['total']);
$level = $taken / $places * count(GATE_DOTS); // the share of places taken, as an exact share of the gate
$doorsAt = lstrtotime((string)($ev['doors_at'] ?: $ev['starts_at']));
$endAt = lstrtotime((string)($ev['ends_at'] ?: $ev['starts_at'])) + ($ev['ends_at'] ? 0 : 6 * 3600);
$open = $ev['status'] === 'published' && time() >= $doorsAt && time() <= $endAt;
return ['places' => $places, 'taken' => $taken, 'level' => $level, 'share' => $taken / $places, 'doors' => $open, 'full' => $taken >= $places];
}
/** True when the site may leave "Powered by Gatecraft" off its public pages, tickets and emails (an add-on option). */
function powered_by_hidden(): bool
{
return (bool)apply_filters('gatecraft_hide_powered_by', false);
}
/** "Powered by Gatecraft". Off on the public site and in emails unless the site owner turns it on (guideline 10). The admin always shows it. */
function powered_by(string $variant = 'color', ?string $href = null): string
{
$mark = gatecraft_mark_small($variant, 'gc-pw-mark');
$inner = $mark . 'Powered by Gatecraft';
$cls = 'gc-powered gc-powered-' . ($variant === 'reversed' ? 'rev' : 'std');
$href ??= GATECRAFT_HOME_URL;
if ($href === '') return '